项目深度

Odoo 门户工时为什么不是“客户能看项目就能看所有 timesheet”:portal 视图切换、域过滤与任务/项目客户字段讲透

很多人以为 Odoo 门户用户一旦被加进项目共享,就自然能看到该项目下所有工时。源码并不是这么做的。本文围绕 `_timesheet_get_portal_domain`、`action_view_subtask_timesheet` 和 portal 专用视图,讲清门户工时可见性为什么同时受 partner 归属、项目隐私和视图降级控制。

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

先说结论

在 Odoo 里,门户用户能不能看到工时,不是“是否共享了项目”这一条规则说了算

源码把它拆成了至少三层:

  1. 记录级 domain:门户用户到底能搜到哪些 account.analytic.line
  2. 视图级切换:门户用户打开工时动作时,看到的是不是 portal 专用 list/form/kanban
  3. 项目隐私前提:项目本身必须处于 invited_usersportal 之类允许门户访问的可见性

更细一点说,/home/ubuntu/odoo-temp/addons/hr_timesheet/models/hr_timesheet.py 里的 _timesheet_get_portal_domain() 已经说明白了:

  • 只要是内部 timesheet 用户,直接走当前用户的 ir.rule
  • 只要不是内部用户,就改走 portal 域
  • portal 域不是“项目被共享即可”,而是:
  • message_partner_ids child_of commercial_partner
  • partner_id child_of commercial_partner
  • 并且 项目 privacy_visibility in ['invited_users', 'portal']

这意味着门户工时的可见性,本质上是 客户关系 + 项目隐私 + 门户视图 的交集。


1. 第一层:门户 domain 并不是“项目共享开关”

_timesheet_get_portal_domain() 的 portal 分支非常关键:

  • 左边条件:timesheet 的 message_partner_idspartner_id 要落在当前门户用户商业主体下
  • 右边条件:项目隐私必须允许门户/受邀访问

这背后对应的是一个很清晰的产品哲学:

门户用户看到的是“和自己客户关系相关的工时”,不是“项目里所有人的内部作业明细”。

测试 addons/hr_timesheet/tests/test_portal_timesheet.py 也验证了这件事。

它先拿到 portal domain,然后创建一条绑定项目与任务的 timesheet,再分别测试三种情况:

  • task.partner_id = portal partner 时,这条工时可见
  • 把任务客户清空后,这条工时不可见
  • 再把 project.partner_id = portal partner,工时重新可见

这说明可见性不是简单挂在“共享项目”按钮上,而是沿着 任务客户优先,项目客户兜底 的关系传播。


2. 第二层:为什么门户打开工时,不会直接复用内部员工视图

action_view_subtask_timesheet() 也很值得看。

这段逻辑会先判断当前用户是不是内部用户:

  • 内部用户:保留完整视图体系,包含 graph 等内部分析能力
  • 门户用户:优先替换成 portal 专用 list/form/kanban 视图
  • 如果 portal 专用视图不存在,还会回退到原始视图 ID

测试里甚至专门做了两次验证:

  1. portal 专用视图存在时,动作返回 portal 版 tree/form/kanban
  2. 把这几个 portal 视图删掉后,动作仍能回退到原始视图,不致于直接报错

这说明 Odoo 不是只在 record rule 上做权限隔离,而是连展示层都做了“降级版门户体验”。

换句话说,门户工时不是把内部工时页面硬开放给客户,而是给客户一套受控、可回退的查看入口。


3. 第三层:为什么 access record 还是默认 inactive

addons/hr_timesheet/security/ir.model.access.xml 里有一条很微妙的配置:

  • analytic.account.analytic.line.timesheet.portal.user
  • group_id = base.group_portal
  • perm_read = 1
  • active = 0

这类设计很典型:

  • 权限能力先定义好
  • 不默认大开闸
  • 让真正的开放路径交给更细的规则、上下文和模块组合去控制

再结合 hr_timesheet.py_compute_readonly_timesheet() 的注释,你会发现 Odoo 对 portal 工时非常谨慎:

  • 即便其他模块可能给 portal 带来某些 write 能力
  • 这里依然把“非内部用户默认只读”当成安全底线

所以如果你在实施里直接粗暴给 portal 开 analytic line 权限,很容易把 Odoo 原本的防线打穿。


4. 为什么很多人会误判“明明共享了项目却看不到工时”

常见误判主要有四种:

误判一:把 collaborator 当成 timesheet 可见性的唯一条件

collaborator 当然重要,但它不是最终 domain 的全部。 真正落到工时层,还要看 partner 归属链是否匹配。

误判二:只看项目 partner,不看任务 partner

源码测试已经说明:task.partner_id 会直接改变 portal 可见性,而且优先级非常高。

误判三:忽略项目隐私类型

就算 partner 关系能对上,项目 privacy_visibility 不在 invited_users / portal 范围内,也不会放开。

误判四:把 portal 页面报错当成权限问题

有时不是 record rule 错,而是 portal 专用视图没装、被删或 XMLID 丢失。action_view_subtask_timesheet() 已经把这种异常场景考虑进去了。


5. 实施建议:别把门户工时设计成“客户看全量内部工单流水”

Odoo 这套设计明显偏向“客户相关工时可见”,而不是“把内部管理系统完全镜像给外部用户”。

因此更合理的落地方式是:

  • 把 task/project 的客户归属维护好
  • 明确哪些项目允许门户可见
  • 保留 portal 专用视图,避免直接暴露内部分析界面
  • 如需更细颗粒度展示,用额外字段或 portal 页面做定制,不要先破基础 domain

参考源码

  • /home/ubuntu/odoo-temp/addons/hr_timesheet/models/hr_timesheet.py
  • _timesheet_get_portal_domain()
  • _compute_readonly_timesheet()
  • action_open_timesheet_view_portal()
  • /home/ubuntu/odoo-temp/addons/hr_timesheet/models/project_task.py
  • action_view_subtask_timesheet()
  • /home/ubuntu/odoo-temp/addons/hr_timesheet/security/ir.model.access.xml
  • /home/ubuntu/odoo-temp/addons/hr_timesheet/tests/test_portal_timesheet.py

DISCUSSION

评论区

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