人力资源

Odoo 员工为什么不是“一人一合同一条线”:看懂 hr.version 才看懂员工生命周期

许多用户以为员工档案只是一行记录加一份合同。Odoo 新版 HR 源码其实把员工变化拆成版本时间线,合同只是其中一层,这让调岗、调薪、换排班、未来生效变更都更好处理。

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

先说结论

如果你还把 Odoo 员工理解成“一个员工 = 一条固定记录 = 一份合同”,那已经太扁平了。

从源码看,Odoo 现在更接近这样建模:

  • hr.employee 是员工主对象
  • hr.version 是员工在不同时间段的有效版本
  • 合同日期只是版本里的一个重要维度,不是全部

也就是说,员工不是只有一个静态档案,而是一条会随时间演化的版本时间线。


为什么要引入 hr.version

现实里的员工不会只变一次。

一个人可能会经历:

  • 入职
  • 试用期结束
  • 岗位调整
  • 部门调整
  • 工时日历变化
  • 合同续签
  • 工资变化
  • 离职或未来待生效变更

如果这些都直接覆盖在 hr.employee 当前字段上,系统会失去一个很关键的能力:

我想知道“某一天”这个员工到底处于什么状态。

hr.version 就是在解决这个问题。


date_versioncontract_date_startdate_start 到底有什么区别

这是很多人第一次看源码时最容易混的地方。

1. date_version

表示这份版本从哪一天开始生效。

它更像“版本切换点”。

2. contract_date_start / contract_date_end

表示合同区间。

它回答的是:这个员工在合同意义上,从什么时候到什么时候处于合同内。

3. date_start / date_end

源码里 _compute_dates() 会根据:

  • 当前版本的 date_version
  • 当前版本的合同日期
  • 下一版本的 date_version

计算出这份版本真正对外生效的区间。

所以它不是手填,而是算出来的“有效时间窗”。

这点很重要:

版本切换点合同边界 不是同一个概念,但会一起决定最终有效期。


为什么一个员工不能有重叠合同区间

hr.version 的约束里会检查:同一员工的合同时间不能互相重叠。

这背后的业务含义很直接:

  • 你可以有多个连续版本
  • 你也可以有未来版本
  • 但不能让同一名员工在同一时期同时落入两段冲突合同里

否则后面的:

  • work entries 生成
  • 排班推导
  • 薪资期间计算
  • 出勤/请假归属

都会失真。

所以这个约束不是“表单校验太严格”,而是在保护整条时间线的可计算性。


is_currentis_pastis_future 为什么比看字段值更重要

源码里直接计算了:

  • is_current
  • is_past
  • is_future

这意味着 Odoo 很在意一个版本处在时间轴上的位置,而不只是字段内容本身。

比如同样一条调岗记录:

  • 今天生效,就是当前版本
  • 下个月生效,就是未来版本
  • 去年那条,就是历史版本

系统后续很多判断,其实都依赖这个“时态”,而不仅仅是岗位名或工资金额。


为什么 create_version() 不是简单复制一行

源码里的 create_version() 做的事情比“复制旧记录”多得多:

  1. 找出指定日期应继承哪一个旧版本
  2. 判断那一天落在哪段合同区间中
  3. 必要时同步已有合同段的结束日期
  4. 复制能继承的字段
  5. 再写入新版本的差异值

所以版本不是“快照备份”,而是带时间语义的继承与切分

这也解释了为什么做 HR 实施时,不能用“直接改当前员工字段”来理解所有业务变化。


create_contract() 暗示了什么

create_contract() 的逻辑也很有代表性:

  • 如果同一天已有版本,就把合同日期写到该版本上
  • 否则创建一个新的版本,把合同起点落进去
  • 如果未来已有另一段合同,还会自动推导当前合同的结束边界

这说明在 Odoo 里,合同不是孤立漂浮的一张纸,而是嵌在员工版本时间线里的。


这套设计给实施带来的现实好处

1. 更容易表达“未来生效”

今天先录好下月调岗,不必立刻污染当前状态。

2. 更容易回答历史问题

比如:

  • 上个月他的工时日历是什么?
  • 那次请假时他属于哪个部门?
  • 工资单期间到底挂哪份版本?

3. 更适合联动 work entry 和排班

因为系统能按时间取到正确版本,而不是只看员工“当前长什么样”。


实施时最危险的误解

最危险的一句往往是:

“反正员工就一条记录,直接改掉就好了。”

短期看很省事,长期会让历史失真。

更稳的理解应该是:

  • hr.employee 是员工身份
  • hr.version 是员工在不同时间的状态片段
  • 合同只是这些状态片段中的关键边界之一

一句话记忆

Odoo 管的不是“一个静态员工”,而是一条随时间变化的员工版本时间线;看懂 hr.version,很多 HR 行为才真正说得通。

DISCUSSION

评论区

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