很多团队把采购预算理解成“采购单页面上直接有余额”,但企业版真正做的是两段式链路:先在采购行里找到预算语义,再把这些语义带进预算报表。account_budget_purchase 并不把采购界面当最终报表,而是把它当预算钻取入口。
purchase.order.line 上的 _compute_analytic_json() 会先把 analytic_distribution 展开成可匹配预算行的结构。这里保留的不只是比例,还有各个 analytic plan 展开的列和值,所以后续 _compute_budget_line_ids() 匹配时,系统拿的是“分析维度事实”,不是一串模糊标签。
_compute_budget_line_ids() 还有两个很容易被忽略的闸门:预算必须覆盖采购日期,而且采购行必须仍有 product_qty - qty_received > 0 的未完全履约数量。也就是说,采购预算不是单据一建完就永远占着,而是跟着收货进度持续重算。
真正把采购链路交给预算模块的是 purchase.order.action_budget()。这个动作不会随便打开一张总表,而是从当前采购单实际命中的分析账户和预算行出发,带着 domain 去打开预算报表。预算报表侧再由 action_open_budget_entries() 继续往下追业务事实,形成“采购单 → 预算报表 → 预算条目”的连续钻取。
这条跨模块链路的价值,在于它把采购执行、分析分摊和预算报表三层语义绑在一起。业务同事在采购单里看到的不是一张静态余额卡片,而是一张能继续追到预算维度的入口;财务同事在预算侧看到的,也不是脱离采购现场的孤立数字。
如果现场出现“采购单能提示预算、但报表打不开正确范围”这类问题,优先检查三处:采购行的 analytic_distribution 是否真的展开成 analytic_json;预算行是否满足日期和公司条件;以及 action 打开报表时带的 domain 是否被自定义模块覆盖。问题往往不在显示,而在上下文传递。
DISCUSSION
评论区