先说结论
Odoo 销售单上的 Shipping Policy,绝对不是“界面上的一个提示字段”。
它真正决定的是:
客户看到的承诺交付节奏,到底是能先到先发,还是必须等齐再发;而 commitment_date 则是在这条规则之上,给系统一个更强的人工承诺时间。
所以这块的本质,不是 UI 选项,而是销售承诺如何压到库存履约层。
这篇文章主要参考了哪些源码
核心参考是:
/home/ubuntu/odoo-temp/addons/sale_stock/models/sale_order.py/home/ubuntu/odoo-temp/addons/sale_stock/models/sale_order_line.py/home/ubuntu/odoo-temp/addons/sale/models/sale_order.py/home/ubuntu/odoo-temp/addons/sale_stock/tests/test_sale_order_dates.py/home/ubuntu/odoo-temp/addons/sale_stock/tests/test_sale_stock_lead_time.py
最重要的源码信号有三个:
picking_policy只有两个值:direct和one_select_expected_date()会根据 policy 选最短还是最长 lead time- 如果修改
commitment_date,系统会把 deadline 传播到相关stock.move
这说明它影响的不是显示文案,而是实际排程语义。
“As soon as possible” 和 “When all products are ready” 到底差在哪
在 sale_stock/models/sale_order.py 里,picking_policy 的两个选项分别是:
direct:As soon as possibleone:When all products are ready
很多人第一次看,会以为这只是:
- 一个允许部分发货
- 一个要求整单发货
这当然没错,但还不够。
更准确地说,它们在表达的是:
direct
以最早可发为导向,让整条履约链尽快启动。
one
以整单齐套为导向,宁可等最慢那部分,也尽量给客户一次性交付。
这不是库存团队的小偏好,而是对客户承诺方式的不同选择。
为什么它会直接影响 expected_date
在 sale_stock/models/sale_order.py 里,_select_expected_date() 很关键:
- 如果是
direct,沿用默认逻辑,偏向最早可交付时间 - 如果是
one,取max(expected_dates)
这意味着当一张销售单里有多条 line、不同产品有不同 lead time 时:
direct更像“先按最快的开始动”one更像“等最慢的那一项准备好再定义这单的整体交付节奏”
所以 expected_date 不是一个纯展示字段,它是在帮销售表达:
- 这张单的承诺,是最快启动
- 还是整单齐发
commitment_date 为什么比 expected_date 更“硬”
在 sale/models/sale_order.py 里,commitment_date 的帮助文本就写得很直白:
- 这是承诺给客户的交付日期
- 如果设置了,就按它来排 delivery order
- 不再只依赖产品 lead time
再看 sale_stock/models/sale_order_line.py 的 _compute_qty_at_date():
- 如果订单有
commitment_date,它就优先拿这个日期作为scheduled_date - 如果没有,才回退到
_expected_date()
这说明:
expected_date 更像系统根据 lead time 算出的“自然结果”;commitment_date 则像销售或运营强行盖下去的“业务承诺”。
两者不是重复字段,而是“系统估算”和“人工承诺”的分层。
为什么改 commitment_date 会影响 stock.move
很多人会忽略 write() 里的这段逻辑。
在 sale_stock/models/sale_order.py 中,如果修改了 commitment_date,系统会:
- 找出相关订单行的 move
- 过滤掉 done / cancel
- 只取目标是 customer 的 move
- 把它们的
date_deadline改成新的承诺日期,或回退到expected_date
这一步非常关键。
因为它说明 commitment_date 不是销售层自娱自乐。
它会继续向下游说:
- 这张单什么时候答应客户
- 相关出库动作的 deadline 应该怎么改
也就是说,销售改了承诺日期,库存排程不是“看情况再说”,而是会收到明确的新约束。
为什么前台可用量提示也会跟着变
在 sale_stock/models/sale_order_line.py 的 _compute_qty_at_date() 里,系统会根据:
order_id.commitment_date- 或
_expected_date() - 再结合 warehouse 分组
- 批量读取该日期点的库存可用性
这就意味着:
- 销售单上的承诺日期一改
- 行上的
scheduled_date、free_qty_today、virtual_available_at_date的解释也跟着变
所以很多销售以为自己只是改了一个“给客户看的日期”,其实连前台库存承诺口径都一起变了。
新手最容易误解的 4 件事
1. 以为 Shipping Policy 只是仓库配置
其实它直接影响销售单整体承诺节奏。
2. 以为 one 只是“不允许部分发货”
更准确地说,它是在把整单最慢项定义为这笔交易的节奏锚点。
3. 以为 commitment_date 只是备注
源码明确表明它会影响 schedule 和 move deadline。
4. 以为 expected_date 和 commitment_date 重复
前者偏系统推算,后者偏业务承诺,层级不同。
实战里该怎么选
我自己的判断标准是这样的:
用 direct 的场景
- 客户更在意尽快收到第一批货
- 允许分批交付
- 订单里存在明显的快慢物料混合
用 one 的场景
- 客户更在意一次性交齐
- 项目交付需要整套到位
- 分批交付会制造更多沟通成本
用 commitment_date 的场景
- 销售已经对客户做了明确承诺
- 需要压过系统自然计算结果
- 运营要拿它驱动内部履约 deadline
如果这三件事没分清,团队就会经常出现:
- 客户理解的交付承诺
- 销售口头承诺
- 系统排程出来的日期
三套口径彼此打架。
一句话记忆法
Shipping Policy 决定“按最快还是按最慢来承诺”,commitment_date 决定“这次我明确答应客户哪一天”。
DISCUSSION
评论区