From 5f5e356c6038117581155ddcf2fd737c5b31f2a0 Mon Sep 17 00:00:00 2001 From: Saran440 Date: Thu, 2 Jul 2026 09:16:05 +0700 Subject: [PATCH] [FIX] account_payment_multi_deduction: preserve multi deductions when changing the payment journal --- .../models/__init__.py | 1 + .../models/account_payment.py | 32 ++++++++++ .../tests/test_payment_multi_deduction.py | 58 +++++++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 account_payment_multi_deduction/models/account_payment.py diff --git a/account_payment_multi_deduction/models/__init__.py b/account_payment_multi_deduction/models/__init__.py index 1912a44448a..1a72b8e6c38 100644 --- a/account_payment_multi_deduction/models/__init__.py +++ b/account_payment_multi_deduction/models/__init__.py @@ -1,3 +1,4 @@ # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html) from . import account_move +from . import account_payment diff --git a/account_payment_multi_deduction/models/account_payment.py b/account_payment_multi_deduction/models/account_payment.py new file mode 100644 index 00000000000..2d06ffd91ab --- /dev/null +++ b/account_payment_multi_deduction/models/account_payment.py @@ -0,0 +1,32 @@ +# Copyright 2026 Ecosoft Co., Ltd (http://ecosoft.co.th/) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html) + +from odoo import models + + +class AccountPayment(models.Model): + _inherit = "account.payment" + + def _prepare_move_lines_per_type( + self, write_off_line_vals=None, force_balance=None + ): + """Re-expand multi deduction write-off lines collapsed by core resync.""" + if write_off_line_vals and len(write_off_line_vals) == 1: + deduct_lines = self.move_id.line_ids.filtered("is_writeoff") + if len(deduct_lines) > 1: + write_off_line_vals = [ + { + "name": line.name, + "account_id": line.account_id.id, + "partner_id": line.partner_id.id, + "currency_id": line.currency_id.id, + "amount_currency": line.amount_currency, + "balance": line.balance, + "analytic_distribution": line.analytic_distribution, + "is_writeoff": True, + } + for line in deduct_lines + ] + return super()._prepare_move_lines_per_type( + write_off_line_vals=write_off_line_vals, force_balance=force_balance + ) diff --git a/account_payment_multi_deduction/tests/test_payment_multi_deduction.py b/account_payment_multi_deduction/tests/test_payment_multi_deduction.py index 04f9e30c441..6a157b6dfcf 100644 --- a/account_payment_multi_deduction/tests/test_payment_multi_deduction.py +++ b/account_payment_multi_deduction/tests/test_payment_multi_deduction.py @@ -185,3 +185,61 @@ def test_04_one_invoice_payment_with_keep_open(self): writeoff = payment.move_id.line_ids.filtered(lambda line: line.is_writeoff) self.assertEqual(len(writeoff), 1) self.assertEqual(writeoff.account_id, self.account_expense) + + def test_05_reset_and_change_journal_keeps_writeoff_lines(self): + """Multi deduction write-off lines must survive a reset + journal change""" + ctx = { + "active_ids": [self.cust_invoice.id], + "active_id": self.cust_invoice.id, + "active_model": "account.move", + } + with Form( + self.payment_register_model.with_context(**ctx), view=self.register_view_id + ) as f: + f.amount = 400.0 # Reduce to 400.0, and mark fully paid (multi) + f.payment_difference_handling = "reconcile_multi_deduct" + with f.deduction_ids.new() as f2: + f2.account_id = self.account_expense + f2.name = "Expense 1" + f2.amount = 20.0 + with f.deduction_ids.new() as f2: + f2.account_id = self.account_expense + f2.name = "Expense 2" + f2.amount = 30.0 + payment_register = f.save() + payment = payment_register._create_payments() + + # Sanity check: 2 write-off lines created. + writeoff = payment.move_id.line_ids.filtered(lambda line: line.is_writeoff) + self.assertEqual(len(writeoff), 2) + original_total = sum(writeoff.mapped("balance")) + + # Reset the payment to draft and switch its journal. + payment.action_draft() + # Setup a second bank journal with a valid outstanding account, so the + # resynchronization triggered by the journal change can rebuild the + # liquidity lines. + other_journal = self.journal_model.create( + { + "name": "Bank Other", + "type": "bank", + "code": "BNK2", + "company_id": self.company_data["company"].id, + } + ) + outstanding = self.env["account.chart.template"].ref( + "account_journal_payment_debit_account_id" + ) + other_journal.inbound_payment_method_line_ids[ + :1 + ].payment_account_id = outstanding + other_journal.outbound_payment_method_line_ids[ + :1 + ].payment_account_id = outstanding + payment.journal_id = other_journal + + # The write-off lines must still be there, line by line. + writeoff = payment.move_id.line_ids.filtered(lambda line: line.is_writeoff) + self.assertEqual(len(writeoff), 2) + self.assertEqual(writeoff.mapped("account_id"), self.account_expense) + self.assertEqual(sum(writeoff.mapped("balance")), original_total)