人力资源

Odoo 为什么有些假你明明有余额也请不下来:Mandatory Day、工作日历与请假边界不是一回事

很多团队以为请假能不能批,主要看余额和审批人。Odoo 的 hr_holidays 源码还加了一层更硬的边界:Mandatory Day。它可以按公司、工时日历、部门和岗位限制某段时间不允许普通员工请假,而且这一层和公休、排班、版本时间线一起工作。

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

先说结论

在 Odoo 里,“有余额”并不等于“这段时间就能请假”。

/home/ubuntu/odoo-temp/addons/hr_holidays/models/hr_leave_mandatory_day.pyhr_leave.py 说明,官方专门保留了一道独立边界:

  • 这天是不是 Mandatory Day
  • 这名员工是否落在受限范围内
  • 这段请假对应的日历和岗位是否被卡住

所以请假真正的判断顺序不是只有:

  • 有无余额
  • 审批人同不同意

还包括一个更硬的问题:

系统是否允许你在这段业务关键期提出这张假单。


第一层:Mandatory Day 不是节假日表,而是“禁止请假的业务窗口”

hr.leave.mandatory.day 模型很小,但信息非常集中:

  • start_date
  • end_date
  • company_id
  • resource_calendar_id
  • department_ids
  • job_ids

这说明 Mandatory Day 的本质不是“法定假日定义”,而是企业自己声明的一段不可自由请假的窗口

它可以表达的典型场景包括:

  • 年终盘点周
  • 门店大促期间
  • 项目上线冻结窗口
  • 学校开学周
  • 工厂换线关键期

官方甚至允许它按:

  • 公司
  • 工时日历
  • 部门
  • 岗位

分别生效,这已经远比“全公司一刀切禁假”更细。


第二层:Mandatory Day 是按员工上下文动态判断,不是静态勾选

_compute_has_mandatory_day() 里,Odoo 并不是简单查“日期有没有落在 mandatory day 里”。

它还会结合:

  • 员工的部门
  • 员工的资源日历
  • 假种所属公司
  • 员工通过 _get_mandatory_days() 能拿到的候选 mandatory day

然后再过滤出真正适用当前员工的记录。

也就是说,同一天在系统里可能既是 Mandatory Day,又不是 Mandatory Day,关键看对谁而言

这种设计很现实,因为企业里的“不能请假”从来都不是纯日期逻辑,而常常是组织范围逻辑。


第三层:普通员工会被拦,Officer/Manager 则保留干预空间

真正的硬限制出现在 _check_validity()

  • 如果普通用户提交的请假命中了 mandatory day
  • 会直接抛 ValidationError
  • 提示你不允许在 Mandatory Day 请假

但这里有一个很重要的边界:

  • 不是所有角色都一样被锁死
  • 代码判断的是 group_hr_holidays_user

这意味着官方承认现实里会有“业务冻结窗口”,但也承认 HR/管理层必须保留例外处理能力。

所以 Mandatory Day 不是绝对技术壁垒,更像:

对普通员工默认关闭,对管理角色保留兜底。


第四层:它和工作日历、版本时间线天然耦合

Mandatory Day 真正有意思的地方,在于它不是独立悬空的。

同一个 hr.leave 在计算过程中还要考虑:

  • resource_calendar_id
  • 员工当前版本能否跨多个版本
  • 不同版本是否用了不同工作日历

_check_contracts() 甚至明确限制:

  • 一张假单不能跨多个使用不同 working schedule 的版本

这说明 Odoo 的思路不是“先申请假,再事后算日历”,而是:

  • 请假一开始就必须落在可解释的工时边界里
  • Mandatory Day 只是其中一层限制
  • 版本 / 日历一致性是另一层限制

两者叠加后,才是最终能不能请的结果。


第五层:它和 Public Holiday 也不是同一件事

很多实施会把 Mandatory Day 和 Public Holiday 混为一谈。

源码告诉你,它们是两回事:

  • Public Holiday 影响请假时长计算与是否需要扣额度
  • Mandatory Day 影响这段时间是否允许普通员工发起请假

举个典型例子:

  • 春节法定假期:更像 Public Holiday
  • 年度大促最后三天不得休假:更像 Mandatory Day

前者回答“这天算不算工时/假时长”,后者回答“这张申请能不能提”。

这两个问题的业务语义完全不同。


第六层:Mandatory Day 其实是在保护排班可执行性

如果只从员工体验看,Mandatory Day 很像“系统不让请假”。

但从源码设计看,它真正保护的是:

  • 某些岗位在关键窗口的人手底线
  • 排班和服务承诺的可执行性
  • 不同工作日历下的可用人力

所以它不是为了“管控更严格”,而是为了避免组织在关键期被零散合法假单掏空。

这也是为什么模型里会出现:

  • resource_calendar_id
  • department_ids
  • job_ids

因为官方关心的是哪类人、在哪套工时规则下、在什么窗口不能随意休假


实施时最容易踩的 4 个坑

1. 把 Mandatory Day 当法定节假日

它们的语义完全不同。

2. 忽略岗位和部门范围

这样会把本应局部受限的规则变成全员误伤。

3. 只看余额,不看 schedule 边界

余额足够也可能因为版本或日历边界过不去。

4. 让管理层也完全无法例外处理

源码本身就给 Officer 保留了干预空间,别把业务弹性设计没了。


最后一句话

Odoo 的 Mandatory Day 本质不是“又一层审批”,而是把企业关键窗口、组织范围和工作日历边界提前塞进请假校验里。

DISCUSSION

评论区

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