如何使用 Odoo web APIs 为 invoice 注册 payment
结论
不能通过调用 account.payment.action_register_payment 来完成付款注册。Odoo 的注册付款本质上是一个向导流程:
- 先将发票过账;
- 以发票为上下文创建
account.payment.register临时记录; - 调用向导的
action_create_payments; - 由 Odoo 创建并过账付款,同时核销发票的应收或应付账款。
不要直接修改发票的 payment_state。这个字段由付款、会计分录和核销状态计算得出。
为什么原调用没有生效
原调用有两个问题:
models.execute_kw(
db,
uid,
password,
'account.payment',
'action_register_payment',
[{"active_id": invoice_id}]
)
action_register_payment 通常是发票侧用于打开付款窗口的界面动作,不是 account.payment 上负责创建付款并核销发票的方法。
另外,active_id、active_ids 和 active_model 都属于 Odoo context,不能作为普通位置参数传入。即使接口没有立即报错,也不能说明付款记录已经创建,更不能说明发票已经核销。
使用付款向导注册付款
下面的写法适用于提供 account.payment.register 和 action_create_payments 的 Odoo 版本。不同版本或本地模块使用的字段可能略有差异。
from datetime import date
import xmlrpc.client
models = xmlrpc.client.ServerProxy(f'{url}/xmlrpc/2/object')
invoice_id = 123
journal_id = 10
# 1. 过账发票
models.execute_kw(
db,
uid,
password,
'account.move',
'action_post',
[[invoice_id]]
)
# 2. 注册付款向导所需的上下文
payment_context = {
'active_model': 'account.move',
'active_id': invoice_id,
'active_ids': [invoice_id],
}
# 3. 创建付款向导
wizard_id = models.execute_kw(
db,
uid,
password,
'account.payment.register',
'create',
[{
'journal_id': journal_id,
'payment_date': date.today().isoformat(),
# 不传 amount 时,通常默认使用发票未付余额
# 'amount': 100.00,
}],
{
'context': payment_context,
}
)
# 4. 生成、过账并核销付款
result = models.execute_kw(
db,
uid,
password,
'account.payment.register',
'action_create_payments',
[[wizard_id]],
{
'context': payment_context,
}
)
其中最重要的是这两项:
'active_model': 'account.move'
'active_ids': [invoice_id]
向导根据这些上下文判断要支付哪些发票。在部分版本中,只传 active_id 并不够。
如果当前版本使用的仍是 post,而不是 action_post,可以继续使用已经确认有效的调用:
models.execute_kw(
db,
uid,
password,
'account.move',
'post',
[[invoice_id]]
)
Odoo 不同版本的方法名并不完全一致,不要仅凭示例替换已经确认有效的过账方法。
确认付款结果
付款完成后,可以读取发票的剩余金额和付款状态:
invoice = models.execute_kw(
db,
uid,
password,
'account.move',
'read',
[[invoice_id]],
{
'fields': [
'name',
'state',
'payment_state',
'amount_total',
'amount_residual',
],
}
)[0]
print(invoice)
全额付款并完成核销后,通常会看到:
{
'state': 'posted',
'payment_state': 'paid',
'amount_residual': 0.0,
}
如果只支付了部分金额,amount_residual 不会归零,payment_state 通常会显示为部分付款状态。
较旧版本的处理方式
部分较旧版本没有独立的 account.payment.register 向导,需要直接创建 account.payment,关联发票后再将付款过账。例如:
payment_id = models.execute_kw(
db,
uid,
password,
'account.payment',
'create',
[{
'payment_type': 'inbound',
'partner_type': 'customer',
'partner_id': partner_id,
'amount': amount,
'currency_id': currency_id,
'journal_id': journal_id,
'payment_date': date.today().isoformat(),
'payment_method_id': payment_method_id,
'invoice_ids': [(4, invoice_id, 0)],
}]
)
models.execute_kw(
db,
uid,
password,
'account.payment',
'post',
[[payment_id]]
)
这段代码仅适用于确实存在 invoice_ids、payment_method_id 和 post 的版本。新版本通常使用 payment_method_line_id,付款和发票也不再通过相同的字段直接关联。因此,应优先采用当前版本界面实际使用的 account.payment.register 流程。
常见注意事项
-
客户发票通常使用:
'payment_type': 'inbound' 'partner_type': 'customer' -
供应商账单通常使用:
'payment_type': 'outbound' 'partner_type': 'supplier' -
journal_id必须指向允许相应收款或付款方式的银行、现金等日记账。 -
付款币种、合作伙伴和公司必须与发票兼容。
-
通过 XML-RPC 调用记录方法时,记录 ID 必须放在列表中,例如
[[wizard_id]]。 -
context 应放在
execute_kw最后一个 kwargs 字典中,不能混入普通参数。 -
注册付款后,某些 Odoo 版本或会计配置会先把发票标记为
in_payment。只有银行流水与付款完成核销后,状态才会变为paid。具体行为取决于付款日记账的 outstanding account 和银行对账配置。 -
如果
action_create_payments、payment_method_line_id或其他字段不存在,应先确认实际使用的 Odoo 版本和已安装的会计模块,避免混用不同版本的接口。
备注:内容仅供参考。
