先说结论
Odoo 的 Down Payment 不是“提前随便开一张金额票”。
它真正表达的是:
在正式交付和最终结算之前,先为销售订单建立一笔有明确来源、可被后续抵扣的预收款语义。
所以预付款不是插队开票,而是先行结算的一段销售金额。
为什么它不是普通发票行
源码里你会看到:
sale.advance.payment.inv向导sale.order.line.is_downpaymentaccount.move._is_downpayment()- 最终发票里对 down payment 的单独处理
这说明 Odoo 并不是把预付款混在普通销售行里,而是给它一整套独立语义。
也就是说,系统想明确知道:
- 哪些行是正式销售内容
- 哪些行只是预付款
- 到最终结算时该怎么把两者对上
为什么要有 is_downpayment
sale.order.line 上的 is_downpayment 很关键。
它不是一个装饰标签,而是在告诉系统:
这条销售行不是正常交付行,而是一条为了预付款开票而存在的特殊结算行。
这会影响:
- 是否参与正常可开票金额逻辑
- 是否单独分组显示
- 最终发票时如何扣减
所以预付款不是“假装卖了个服务产品”这么简单,尽管表面上它常常落在一个 Deposit 产品上。
向导为什么不是多余的
sale.advance.payment.inv 向导会要求你选:
- 固定金额
- 百分比
- 是否扣减历史 down payment
这说明 Odoo 把预付款设计成一种可控的开票策略,而不是一条死规则。
它要解决的问题包括:
- 先收 30%
- 先收固定 1 万
- 最终开整单时,把已收部分扣掉
所以这个向导本质上是在帮你决定“这次预收款要怎么切进销售单”。
为什么最终发票里会单独出现预付款区块
在 sale_order.py 里,官方会把 down payment 行和普通行分开处理,甚至创建专门 section。
这背后的含义非常明确:
预付款虽然属于这张销售订单,但它和实际交付内容不是同一种东西。
最终开票时,系统会:
- 展示已发生的 down payment
- 再对正式应开金额做扣减
所以预付款不是重复收费,而是提前计收、最终抵扣。
新手最容易误解的 4 件事
1. 以为预付款就是随便开一张金额票
其实它必须回挂销售单,并可被后续结算识别。
2. 以为 down payment 行和普通销售行一样
它有独立语义和扣减逻辑。
3. 以为最终发票要手工减掉预付款
Odoo 本来就有自动处理这条链的设计。
4. 以为预付款开票就等于交付完成
预付款只解决先收款,不代表交付语义已经完成。
一句话记忆法
Down Payment 不是先乱开一张票,而是先把销售金额的一部分独立结算出来,并在最终发票时按规则扣回去。
DISCUSSION
评论区