企业销售 / 税务

Odoo 企业版订阅外部税为什么不是“开票时调用一次税接口”而已:递延到期日、可开票行过滤与门户预览讲透

sale_subscription_external_tax 处理的是 recurring invoice 的真实税务边界:订阅订单还没到可开票期的行不能提前送税,客户从 portal 看订阅时也要先重算外部税。

企业 销售
进阶 开发者 1 分钟阅读
0 评论 0 点赞 0 收藏 5 阅读

订阅税务最危险的地方在于“客户还没到下一期,但门户上已经看到价格”;如果税额是外部服务计算,就必须保证预览和正式开票口径一致。

核心链路

  1. models/sale_subscription.py_create_recurring_invoice() 在父类生成发票后,立即对这些未验证单据调用 _get_and_set_external_taxes_on_eligible_records()。企业版认为 recurring 发票在验证前就应该带上正确税额。
  2. _do_payment() 又在支付前再次触发税计算,避免客户支付时税额还是旧值。对订阅来说,开票与支付并不是一瞬间的同一事件。
  3. _get_external_tax_service_params() 如果当前订单是 subscription,会把 document_date 设成 next_invoice_date。这很关键:订阅税额通常应基于下一期开票日期,而不是今天浏览门户的日期。
  4. _get_line_data_for_external_taxes() 更是专门过滤 confirmed subscription 上真正 order._get_invoiceable_lines() 的行;尚不可开票的订阅行不会被提前送去算税。
  5. 控制器 controllers/portal.pysubscription() 在渲染 portal 页面前,也会对订单调用 _get_and_set_external_taxes_on_eligible_records()。所以客户在门户里看到的订阅金额,理论上应与正式开票保持同一税服务口径。

关键源码位置

  • /home/ubuntu/odoo-temp/enterprise/sale_subscription_external_tax/models/sale_subscription.py
  • /home/ubuntu/odoo-temp/enterprise/sale_subscription_external_tax/controllers/portal.py

容易误解的地方

  • 误区一:外部税只在发票 validate 时才需要。企业版在 recurring invoice 生成和支付前都可能重算。
  • 误区二:门户预览展示的是静态价格。这里会在展示前主动刷新外部税。
  • 误区三:所有订阅行都应送税服务。源码只保留真正可开票的行。

实战注意事项

  • 跨州/跨国订阅业务里,先定义税服务的 document_date 基准,否则同一订阅可能今天看和出账日看税额不同。
  • 若客户投诉 portal 金额与发票不一致,优先检查门户控制器是否正确跑了外部税刷新。
  • 做税务接口压测时,不要只测批量出账,也要测高并发 portal 浏览。

结语

企业版这些代码共同说明一件事:真正可上线的业务流程,靠的不是“页面上看起来能点通”,而是权限、状态、时机、对账口径和跨模块回写都被收紧。理解这些边界,实施和二开时就不容易走进“功能演示能跑、真实业务一用就散”的坑。

DISCUSSION

评论区

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