官网招聘

Odoo 官网招聘为什么不是“挂个职位收简历”这么简单:申请去重、阶段初始化与岗位检索链路讲透

很多人把 Odoo 官网招聘理解成职位页加一个投递表单,但 website_hr_recruitment 实际把岗位搜索、地区筛选、模糊检索、重复申请提醒、关闭岗位拦截和 applicant 初始阶段设置串成了一条完整链路。

网站
进阶 开发者 1 分钟阅读
0 评论 0 点赞 0 收藏 5 阅读

先说结论

Odoo 的官网招聘,不是“网站上展示几条职位,再把表单内容塞进 hr.applicant”这么简单。

website_hr_recruitment 的 controller 和 model 看,它真正关心的是:

  • 岗位如何在官网上被搜索到;
  • 访客如何按国家、部门、办公地、合同类型筛选;
  • 已关闭岗位怎样阻止继续投递;
  • 同一候选人最近有没有重复申请;
  • 新申请进入系统时,该落到哪个招聘阶段。

所以这个模块本质上不是“官网页面接 HR 后台”,而是:

把招聘官网、候选人投递体验和后端招聘流程的起点对齐。


一、为什么职位页不是简单列表,而是一套可搜索内容对象

jobs() 入口里最值得注意的是:

  • 它不是普通 search()
  • 而是走 website._search_with_fuzzy("jobs", ...)

这说明 Odoo 没把职位页当成静态展示,而是当成网站搜索体系里的一类内容。

同时 hr.job 还继承了:

  • website.seo.metadata
  • website.published.multi.mixin
  • website.searchable.mixin

这几层叠在一起,意味着官网职位并不是 HR 模块的副产物,而是:

  • 可以被搜索;
  • 可以有 SEO;
  • 可以参与网站发布管理;
  • 可以按网站域隔离。

所以如果你做官网招聘,只把它当个表单页,实际上会低估 Odoo 已经做好的内容侧能力。


二、为什么筛选器不是前端拼 URL,而是“互相污染”的结果集计算

jobs() 里有一段比较有意思的逻辑:

  • 先取到搜索结果;
  • 再计算各筛选条件下的计数;
  • 还会在计算某一类筛选时,临时禁用这类筛选本身,去看其他筛选条件下还有多少岗位。

这就是源码里注释说的“contaminating the jobs with the other filters”。

通俗说,Odoo 想解决的是:

  • 用户现在按“国家 + 部门”筛完后,页面上“办公地”“合同类型”这些筛选项还能不能显示一个可信数量;
  • 而不是把筛选器做成一堆互相打架的死按钮。

这点看似只是列表页体验,实际上很影响投递效率。因为职位筛选一旦做得粗糙,候选人会很快失去耐心。


三、为什么官网会主动提醒“你最近已经投过了”

/website_hr_recruitment/check_recent_application 这条 JSON RPC 很值得讲。

它会根据候选人输入的:

  • 姓名
  • 邮箱
  • 电话
  • LinkedIn

去找同岗位、同网站下的历史申请,并区分:

  • 仍在进行中的 ongoing
  • 近 6 个月内被拒且已关闭的 refused

如果命中,系统会给出提醒,而不是傻傻地再收一份一模一样的申请。

这背后的价值非常现实:

  1. 候选人少做无效重复劳动;
  2. HR 少看重复简历;
  3. 官网投递体验更像“我在和一个有记忆的招聘系统互动”,不是“往黑洞里再扔一次表单”。

四、为什么岗位关闭后,website form 还要再做一次拦截

hr.applicant.website_form_input_filter() 里,源码明确检查:

  • 如果传入了 job_id,但该岗位 active=False,直接报错:The job offer has been closed.

这个设计很重要。

因为官网页面可能存在这些现实情况:

  • 候选人开着旧页面很久没刷新;
  • 外部分享链接还在流传;
  • 搜索引擎缓存了旧职位页;
  • HR 在后台刚把职位关闭。

如果没有模型层这一挡,前台很容易继续接到“已经不该收”的简历。

所以 Odoo 不是只在页面上隐藏按钮,而是在真正写入 applicant 前再做一次业务拦截。


五、为什么申请创建时要顺手设置初始阶段

还是这个 website_form_input_filter(),另一个关键动作是:

  • 按岗位找第一个未 fold 的招聘阶段;
  • 如果该阶段适用于该岗位或是全局阶段,就把它写到 stage_id

很多人觉得建 applicant 默认进第一阶段不是理所当然吗?

其实不一定。

招聘流程往往有:

  • 通用阶段;
  • 针对某岗位的专属阶段;
  • 已折叠的历史阶段;
  • 不同团队自己维护的阶段顺序。

Odoo 在网站入站时就把这件事处理好,目的很明确:

官网投递不是孤零零造一条记录,而是要让它一进入后端就站在正确流程位置上。


六、为什么“已发布职位”不等于普通 active 记录

hr.job 里同时有:

  • website_published
  • is_published
  • published_date
  • website_url

并且 website_published 的 onchange 会驱动 is_published

这说明 Odoo 区分了:

  • 岗位记录在后端是否存在;
  • 岗位是否允许在官网公开显示。

再加上 _search_get_detail() 里会把 website.website_domain() 纳入搜索域,你就会发现:

  • 多网站情况下,职位是否该在当前官网出现,也不是随便的。

所以官网招聘不是“HR 有岗位 -> 网站自动展示”,中间还有一层网站发布语义。


七、实施时最容易踩的坑

1. 只管投递表单,不管职位搜索体验

候选人首先看到的是职位列表,不是 applicant 表。

2. 只在前端隐藏关闭岗位,忘了模型层二次拦截

这会导致旧链接照样继续收简历。

3. 不做重复申请提醒

HR 会被重复候选人淹没,候选人也会怀疑系统有没有记住自己。

4. 让官网投递生成的 applicant 落到错误阶段

后端一开始就乱,后续统计和流程都会偏。


最后总结

Odoo 的 website_hr_recruitment 真正难的地方,不是把职位放到官网,而是把:

  • 网站搜索和筛选;
  • 岗位发布状态;
  • 候选人重复识别;
  • 关闭岗位拦截;
  • applicant 流程初始化;

几件事拼成同一条链路。

所以更准确地说,它是一套:

把“官网获客入口”直接接到“招聘流程起跑线”的职位投递系统。

DISCUSSION

评论区

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