如何通过 OpenERP 7 XML-RPC API 验证发票并付款?
明确结论
在 OpenERP 7 中,这两个操作由不同的机制完成:
- 验证发票:对
account.invoice发送工作流信号invoice_open。 - 登记并核销付款:通过
account.voucher创建收款或付款凭证,再调用proforma_voucher过账。
account.payment.term 用于定义付款期限,payment.order 主要处理批量付款指令。两者都不是登记发票付款的核心 model。
验证发票
OpenERP 7 通过工作流验证发票,所以只查看 account.invoice 的普通 CRUD 方法,很难找到对应的调用入口。通过 XML-RPC 操作时,应调用对象服务的 exec_workflow:
import xmlrpclib
url = 'http://localhost:8069'
db = 'your_database'
username = 'admin'
password = 'admin'
common = xmlrpclib.ServerProxy('%s/xmlrpc/common' % url)
uid = common.login(db, username, password)
models = xmlrpclib.ServerProxy('%s/xmlrpc/object' % url)
invoice_id = 123
result = models.exec_workflow(
db,
uid,
password,
'account.invoice',
invoice_id,
'invoice_open'
)
执行成功后,发票通常会从草稿变为已验证或未付款状态,系统也会生成相应的会计凭证。
调用前应确认:
- 发票中至少有一条有效的发票行;
- 发票已经设置合作伙伴、科目、日期和币种;
- 发票行的收入或费用科目完整;
- 对应的会计期间处于开放状态;
- 当前用户有权验证发票并创建会计凭证。
使用 account.voucher 登记付款
客户发票收款通常创建 type='receipt' 的 voucher,供应商发票付款通常使用 type='payment'。
付款凭证至少需要以下内容:
partner_idjournal_idaccount_idamountdatetype- 与待核销发票会计分录对应的
account.voucher.line
示意代码如下:
import datetime
payment_date = datetime.date.today().strftime('%Y-%m-%d')
voucher_id = models.execute(
db,
uid,
password,
'account.voucher',
'create',
{
'partner_id': partner_id,
'journal_id': bank_journal_id,
'account_id': bank_account_id,
'amount': payment_amount,
'date': payment_date,
'type': 'receipt',
'reference': 'Payment for invoice %s' % invoice_id,
}
)
只创建 voucher,系统不会自动将付款应用到指定发票。还需要创建 voucher line,把付款关联到发票生成的应收或应付会计分录:
voucher_line_id = models.execute(
db,
uid,
password,
'account.voucher.line',
'create',
{
'voucher_id': voucher_id,
'name': invoice_number,
'account_id': receivable_account_id,
'move_line_id': invoice_move_line_id,
'type': 'cr',
'amount': payment_amount,
'amount_unreconciled': invoice_residual,
'reconcile': payment_amount >= invoice_residual,
}
)
客户发票中,尚未核销的应收分录通常位于借方,因此 voucher line 一般使用 type='cr'。供应商付款的方向通常相反。具体方向应根据发票生成的 account.move.line 判断,不要硬编码。
创建完成后,调用 proforma_voucher 过账付款:
result = models.execute(
db,
uid,
password,
'account.voucher',
'proforma_voucher',
[voucher_id]
)
某些 OpenERP 7 安装会将该动作配置到工作流中。如果无法直接调用 proforma_voucher,需要查看当前安装的 account_voucher 模块代码和工作流配置,确认是否应该发送相应的工作流信号。
如何找到发票对应的会计分录
发票验证后,先读取它的 move_id:
invoice = models.execute(
db,
uid,
password,
'account.invoice',
'read',
[invoice_id],
['number', 'partner_id', 'account_id', 'move_id', 'residual', 'currency_id']
)[0]
然后在 account.move.line 中查找该会计凭证下尚未核销的应收或应付分录:
move_id = invoice['move_id'][0]
move_line_ids = models.execute(
db,
uid,
password,
'account.move.line',
'search',
[
('move_id', '=', move_id),
('account_id', '=', invoice['account_id'][0]),
('reconcile_id', '=', False),
]
)
读取这些分录后,根据借贷方向、剩余金额和币种创建相应的 account.voucher.line。
更稳妥的处理方式
OpenERP 客户端创建付款时,通常会调用 account.voucher 的 onchange_partner_id。服务端会据此计算可以核销的发票行、币种和金额。通过 XML-RPC 集成时,也可以调用这个 onchange,再使用返回的 line_cr_ids、line_dr_ids 等数据创建 voucher。
与手工拼装 voucher line 相比,这种方式更可靠,尤其适合以下情况:
- 部分付款;
- 一笔付款核销多张发票;
- 多币种付款;
- 存在汇兑差额;
- 客户同时有贷项通知单;
- 系统安装了本地化会计模块。
不过,不同补丁版本和扩展模块可能采用不同的 onchange_partner_id 参数。具体调用方式应以目标服务器上 account_voucher 模块的方法签名为准。
注意事项
如果付款金额等于发票的剩余金额,voucher 过账后通常会完成核销,发票也会进入已付款状态。部分付款只会减少 residual,发票仍处于未完全付款状态。
不要直接修改发票的 state、residual 或付款状态字段。这些值应由发票工作流、会计凭证和核销结果共同决定。直接修改容易导致发票状态与总账数据不一致。
完整流程如下:
创建 account.invoice
→ 创建发票行
→ exec_workflow(..., 'invoice_open')
→ 创建 account.voucher
→ 创建或通过 onchange 生成 account.voucher.line
→ proforma_voucher([voucher_id])
→ 检查 invoice.residual 和付款状态
备注:内容仅供参考。
