先说结论
采购单出现这些状态时,最容易把人搞乱:
receipt_status = pending / partial / fullinvoice_status = no / to invoice / invoiced
很多人一急,就开始:
- 在 PO 里翻
- 在收货单里翻
- 在 Vendor Bill 里翻
- 最后越翻越乱
更高效的办法其实是:
不要先按单据找,而要先按“状态是由哪个字段算出来的”去找。
这就是源码式排错。
第一步:先分清 receipt_status 和 invoice_status 根本不是同一层
在 purchase_stock/models/purchase_order.py,receipt_status 的计算很直白:
- 没有 picking,或全取消:False
- 全部 done/cancel:
full - 至少有一个 done:
partial - 否则:
pending
也就是说它看的主要是:
- 收货 picking 有没有生成
- 这些 picking 现在处于什么状态
它并不直接看账单。
而 purchase/models/purchase_order.py 的 invoice_status,核心是看:
- 订单状态
- 各行
qty_to_invoice是否还非零
所以它盯的是:
- 还剩多少可开 / 应冲的数量
它并不直接看 picking header 有没有 done。
这两个状态经常同时出问题,但根子未必在同一个地方。
第二步:如果 receipt_status 不对,先查 picking,不要先查账单
如果你觉得“明明收了货,为什么还是 pending / partial”,排查顺序建议这样走:
- 这张 PO 有没有
picking_ids - picking 是否都还是 waiting / assigned / done / cancel
- 有没有只做了部分回单,导致一些 picking done、一些没 done
- 是否存在 return picking,把你直觉里的“已经收完”又冲淡了
因为 receipt_status 本质上是 单头级收货执行状态,不是行级开票状态。
第三步:如果 invoice_status 不对,先查采购行三件套
比起单头,invoice_status 更应该先去看采购行:
qty_receivedqty_invoicedqty_to_invoice
为什么?因为订单头的 invoice_status,其实就是对这些行结果的汇总表达。
你真正要问的不是“PO 为什么显示 to invoice”,而是:
- 哪一行还有
qty_to_invoice != 0 - 这个数为什么不是 0
- 它是正数,还是负数
正数往往意味着还能继续开票;负数往往意味着之前账开多了,该走 refund 语义。
第四步:qty_received 异常时,再往 stock move 层钻
如果产品接了 purchase_stock,采购行的 qty_received 往往不是纯手工值,而是从 move 反推。
这时就要继续问:
qty_received_method是manual还是stock_moves- 关联 move 有没有 done
- 有没有采购退货 move 被减回去
- 有没有 dropship / return 边界导致某些 move 不计入
也就是说:
采购开票问题表面在 PO 行,很多时候根因却在 stock move 的 done 事实。
第五步:别忽略“状态看起来矛盾,其实是正常组合”
这类组合经常把新人吓到,但并不一定有错。
组合一:receipt_status = pending,invoice_status = to invoice
可能是按订购数量开票。
组合二:receipt_status = full,invoice_status = no
可能是已经全部开完票,或当前订单状态不再允许继续开票。
组合三:receipt_status = partial,invoice_status = invoiced
如果产品按 ordered quantities 开票,这并不稀奇。
很多“异常感”其实只是你拿错了控制口径。
一个很实战的排错顺序
以后遇到采购卡单,建议就按这个顺序:
- 先看是哪种状态异常:receipt 还是 invoice
- receipt 异常:先查
picking_ids和 picking state - invoice 异常:先查
qty_to_invoice非零的采购行 - 行数量异常:再往
qty_received/qty_invoiced追 qty_received异常:最后才钻stock.move
这样你会比“打开十个页面乱点”快很多。
一句话记忆法
采购排错时,receipt_status 是 picking 执行状态的投影,invoice_status 是采购行可开票数量的投影;先分清投影来源,再查根因。
DISCUSSION
评论区