企业会计 / 框架

Odoo 企业版 SAF-T 导出为什么不是“点一下导出总账”:warning 注入、report values 组装与税务字段准备讲透

account_saft 不是简单导出总账行,而是先对公司资料发 warning,再把 report lines 组装成账户汇总、分录明细、税务明细和模板值。任何一段缺数据,都可能让导出文件被拒。

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

很多人把 SAF-T 导出理解成“把总账报表另存为 XML”。但企业版 account_saft 的实现清楚说明:它做的不是“导出当前页面”,而是把公司资料检查、报表行抽取、税务明细补全、模板值组装整合成一条合规导出管线。

一、第一步不是取账,而是先检查公司资料是否够合规

_customize_warnings() 会检查 company registry、电话、城市/邮编等信息,不足时往 warnings 里注入 account_saft.company_data_warning。这说明 SAF-T 从一开始就不是“有账就能导”。

审计交换文件的逻辑是:会计数据正确还不够,主体身份信息也必须完整

二、总账值提取不是直接读 move line,而是先走报表层

_get_report_values() 会重新构造 report options,强制 export_mode=fileunfold_all=True,再用报表 line 解析账户汇总与未分配利润提示。这一步很重要,因为它说明 SAF-T 依赖的是 account reports 的既有汇总能力,而不是重新发明一套账务统计。

这带来的好处是:

  • 报表层口径更统一;
  • 导出和报表展示不会轻易分叉;
  • 某些异常(如 undistributed earnings)可以在导出前就被捕获。

三、账户、分录、税务明细是分段准备的

源码把导出值拆成多段填充:

  • _saft_fill_report_general_ledger_accounts():准备账户层 opening/closing balance;
  • _saft_fill_report_general_ledger_entries():准备分录、journal、期间借贷总额;
  • _saft_fill_report_tax_details_values():补税务明细映射;
  • _saft_prepare_report_values():最后统一格式化为模板渲染值。

这说明 SAF-T 的本质不是“一个 SQL 查完所有列”,而是把不同粒度的会计/税务语义分层准备,再汇总成最终模板数据。

四、最容易被忽略的是导出约束本身

_saft_prepare_report_values() 里明确限制:只支持一个 column group,否则直接报错。这个细节很典型,它说明 SAF-T 不是任意组合报表过滤器都能套进去。合规导出要的是稳定、单义、可审计,而不是前端报表的自由度。

五、新手误区

1. 以为只要账对,导出就会成功

公司资料缺字段,一样会在导出前被 warning 甚至被审计端拒绝。

2. 以为 SAF-T 就是把总账行转 XML

实际上还要准备账户摘要、税务细节、模板层格式化值。

3. 以为报表能显示的所有筛选都能导出

源码明确限制了 column group 语义。

六、实战注意事项

  • 导出前先补齐公司主数据,别等 warning 出来再补;
  • 如果数字和报表不一致,先确认 report options 是否处于 export 模式;
  • 审计失败时,别只看 XML 文件本身,也要回头看账户、税务、主体字段准备过程;
  • 二开国家本地化时,优先扩展 _saft_get_account_type() 和各段 fill 方法,而不是粗暴改模板。

结语

企业版 SAF-T 真正解决的问题,不是“导出一份账务文件”,而是把报表口径、主体信息、税务明细和模板约束压成一条审计可接受的导出管线。理解这层,才能真正把它当成框架能力来看。

DISCUSSION

评论区

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