人力资源

Odoo 员工在不在岗,为什么不只看聊天绿点:IP、邮件、手动改状态三套信号怎么一起工作

很多团队把 Presence 理解成一个在线状态灯。Odoo 的 hr_presence 源码其实在拼三类证据:工作时段内是否应在岗、今天是否有 IP/邮件活动、HR 是否做了手动覆盖。它想回答的不是‘聊天在线吗’,而是‘这名员工现在是否值得被当作在岗处理’。

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

先说结论

Odoo 的 Presence 从来不是一个“谁在线谁不在线”的聊天小功能。

/home/ubuntu/odoo-temp/addons/hr_presence/models/hr_employee.py 里,官方真正做的是一套在岗推断机制

  • 先判断员工现在是不是理论上应该在岗
  • 再看今天有没有 IP 活动
  • 再看今天有没有 邮件发送活动
  • 最后允许 HR 手动覆盖

所以它的目标不是回答“人是不是开着电脑”,而是回答:

这名员工在当前工作时段里,是否有足够证据被视为 present。


第一层:Presence 先依赖“现在是不是工作时间”

_compute_presence_state() 里最关键的不是 IP,也不是 email,而是 working_now_list

这意味着 Presence 不是全天候判定的。只有当员工此刻落在自己的工作时间里,系统才会认真区分:

  • present
  • absent
  • out_of_working_hour

这三个状态的业务含义完全不同。

很多实施会误把 absent 当成“今天没来上班”。源码并不是这么说的。

更准确地讲:

  • out_of_working_hour:现在本来就不该上班
  • absent:现在应该在岗,但系统没抓到足够的活动信号
  • present:现在应该在岗,并且有足够信号证明他活跃

所以 Presence 是一个时段内判断,不是日终考勤结论。


第二层:IP 检查看的不是登录记录,而是“今天是否从受控网段出现过”

_check_presence() 会先把全公司员工当天的 Presence 辅助标记重置掉:

  • email_sent = False
  • ip_connected = False
  • manually_set_present = False
  • manually_set_presence = False

然后才重新计算。

如果公司启用了 hr_presence_control_ip,系统会去查 res.users.log,并只看:

  • 当前员工关联用户
  • ip 不为空
  • create_date 在今天 0 点之后

/home/ubuntu/odoo-temp/addons/hr_presence/models/res_users_log.py 还专门给 res.users.log 扩了 ip 字段,说明官方是把“今天是否从某些办公网段活跃过”当成 Presence 证据之一。

这一步的重点不是精确定位,而是一个比较务实的判断:

今天在受控 IP 列表里出现过,就更像是在岗。

所以它更像“办公网络信号”,不是“物理门禁信号”。


第三层:邮件阈值不是沟通统计,而是活跃代理指标

如果公司启用了 hr_presence_control_email,系统还会统计员工今天发出的邮件数。

源码看的是:

  • mail.message
  • 作者是该员工 user_id.partner_id
  • 时间区间在今天 0 点到现在
  • 数量达到 hr_presence_control_email_amount

这一步很有意思。

Odoo 并没有把“发邮件多”理解成 KPI,而只是把它当成一个活跃代理信号

  • 发过足够数量的业务邮件
  • 说明今天至少在系统里有工作动作
  • 因而可用来支持 present 判断

它不是为了评价绩效,而是为了降低“明明在办公却被标成 absent”的误判率。


第四层:手动改状态不是备注,而是强制覆盖

action_set_present() / action_set_absent() 最值得注意的地方,是它们并不是简单写一个展示字段。

HR Manager 手动处理后,系统会写:

  • manually_set_present
  • manually_set_presence
  • hr_presence_state_display

随后 _compute_presence_state() 里第一优先级就会检查:

  • 如果 manually_set_presence 为真
  • 直接采用 hr_presence_state_display

这说明手动 Presence 不是“给界面加个小标签”,而是覆盖自动判定结果

也就是说,官方非常清楚自动信号会有噪声,所以给了 HR 一个可解释、可纠偏的人工兜底入口。


第五层:Presence 和缺勤处理之间还有动作链

源码里 get_presence_server_action_data() 会准备一组服务器动作,包含:

  • 标记 present
  • 标记 absent
  • 写日志
  • 发送短信
  • 发起 Time Off

再看 action_open_leave_request(),你会发现 Presence 不是停在“看板颜色”。

它还能把“非计划缺勤”推进到后续动作:

  • 单人时打开 hr.leave
  • 多人时打开批量缺勤向导
  • 默认原因就是 Unplanned Absence

这一步很关键,因为它说明 Presence 不是最终事实,而是运营入口

看见异常在岗状态后,HR 可以顺着它继续补日志、催沟通、补请假。


第六层:为什么官方每天都先清零再重算

很多人第一次看到 _check_presence() 里那段重置代码,会觉得“这不是会丢历史吗”。

其实 Presence 本来就不是历史归档对象。

官方在这里强调的是:

  • Presence 是当日即时状态
  • 不是长期稽核明细
  • 真正的历史凭证仍在邮件、日志、请假、考勤等其他对象里

因此每天先清零再重算,反而能避免昨天的信号污染今天的判断。

这也解释了为什么 res.company 里只保留了一个 hr_presence_last_compute_date

  • 用来确认当天是否已重算
  • 而不是保存一整套 Presence 历史账本

实施时最容易踩的 4 个坑

1. 把 Presence 当考勤

Presence 只能说“现在像不像在岗”,不能直接替代 Attendance 或 Payroll。

2. 把 IP 证据当绝对事实

员工用 VPN、移动网络、远程桌面时,IP 证据会失真。

3. 把邮件阈值当绩效考核

它只是 Presence 信号,不是绩效分。

4. 忘了手动覆盖优先级最高

如果 HR 频繁手改状态,却没有配套流程,就会让自动判定失去可信度。


最后一句话

Odoo Presence 的本质不是“在线灯”,而是把工作时段、系统活动和人工纠偏拼成一张当日“是否在岗”的推断图。

DISCUSSION

评论区

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