很多企业以为 timesheet 就是工资工时来源,但 Odoo 企业版没有这么偷懒。项目工时、休假生成的内部工时、以及工资规则需要的小时类型其实属于不同语义层;企业版真正做的是在这些层之间搭桥,而不是直接把 analytic line 塞进 payslip。
## 1. Timesheet 会显式避开 holiday 生成的行,防止项目工时污染休假语义
在 enterprise/timesheet_grid_holidays/models/hr_employee.py 与 models/analytic.py 里,系统在统计 worked hours 时排除了 holiday_id 和 global_leave_id,同时阻止用户把与休假请求绑定的 timesheet 随意 merge。也就是说,timesheet 模块先保证“项目工作小时”和“休假占位小时”不会混账。
2. 休假可以生成内部任务工时,但这不等于 payroll 直接吃 analytic line
测试 test_timesheet_holidays.py 很清楚:批准休假后会生成 holiday.timesheet_ids,并放在内部 leave task 上。这主要服务于工时展示、提醒和项目视角统计,而不是直接作为工资规则输入。这里已经出现第一层桥:同样是一小时,项目维度与薪资维度不是同一个对象。
3. Payroll 端真正接住的是 work entry 和薪资版本字段
到了 enterprise/hr_work_entry_enterprise/models/hr_work_entry.py 与 enterprise/hr_contract_salary_payroll/models/hr_payslip_worked_days.py,工资计算看的还是 work entry、number_of_hours、wage_with_holidays 以及合同版本设定。timesheet 与 leave 只是在前端和业务层把“工作/休假小时”分开,最后仍要通过 work entry 和工资版本字段进入薪资。
4. 实施里的危险做法,是把项目工时字段当作唯一工资依据
如果直接拿 analytic line 汇总进工资,很容易把 leave task、global leave 或不可计费项目小时一起带进来。企业版源码的设计其实是在提醒你:timesheet 是业务记录层,payroll 是结算层,中间必须经过 hours type 和 work entry 的翻译。
## 结论
所以,Odoo 企业版不是“员工填完 timesheet,工资自然会算出来”,而是先把项目工时和休假工时拆开,再通过 work entry 与合同版本把这些小时翻译成 payroll 可理解的结算语义。
主要源码锚点:
- `enterprise/timesheet_grid_holidays/models/hr_employee.py`
enterprise/timesheet_grid_holidays/models/analytic.pyenterprise/timesheet_grid_holidays/tests/test_timesheet_holidays.pyenterprise/hr_work_entry_enterprise/models/hr_work_entry.pyenterprise/hr_contract_salary_payroll/models/hr_payslip_worked_days.py
DISCUSSION
评论区