企业 薪资考勤

Odoo 企业版薪资考勤为什么不是“工资单抓一下打卡”而已:工资期窗口、时区归属与 overtime worked days 边界讲透

基于 hr_payroll_attendance 源码与测试,讲清工资单如何匹配考勤区间、为什么按 check_in:day 聚合会影响跨时区归属,以及 overtime 如何进入 worked days 但不应被算成半天。

人力资源 企业
进阶 开发者 1 分钟阅读
0 评论 0 点赞 0 收藏 6 阅读

工资单接考勤,最容易被误解成一句话:在工资期里把打卡加总一下就好。但 /home/ubuntu/odoo-temp/enterprise/hr_payroll_attendance 明显不是这么做的。官方真正关心的是:哪些打卡属于哪张工资单、跨日跨时区怎么归属、加班又该以什么形式进入薪资计算。

参考入口:

  • enterprise/hr_payroll_attendance/models/hr_payslip.py
  • enterprise/hr_payroll_attendance/models/hr_payslip_worked_days.py
  • enterprise/hr_payroll_attendance/tests/test_payslip_attendance.py
  • enterprise/hr_payroll_attendance/tests/test_payslip_overtime.py

一、工资单匹配考勤不是简单按完整落入区间过滤

_get_attendance_by_payslip() 的域条件是:

  • 员工相同;
  • check_in <= date_to
  • check_out >= date_from

也就是说,只要打卡区间与工资期有重叠,就先纳入候选。然后官方再按 check_in:day 聚合,并根据 slip 的 date_from <= check_in.date() <= date_to 来决定归属。

这说明它不是只接受“完全落在工资期内”的记录,而是先找相交考勤,再按日期粒度切归属。

二、为什么测试特别强调时区

test_get_attendance_from_payslip_with_timezone 很关键。相同的打卡,在 Europe/Brussels 上下文里可能落到不同日期边界。换句话说,工资单归属不是纯数据库 UTC 比较,而是用户看见的业务日期也会影响结果。

这正是薪资系统最容易踩坑的地方:夜班、跨午夜、跨国团队,只要你忽略时区,某些 attendance 就会被分到错误工资期。

三、attendance_count 是解释入口,不只是一个统计数字

_compute_attendance_count()action_open_attendances() 做的事情很朴素:把工资单对应到具体考勤列表,并给 HR 一个可钻取入口。这个设计非常务实,因为薪资对账时最怕“总额不对但找不到底层记录”。

也就是说,attendance_count 的真正价值是把工资结果回链到原始打卡事实

四、overtime 进 worked days,但不能被当成半天假

HrPayslipWorkedDays._is_half_day() 明确排除了 work_entry_type_overtime。这行代码很短,但业务含义非常重:加班是额外工时,不应套用请假/缺勤那套半天语义。

测试里还覆盖了:

  • 工资期外的 overtime 不进本次工资单;
  • 负向 overtime 不一定生成行;
  • 需要审批的加班,在 action_approve_overtime() 之前不会进入 worked days。

所以 overtime 不是“只要出现就进薪资”,而是受工资期、审批状态和工时语义共同约束。

五、实战注意事项

  • 先确认员工 version_id.work_entry_source 是否真的是 attendance,否则工资单根本不会走这套逻辑。
  • 发现某条打卡没进工资期时,先查时区边界,再查审批状态,最后再看重叠区间。
  • 不要把 overtime worked day 当成休假型行去复用半天算法。

六、结论

hr_payroll_attendance 解决的不是“把打卡算进工资”这么简单,而是把工资期、业务日期、考勤事实和 overtime 审批串成一条可追溯的链路。只有把这些边界守住,工资单才不会在跨时区与异常加班场景里出错。

DISCUSSION

评论区

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