先说结论
Odoo 的采购审批,真正的问题不是“金额大不大”,而是:
- 公司是否启用了
po_double_validation - 审批阈值是否要按订单币种重新换算
- 当前用户是不是
purchase.group_purchase_manager button_confirm()到底是直接button_approve(),还是先把状态写成to approve
所以它不是一个 UI 小开关,而是一条明确的状态分流逻辑。
核心链路在 purchase.order
在 /home/ubuntu/odoo-temp/addons/purchase/models/purchase_order.py 里,button_confirm() 的处理顺序非常清楚:
- 先校验订单行是否可确认
- 校验 analytic distribution
- 调用
_add_supplier_to_product()补供应商信息 - 再进入审批判断
关键分叉在这里:
- 如果
_approval_allowed()返回 True,就直接button_approve() - 否则,订单状态被写成
to approve
也就是说:
“确认采购单”并不保证订单一定立刻进入
purchase。
这正是很多实施同学第一次排错时最容易误解的地方。
_approval_allowed() 真正在判断什么
源码里 _approval_allowed() 大致分三种情况:
1)公司配置为一步审批
如果 company_id.po_double_validation == 'one_step',那就不用多说,直接可批。
2)公司配置为双重审批,但订单金额低于阈值
如果是 two_step,并不代表所有单都必须经理批。
源码会把公司配置的 po_double_validation_amount,按:
- 订单币种
- 公司
date_order
做一次 _convert(...),然后拿结果和 amount_total 比较。
这意味着一个经常被忽略的事实:
审批阈值不是死盯公司本位币显示值,而是要先换算到当前采购单币种语境里。
如果你做多币种采购,这个细节特别重要。
3)当前用户本身就是采购经理
就算金额超过阈值,只要用户有 purchase.group_purchase_manager,仍然可以通过。
所以双重审批不是“系统强制卡死”,而是:
- 对普通采购员卡阈值
- 对经理保留越过阈值的审批权
这才是它的真实管理边界。
to approve 不是失败,而是故意停在中间态
很多用户看到 to approve 会以为:
- 配错了
- 没确认成功
- 系统没往下跑
其实都不对。
to approve 不是异常状态,而是采购流程里的有意暂停。
它表达的是:
- 业务上订单已经具备确认条件
- 但组织权限上还不能直接承诺给供应商
- 所以先把单据停在“待经理批准”层
这和报错完全不是一回事。
button_approve() 做的也不只是改状态
源码里 button_approve() 至少做了两件关键事:
- 把状态写成
purchase - 记录
date_approve
此外,如果公司配置 lock_confirmed_po == 'lock',还会顺手把 locked=True。
这意味着审批动作还会影响后续行为:
- 采购单是否正式生效
- 审批时间是否落档
- 订单能否继续被普通方式编辑
所以审批按钮本质上是“让订单进入受控生效态”,不是“纯表单操作”。
新手最容易误解的 3 个点
误解 1:双重审批只看总金额
不对。它还看:
- 公司配置
- 用户组
- 币种换算
- 订单日期
误解 2:点 Confirm 没变成 Purchase 就是失败
不对。进入 to approve 往往正说明系统在按设计工作。
误解 3:经理审批只是补一个状态
也不对。审批还会写 date_approve,并可能触发锁单。
实战排错建议
如果你遇到“为什么这张 PO 直接确认了,那张却进了 to approve”,别先看界面,先按这个顺序查:
company_id.po_double_validation是one_step还是two_steppo_double_validation_amount是多少- 订单币种与公司币种是否不同
date_order对应的汇率换算结果是什么- 当前操作者是否属于
purchase.group_purchase_manager
很多所谓“审批异常”,其实只是阈值换算或权限组没有想清楚。
一句话记忆
Odoo 采购双重审批不是“金额大多一个按钮”,而是“公司规则 + 币种换算 + 用户权限”共同决定订单能否直接进入
purchase。
DISCUSSION
评论区