出库时的 stock.move.line 是如何确定的
用通俗但不失源码细节的方式,讲清楚 Odoo 出库时 stock.move.line 的生成逻辑:从 stock.move、stock.quant、移除策略到 lot/serial 拆行。
CATEGORY FOCUS
聚合 Odoo 开发基础、源码理解、ORM、模型、视图、安全与扩展实践。
TOPIC PICKS
用通俗但不失源码细节的方式,讲清楚 Odoo 出库时 stock.move.line 的生成逻辑:从 stock.move、stock.quant、移除策略到 lot/serial 拆行。
很多人以为 Odoo 的周期任务只是“关掉一张,系统再复制一张”。但源码里真正决定会不会继续生成、复制哪些字段、截止日期怎么顺延、子任务会不会一起带过去的,是 project.task 与 project.task.recurrence 的一整套协作逻辑。本文把这条链路拆开讲清。
`company_dependent=True` 看起来像给字段加了个多公司开关,但它背后不是普通列值覆盖,而是由 ir.property、默认回退和上下文公司共同决定读写结果。理解这条链,才能解释为什么同一字段在不同公司下会变、为什么搜索也不像普通字段那样直译成简单 SQL。
很多人第一次看 Pull Rule,会觉得系统像“倒着长单据”:明明只是下游库位缺货,怎么上一段调拨、采购或制造动作就自己冒出来了?从 stock_rule.py 看,Pull Rule 的关键不是“货往哪走”,而是“哪里产生需求、系统就去哪里找能把货拉过来的规则”。
很多人以为 Chatter 里的字段变更只是生成一句“X 改成 Y”。但从 mail.tracking.value 与 account 对 mail.message 的扩展看,Odoo 真正在维护的是一份结构化差异数据:既要按字段类型存储旧值/新值,又要在展示时再判断当前用户有没有权限看到这些字段。
很多人以为 FIFO 成本就是“当前库存数量 × 最近单价”。但 stock_account 的实现真正依赖的是尚未耗尽的入库 move 栈:_run_fifo_get_stack 先找剩余层,_get_remaining_moves 计算 remaining_qty,出库再沿栈取值。
结合 base_sparse_field 源码,讲清 Odoo 为什么不总是为每个动态配置都新建数据库列,以及 sparse 字段怎样借助 serialized 字段完成读写、清空与反射。