[FIX] account_payment_order: Grouped partial reconcile

When using a mode with "Group Transactions in Payment Orders"
in a payment order with multiple bills from the same supplier,
if e.g. the first bill's payment amount is reduced, the
reduction was applied to the last bill instead of the specified one.
This commit is contained in:
Danny W. Adair
2023-02-24 15:47:20 +13:00
parent 86cb24ee72
commit 00d9e89f3d
2 changed files with 89 additions and 6 deletions

View File

@@ -417,15 +417,42 @@ class AccountPaymentOrder(models.Model):
return action
def generated2uploaded(self):
"""Post payments and reconcile against source journal items
Partially reconcile payments that don't match their source journal items,
then reconcile the rest in one go.
"""
self.payment_ids.action_post()
# Perform the reconciliation of payments and source journal items
for payment in self.payment_ids:
(
payment.payment_line_ids.move_line_id
+ payment.move_id.line_ids.filtered(
lambda x: x.account_id == payment.destination_account_id
)
).reconcile()
payment_move_line_id = payment.move_id.line_ids.filtered(
lambda x: x.account_id == payment.destination_account_id
)
apr = self.env["account.partial.reconcile"]
excl_pay_lines = self.env["account.payment.line"]
for line in payment.payment_line_ids:
if not line.move_line_id:
continue
if line.amount_currency != -line.move_line_id.amount_residual_currency:
if line.move_line_id.amount_residual_currency < 0:
debit_move_id = payment_move_line_id.id
credit_move_id = line.move_line_id.id
else:
debit_move_id = line.move_line_id.id
credit_move_id = payment_move_line_id.id
apr.create(
{
"debit_move_id": debit_move_id,
"credit_move_id": credit_move_id,
"amount": abs(line.amount_company_currency),
"debit_amount_currency": abs(line.amount_currency),
"credit_amount_currency": abs(line.amount_currency),
}
)
excl_pay_lines |= line
pay_lines = payment.payment_line_ids - excl_pay_lines
if pay_lines:
(pay_lines.move_line_id + payment_move_line_id).reconcile()
self.write(
{"state": "uploaded", "date_uploaded": fields.Date.context_today(self)}
)

View File

@@ -305,6 +305,62 @@ class TestPaymentOrderOutbound(TestPaymentOrderOutboundBase):
fields.Date.context_today(outbound_order),
)
def test_partial_reconciliation(self):
"""
Confirm both supplier invoices
Add invoices to payment order
Reduce payment amount of first invoice from 100 to 80
Take payment order all the way to uploaded
Confirm 80 reconciled with first, not second invoice
generated2uploaded() does partial reconciliation of non-matching
line amounts before running .reconcile() against the remaining
matching line amounts.
"""
# Open both invoices
self.invoice.action_post()
self.invoice_02.action_post()
# Add to payment order using the wizard
self.env["account.invoice.payment.line.multi"].with_context(
active_model="account.move",
active_ids=self.invoice.ids + self.invoice_02.ids,
).create({}).run()
payment_order = self.env["account.payment.order"].search(self.domain)
self.assertEqual(len(payment_order), 1)
payment_order.write({"journal_id": self.bank_journal.id})
self.assertEqual(len(payment_order.payment_line_ids), 2)
self.assertFalse(payment_order.payment_ids)
# Reduce payment of first invoice from 100 to 80
first_payment_line, second_payment_line = payment_order.payment_line_ids
first_payment_line.write({"amount_currency": 80.0})
# Open payment order
payment_order.draft2open()
# Confirm single payment (grouped - two invoices one partner)
self.assertEqual(payment_order.payment_count, 1)
# Generate and upload
payment_order.open2generated()
payment_order.generated2uploaded()
self.assertEqual(payment_order.state, "uploaded")
with self.assertRaises(UserError):
payment_order.unlink()
# Confirm payments were reconciled against correct invoices
self.assertEqual(first_payment_line.amount_currency, 80.0)
self.assertEqual(
first_payment_line.move_line_id.amount_residual_currency, -20.0
)
self.assertEqual(second_payment_line.amount_currency, 100.0)
self.assertEqual(second_payment_line.move_line_id.amount_residual_currency, 0.0)
def test_supplier_refund(self):
"""
Confirm the supplier invoice