☰
ERPNext v13.0.2 版本修复深度解读:销售退货入价、意大利电子发票与调度器检查机制
2026/10/1 1:59:01 网站建设 项目流程
  • 后端
  • 企业应用

【免费下载链接】erpnext

Free and Open Source Enterprise Resource Planning (ERP)

项目地址:https://gitcode.com/GitHub_Trending/er/erpnext
点击查看免费下载

导读

本文基于当前仓库中的官方版本说明 erpnext/change_log/v13/v13_0_2.md,逐条拆解 ERPNext 13.0.2 补丁版本包含的四项核心修复:DocType 方法的frappe.whitelist授权、销售退货(Credit Note)的入库价(incoming rate)计算错误、意大利 e-invoicing(电子发票)的校验与税额计算,以及调度器检查时间的更新。通过结合仓库内的源码实现与测试用例,你将理解每项修复背后的业务逻辑、触发场景与底层调用链,从而能在自己的 ERPNext 实例中准确判断升级影响、排查相关问题。

一、v13.0.2 版本概览:一次聚焦正确性的补丁发布

v13_0_2.md全文虽然精炼,却精确列出了该补丁版本的完整修复清单,全部为 bugfix(修复)性质,不涉及新增功能或破坏性变更:

  • fix: frappe.whitelist for doc methods(PR #25231)
  • fix: incorrect incoming rate for the sales return(PR #25306)
  • fix(e-invoicing): validations & tax calculation fixes(PR #25314)
  • fix: update scheduler check time(PR #25295)

从修复类型可以推断,13.0.2 的目标是提升凭证处理(特别是退货场景)、区域化合规(意大利电子发票)和系统后台调度三个方向的正确性。仓库中完整的版本演进记录集中在 erpnext/change_log 目录,其中 v13 的历史版本说明位于 erpnext/change_log/v13,可作为对比相邻补丁变更范围的参考。

二、修复一:为 DocType 方法正确启用 frappe.whitelist(PR #25231)

2.1 修复背景

在 Frappe 框架中,服务端方法默认不允许被客户端(浏览器或移动端)直接调用。只有通过@frappe.whitelist()装饰器标记的方法,才能通过frappe.call从前端安全调用,同时仍会执行框架内置的权限检查。当 Controller(DocType 控制器)中的自定义方法缺少正确标记,或装饰器与框架对 doc methods 的识别逻辑存在偏差时,前端调用会抛出 "Method not found" 或权限类错误。

2.2 仓库内的实际用法

在当前仓库中,@frappe.whitelist()遍布各类 DocType 控制器。例如 账户余额时间线数据源 在数据源类上直接标注@frappe.whitelist();账户 Doctype 控制器 内多个方法(第 459、470、503、555、620、659 行附近)均通过@frappe.whitelist()暴露给报表和前端工具调用;科目表导入 中也有多处同类用法。此外,批量付款工具 的入口方法同样使用了@frappe.whitelist()。

这一修复的意义在于:确保这些作为文档方法(doc method,即隶属于 Doctype 控制器的实例方法)暴露的接口,在经过frappe.get_doc(...)获取文档实例后依然能被白名单机制正确识别,从而避免因装饰器判定逻辑差异导致的调用失败。

三、修复二:销售退货入库价(incoming rate)计算修正(PR #25306)

3.1 问题现象

当用户基于销售发票(Sales Invoice)或交货单(Delivery Note)创建销售退货(Credit Note)时,系统需要确定退回物品的"入库价",用于生成库存估价分录(stock value difference)。在 13.0.2 之前的某些路径下,退货行使用了错误的 incoming rate,导致库存价值(stock balance)与总账(GL Entry)之间出现偏差。

3.2 底层实现:get_rate_for_return 的取价链路

退货取价的核心逻辑位于 erpnext/controllers/sales_and_purchase_return.py 中的get_rate_for_return()函数(约第 766 行起)。其取价优先级可以概括为:

  1. 采购侧直接读取库存分录的 incoming_rate 字段:当凭证类型为 Purchase Receipt、Purchase Invoice 或 Subcontracting Receipt 时,直接查询 Stock Ledger Entry 上的incoming_rate列;
  2. 销售侧按库存分录计算:对 Sales Invoice / Delivery Note,则从 Stock Ledger Entry 计算ABS(stock_value_difference / actual_qty),即实际入库均价;
  3. 回退到凭证行的 incoming_rate:若上述取不到值且存在return_against,则读取销售明细行上缓存的incoming_rate字段;
  4. 调用 _get_incoming_rate 兜底:仍未取到时,调用 erpnext/stock/utils.py 中的_get_incoming_rate()(封装入口为get_incoming_rate(),约第 292–308 行),按批次、序列号或 FIFO/Moving Average 估值方法重新计算入库价;
  5. 最终兜底为销售价:当物品允许零估值(allow_zero_valuation_rate)未开启时,直接使用明细行的rate作为退货入库价,保证退货分录不会因估价缺失而中断。

此外,该函数还处理了一个边界场景:当启用set_zero_rate_for_expired_batch且退货涉及已过期批次时,会将退货行的incoming_rate显式置为 0 后返回,避免过期批次以错误价格入库。

3.3 相关佐证:调整入库价与测试

  • 采购发票侧的adjust_incoming_rate开关在 billing_status.py(第 77 行)与 gl_composer.py(第 174、375 行附近)中被读取,用于在退货/成本调整时修正入库价,说明 incoming rate 的准确性直接影响 GL 分录组成;
  • 仓库测试 test_purchase_invoice.py 包含多组针对入库价调整与多币种、部分结算场景的断言(如第 2161、2269、2318、3390、3446 行附近的用例),验证默认计算与调整后的入库价数值;
  • 销售发票侧测试 test_sales_invoice.py(第 2022–2028 行附近)也断言了退货/出货场景下incoming_rate与stock_value_difference的一致性。

因此,13.0.2 的该修复本质上是修正了销售退货场景下入库价取值路径的优先级与兜底逻辑,确保 Credit Note 的库存估价与成本核算更贴近实际入库成本。

四、修复三:意大利 e-invoicing 校验与税额计算(PR #25314)

4.1 修复范围

fix(e-invoicing)针对的是 ERPNext 的意大利地区化电子发票模块。意大利自 2019 年起强制企业通过 Sistema di Interscambio (SDI) 提交电子发票(fattura elettronica),因此 ERPNext 在提交销售发票时需同步生成符合 FatturaPA 规范的 XML 附件。13.0.2 的该修复集中于两处:提交前的数据完整性校验(validations)与税额汇总计算(tax calculation)。

4.2 提交前校验:sales_invoice_validate

实现位于 erpnext/regional/italy/utils.py 的sales_invoice_validate()(约第 221 行起),该函数作为 Sales Invoice 的 validate 钩子执行,校验项包括:

  • 公司侧:必须设置公司地址(company_address)且地址含 pincode、city、country_code;公司必须设置税制(fiscal_regime)、税号(tax_id)与财政代码(fiscal_code);
  • 客户侧:个人客户必须设置 fiscal_code;公共行政机构(is_public_administration)需设置 fiscal_code,其余企业客户需设置 tax_id;必须存在客户地址;
  • 税务侧:Taxes and Charges 表至少一行;若税率为 0 且税额为 0,则必须填写免税理由(tax_exemption_reason);
  • 付款侧:付款计划(payment_schedule)中的付款方式缺失时,自动回填对应mode_of_payment_code。

同时在提交钩子sales_invoice_on_submit()(约第 305 行起)中,若公司所在国家为意大利(含 Italia、Italian Republic、Repubblica Italiana 等写法),会强制校验付款方式及其代码,随后调用prepare_and_attach_invoice()生成 XML 附件;取消发票时由sales_invoice_on_cancel()清理对应附件。

4.3 税额计算修正

update_itemised_tax_data()(第 14 行起)按物品明细重算税额:

row.tax_rate = flt(tax_rate, row.precision("tax_rate")) row.tax_amount = flt((row.net_amount * tax_rate) / 100, row.precision("net_amount")) row.total_amount = flt((row.net_amount + row.tax_amount), row.precision("total_amount"))

即tax_amount = net_amount × tax_rate / 100,total_amount = net_amount + tax_amount,并依据字段精度做浮点规整——这正是"税计算修正"的核心,避免因舍入或重复累计导致 XML 中的应税基数与税额不一致。

汇总侧get_invoice_summary()(第 144 行起)将税额按税率归组(key 为税率字符串),支持:

  • 仅计入 VAT 类税款(charge_type == "Actual"的印花税等被排除,但 2 欧元的 Bollo 印花税会在prepare_invoice()中被单独识别为stamp_duty);
  • 将On Previous Row Total/On Previous Row Amount类型的附加费以 charges 形式追加为 e-invoice 行项目(append_row_as_charges());
  • 税率为 0 时记录免税理由(tax_exemption_reason)与法律依据(tax_exemption_law)。

最终 XML 由模板 erpnext/regional/italy/e-invoice.xml 渲染生成,发票命名遵循IT{税号}_.#####的渐进编号规则(get_progressive_name_and_number())。

五、修复四:调度器检查时间更新(PR #25295)

5.1 修复意图

ERPNext/Frappe 依赖后台调度器(scheduler)周期执行定时任务(如自动报表、规则评估、重过账等)。系统需要记录"最近一次调度器检查时间",以判断调度器是否健康运行;若该时间戳未被正确更新,系统可能误判调度器停止,从而在界面上给出误导性的"调度器未运行"警告,或在事务性数据库中造成不必要的重复调度。

5.2 仓库中的调度器相关实现

  • 在 银行对账单导入 中,通过frappe.utils.scheduler.is_scheduler_inactive()(第 87–90 行)检测调度器是否停用,来决定是否必须立即执行导入(run_now)——这体现了"检查时间/运行状态"对用户操作路径的实际影响;
  • 银行交易规则 中的scheduler_run_rule_evaluation()(第 225 行)则是典型的调度器驱动任务,说明调度器的准时性直接关系到银行交易自动匹配等后台功能;
  • 财政年度控制器(第 111 行附近)的注释还提示了调度事务在 PostgreSQL 上的原子性考量,佐证了调度器时间戳维护需要谨慎处理事务边界。

13.0.2 对该问题的修复,即确保调度器每次健康检查后都及时刷新检查时间戳,让调度器状态判断与界面提示保持准确。

六、升级与验证建议

  1. 确认当前版本:本仓库为 v13 分支快照,完整变更记录见 erpnext/change_log/v13;生产环境升级前请对照自身版本与 v13_0_2 之间的差异。
  2. 回归重点:
    • 创建基于销售发票/交货单的退货单(Credit Note),核对退货行的 incoming rate 与库存价值差异(可参照 test_purchase_invoice.py 与 test_sales_invoice.py 中的断言思路);
    • 若使用意大利本地化,提交销售发票时确认公司/客户税号、财政代码、地址与免税理由等必填项校验,并检查生成的 XML 附件中税额汇总是否与发票一致;
    • 观察系统"调度器未运行"提示是否因时间戳更新逻辑而消失。
  3. 回滚考量:四项均为修复型变更,不引入新的必填字段或数据迁移;如遇异常,可结合 erpnext/change_log 中相邻版本说明判断是否存在已知的后续回归修复。

小结

ERPNext 13.0.2 是一份小而精的补丁版本,四项修复分别落在 API 授权边界(frappe.whitelist)、库存估价正确性(销售退货 incoming rate)、区域合规(意大利电子发票校验与税额)与系统健康监测(调度器检查时间)四个维度。通过 销售退货取价实现、意大利 e-invoicing 工具 等源码,可以清晰还原每个修复的业务上下文,也为后续排查同类型问题提供了直接的代码级参考。

  • 后端
  • 企业应用

【免费下载链接】erpnext

Free and Open Source Enterprise Resource Planning (ERP)

项目地址:https://gitcode.com/GitHub_Trending/er/erpnext
点击查看免费下载
上一篇:终极zsh语法高亮指南:提升Shell脚本代码风格的10个最佳实践
下一篇:告别手写JSON:JsonCpp反射式序列化实战指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询