企业|框架

Odoo 企业版电商外部税,为什么不是“结账时请求一下税率接口”

从网站结账、销售确认到发票过账重复计算,讲清外部税为什么必须在多个业务节点重放同一份上下文。

企业 框架
进阶 开发者 1 分钟阅读
0 评论 0 点赞 0 收藏 6 阅读

结论先行

“外部税”最容易被误解成一次同步调用:客户到支付页时请求税率服务,算个金额就结束。企业版的实现正好证明不是这样。税务上下文会在网站、销售、会计三个阶段被反复重放,因为每个阶段承担的法律与业务责任不同。

第一层:入口或表面动作

网站阶段,website_sale_external_tax_order_summary_values()_get_shop_payment_errors() 里都会调用 order._get_and_set_external_taxes_on_eligible_records()。前者是为了让订单摘要显示正确税额,后者是为了在支付前发现地址无效等错误。这里最重要的是:网站层只是预演,不是最终承诺。它会把错误反馈给用户,但并不以页面上看到的税额作为最终会计真相。

第二层:真正的业务护栏

到了销售阶段,sale_external_tax.sale_order.action_confirm() 又会重新跑一次 _get_and_set_external_taxes_on_eligible_records()。原因很现实:地址、折扣、行项目、送货方式在客户点支付前后都可能变化,销售单确认时必须再拿一次“当前订单事实”向税务服务求值。_get_line_data_for_external_taxes() 也说明了这一点,它重新从 base lines 组装待税务计算的数据,而不是复用网站缓存。

第三层:状态落点与边界

真正的法律边界在会计。account_move._post() 在发票过账前再次拉外部税;button_draft()unlink() 则通过 _uncommit_external_taxes()_void_external_taxes() 撤销或作废外部税承诺。也就是说,企业版不是“算出税额”就完,而是把外部税当成会计对象生命周期的一部分:未过账可改、回草稿要反提交、删除要作废。

为什么这套设计更稳

这种多节点 replay 的设计非常像消息系统里的幂等消费者。网站在乎体验,销售在乎订单一致性,会计在乎法定凭证,三者都要拿到同一份税务上下文,但没有任何一层能永久相信上一层算出来的结果。你若把外部税结果缓存成一个固定字段,只在 checkout 算一次,后面任何改价、改地址、拆单、重开票都会让税额失真。

实战启示

所以这类扩展最该学到的不是“怎么接税务接口”,而是“怎么在多个关键节点重放、校验并撤销外部状态”。企业版把 mixin、sale.order、account.move、website controller 各管一段,正是为了让外部税既能穿透前台结账,也能在后台会计生命周期里自洽。

DISCUSSION

评论区

想参与讨论?先 登录 再发表评论。
还没有评论,你可以成为第一个留言的人。