Odoo 看板为什么能显示空列:group_expand、read_group 与阶段补全机制
很多人以为 Odoo 看板上的空列只是前端自己补出来的占位 UI,但 Odoo 19 实际把这件事做进了字段定义与 read_group 结果整形层:字段声明 group_expand 后,系统会主动把“当前没有记录的组”补进结果里。
ARTICLE LIBRARY
持续记录源码理解、业务流程、模块开发经验与踩坑总结。
很多人以为 Odoo 看板上的空列只是前端自己补出来的占位 UI,但 Odoo 19 实际把这件事做进了字段定义与 read_group 结果整形层:字段声明 group_expand 后,系统会主动把“当前没有记录的组”补进结果里。
很多人以为给 recordset 套上 sudo() 或 with_user(admin) 之后,one2many / many2many 的 Command 就一定能通过。Odoo 19 实际专门给 x2many 命令加了一层防线:当目标模型声明 _allow_sudo_commands=False 时,框架会主动撤销这类提权写法,重新按事务原始用户做权限检查。
销售里最常见的误解之一,就是把 `invoice_status` 当成一个简单状态字段。实际上,从 Odoo 19 的 `sale_order_line.py` 和 `sale_order.py` 看,它是由 `qty_to_invoice`、产品开票策略、已交付数量、首付款逻辑,以及整单层的聚合规则共同推出来的结果。本文把这条链路讲清楚。
很多人一看到视图改动没显示,就立刻怀疑 XPath、怀疑浏览器缓存。但从 Odoo 19 的 `ir_ui_view.py` 看,真正需要先想清的是:这次拿到的是哪一个 cache key、这个 key 下缓存的是哪一种视图变体,以及用户最终看到的是否还是缓存结果再经过 group 裁剪后的版本。本文把这个链路讲透。
很多开发者把 `has_group()` 当成一个轻量 if 判断,但从 Odoo 19 的 `res_users.py` 和 `res_groups.py` 看,它背后其实连着 XMLID 解析、组定义缓存、隐含组展开,以及对“是否允许检查别人权限”的访问边界。本文讲清 `has_group()` 真正改变的是什么,以及为什么它常常把 bug 藏得更深。
很多人写 Odoo 定时任务时,只想着“把数据处理完”,却忽略了调度器本身的运行契约。基于 Odoo 19 的 `ir_cron.py` 源码,本文讲清 `_commit_progress()`、剩余时间、分批循环与部分完成状态,解释为什么一个健康的 cron 不是“尽量久地跑”,而是“持续可恢复地跑”。