先说结论
Odoo Fleet 里的 fleet.vehicle,不是一张静态资产卡,而是一个不断汇聚运营信号的车辆中心对象。
从 /home/ubuntu/odoo-temp/addons/fleet/models/fleet_vehicle.py 来看,它至少同时处理了:
- 车型模板到具体车辆的字段继承
- 当前车辆状态与责任人信息
- 里程表最新值展示与日志回写
- 服务活动的紧急程度归纳
- 合同、维修、里程、历史数量统计
所以它真正解决的问题不是“系统里有没有一辆车的资料”,而是:
当车辆在使用、维修、换人、累计里程时,系统如何让一张车辆记录始终反映当前运营现实。
第一层:为什么车型和车辆要分成两层
源码里有一组非常关键的映射 MODEL_FIELDS_TO_VEHICLE,把车型上的很多字段复制到车辆上,例如:
- 变速箱
- 年款
- 颜色
- 座位数
- 马力
- CO₂
- 燃料类型
- 车系分类
- 续航与单位
这说明 Odoo 没把 fleet.vehicle.model 当成纯展示分类,也没把 fleet.vehicle 当成完全独立录入对象。
它采用的是更实用的两层结构:
- 车型负责默认知识
- 车辆负责实例现实
这样做有明显好处:
1. 建车更快
新建车辆时,不需要每次从零填一遍技术参数。
2. 规则更一致
同车型多台车可以共享基础属性,减少手工录入漂移。
3. 仍保留实例调整空间
字段被写到车辆上后,又不是完全只读,因此仍可针对具体车辆修正。
这比“全都放车型上”或“全都手填到车辆上”都更适合真实车队管理。
第二层:为什么里程表字段其实不是一格数字
fleet.vehicle 上有个看起来很普通的字段:odometer。
但源码很清楚地告诉你,它并不是单独保存的最终真相。
_get_odometer() 会去查 fleet.vehicle.odometer 日志,取当前车辆相关的最新读数。
而 _set_odometer() 也不是直接覆盖一个静态数值,而是新建一条里程日志记录。
这背后的产品选择非常重要:
车辆里程应该被当作时间序列,而不是一块不断被覆盖的数字。
为什么? 因为里程不是展示字段,它还关系到:
- 保养周期
- 使用强度
- 成本分析
- 异常波动检查
- 二手残值判断
如果只是反复覆盖当前数值,历史就丢了,很多后续分析都做不出来。
Odoo 选择“车辆页显示当前值,底层保存日志流”,这是一种很成熟的业务建模方式。
第三层:为什么维修紧急程度要被压缩成一个 service_activity
_compute_service_activity() 会从 log_services 关联的活动状态里抽取结果,并把它归纳成:
nonetodayoverdue
很多人看到这里会觉得信息被“压扁”了。 但这恰恰体现了运营界面的思路。
车队经理打开车辆列表时,往往不想先看所有服务工单细节,而是想知道:
- 有没有车需要立刻关注
- 哪些车今天有动作
- 哪些车已经超期
也就是说,运营首页需要的是信号灯,不是明细表。
service_activity 的价值就在这里:
- 它不代替维修记录
- 它是对维修记录的风险提炼
这和很多成熟产品里的 traffic light 一样,本质是把复杂明细压缩成可决策的入口信号。
第四层:为什么车辆名不是用户手写,而是自动拼出来
_compute_vehicle_name() 会用:
- 品牌名
- 车型名
- 车牌号
自动生成车辆显示名。
看起来像小细节,其实很合理。
因为车队系统里最常见的检索语境并不是“正式资产编号”,而是:
- 这台是什么品牌什么型号
- 车牌是多少
- 谁现在在用
自动拼接后的名称,能在列表、搜索和关联字段里更稳定地表达车辆身份。
这说明 Odoo 并不是只关心数据库规范化,也在照顾实际运营人员的识别习惯。
第五层:为什么统计计数都挂回车辆主记录
fleet.vehicle 会计算:
contract_countservice_countodometer_counthistory_count
这非常说明问题。
如果系统只是资产台账,完全可以让用户自己点进相关菜单慢慢看。 但 Odoo 反而把这些数字主动汇总回车辆页,说明它把车辆视为所有后续运营动作的主入口。
换句话说:
- 合同是围绕车辆展开的
- 维修是围绕车辆展开的
- 里程历史是围绕车辆展开的
- 驾驶员变更历史也是围绕车辆展开的
这就让 fleet.vehicle 从“表头资料”升级成了“运营中心页”。
第六层:为什么车辆状态还要保留大量看似杂的字段
源码里你会看到很多字段并不只是传统汽车档案字段,例如:
future_driver_idnext_assignation_dateplan_to_change_carplan_to_change_bikevehicle_rangerange_unitelectric_assistancecontract_state
这说明 Odoo 的 Fleet 不只想回答“这辆车是什么”,还想回答:
- 接下来谁会接手
- 是否要换车或换车架方案
- 电动车或自行车场景下如何描述续航与助力
- 当前合同是否健康
也就是说,Fleet 的对象边界比“汽车档案”宽得多,它更接近组织内部交通工具运营台账。
最容易误解的四个点
误区一:车型只是分类标签
不对。车型承担了大量默认值模板职责。
误区二:里程表就是一个当前数字
实际上当前值只是入口,底层真正重要的是 odometer 日志流。
误区三:维修状态要看明细才能知道紧不紧急
源码特意把它压缩成 service_activity,就是为了先给运营人员一个清晰信号。
误区四:车辆页只是资产资料页
并不是。它是合同、维修、里程和责任变更的汇总枢纽。
实战上怎么把 Fleet 用得更稳
如果你在实施 Odoo Fleet,我会建议:
- 先把车型模板数据维护扎实,再大批量建车
- 不要把里程更新当成覆盖动作,尽量保留连续日志来源
- 车辆列表里优先关注
service_activity和合同状态,而不是只看静态字段 - 对电动车、自行车等非传统车辆,尽量把续航和助力字段也用起来
- 让运营人员养成“从车辆主记录进去看所有动作”的使用习惯
最后总结
Odoo Fleet 最值得学的地方,不是它给车辆加了很多字段,而是它很明确地把车辆做成了一个持续聚合运营信号的主对象:
- 车型给它默认结构
- 里程日志给它时间序列
- 维修活动给它风险信号
- 合同与历史记录给它上下文
所以真正理解 Fleet,不是把它看成“车辆资料表”,而是把它看成:
一辆车在组织内部如何被持续使用、维护、观察和接手的运营中心。
DISCUSSION
评论区