项目深度

Odoo 请假工时为什么会进项目任务:Time Off task、leave timesheet 与项目工时口径到底怎么对齐

Odoo 里请假并不是单纯从工时视角“扣掉可用时间”,官方还会把请假转成挂在内部项目/任务上的分析行。这篇文章把 `project_timesheet_holidays` 如何把 Time Off 接进项目与工时统计讲透。

项目
进阶 开发者 1 分钟阅读
0 评论 0 点赞 0 收藏 5 阅读

先说结论

很多人以为 Odoo 的请假和项目工时是两套平行系统:

  • 请假在 Time Off 里审批
  • 工时在 Timesheets / Project 里登记
  • 两边最多在报表层做一下扣减

但如果你去看 /home/ubuntu/odoo-temp/addons/project_timesheet_holidays/,会发现官方选的是更强耦合的方案:

  • 请假审批通过时,自动生成 account.analytic.line
  • 这些分析行挂到公司配置的内部项目 internal_project_id
  • 同时挂到专用任务 leave_timesheet_task_id
  • 公共假期也能为员工批量生成 future timesheets
  • 并且普通用户不能手工篡改这类请假工时

所以这套设计真正想解决的问题不是“请假要不要影响工时”,而是:

请假如何作为一类正式工时事实,进入项目/分析账户体系。


第一层:为什么 Odoo 不满足于“请假只在考勤侧生效”

如果请假只停留在 HR 视角,系统当然也能算出某人休了几天。

但项目和工时分析还会继续遇到几个问题:

  • 员工当月记录了多少可计入工时的时间
  • 利用率分母分子怎么统一
  • 项目分析账户里哪些时间是交付工时,哪些是请假占用
  • 公共假期是否影响工时报表

于是官方没有只在人事模块里“减库存”,而是把请假变成正式分析行。

这一步说明:

在 Odoo 里,请假不是项目系统外的一块阴影,而是会进分析账的时间事实。


第二层:审批通过后为什么直接生成分析行

hr_leave.py 里,_validate_leave_request() 会调用 _generate_timesheets()

生成逻辑会:

  • 找公司配置的内部项目和请假任务
  • 按员工日历拆出每天对应的工时数
  • 为每一天构造 account.analytic.line
  • 带上 holiday_idemployee_idtask_idproject_id

这说明官方不是等报表查询时临时把请假折算成工时,而是在审批落地那一刻就把它记成分析事实。

这样后续无论你看:

  • 工时报表
  • 分析账户
  • 员工工时汇总
  • 项目视角的时间占用

都可以站在同一类底层记录上工作。


第三层:为什么一定要挂到内部项目和专用任务

很多系统做到这一步,会只在分析行里留一个“请假”类型字段。

Odoo 更进一步,要求公司配置:

  • internal_project_id
  • leave_timesheet_task_id

这意味着请假工时不是漂浮在系统里的匿名记录,而是明确归属到:

  • 某个内部项目
  • 某个任务容器

这有两个好处:

1. 时间数据结构统一

正常工作工时和请假工时都用 project/task/account 的结构承载。

2. 报表视角统一

很多以项目/任务为入口的分析,不需要为请假单独再造一套数据模型。

所以官方其实是在用项目系统承接“非交付时间”。


第四层:为什么公共假期也会生成 future timesheets

hr_employee.py 里有一段非常容易被忽视但很重要的逻辑:

  • 新员工创建后,会补未来公共假期 timesheets
  • 员工重新激活、工作日历变化时,也会删除并重建相关 future public holiday timesheets

这说明 Odoo 对公共假期的态度不是“到时候报表少算一天就行”,而是:

公共假期也应预先形成结构化时间事实,并随着员工状态和日历变化重新校准。

这对多日历、多公司、弹性工时环境尤其重要。


第五层:为什么普通用户不能直接编辑这类工时

account_analytic.py 里对这类分析行加了很多保护:

  • linked to holiday_id 的 timesheet 不能随便删
  • linked to global_leave_id 的 timesheet 不能手工删
  • 非 sudo 用户不能改请假关联的 timesheet
  • 也不能直接给 is_timeoff_task 任务新建普通工时

这套限制的目的非常明确:

  • 请假事实应由 Time Off 应用驱动
  • Timesheets 页面只能消费结果,不能反向篡改原始请假业务

否则你就会得到“工时改了,但请假单没改”或者“请假取消了,工时没回收”的数据撕裂。


第六层:is_timeoff_task 到底解决了什么问题

project_task.py 里会计算:

  • leave_types_count
  • is_timeoff_task

本质上它要识别:

  • 哪些任务已经承担了请假工时容器的角色

然后在 timesheet 创建域与权限校验里,禁止把这类任务当普通项目任务乱用。

所以 Time Off task 不是一个为了界面好看设的标签,而是一个数据边界标记:

这个任务是 HR/工时系统共用的特殊任务,不是普通交付任务。


新手最容易误解的 4 件事

1. 以为请假只会影响 HR 模块,不会进项目

不对,审批通过后会生成项目分析行。

2. 以为请假工时只是报表动态折算

不对,Odoo 是实打实创建 account.analytic.line

3. 以为请假 task 只是个默认值,删改无所谓

不对,它是整套时间归集逻辑的锚点。

4. 以为用户可以直接改请假工时行来修数据

不对,源码明确限制了删除与修改入口。


实战里最该注意什么

1. 客户一说“请假没体现在工时里”,先查公司配置

  • internal project 有没有
  • leave timesheet task 有没有

没有这两个,后面很多逻辑都落不下来。

2. 遇到公共假期工时异常,不只看请假单,还要看员工日历和激活状态

因为 future timesheets 会随着这些条件重建。

3. 不要让顾问用“直接删 analytic line”修请假问题

正确入口应该是:

  • 调整请假单
  • 调整公共假期
  • 或校正公司/员工配置

否则数据会越修越裂。


一句话记忆法

Odoo 的请假不是报表层扣减,而是在审批后生成挂到内部项目与专用任务上的分析行,让请假时间也能以正式工时事实进入项目体系。

DISCUSSION

评论区

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