项目深度

Odoo 任务分析为什么不是“列表上多几个统计字段”:`report.project.task.user` 这张 SQL 视图到底在汇总什么

Odoo 项目分析页看起来只是任务列表加图表,但底层并不是直接查 `project.task`。官方专门做了一张 `report.project.task.user` 视图,把任务、评分、依赖、里程碑超期和销售剩余工时等指标提前揉成分析底座。本文把这张视图讲透。

项目
进阶 开发者 2 分钟阅读
0 评论 0 点赞 0 收藏 34 阅读

先说结论

很多人打开 Odoo 项目的分析页面,会觉得它不过是:

  • 任务列表
  • 加几张透视图 / 图表
  • 再多几个统计字段

如果你去读 /home/ubuntu/odoo-temp/addons/project/report/project_report.py/home/ubuntu/odoo-temp/addons/sale_timesheet/report/project_report.py,会发现官方根本不是这么做的。

Odoo 专门维护了一张 SQL 视图模型:

  • report.project.task.user

它不是“任务表的另一个名字”,而是一张专门给分析场景准备的汇总底座,用来把:

  • 任务主信息
  • 负责人维度
  • 阶段 / 状态
  • 评分
  • 里程碑逾期
  • 依赖关系计数
  • 工时开关与关闭时长
  • 销售剩余工时

统一揉进一个可 group by、可图表化、可透视的分析模型里。

所以项目分析页不是“把任务字段原样展示出来”,而是站在一张分析视图上重新看任务执行系统


第一层:为什么分析不用直接查 project.task

如果你只看业务对象,似乎直接查 project.task 就够了。

但分析场景有几个特殊要求:

  • 很多指标需要聚合
  • 有些指标来自别的表,如 rating、dependency、milestone
  • 图表与 pivot 希望字段是“现成可 group 的”
  • 还要排除模板项目等不该混进经营视图的数据

于是官方在 project_report.py 里选择 _auto = False,自己建一张 SQL view。

这其实是一个很典型的 Odoo 设计信号:

当业务对象的原子记录不适合直接做经营分析时,官方更愿意抽一张报告视图,而不是在原表上硬堆分析字段。


第二层:这张视图不是只搬运字段,而是在重新定义“任务分析的最小粒度”

report.project.task.user_select() 里,不只是简单取 task 字段,还加入了很多分析语义。

例如:

  • nbr 固定为 1,方便统计任务数
  • is_closed 按状态归类,而不是只用原始 state
  • has_late_and_unreached_milestone 判断里程碑是否逾期未达成
  • rating_avg 来自评分表聚合
  • delay_endings_days 用 deadline 和当前时间动态算
  • dependent_ids_count 统计依赖数量

这说明这张视图在做的事情不是“把 task 表复制一遍”,而是把任务转译成一组更适合经营与管理观察的分析指标。

换句话说,原始任务表讲的是“任务是什么”;报告视图讲的是“这个任务在管理上意味着什么”。


第三层:为什么评分、依赖、里程碑这些跨表信息要提前揉进来

_from() 里,这张视图会 left join:

  • rating_rating
  • project_milestone
  • task_dependencies_rel
  • project_project

这几个 join 很能说明官方对项目分析的理解。

1. 评分不是附属信息,而是任务质量反馈的一部分

rating_avgrating_last_value 被直接拉进分析视图,说明客户反馈在 Odoo 里不是只给详情页看的,而是应该进入任务管理分析。

2. 依赖数量不是结构信息,而是执行复杂度信号

任务被多少别的任务依赖、它又依赖多少任务,这些信息在执行层很关键。把依赖计数放进视图后,才能在图表和透视里直接看到哪些任务天生更复杂、更容易卡住。

3. 逾期未完成的 milestone 是项目风险信号

pm.is_reached = False 且 deadline 已过,就会形成一个风险标记。这不是单纯项目配置数据,而是执行健康度的一部分。


第四层:为什么视图要明确排除模板项目

_where() 里,官方特意限定:

  • t.project_id IS NOT NULL
  • p.is_template IS NOT TRUE

这一步看起来普通,其实很重要。

因为模板任务虽然结构上像任务,但它不是正在执行的交付事实。如果把模板项目也混入分析:

  • 任务数量会虚高
  • 阶段统计会失真
  • 平均关闭时长、评分、依赖计数都会被噪声污染

所以 Odoo 很明确地把“可复用交付蓝图”和“真实执行任务”分开看待。

这也是做项目分析时特别值得学的一点:

不要把模板、草稿结构和真实履约数据混进同一张经营看板。


第五层:为什么 sale_timesheet 只加了一个字段,却很有分量

到了 sale_timesheet/report/project_report.py,扩展看起来很轻:

  • 新增 remaining_hours_so
  • _from() 里 join sale_order_line
  • _select() / _group_by() 里把它带进来

但这一个字段非常有业务含金量。

因为它把原本偏执行分析的任务视图,进一步接到了销售合同侧。

于是任务分析不再只是看:

  • 什么时候创建
  • 什么时候指派
  • 什么时候关闭
  • 评分如何

还可以顺便看:

  • 这张任务背后的销售工时余额还有多少

这代表项目分析从“纯项目视角”迈向了“项目 + 商业承诺”视角。


第六层:为什么官方宁可在报告视图里加字段,也不直接在图表查询时临时 join

很多自定义开发喜欢这样做:

  • 打开图表页时动态拼 SQL
  • 或在 read_group 里临时做扩展

官方这里选择的是更稳的路线:

  • 先把分析底座定义好
  • 再让上层 pivot / graph / search 直接复用

这样做的好处是:

1. 语义稳定

所有分析界面看到的“任务分析”都共享同一套字段定义。

2. 复用简单

报表、搜索、图表、透视不需要各自重复拼 join。

3. 更容易扩展

sale_timesheet 这样,只要在这张视图上增量扩字段,就能把销售语义接进项目分析体系。

这也是 Odoo 报表层很典型的设计哲学:

  • 先抽象分析模型
  • 再让 UI 和 read_group 站在分析模型上工作

第七层:这张视图到底在帮助管理者看什么

如果把视角拉高一点,report.project.task.user 最终帮管理者回答的其实是三类问题。

1. 执行效率问题

  • 平均多久被分派
  • 平均多久关闭
  • 截止日期还差多少天

2. 交付风险问题

  • 是否有逾期未完成里程碑
  • 依赖关系是否过重
  • 是否长时间停留在特定阶段

3. 经营协同问题

  • 客户评分如何
  • 项目任务与销售剩余工时是否开始脱节

这也解释了为什么这张视图会同时站在:

  • 项目任务
  • 客户反馈
  • 依赖关系
  • 里程碑
  • 销售合同

这些边界上。

因为真正的项目分析,本来就不该只盯任务表本身。


新手最容易误解的 5 件事

1. 以为项目分析页就是直接查 project.task

不对。核心底座是 report.project.task.user 这张 SQL 视图。

2. 以为分析视图只是把任务字段搬过去

不对。它会重新生成很多管理语义字段。

3. 以为评分、依赖、里程碑只是细节数据

不对。官方把它们直接揉进分析模型,说明它们本来就是项目健康度指标。

4. 以为模板任务也应该参与任务分析

不对。模板项目会被主动排除。

5. 以为销售剩余工时只属于销售页

不对。sale_timesheet 已把它扩进项目任务分析视图。


实战里最该注意什么

1. 如果你要做项目分析自定义,优先考虑扩展报告视图,而不是直接污染 project.task

这样后续图表、搜索、透视更容易保持一致。

2. 项目分析指标要尽量站在“管理问题”上设计

不要只堆字段,先想清楚它回答的是:

  • 效率
  • 风险
  • 经营协同

哪一类问题。

3. 如果你的项目是按预付工时包交付,别忽略 remaining_hours_so

它是把执行分析和合同消耗连接起来的关键指标。


一句话记忆法

Odoo 的任务分析不是从 project.task 直接画图,而是先用 report.project.task.user 把执行、风险、反馈与销售余额揉成一张分析视图,再让前台报表站在这张视图上工作。

DISCUSSION

评论区

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