如何在 odoo10 中通过 psql 完成 invoice payment
结论
不要用 psql 直接把 Odoo 10 发票的 state 改为 paid。在 Odoo 10 中,发票的“已付款”状态来自付款凭证过账,以及付款分录与发票应收或应付分录的核销。只修改 account_invoice.state,无法正确完成这些会计处理。
应通过 Odoo ORM 创建并过账 account.payment,再调用付款登记向导完成核销。相关代码可以在服务器的 Odoo shell 中执行。底层数据仍会写入 PostgreSQL,同时能够保留完整的会计逻辑。
推荐操作步骤
操作前先备份数据库,并确认以下事项:
- 发票已经验证或过账,状态通常为
open。 - 收款使用的银行或现金日记账配置正确。
- 客户发票使用入账付款方式,供应商账单使用出账付款方式。
- 执行账户具有操作会计付款和发票的权限。
进入 Odoo shell:
./odoo-bin shell -d your_database
部分 Odoo 10 部署使用:
./odoo.py shell -d your_database
客户发票收款示例
以下代码根据发票编号查找一张未付款的客户发票,再通过 Odoo 10 的付款登记向导创建付款并完成核销:
invoice = env['account.invoice'].search([
('number', '=', 'INV/2017/0001'),
('type', '=', 'out_invoice'),
('state', '=', 'open'),
], limit=1)
if not invoice:
raise Exception('未找到处于 open 状态的客户发票')
journal = env['account.journal'].search([
('type', 'in', ['bank', 'cash']),
('company_id', '=', invoice.company_id.id),
], limit=1)
if not journal:
raise Exception('未找到可用的银行或现金日记账')
payment_method = journal.inbound_payment_method_ids[:1]
if not payment_method:
raise Exception('该日记账没有配置入账付款方式')
payment_register = env['account.register.payments'].with_context(
active_model='account.invoice',
active_ids=invoice.ids,
).create({
'payment_date': fields.Date.context_today(invoice),
'journal_id': journal.id,
'payment_method_id': payment_method.id,
'amount': invoice.residual,
})
payment_register.create_payments()
invoice.invalidate_cache()
print(invoice.state)
正常情况下,足额付款并成功核销后,invoice.state 应变为 paid。如果付款金额小于 invoice.residual,发票通常仍处于 open 状态,但剩余未付金额会相应减少。
Odoo 10 的不同补丁版本或定制模块可能会为向导增加必填字段。如果 create() 报告缺少字段,应先通过 Odoo 界面检查付款配置,或者查看当前实例中 account.register.payments 的字段定义。不能假定所有 Odoo 10 数据库的字段和配置都完全一致。
供应商账单付款
为供应商账单付款时,需要使用出账付款方式:
invoice = env['account.invoice'].search([
('number', '=', 'BILL/2017/0001'),
('type', '=', 'in_invoice'),
('state', '=', 'open'),
], limit=1)
if not invoice:
raise Exception('未找到处于 open 状态的供应商账单')
journal = env['account.journal'].search([
('type', 'in', ['bank', 'cash']),
('company_id', '=', invoice.company_id.id),
], limit=1)
payment_method = journal.outbound_payment_method_ids[:1]
if not payment_method:
raise Exception('该日记账没有配置出账付款方式')
wizard = env['account.register.payments'].with_context(
active_model='account.invoice',
active_ids=invoice.ids,
).create({
'payment_date': fields.Date.context_today(invoice),
'journal_id': journal.id,
'payment_method_id': payment_method.id,
'amount': invoice.residual,
})
wizard.create_payments()
为什么不能直接执行 SQL
不要执行下面这种更新:
UPDATE account_invoice
SET state = 'paid'
WHERE number = 'INV/2017/0001';
这条 SQL 只改变了发票表中的状态字段,不会:
- 创建付款记录;
- 创建并过账会计凭证;
- 更新银行或现金科目;
- 核销应收账款或应付账款;
- 创建
account_partial_reconcile或相关核销记录; - 正确更新发票剩余金额;
- 执行 Odoo 的模型约束、权限检查和自动化逻辑。
这样处理后,发票可能显示为已付款,但总账中仍有未核销余额。数据不一致的问题可能会在应收账龄、合作伙伴余额、付款报表或取消发票时暴露出来。
已经用 SQL 改过状态怎么办
不要继续手工补写付款表和核销表。应先将发票恢复到原来的实际状态,再通过 ORM 正常登记付款。恢复之前,需要检查对应的应收或应付分录是否已经核销,因为只看 account_invoice.state 无法判断完整的会计状态。
至少应核对以下数据:
SELECT id, number, state, residual, move_id
FROM account_invoice
WHERE number = 'INV/2017/0001';
SQL 查询可以用于诊断,但修复数据和登记付款应在备份数据库后通过 Odoo ORM 完成。生产环境还应先在数据库副本中验证,尤其是安装了本地化会计模块或自定义付款模块的实例。
备注:内容仅供参考。
