PAYATHON 2026

如何在 OpenERP v6.1 中创建并抵扣 credit note?

支付小周

结论

在 OpenERP v6.1 中,Supplier Refund 是独立的供应商贷项凭证。即使供应商相同或退款单关联了原发票,Payment Order 也不会自动抵扣。

正确的处理流程如下:

  1. 创建并确认 Supplier Refund;
  2. 在应付账款科目中核销退款单与原 Supplier Invoice;
  3. 核销完成后,原发票的未付余额会相应减少;
  4. 创建 Payment Order,支付核销后的剩余金额。

例如,供应商发票金额为 1,000,退款单金额为 200。核销 200 后,发票的剩余应付金额为 800,Payment Order 应按 800 处理。

为什么 Payment Order 没有自动扣除

两张单据的会计分录方向相反:

Supplier Invoice
借:费用或采购科目       1,000
贷:应付账款             1,000

Supplier Refund
借:应付账款               200
贷:费用或采购科目         200

退款单会在应付账款科目中形成 200 的借方余额,但在完成核销前,它仍是一笔独立的未核销项目。

Payment Order 用于选取待付款项目并生成付款指令,不负责判断某张退款单应抵扣哪张发票。因此,未核销的 Invoice 和 Refund 通常会作为两笔独立项目存在,付款单不会自动将两者相减。

推荐操作步骤

1. 从原发票创建 Credit Note

如果界面提供退款或 Credit Note 功能,建议从原 Supplier Invoice 发起,不要单独新建 Supplier Refund。这样通常能保留原发票引用,并复制供应商、币种、税项和明细。

根据安装配置,按钮名称可能是:

Refund
Credit Note
Create Refund

退款向导可能包含以下处理方式:

  • 只创建退款单;
  • 创建退款单并取消原发票;
  • 创建退款单、取消原发票,并生成一张可以修改的新发票。

如果只是部分折让,应选择创建退款单,并填写需要抵扣的金额,不要取消整张原发票。

如果界面中没有从发票创建退款的入口,也可以通过以下菜单手工创建:

Accounting → Suppliers → Supplier Refunds

手工创建时,需要逐项确认供应商、应付科目、税额、币种及原始单据引用是否正确。

2. 确认退款单

退款单必须完成确认或过账。处于 Draft 状态的退款单不会生成正式会计分录,也不能参与核销。

确认后检查以下内容:

  • Supplier 与原发票一致;
  • Payable Account 与原发票一致;
  • Company 和 Currency 一致;
  • 会计期间处于开放状态;
  • 退款金额和税额正确;
  • 两张单据均已生成会计分录。

3. 核销发票和退款单

进入会计核销功能。OpenERP v6.1 的菜单名称可能因已安装模块、用户权限和界面语言而异,常见位置如下:

Accounting
└── Periodical Processing
    └── Reconciliation
        └── Manual Reconciliation

选择对应的供应商和应付账款科目,同时选中:

  • Supplier Invoice 的应付分录行;
  • Supplier Refund 的反向应付分录行。

金额相同时可以完全核销;退款金额小于发票金额时,应进行部分核销。

示例:

原发票未付金额:1,000
退款单金额:      200
本次核销金额:    200
核销后发票余额:  800
退款单余额:        0

不要将 800 的差额作为 write-off 注销。这部分金额仍是需要实际支付给供应商的应付款。

4. 再创建 Payment Order

核销完成后,重新打开或创建 Payment Order,并重新加载待付款项目。

此时,系统通常会显示原发票的 residual amount,也就是 800,而不是原始金额 1,000。如果 Payment Order 在核销前已经创建,原有付款明细可能不会自动刷新。遇到这种情况,通常需要删除旧明细,再重新选择待付款项目。

旧版 API 示例

下面是 OpenERP 6.x 旧式 ORM 的处理思路:查找同一供应商、同一应付科目中的发票和退款分录行,再执行部分核销。具体字段和方法签名可能受已安装模块影响,使用前应先在测试数据库中确认。

invoice = invoice_obj.browse(cr, uid, invoice_id, context=context)
refund = invoice_obj.browse(cr, uid, refund_id, context=context)

line_ids = []

for move_line in invoice.move_id.line_id:
    if (
        move_line.account_id.type == 'payable'
        and move_line.partner_id.id == invoice.partner_id.id
        and not move_line.reconcile_id
    ):
        line_ids.append(move_line.id)

for move_line in refund.move_id.line_id:
    if (
        move_line.account_id.type == 'payable'
        and move_line.partner_id.id == invoice.partner_id.id
        and not move_line.reconcile_id
    ):
        line_ids.append(move_line.id)

move_line_obj.reconcile_partial(
    cr,
    uid,
    line_ids,
    context=context
)

这段代码说明了核销对象:系统真正核销的是 account.move.line,并非直接修改 account.invoice 的金额。

不要通过 SQL 修改 amount_total、residual 或付款状态。OpenERP 的余额和状态取决于会计分录及其核销关系。直接修改字段,容易导致总账、供应商余额和付款状态不一致。

如果核销后仍显示原金额

按顺序检查以下项目:

  1. Refund 是否仍处于 Draft 状态;
  2. Refund 是否使用了不同的 Payable Account;
  3. 两张单据是否属于不同的供应商、公司或币种;
  4. 核销时是否误选了费用明细行,而不是应付账款分录行;
  5. 是否只创建了退款单,尚未执行 reconciliation;
  6. Payment Order 是否仍保留核销前生成的旧明细;
  7. 自定义付款模块是否按原始金额取数,而不是使用 residual amount。

判断的依据不是退款单是否存在,而是原发票的应付分录是否已经与退款分录完成核销。核销完成后,OpenERP 才会将 credit note 计入原发票未付余额,使其相应减少。

备注:内容仅供参考。