先说结论
如果你把 Odoo 的 Talent Pool 理解成“给候选人多打一个标签”,那就低估它了。
从 hr_recruitment 源码看,人才库至少在做四件事:
- 把某些候选人变成可以长期复用的 talent 记录
- 用
pool_applicant_id把“原申请”和“池中代表记录”串起来 - 通过邮箱、电话、LinkedIn 识别是不是同一个人
- 在加池动作里尽量避免重复塞进同一套人才池体系
所以 Talent Pool 不是装饰功能,而是在解决招聘里非常现实的问题:
同一个人会被不同岗位、不同时间、不同招聘者反复接触,系统怎样既保留申请上下文,又不要把人才资产弄碎。
为什么人才库不能只是 many2many tags
如果只是给 hr.applicant 挂一个 pool 标签,会马上遇到几个问题:
1. 原申请和长期人才资产会混在一起
某次 Java 后端岗位的申请,只是一个具体场景;但这个人的能力和潜在可复用价值,可能应该跨岗位、跨时间保留。
2. 同一个人再次投递时,很难判断是不是“已在池中”
如果只是标签化,系统通常只知道“这条申请有没有标签”,不容易知道“另一个申请是不是同一个人”。
3. 不同申请上下文会互相污染
岗位、阶段、面试反馈、拒绝原因,本来属于具体申请,不一定都该沉淀到长期人才资产上。
所以 Odoo 没把 Talent Pool 做成一层轻标签,而是做成了一套“申请记录 + 人才池代表记录 + 同人识别”的结构。
pool_applicant_id 在表达什么
源码里最关键的字段之一,就是 pool_applicant_id。
它的含义可以理解成:
- 这条申请本身是不是池中代表记录
- 如果不是,它对应的池中代表是谁
而当系统把一个普通申请加入人才池时,向导 talent.pool.add.applicants 有两条分支:
情况一:这个 applicant 本来就已经有 talent_pool_ids
那就直接给它继续追加池子和分类。
情况二:它还不是一个 talent
系统会 copy() 一份新记录:
job_id被清空- 写入
talent_pool_ids - 合并
categ_ids - 新记录把
pool_applicant_id指向自己 - 原申请也回指到这个 talent
这非常关键。
它说明 Odoo 的思路不是“把原申请直接改造成人才池记录”,而是:
必要时复制出一个更适合长期复用的 talent 视角。
为什么复制后要把 job_id 清空
这是很多人第一次看源码时最能看出设计味道的细节。
把候选人放入人才池时,新复制的 talent 会把 job_id 设成 False。
这几乎是在明说:
人才池不是某个岗位下的附属页签,而是脱离单一岗位上下文的人才资产。
也就是说,原申请可以保留“我当时投的是销售经理”;但池中 talent 代表的是“这个人未来可能还适合别的岗位”。
系统怎么判断“是不是同一个人”
Odoo 在人才池识别上没有只盯一个主键,而是组合使用:
email_normalizedpartner_phone_sanitizedlinkedin_profile
在 _compute_is_applicant_in_pool() 和 _compute_talent_pool_count() 里,源码都会去搜:
- 直接已在池中的申请
- 与它们在邮箱 / 电话 / LinkedIn 上相同的其他申请
这说明 Odoo 已经接受了招聘里的一个现实:
同一个候选人可能会用不同申请记录出现,但仍然应该被识别成同一个人才资产网络的一部分。
这比只靠姓名靠谱得多,也比只靠邮箱更稳,因为现实里有人会换邮箱、只留电话,或只给 LinkedIn。
为什么“间接在池中”也算在池里
源码明确区分了:
- direct:自己就有
talent_pool_ids或pool_applicant_id - indirect:虽然自己没直接挂池,但和池中记录共享邮箱、电话或 LinkedIn
这很聪明。
因为招聘现场经常发生这种情况:
- 候选人去年投过 A 岗并被拉进人才池
- 今年又投了 B 岗
- 新申请并没有手工重新挂池
如果系统不能把这两条连起来,人才库就会逐渐碎成很多孤岛。
Odoo 的实现等于在说:
“是否在池中”不只看当前这条记录被没被手工打标,还看它是否能和已知 talent 识别为同一个人。
为什么搜索逻辑甚至专门为去重写了 SQL
_search_is_applicant_in_pool() 里直接写了一段 SQL,用来搜索:
- 直接已在池中的申请
- 邮箱命中池中申请的申请
- 电话命中池中申请的申请
- LinkedIn 命中池中申请的申请
而注释里也写得很直白:
这是为了在“添加到人才池”的动作里,隐藏重复项。
这说明 Odoo 不是把去重留给招聘顾问肉眼判断,而是尽量在搜索域层就减少重复操作。
这套设计最聪明的地方:既保留申请历史,又复用人才资产
如果只保留一个 Applicant,你会失去每次投递的上下文。
如果每次投递都完全独立,又会失去“这是同一个人”的长期积累。
Talent Pool 这套结构恰好在两者之间找了平衡:
- 原申请继续保留具体岗位、阶段、面试过程
- 池中 talent 代表长期可复用的人才对象
- 系统再用邮箱/电话/LinkedIn 把相关申请串起来
这比“标签化”成熟很多。
实施时最容易犯的误解
误解一:人才库就是 candidate tag
这样会低估去重和复用的复杂度。
误解二:进池以后还应保留原岗位 job_id
源码相反,复制成 talent 时会清掉 job_id,因为人才池要脱离单岗位语境。
误解三:只靠邮箱就够了
Odoo 明确同时用了标准化邮箱、清洗后的电话和 LinkedIn,说明单一标识在招聘场景里并不可靠。
一句话记忆
Odoo 的 Talent Pool 不是给申请贴标签,而是把“具体申请”与“长期人才资产”分开,再通过邮箱、电话、LinkedIn 把同一个人重新连起来。
DISCUSSION
评论区