Odoo 17:通过API为销售订单创建发票的正确方法
我已使用sale.order模型及以下请求体创建了Odoo销售订单(测试时所有订单行使用同一Odoo产品ID):
{ "company_id": 1, "name": "10000", "partner_id": 17, "partner_invoice_id": 22, "partner_shipping_id": 23, "client_order_ref": "10000", "carrier_id": 2, "order_line": [ [ 0, 0, { "product_id": 414, "display_name": "Product #2", "name_short": "Product #2", "name": "Product #2", "product_uom_qty": 1, "price_unit": 103.36, "purchase_price": 40, "price_tax": 19.64 } ], [ 0, 0, { "product_id": 414, "display_name": "Demo Product with Variants", "name_short": "Demo Product with Variants", "name": "Demo Product with Variants", "product_uom_qty": 1, "price_unit": 84.03, "purchase_price": 40, "price_tax": 15.97 } ], [ 0, 0, { "product_id": 414, "display_name": "Shipping Costs", "name_short": "Shipping Costs", "name": "Shipping Costs", "product_uom_qty": 1, "price_unit": 8.4, "purchase_price": 40, "price_tax": 0 } ] ] }
之后尝试为该销售订单创建发票时,发现action_invoice_generate方法已废弃,于是改用account.move模型手动创建发票,请求体如下(通过invoice_origin关联销售订单):
{ "partner_id": 22, "move_type": "out_invoice", "invoice_date": "2024-04-19", "invoice_line_ids": [...], "invoice_origin": "10000" }
现在发票已创建并关联销售订单,但重新打开销售订单时,「Create Invoice」按钮仍可用,且未显示该发票。我考虑手动将发票ID添加到sale.order的invoice_ids列表,并设置invoice_status,但不确定invoice_count、amount_invoiced等字段该如何处理,请问通过API为销售订单创建发票的最佳方式是什么?
优先使用Odoo标准API方法
废弃action_invoice_generate后,Odoo提供了**sale.order模型的action_create_invoice方法**,这是前端「Create Invoice」按钮对应的后台方法,能自动处理所有关联逻辑、状态更新和字段计算,是最优方案。
调用该方法的核心优势:
- 自动创建与销售订单双向关联的发票(同步销售订单
invoice_ids和发票sale_order_ids) - 自动更新销售订单的
invoice_status、invoice_count、amount_invoiced等计算字段 - 自动同步订单行已开票数量(
qty_invoiced),保证数据一致性 - 无需手动处理复杂的关联逻辑
调用示例(JSON-RPC)
import json import requests url = "http://your-odoo-instance/jsonrpc" payload = { "jsonrpc": "2.0", "method": "call", "params": { "model": "sale.order", "method": "action_create_invoice", "args": [[1]], # 1为目标销售订单ID,传入列表格式 "kwargs": { # 可选:自定义发票参数,如开票日期 "invoice_date": "2024-04-19" }, "context": {"lang": "zh_CN", "tz": "Asia/Shanghai"} }, "id": 1 } response = requests.post(url, json=payload) result = response.json() # 返回结果包含创建的发票ID列表 invoice_ids = result.get("result", [])
特殊场景下手动创建发票的完整流程
如果因业务需求必须手动创建account.move,需要完成以下步骤保证数据完全同步:
创建发票时关联销售订单及订单行
创建account.move时,不仅要通过sale_order_ids关联销售订单,还要为每个发票行通过sale_line_ids关联对应销售订单行,示例:{ "partner_id": 22, "move_type": "out_invoice", "invoice_date": "2024-04-19", "invoice_line_ids": [ [ 0, 0, { "product_id": 414, "name": "Product #2", "quantity": 1, "price_unit": 103.36, "sale_line_ids": [[4, 123]] # 123为对应销售订单行ID } ] ], "sale_order_ids": [[4, 1]] # 1为目标销售订单ID }更新销售订单的关联与状态
调用sale.order的write方法,将发票ID添加到invoice_ids并设置正确的发票状态:{ "model": "sale.order", "method": "write", "args": [ [1], # 目标销售订单ID { "invoice_ids": [[4, invoice_id]], # invoice_id为刚创建的发票ID "invoice_status": "invoiced" # 根据实际情况设置:invoiced/to invoice/no invoice } ] }强制触发计算字段更新
如果invoice_count、amount_invoiced等字段未自动更新,可手动调用销售订单的计算方法:{ "model": "sale.order", "method": "_compute_invoice_count", "args": [[1]] }{ "model": "sale.order", "method": "_compute_amount_invoiced", "args": [[1]] }
总结
- 绝大多数场景下,直接调用
action_create_invoice方法是最简单、最可靠的方式,完全避免手动处理关联和计算的问题 - 仅在特殊业务需求下才考虑手动创建发票,且必须完成完整的双向关联和字段同步,否则会出现数据不一致的情况
内容的提问来源于stack exchange,提问作者Dennis

