很多团队把工时审批理解成“经理点一下通过”。可企业版 timesheet_grid 真正做的,是在审批通过后建立一条 时间边界:这条边界之前的工时应该被冻结、计时器不该继续跑、后续草稿也不该再悄悄插回去。
主要参考:
enterprise/timesheet_grid/models/account_analytic_line.pyenterprise/timesheet_grid/models/project_task.pyenterprise/timesheet_grid/views/*
一、validated 会改变记录可写性,不只是显示状态
validated 一旦为真,_is_readonly() 就会把这条工时纳入只读逻辑。也就是说,审批通过不是视觉上的帽子,而是数据生命周期切换:这条工时从“可编辑草稿”进入“应被尊重的已确认事实”。
很多新手系统上线后第一句抱怨就是“为什么批完就不能改”。但从管理角度看,审批如果不带来写入边界,就等于没有审批。
二、审批动作会先停 timer,再写 validated
action_validate_timesheet() 里非常关键的一步是 analytic_lines._stop_all_users_timer()。企业版很清楚:如果某个工时还在跑计时器,你今天把它审批了,明天又继续往上累加,这条审批就失去了意义。
因此系统会先停掉相关 timer,再把记录置为 validated。审批顺序本身就是控制逻辑的一部分,不是随便排的。
三、last_validated_timesheet_date 是审批边界的核心锚点
审批后,_update_last_validated_timesheet_date() 会把每个员工最近审批到哪一天记下来;而 _search_last_validated_timesheet_date() 会在反审批时重新搜索回填。这个字段很像一道堤坝:它让系统知道“从哪一天往前,工时不该再被草稿穿透”。
这也解释了为什么企业版不是简单在单条工时上打一个 validated 勾就结束——它还需要一个员工级汇总边界,供后续规则统一引用。
四、display timer 与 hatched UI,背后都是审批边界的投影
_should_not_display_timer() 会在员工不匹配或工时已审批时隐藏 timer。is_hatched 则根据 validated 状态切换样式。看起来像 UI 细节,实际上都在把同一条业务边界投影到界面层:已审批,就别再像草稿一样继续录。
这类设计对新人很友好,因为它不是只在后端报错,而是在前端也尽量降低误操作概率。
五、实战误区
- 以为审批只是给报表看。实际上它会影响只读、timer、员工级日期边界。
- 以为 timer 是独立模块。审批链里 timer 会被主动干预。
- 以为反审批只需要把 validated 改回 False。事实上还要重算员工最近审批日。
六、落地建议
- 先明确组织里谁有 approver 权限,再启用审批;否则会出现“谁都看得懂、没人能执行”的状态。
- 员工培训时要说清楚:一旦工时被审批,通过补 timer 回写旧日期基本不可取。
- 若团队频繁需要反审批,优先排查流程设计,而不是把审批边界做松。
七、结论
timesheet_grid 的审批不是一个“确认按钮”,而是一条时间边界治理机制:停 timer、锁记录、记录最近审批日、阻止旧区间继续漂移。把这条边界建立起来,项目工时才真正有机会成为可信的管理数据。
DISCUSSION
评论区