企业|Odoo 开发

Odoo 企业版项目预测到销售续单到工时上账,为什么不是“卖掉工时包后慢慢记工时”

从 planning forecast、sale line 到 validated timesheet 的数量回写,讲清项目售前承诺、排班兑现与交付量计算的接力。

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

结论先行

服务型项目里最容易失真的,不是记工时本身,而是“售前承诺了多少、排班已经吃掉多少、最后能开票多少”三套口径各说各话。企业版把这件事做成一条显式链路:sale line 是商业承诺,planning slot 是未来分配,timesheet 是实际消耗,交付量计算则只认被允许入账的那部分事实。

第一层:入口或表面动作

sale_project_forecast 先把销售上下文带进 planning。planning.slot._compute_project_id 会从 sale_line_id.project_id 或 task 所属项目反推 project;_compute_sale_line_id 则反向把项目挂回 sale line。更关键的是 _get_shifts_to_plan_domain():当界面上下文带 default_project_id 时,它会通过项目拉取相关 sale order items,再限制可规划班次的 domain。也就是说,预测排班不是孤立的排班,而是在销售承诺允许的边界内排

第二层:真正的业务护栏

到了 project_timesheet_forecast_sale,排班开始消费项目可分配工时。_init_remaining_hours_to_plan_update_remaining_hours_to_plan_and_values 会根据 project.allocated_hours - total_forecast_time 实时裁剪 planning slot,如果剩余额度不够,复制/延展班次时会被截断甚至拒绝。这一层把 forecast 从“看板上的预计”变成了硬约束。

第三层:状态落点与边界

实际交付则落在 timesheet。analytic_account_line.write() 一旦改了 validatedunit_amount,会对关联 so_line 触发 _post_process_planning_sale_line();而 sale_timesheet_enterprise.sale_order_line_timesheet_compute_delivered_quantity_domain()get_planned_and_worked_hours_domain() 又进一步规定,只统计符合规则的 timesheet,尤其是在配置为 approved-only 时,只认 validated 工时。于是商业口径、排班口径、交付口径通过 sale line 串在了一起。

为什么这套设计更稳

这条链真正解决的问题不是“自动算工时”,而是防止销售超卖、项目超排、财务超开票。没有 remaining_hours_to_plan 这一层,项目经理可以把未来两个月的班次排满,却完全不知道已经超过 sold hours;没有 validated-only 的 delivered quantity 规则,顾问刚录入未审批工时就会把交付量顶上去。

实战启示

所以如果你要扩展这套逻辑,千万别直接在 project 上写一个 remaining_hours 字段就了事。源码把约束放在 planning slot 复制、timesheet 修改、sale line 交付量计算三个不同节点,目的是让每一次状态变化都能把下游口径重新拉齐。真正的跨模块价值,正是这种“每经过一层都重新校准一次”的接力。

DISCUSSION

评论区

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