ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

ERPNext v6.25 变更深度解析:财务报表零值隐藏、库存结存强制筛选与打印、结算细节优化

ERPNext v6.25 变更深度解析:财务报表零值隐藏、库存结存强制筛选与打印、结算细节优化 后端企业应用【免费下载链接】erpnextFree and Open Source Enterprise Resource Planning (ERP)项目地址https://gitcode.com/GitHub_Trending/er/erpnext点击查看免费下载本文基于 ERPNext 仓库中 v6.25 变更日志 展开系统梳理该版本在财务报表展示、库存报表筛选、单据打印模板与 POS 结算四个方向上的关键改动并结合仓库源码逐一还原其底层实现机制。读完本文你将理解零值账户隐藏的判定逻辑、Stock Balance 报表的筛选约束、Compact Item Print 的列合并原理、全局禁用金额大写In Words的实现方式以及 POS 默认付款方式非现金时 Paid Amount 计算的修正思路。v6.25 是 ERPNext 在 v6 系列中期的一个“体验打磨型”版本它不引入新模块而是集中修正报表可读性、打印输出质量与 POS 结算准确性。其中多项改动如 Compact Item Print与前一版本 v6.22 的功能一脉相承共同构成了当时打印与报表体系的完整优化闭环。一、资产负债表与损益表隐藏余额为零的账户1.1 变更内容Improved logic to hide accounts with zero values in Balance Sheet and Profit Lossv6.25 优化了**资产负债表Balance Sheet与损益表Profit Loss**中对余额为零账户的隐藏逻辑。在此之前即使账户没有发生额也会在报表中占据一行导致财务报表冗长难读此版本后只要账户在所选期间内所有列的值均为零该行及其空父级科目将不再出现在报表中。1.2 底层实现从has_value到filter_out_zero_value_rows该能力由财务报表共用引擎 financial_statements.py 提供。报表在组装每一行时会先按币种精度阈值判断该行是否“有值”if abs(row[period.key]) get_zero_cutoff(company_currency): # ignore zero values has_value True row[has_value] has_value见 financial_statements.py随后由filter_out_zero_value_rows完成真正的“剪枝”def filter_out_zero_value_rows(data, parent_children_map, show_zero_valuesFalse): def get_all_parents(account, parent_children_map): for parent, children in parent_children_map.items(): for child in children: if child[name] account and parent: accounts_to_show.add(parent) get_all_parents(parent, parent_children_map) data_with_value [] accounts_to_show set() for d in data: if show_zero_values or d.get(has_value): accounts_to_show.add(d.get(account)) get_all_parents(d.get(account), parent_children_map) for d in data: if d.get(account) in accounts_to_show: data_with_value.append(d) return data_with_value见 financial_statements.py其核心逻辑是遍历所有行凡has_value为 True 的账户或用户显式勾选了 “Show zero values”进入“待展示集合”通过get_all_parents递归向上收集其父级科目——即使父科目本身余额为零只要存在非零子科目父级也必须保留以维持报表的层级结构最终仅输出待展示集合内的行从而同时隐藏“自身为零且无有效子项”的叶子账户和“整棵子树都为空”的父级账户。1.3 哪些报表受益filter_out_zero_value_rows目前被以下报表复用报表调用位置资产负债表 Balance Sheetbalance_sheet.py损益表 Profit Lossprofit_and_loss_statement.py合并财务报表 Consolidated Financial Statementconsolidated_financial_statement.py合并试算表 Consolidated Trial Balanceconsolidated_trial_balance.py维度账户余额报表 Dimension-wise Accounts Balancedimension_wise_accounts_balance_report.py在报表前端Balance Sheet 与 PL 均提供了“Show zero values”复选框见 balance_sheet.js默认不勾选。也就是说默认隐藏零值账户勾选后恢复展示——这正是 v6.25 “改进隐藏逻辑”后形成的最终交互形态。实操提示当你的资产负债表“莫名缺少”某些长期未使用、余额为零的科目时多半不是数据丢失而是零值隐藏逻辑生效勾选 “Show zero values” 即可核对。二、Stock Balance 报表强制提供 Item Code 或 Warehouse 筛选2.1 变更内容Item Code or Warehouse filter mandatory in Stock Balance Reportv6.25 起库存结存Stock Balance报表要求用户在运行报表前必须提供Item Code物料或Warehouse仓库筛选条件之一。其动机非常直观Stock Balance 以“物料 × 仓库”为基本聚合维度源码中分组键即(item_code, warehouse)见 stock_balance.py若两者都不限定报表会一次性扫描全公司全部物料的全部仓库既拖慢查询又难以阅读限定任一维度后数据范围被显著收敛报表输出才具备实际分析价值。2.2 报表过滤器结构当前版本中Stock Balance 的过滤器定义集中在共享的 stock_balance_report.js并由 stock_balance.js 以及serial_and_batch_wise_stock_balance等衍生报表复用。其中与筛选约束相关的关键字段包括Itemsitem_codeMultiSelectList类型支持多选物料并通过item_query联动 Item Group 过滤WarehouseswarehouseMultiSelectList类型支持多选仓库可联动 Warehouse Type 与 CompanyInclude Zero Stock Items默认开启控制是否展示余额为零的行。2.3 与零库存行隐藏的联动与第一条改动类似Stock Balance 报表自身也有零值行处理逻辑。在数据组装阶段def is_hidden_zero_stock(self, row) - bool: return not self.filters.get(include_zero_stock_items) and row.bal_qty 0 and row.bal_val 0见 stock_balance.py即当include_zero_stock_items未勾选时期末数量与期末价值同时为零的行会被跳过。配套的单元测试 test_stock_balance.py 专门验证了这一行为——先产生数量为 5 的入库再产生数量为 5 的移库使余额净零此时默认过滤器返回空结果集只有开启include_zero_stock_items后行才会出现。测试同时断言了报表的核心不变量bal_qty opening_qty in_qty - out_qty、bal_val与 Stock Ledger Entry 的qty_after_transaction/stock_value一致为报表正确性提供了自动化保障。实操提示v6.25 引入的“强制筛选”与“零库存行隐藏”是两个独立维度——前者限定查询范围后者控制零值行的显隐。排查“报表行数异常少”时应先确认 Item Code / Warehouse 是否已限定再确认include_zero_stock_items开关状态。三、Compact Item Print将物料多列合并进 Description 列3.1 变更内容For Item table print, combine Item Code, Item Name, Description and additional columns in Description only ifCompact Item Printis checked inFeatures Setupv6.25 对上一版本v6.22引入的Compact Item Print做了关键增强。v6.22 首次提供该开关见 v6_22_0.md使 Item 表在打印时仅展示 “Description、Quantity、Rate、Amount” 四列v6.25 在此基础上进一步规定当 Compact Item Print 开启时Item Code、Item Name、Description 以及其余附加列将全部合并进 Description 单元格内以“标签: 值”的形式逐行呈现而不是各自独占一列。3.2 配置入口该开关并非 Frappe 自带字段而是 ERPNext 安装时通过自定义字段注入到Print Settings中的def create_print_setting_custom_fields(): create_custom_fields( { Print Settings: [ { label: _(Compact Item Print), fieldname: compact_item_print, fieldtype: Check, default: 1, insert_after: with_letterhead, }, ... ] } )见 setup/install.py注意两点一是字段默认值即为1默认开启紧凑打印二是变更日志所称 “Features Setup” 在当时的界面中即指打印设置相关配置该开关字段位于 Print Settings在现代版本中可通过Setup Customize Print Settings调整。3.3 实现机制模板分发与列裁剪核心逻辑位于 controllers/print_settings.pydoc.flags.compact_item_fields [description, qty, rate, amount] if settings.compact_item_print: doc.child_print_templates[items][ description ] templates/print_formats/includes/item_table_description.html doc.flags.format_columns format_columns即开启紧凑打印后定义“紧凑字段集”为description / qty / rate / amount将 description 单元格的渲染模板替换为专用的 item_table_description.html挂载format_columns用于把image、item_code、item_name追加进紧凑字段集使它们在表格列头中被排除、转而进入 Description 单元格渲染。在 items.html 中列头与单元格的可见性均由同一条件控制{% if (data and not print_settings.compact_item_print) or tdf.fieldname in doc.flags.compact_item_fields %} th ...{{ _(tdf.label) }}/th {% endif %}因此开启紧凑打印后表格只保留 Sr、Description、Qty、Rate、Amount 等核心列而 item_table_description.html 会在 Description 单元格内依次渲染Item Codecompact模式下以加粗主标题样式展示Item Name当与 Item Code 不同时展示Description文本其余所有被排除的附加列以字段标签: 格式化值的形式逐行罗列columns即format_columns裁剪后的结果。这套机制的好处是单据的打印版式不再受限于物料主数据中“Item Code/Name/Description 各不相同”或“附加列很多”的情况所有信息都收纳进一个自适应的 Description 区块特别适合小票、送货单等窄幅打印场景。四、全局禁用金额大写In Words4.1 变更内容Disable In Wordsfrom all documents via Setup Global Settingsv6.25 在Setup Global Settings中新增了Disable In Words开关允许管理员一次性隐藏全部业务单据上的金额大写In Words字段无需逐个单据修改。对于不使用英文大写金额表述或打印模板已不需要该字段的企业这是一个显著的配置简化。4.2 实现机制Property Setter 批量隐藏字段定义与联动逻辑位于 global_defaults.pydisable_in_words: DF.Check见 global_defaults.py保存 Global Defaults 时toggle_in_words会对所有受影响的单据批量生成 Property Setterdef toggle_in_words(self): # Make property setters to hide in words fields for doctype in ROUNDED_TOTAL_DOCTYPES: make_property_setter( doctype, in_words, hidden, cint(self.disable_in_words), Check, validate_fields_for_doctypeFalse, ) make_property_setter( doctype, in_words, print_hide, cint(self.disable_in_words), Check, validate_fields_for_doctypeFalse, )见 global_defaults.py它同时下发hidden表单内隐藏与print_hide打印时隐藏两条 Property Setter即一处勾选表单与打印输出同步失效。影响范围由ROUNDED_TOTAL_DOCTYPES常量决定ROUNDED_TOTAL_DOCTYPES ( Quotation, Sales Order, POS Invoice, Sales Invoice, Delivery Note, Supplier Quotation, Purchase Order, Purchase Invoice, Purchase Receipt, )见 global_defaults.py覆盖了采购、销售、POS 三条主链路上的全部核心单据。4.3 与大写生成逻辑的关系值得注意的是该开关只是隐藏字段并不会关闭大写金额的计算。单据保存时大写金额仍由各控制器生成例如采购侧 buying_controller.py 与销售侧 selling_controller.py 的set_total_in_words()def set_total_in_words(self): from frappe.utils import money_in_words if self.meta.get_field(in_words): if self.meta.get_field(rounded_total) and not self.is_rounded_total_disabled(): amount abs(flt(self.rounded_total)) else: amount abs(flt(self.grand_total)) self.in_words money_in_words(amount, self.currency)见 buying_controller.py金额取值遵循“启用舍入总额时用rounded_total否则用grand_total”的规则而舍入开关本身也来自 Global Defaultsdisable_rounded_total判断逻辑见 accounts_controller.py。因此Disable In Words与Disable Rounded Total是彼此独立的两组开关前者只管显示后者影响金额计算口径。五、Bug 修复POS 默认付款方式非现金时的 Paid Amount5.1 变更内容与问题背景Bug fix: Paid Amount in POS view when the default Mode of Payment is not Cash这是 v6.25 收录的一处 POS 结算缺陷修复。在 POS 界面中新建单据会根据POS Profile的默认付款方式自动预填付款行POS Profile 中对应字段为set_grand_total_to_default_mop见 pos_invoice.py。当默认付款方式是现金Cash时传统逻辑按“实收现金 → 计算找零”的思路工作正常但当默认付款方式被设置为银行卡、移动支付等非现金方式时预填的付款行金额与最终paid_amount的计算曾出现偏差导致单据在付款环节显示错误的已付金额。5.2 修复相关的结算逻辑修复后的结算金额计算集中在 POS Invoice 的update_payments白名单方法中见 pos_invoice.pypaid_amount flt(self.paid_amount) total flt(self.rounded_total) or flt(self.grand_total) if paid_amount total: frappe.throw(title_(Invoice Paid), msg_(This invoice has already been paid.)) for d in payments: payment create_payments_on_invoice(self, idx, frappe._dict(d)) paid_amount flt(payment.amount) self.append(payments, payment) self.save() paid_amount flt(flt(paid_amount), self.precision(paid_amount)) base_paid_amount flt(flt(paid_amount * self.conversion_rate), self.precision(base_paid_amount)) outstanding_amount ( flt(flt(total - paid_amount), self.precision(outstanding_amount)) if total paid_amount else 0 ) change_amount ( flt(flt(paid_amount - total), self.precision(change_amount)) if paid_amount total else 0 )关键点在于paid_amount不再单纯依赖“现金”假设而是以单据当前已付金额为基数逐行累加传入的付款记录金额再按单据精度统一回写paid_amount、base_paid_amount、outstanding_amount与change_amount四个字段。change_amount仅在“已付金额大于应付款总额”时才会产生从逻辑上天然兼容任何默认付款方式。此外reset_mode_of_payments见 pos_invoice.py会在 POS Profile 变更时重置付款行并清零paid_amount避免跨 Profile 切换时残留旧付款数据。实操提示升级后若发现 POS 单据付款金额异常可重点检查 POS Profile 中“默认付款方式”与set_grand_total_to_default_mop的组合配置该修复确保的是“任何默认付款方式下已付金额都按付款行实算”而非特定付款方式专属行为。六、版本背景与升级建议v6.25 属于 v6 系列的中期维护版本全部改动均围绕“报表可读性、打印可控性、结算准确性”三条主线不含破坏性的数据模型变更升级成本较低。从仓库的 change_log/v6 目录结构看v6 系列其余版本同样以类似的短条目形式记录迭代便于对照排查历史行为变化。升级或配置时建议按以下顺序验证财务报表勾选/取消 “Show zero values”确认资产负债表与损益表的行数随零值账户显隐正确变化库存报表确认 Stock Balance 在未提供 Item Code/Warehouse 时无法全量运行并提供后可正常出数打印模板在 Print Settings 中切换 Compact Item Print预览 Sales Invoice / Purchase Invoice 的 Item 表列结构是否符合预期Global Settings勾选 Disable In Words 后抽查上述 9 类单据的表单与打印预览确认 in_words 字段均已隐藏POS 结算将默认付款方式分别设为现金与非现金各做一笔完整销售核对 paid_amount、outstanding_amount 与 change_amount 的联动结果。赞分享后端企业应用【免费下载链接】erpnextFree and Open Source Enterprise Resource Planning (ERP)项目地址https://gitcode.com/GitHub_Trending/er/erpnext点击查看免费下载相关推荐ERPNext v5.0.25 变更日志深度解读财务报告性能、制造校验与采购销售细节优化ERPNext v5.0.25 变更日志深度解读财务报告性能、制造校验与采购销售细节优化 本篇指南围绕开源 ERP 项目 ERPNext 的 v5.0.25后端企业应用ERPNext v15.56.0版本深度解析库存与财务模块的重大优化ERPNext v15.56.0版本深度解析库存与财务模块的重大优化 项目简介 ERPNext是一款开源的综合性企业资源规划系统涵盖了财务、库存、制造、销售后端企业应用ERPNext v6.26 变更实战解读财务年度从交易单据退场、假日列表区间化与库存报表性能治理ERPNext v6.26 变更实战解读财务年度从交易单据退场、假日列表区间化与库存报表性能治理 本篇文章基于 erpnext/change_log/v6/v后端企业应用上一篇终极 Temporal Polyfill 指南现代 JavaScript 日期时间处理的完整解决方案下一篇React Native Audio Toolkit安装与使用指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表