Odoo FIFO 成本为什么不能只看现有库存:remaining_qty、FIFO 栈与出库估值链路
很多人以为 FIFO 成本就是“当前库存数量 × 最近单价”。但 stock_account 的实现真正依赖的是尚未耗尽的入库 move 栈:_run_fifo_get_stack 先找剩余层,_get_remaining_moves 计算 remaining_qty,出库再沿栈取值。
ARTICLE LIBRARY
持续记录源码理解、业务流程、模块开发经验与踩坑总结。
很多人以为 FIFO 成本就是“当前库存数量 × 最近单价”。但 stock_account 的实现真正依赖的是尚未耗尽的入库 move 栈:_run_fifo_get_stack 先找剩余层,_get_remaining_moves 计算 remaining_qty,出库再沿栈取值。
注册付款并不是简单打个“已付”标记。account_payment_register 会先分批生成 payment,再按应收应付科目做 reconcile,最后 account.move 根据残额、核销对手和 payment 匹配状态重算 payment_state。
很多人勾选一个组以后,发现用户权限自己多了一串组。真正原因不是后台在“乱补”,而是 res.groups 通过 implied_ids 计算 all_implied_ids,再让用户 all_group_ids 获得传递闭包;portal、public、employee 这类组还存在互斥约束。
很多人以为 Odoo 默认值只有字段 default。其实 models.py 的 default_get 明确按 context、ir.default、field.default、company_dependent fallback 与 inherited 字段委托顺序取值。
很多团队把上门维修理解成一张 repair order,但客户现场维修真正要承接的是报修受理、派工、现场处理、配件消耗、返厂分流与收费闭环。本文结合 Odoo 标准模块与源码边界,给出一套更稳的落地蓝图。
结合 account_debit_note 源码,讲清 Odoo 借项通知单为什么不是普通新发票:哪些单据能发起、为什么默认草稿、何时复制行、如何保留原始单据关联,以及独立借项编号怎样生效。