Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions account_payment_multi_deduction/models/__init__.py
Original file line number Diff line number Diff line change
@@ -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
32 changes: 32 additions & 0 deletions account_payment_multi_deduction/models/account_payment.py
Original file line number Diff line number Diff line change
@@ -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
)
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Loading