排班、打卡、发工资这三件事在很多系统里各算各的,最后只能人工对账。Odoo 企业版用 hr_work_entry_planning_attendance、planning_attendance 和 hr_payroll_attendance 把这三者收束到同一条 work entry 主链里,重点不是“谁数据更多”,而是谁拥有最终可结算的时间语义。
## 1. Planning 先给出预期工作区间,再允许 Attendance 覆盖真实发生区间
在 enterprise/hr_work_entry_planning_attendance/models/hr_employee.py,系统先按 planning.slot 计算 schedule interval,再把这些 interval 作为 work 区间写入返回结果。排班在这里提供的是“应当工作”的边界。
2. 当合同声明 work_entry_source=planning 时,Attendance 不再是独立账本
enterprise/hr_work_entry_planning_attendance/models/hr_version.py 会先筛出 work_entry_source == planning 且 overtime_from_attendance 的合同,再查 hr.attendance、计算 overtime intervals,并把 approved overtime 映射成 work entry。也就是说,打卡并不是单独参与工资计算,而是被翻译成对 planning 区间的偏差修正。
3. Payroll 只认最终 work entry 语义,而不是原始打卡明细
enterprise/hr_payroll_attendance/models/hr_payslip.py 里 _get_attendance_by_payslip() 会把工资单与 attendance 对齐,但前提仍是工资单版本的 work_entry_source。与此同时 hr_payslip_worked_days.py 对 overtime 类型做单独处理,说明 Payroll 关注的是哪些时间已经被提升为可结算类型,而不是简单罗列所有打卡。
4. 分析报表只是审计层,不是结算层
很多实施会把 planning_attendance 报表当成事实来源,但 planning.attendance.analysis.report 更适合做“计划与实际偏差”分析。真正进入结算的是那条已经经过 planning、attendance 与 overtime 规则折算后的 work entry 链。把分析报表和结算事实混在一起,是工资工时冲突的常见来源。
## 结论
所以,Odoo 企业版不是让 Planning、Attendance、Payroll 各自持有一套“工时真相”,而是先用 planning 给出预期,再用 attendance 修正现实,最后让 payroll 只消费统一的 work entry 结果。
主要源码锚点:
- `enterprise/hr_work_entry_planning_attendance/models/hr_employee.py`
enterprise/hr_work_entry_planning_attendance/models/hr_version.pyenterprise/planning_attendance/report/planning_attendance_analysis_report.pyenterprise/hr_payroll_attendance/models/hr_payslip.py
DISCUSSION
评论区