企业预算 / Odoo 开发

Odoo 企业版预算行为什么不是“填目标金额等报表汇总”:practical amount 查询引擎、analytic 口径与 crossover 窗口讲透

account_budget 的预算行不是静态台账,而是把预算期间、分析账户和实际发生额查询拼成一条可重复计算链。真正会影响结果的,是 `_compute_all()`、`_compute_theoritical_amount()`

Odoo 开发 企业
进阶 开发者 1 分钟阅读
0 评论 0 点赞 0 收藏 6 阅读

很多团队第一次接触企业版预算时,会把预算行理解成一张“目标金额表”:填好预算、跑报表、看偏差。可真正上线后,最常见的问题不是预算没填,而是为什么同一条预算线,在不同时间点、不同 analytic 维度下看到的 actual / theoretical 金额都在变

这里的关键不是 UI,而是三段后端逻辑怎么配合:

一、它先算实际发生额,而不是先看预算本身

BudgetLine._compute_all() 并不直接扫凭证行,而是通过 budget.report_read_group() 聚合,把当前预算线 id 放进上下文后统一汇总 achieved。这说明预算行本质上只是“口径入口”,真正的已发生金额来自预算报表层的聚合结果。

这样设计有两个好处:

  • 预算列表页和报表页共用同一套汇总口径,不容易出现“列表一个数、报表另一个数”。
  • 后续如果 analytic plan、维度列、聚合逻辑变化,预算线不需要重新发明一套 SQL。

二、理论值不是平均摊,而是按包含首尾日的时间窗口推进

_compute_theoritical_amount() 很值得细看。它先确保 date_from/date_to 合法,然后把开始日和结束日都算进周期长度。源码里专门写了 “April 1 到 April 30 要算 30 天”。这意味着理论预算不是粗暴按月份分摊,而是按实际经过的天数比例推进。

新手最容易忽略的点有两个:

  • 今天早于开始日,理论值会被压到起始边界;
  • 今天晚于结束日,理论值会封顶到整个预算金额。

所以理论金额不是“实时进度条动画”,而是一个带上下界的时间函数。

三、analytic 口径决定你到底在看哪一类实际发生

action_open_budget_entries() 会遍历所有 analytic plans,把预算线上已设置的维度拼进 domain,然后打开 account_budget.budget_report_action。这一步非常关键:预算线不是只有一个金额字段,它其实隐含了多维 analytic 过滤条件

也就是说,预算线钻取出来的明细,不是“这段时间里所有发生额”,而是“符合该预算 analytic 组合的发生额”。项目、部门、成本中心只要有一个维度没对齐,用户就会以为系统算错了。

四、真正的主链路是“预算定义 → 聚合计算 → 维度钻取”

结合 budget_analytic.py 可以把主链路梳理成:

  1. 预算主单进入确认态,预算线开始承担控制和分析语义;
  2. 预算线通过 _compute_all() 从预算报表聚合实际值;
  3. 通过 _compute_theoritical_amount() 计算当前日期下的理论进度;
  4. 用户再从 action_open_budget_entries() 钻到具体报表行核对原因。

所以预算不是“静态录入 + 静态对比”,而是一个持续重算的分析视图

五、新手最容易踩的坑

1. 以为预算超支就是源码 bug

很多“超支异常”其实来自 analytic 维度挂错,或者预算线时间窗口比业务理解更窄。

2. 以为理论值按月平均

源码按日期差算,不按自然月平均。跨月、半月预算、月末创建预算时,这个差异特别明显。

3. 以为钻取出来的是总账明细原样列表

实际上钻取动作仍然带预算维度 domain,看到的是预算口径下的报表结果,不是裸凭证全集。

六、实战注意事项

  • 先统一 analytic 维度命名和挂载规则,再谈预算准确性。
  • 预算线日期不要“图省事”写整年;窗口越粗,理论值越失真。
  • 预算异常先看钻取 domain,再怀疑聚合逻辑。
  • 如果要做二开,优先复用 budget.report 口径,别绕开它直接写另一套统计。

结语

企业版预算线真正解决的问题,不是“给会计多一个目标金额字段”,而是把预算定义、实际发生、时间进度、analytic 维度压进同一条可追溯链路里。理解了这一点,很多“为什么数字不对”的问题,都会变成“到底是哪层口径没对齐”。

DISCUSSION

评论区

想参与讨论?先 登录 再发表评论。
还没有评论,你可以成为第一个留言的人。