月末采购审批里最容易让人误会的一步,是“系统不是已经知道供应商了吗,为什么还会提示没 vendor”。
这篇文章主要参考:
enterprise/approvals_purchase/models/approval_product_line.py
一、它先解决的不是审批,而是“数量语义要统一”
approval.product.line 上录入的数量,不一定就是采购单真正该写入的数量。源码里的 _compute_po_uom_qty() 会先根据 product_uom_id 把审批数量换算到产品采购主单位,也就是后续 _select_seller() 真正拿来比最小采购量、阶梯价和供应商规则的数量。
这一步很关键。很多实施项目里,审批单用的是“需求单位”,采购单用的是“采购单位”。如果不先做换算,就会出现:审批人填了 10 箱,供应商规则却按“件”维护,最后看起来像“有供应商却没选中”。
二、核心链路:domain、seller、has_no_seller 三段式
1)产品 domain 先把非采购品挡掉
_domain_product_id() 会在审批类别是 purchase 时加上 purchase_ok = True。也就是说,采购审批不是任意产品池,而是先收窄到允许采购的商品。
2)seller 选择强依赖 company 上下文
_compute_seller_id() 不是裸调 _select_seller(),而是 product_id.with_company(line.company_id) 后再找 vendor。多公司环境下,这决定了拿哪家公司的供应商条件、币种与付款属性。
3)没有完全命中数量,也会再退一步找“任意 vendor”
如果按当前数量找不到 seller,源码还会再用 quantity=None 试一次。意思不是放弃规则,而是区分两类问题:一类是没命中当前数量门槛,另一类是这个产品压根没供应商。只有第二类,has_no_seller 才会保持为真,并在 _check_products_vendor() 里抛错。
三、最容易被误解的点
第一,seller_id 只是“找到一个可落单的供应商候选”,不是说价格、交期、税务已经完全无误。第二,报“无 vendor”不一定是主数据没建,也可能是采购单位没配对、公司上下文错了、审批数量换算后落在错误区间,或者产品根本没有 purchase_ok。第三,真正决定成败的是行级逻辑,而不是请求头。
四、实战排查建议
- 先看审批类别是否真的是
purchase,产品 domain 有没有被正确限制。 - 再核对
product_uom_id -> product_id.uom_id的换算结果。 - 用同一公司上下文检查
_select_seller()能否命中。 - 最后再看用户手工选的
seller_id是否被允许写回。
五、结论
Odoo 企业版采购审批的“供应商选择”不是一个下拉框动作,而是一条严格的数量与公司语义链。你看到的报错,通常不是系统太死板,而是在提醒:这条采购行还没有达到可安全生成 RFQ 的条件。
DISCUSSION
评论区