account_budget_purchase 真正解决的问题,不是给采购单加一个预算提示,而是把采购承诺、分析分布与预算实绩放进同一条核算链路。
主要参考:
- `enterprise/account_budget_purchase/models/purchase_order_line.py`
enterprise/account_budget_purchase/models/budget_line.pyenterprise/account_budget_purchase/tests/test_commited_achieved_amount.py-
enterprise/account_budget/models/budget_line.py
一、这不是单模块按钮,而是一条跨模块链路
很多人把这个功能理解成某个界面上的一个按钮、一个 smart button,或者一次自动创建。但从源码看,真正重要的是:上游对象先保留业务上下文,中间层做状态/域/权限判断,下游对象再接住这个上下文继续工作。只看最后一个界面动作,很容易把问题看窄。
二、核心跨链路是怎么跑通的
- 采购行先把
analytic_distribution转成analytic_json,把多分析计划上的比例拆成预算可搜索的列。 - 预算行搜索不仅看日期,还要求
budget_analytic_id已确认且预算类型不是 revenue,避免采购承诺误进收入预算。 - 当采购还没完全收票时,未开票部分会以
uncommitted_amount继续占住预算,因此预算面板要同时解释 committed 与 achieved。
这就是为什么我把它归类为“跨模块链路”题:这里至少同时牵涉了业务对象、会计/项目/销售对象,以及状态或权限判断,而不是单个模型内部的小机制。
三、最容易踩错的边界
- 没有
budget.analytic读取权限时,预算行不会被随意暴露给采购用户。 - 如果采购数量已经全部收票,承诺占用会缩回到实际发生,避免 committed 永远挂着不释放。
- 预算匹配会把未填写的分析列显式补成 False,防止“只匹配一半维度”导致预算串线。
这些边界决定了数据是否还能回到正确的模块继续流动。如果边界被自定义绕开,后面最常见的结果就是:报表看起来还能出, drill-down 却已经解释不通。
四、落地时最值得先验的三件事
- 采购、财务、项目要先统一分析分布规则,不然预算超标提示会变成噪音。
- 预算 review 时要把 committed 与 achieved 分开展示,否则采购会误以为预算被重复计算。
- 项目型采购最好把订单日期、开票日期、收货日期三套口径分别讲清。
五、结论
重点不是“超预算提醒”,而是采购承诺、分析维度和预算实绩必须一起解释。 这也是企业版功能最容易被低估的地方:看上去只是一个入口,实质上是在多个子系统之间持续传递状态、上下文、数据或权限。
- 采购行先把
DISCUSSION
评论区