结论先行
在 Odoo 里,冲销不是把原凭证“撤回到不存在”,而是:
保留原凭证作为已发生事实,再创建一张方向相反的新凭证,通过
reversed_entry_id把两者连起来,并在需要时进一步做核销或重建。
所以 Reverse Entry 的本质不是删除,而是用新的会计事实去抵消旧的会计事实。
这听起来很保守,但对审计和追溯来说反而最稳。
第一层:为什么会计系统宁愿冲销,也不喜欢“直接删”
很多业务系统在发现录错单据时,会倾向于:
- 打开原单
- 改掉内容
- 或者直接删除重来
但会计系统不太能这么干。
因为 posted 凭证一旦存在,就不仅仅是一个表单记录,它还是:
- 报表的一部分
- 对账链的一部分
- 税务链的一部分
- 审计轨迹的一部分
如果你把原凭证直接抹掉,结果虽然“看起来正确了”,但过程消失了。
而冲销的哲学是:
- 承认原来那笔已经发生过
- 再用一笔相反记录把它抵掉
- 必要时再生成正确的新凭证
这比“删除历史”更符合会计世界的可信度要求。
第二层:源码里的 reversal 不是简单 copy 一下负数
从 /home/ubuntu/odoo-temp/addons/account/wizard/account_move_reversal.py 和 account_move.py 可以看到,标准冲销链路至少包含这些元素:
account.move.reversal向导- 目标
move_ids必须是posted - 生成默认 reversal 值
- 调用
_reverse_moves() - 为新凭证写入
reversed_entry_id - 视情况决定是否
cancel=True
这说明官方没有把 reversal 理解成“随手复制一张反向凭证”,而是理解成一套有语义的会计动作。
尤其 reversed_entry_id 很关键。
它意味着系统不是只关心“金额反了没有”,还关心:
这张新凭证究竟是在反哪一张原凭证。
有了这层链接,后续追溯、界面提示、自动核销才有基础。
第三层:cancel 和普通 reversal 到底差在哪
_reverse_moves(self, default_values_list=None, cancel=False) 这个签名非常值得记。
因为它直接告诉你:
- reversal 不一定等于 cancel
- cancel 只是 reversal 的一种更强语义
源码里,如果 cancel=True:
- 先对原 move 的相关行
remove_move_reconcile() - 再生成反向 move
- 再把反向 move 过账
- 后续让原分录和冲销分录进入
_reconcile_reversed_moves()
也就是说,cancel 不是单纯“多打一张反方向凭证”,它通常还带着“把旧关系拆开,再让新旧正式闭环”的动作。
这比表面按钮文案深很多。
第四层:为什么 modify 模式更像“冲销 + 重做”
向导里除了 refund_moves(),还有 modify_moves()。
这个模式特别容易被忽略。
它做的不是只生成反向单,而是:
- 先按 reversal 逻辑把原凭证冲掉
- 再基于原单内容复制出一张新的草稿
- 并且通常只保留真正业务相关的行
所以 modify 的真实含义更接近:
先承认旧的错了,再留一张可继续修正的新草稿。
这比“直接回到原单继续改”更稳,因为它保留了错误发生过、后来被纠正的完整链路。
第五层:为什么 future date reversal 会出现 auto_post
向导 _prepare_default_reversal() 里还会根据 reversal date 判断:
- 如果 reversal date 在未来
- 那新 move 可以
auto_post = 'at_date'
这说明 Odoo 的 reversal 不是只面向“马上冲掉”。 它也承认现实世界里存在:
- 今天决定要冲销
- 但会计效果要在未来某个日期正式生效
比如跨期调整、预先安排的更正动作等。
所以 reversal 在 Odoo 里其实是一种可被计划的正式会计动作,而不是一个 UI 撤销键。
常见误区
误区 1:冲销就是删除原凭证
不是。 冲销的价值恰恰在于不删除原凭证。
误区 2:reversal 就是一张金额相反的 copy
不完整。
它还带着 reversed_entry_id、过账、核销与后续追溯语义。
误区 3:cancel 和 reverse 是完全同义词
不是。
cancel=True 代表更强的闭环动作。
误区 4:modify 只是普通 reversal 的别名
也不是。 modify 更像“冲销后再生成新草稿继续修正”。
误区 5:Reverse Entry 按钮就是界面便捷功能
不对。 它背后是完整的会计更正设计。
实战判断顺序
当你需要更正 posted 凭证时,可以这样判断:
1. 先问:你是要保留历史还是假装历史没发生
会计系统里通常只能选前者。
2. 再问:只是做一张反向抵消,还是冲完还要重做正确版本
这决定你更接近 reverse 还是 modify。
3. 再看:原凭证是否已经参与核销
这会影响 cancel 链路里的拆解与重连。
4. 再决定 reversal date
别忽略未来日期会触发 auto_post 语义。
5. 最后才去看按钮文案
真正决定行为的是底层链路,不是按钮上那几个字。
一句话记忆法
Odoo 的冲销不是把原凭证删掉,而是新增一张带
reversed_entry_id的反向凭证,让“错误发生过、后来被抵消”这件事留下完整轨迹。
DISCUSSION
评论区