先说结论
Odoo 销售里的 warning,从来不只是“弹个窗提醒一下”。
它至少有三层不同语义:
- 提醒语义:告诉销售员这单有风险
- 阻断语义:在某些节点不允许继续推进
- 消息语义:把某次业务动作写进 chatter / message history,形成可追溯记录
而这三层语义,并不是自动混在一起的。
很多实施误解 warning,往往就是因为把三件事混成一件:
- 以为看到提示就等于已经阻止业务
- 以为阻止业务就一定会自动写 message
- 以为 message 里有记录,就代表业务规则已经被执行
实际上,官方源码对这些边界划得非常清楚。
先分清两类对象:partner warning 和 product warning
从 sale 模块继承关系来看,销售单上的 warning 主要来自两种来源:
1. Partner 侧
例如客户、发票联系人、送货联系人带来的 warning / blocking 语义。
2. Product 侧
例如某个商品不适合卖给当前客户、需要额外提醒、或者应该阻止继续添加。
这和采购场景类似:warning 不是单一字段,而是主数据在交易单据上的风险投影。
所以 warning 的第一重理解不是“订单表单上多了个红字”,而是:
客户与商品主数据里的风险规则,沿着销售录单链路向 sale.order / sale.order.line 传播。
warning 的第一层,是交互提示,不等于最终业务裁决
在绝大多数一线使用者眼里,warning 最明显的表现就是:
- 选了客户,弹一个警告
- 选了产品,弹一个警告
但从机制上说,这只是第一层:UI 反馈。
UI 反馈解决的是:
- 销售员是否被及时提醒
- 风险是否在录单当下暴露
它没有天然保证:
- 后续一定不能确认订单
- 后续一定不能开票
- 这次提示一定会形成可追溯历史
所以 warning 的一个基本边界是:
UI 提示 ≠ 阻断规则
你看到了 warning,只能说明系统把风险告诉了当前操作者;不代表这件事已经被制度化地拦住。
blocking 的关键,不在“文字更凶”,而在流程节点是否被拒绝
业务里常见两种误解:
- 把“Warning”理解成软性提醒
- 把“Blocking Message”理解成只是更强硬的提示文案
但从系统设计看,真正的 blocking 边界不在文案,而在:
某个动作是否被真正拒绝执行。
比如一个客户可能有销售警告;一个产品也可能有销售警告。
实施真正要关心的是:
- 是在选 partner / product 时阻止继续录入
- 还是允许录入、但在确认时阻止
- 还是只提示、由销售自行判断是否继续
也就是说,阻塞不是“长得像提示框”,而是对业务流转动作产生硬结果。
这也是为什么成熟实施要单独梳理:
- 哪些 warning 只是信息提示
- 哪些 warning 必须升级为 blocking
- blocking 发生在哪个节点最合理
message 传播是另一条链:记录发生了什么,不等于决定能不能做
在销售主链里,很多关键动作都会额外 message_post(...)。
例如预付款发票创建时,系统会在订单和发票上都写消息,记录:
- 发票从哪个销售单创建
- 某张 Down payment invoice 已生成
这给我们一个很重要的参照:
Odoo 的 message/chatter 语义通常是:
- 记录业务事件
- 让协作者看到上下文
- 形成后续可追踪历史
所以把这个思路放回 warning 上,就很容易看清边界:
warning
偏“当前动作的风险判定”
message/chatter
偏“把发生过的事情沉淀下来”
两者经常一起出现,但本质不同。
如果你的实现只是弹 warning,不写 message,那么:
- 当下操作者看到了
- 但其他协作者未必知道
- 事后也很难审计
反过来,如果只是写 message,不做 blocking 或 warning,也不代表当前操作被真正控制。
为什么“传播”二字很重要:谁该看到、在哪个对象上看到、看到多久
warning 机制最容易被低估的一点,是大家只盯着“有没有提示”,不盯“传播路径”。
真正重要的问题是:
1. 风险先附着在哪个对象上
- partner
- product
- sale.order
- sale.order.line
2. 它在什么时候被带到当前交易
- 选客户时
- 选商品时
- 确认时
- 开票时
3. 最终有没有沉淀成可共享消息
- 只有当前用户看到了弹窗
- 还是订单 chatter 里留下记录
- 还是相关下游对象也能看到上下文
一旦你按“传播”去看 warning,就会发现这不是单点字段,而是一个协作设计问题。
实战里最危险的 4 个误区
1. 以为 warning 已经等于拦截
很多系统实际上只是提醒,没有阻断。结果销售员习惯性点掉继续走。
2. 以为 blocking 一定会留痕
并不一定。阻断了动作,不代表 chatter 已经记录了原因和上下文。
3. 以为 message 多了就代表风控做完了
message 只保证“有人记录过”,不保证规则在关键节点被执行。
4. 只设计当前操作者体验,不设计协作传播
订单交接、财务、客服、仓库可能都需要知道 warning 背景,但单次弹窗不会自动解决这个问题。
实施时最稳的拆法
如果你要把 sales warnings 设计清楚,最稳的方式不是只讨论字段,而是分三张表来想:
第一张:风险来源表
- 客户风险
- 商品风险
- 组合销售风险
第二张:动作控制表
- 录单时提示
- 确认时阻断
- 开票时阻断
- 允许 override 还是完全禁止
第三张:传播留痕表
- 是否写 chatter
- 写到 sale.order 还是下游对象
- 是否要求负责人/审批人被通知
一旦这么拆,warning、blocking、message 三者就不会再糊成一团。
一句话总结
Odoo 销售里的 warnings 真正要分开看的是三条链:
- warning 链:把风险及时暴露给当前操作者
- blocking 链:在关键节点真正阻止错误业务继续推进
- message 链:把风险处理过程和结果沉淀为可追溯上下文
它们可以协作,但从来不是同一件事。
所以最稳的理解应该是:
sales warning 解决“现在该不该继续”,message 解决“后来谁还能看见发生过什么”,而 blocking 决定“系统最终放不放行”。
DISCUSSION
评论区