diff --git a/addons/account/models/account_payment.py b/addons/account/models/account_payment.py index 48be955235a..6ef2998e6bb 100644 --- a/addons/account/models/account_payment.py +++ b/addons/account/models/account_payment.py @@ -193,23 +193,32 @@ class AccountPayment(models.Model): self.journal_id.display_name)) # Compute amounts. - write_off_amount = write_off_line_vals.get('amount', 0.0) + write_off_amount_currency = write_off_line_vals.get('amount', 0.0) if self.payment_type == 'inbound': # Receive money. - counterpart_amount = -self.amount - write_off_amount *= -1 + liquidity_amount_currency = self.amount elif self.payment_type == 'outbound': # Send money. - counterpart_amount = self.amount + liquidity_amount_currency = -self.amount + write_off_amount_currency *= -1 else: - counterpart_amount = 0.0 - write_off_amount = 0.0 + liquidity_amount_currency = write_off_amount_currency = 0.0 - balance = self.currency_id._convert(counterpart_amount, self.company_id.currency_id, self.company_id, self.date) - counterpart_amount_currency = counterpart_amount - write_off_balance = self.currency_id._convert(write_off_amount, self.company_id.currency_id, self.company_id, self.date) - write_off_amount_currency = write_off_amount + write_off_balance = self.currency_id._convert( + write_off_amount_currency, + self.company_id.currency_id, + self.company_id, + self.date, + ) + liquidity_balance = self.currency_id._convert( + liquidity_amount_currency, + self.company_id.currency_id, + self.company_id, + self.date, + ) + counterpart_amount_currency = -liquidity_amount_currency - write_off_amount_currency + counterpart_balance = -liquidity_balance - write_off_balance currency_id = self.currency_id.id if self.is_internal_transfer: @@ -242,33 +251,33 @@ class AccountPayment(models.Model): { 'name': liquidity_line_name or default_line_name, 'date_maturity': self.date, - 'amount_currency': -counterpart_amount_currency, + 'amount_currency': liquidity_amount_currency, 'currency_id': currency_id, - 'debit': balance < 0.0 and -balance or 0.0, - 'credit': balance > 0.0 and balance or 0.0, + 'debit': liquidity_balance if liquidity_balance > 0.0 else 0.0, + 'credit': -liquidity_balance if liquidity_balance < 0.0 else 0.0, 'partner_id': self.partner_id.id, - 'account_id': self.journal_id.payment_debit_account_id.id if balance < 0.0 else self.journal_id.payment_credit_account_id.id, + 'account_id': self.journal_id.payment_credit_account_id.id if liquidity_balance < 0.0 else self.journal_id.payment_debit_account_id.id, }, # Receivable / Payable. { 'name': self.payment_reference or default_line_name, 'date_maturity': self.date, - 'amount_currency': counterpart_amount_currency + write_off_amount_currency if currency_id else 0.0, + 'amount_currency': counterpart_amount_currency, 'currency_id': currency_id, - 'debit': balance + write_off_balance > 0.0 and balance + write_off_balance or 0.0, - 'credit': balance + write_off_balance < 0.0 and -balance - write_off_balance or 0.0, + 'debit': counterpart_balance if counterpart_balance > 0.0 else 0.0, + 'credit': -counterpart_balance if counterpart_balance < 0.0 else 0.0, 'partner_id': self.partner_id.id, 'account_id': self.destination_account_id.id, }, ] - if write_off_balance: + if not self.currency_id.is_zero(write_off_amount_currency): # Write-off line. line_vals_list.append({ 'name': write_off_line_vals.get('name') or default_line_name, - 'amount_currency': -write_off_amount_currency, + 'amount_currency': write_off_amount_currency, 'currency_id': currency_id, - 'debit': write_off_balance < 0.0 and -write_off_balance or 0.0, - 'credit': write_off_balance > 0.0 and write_off_balance or 0.0, + 'debit': write_off_balance if write_off_balance > 0.0 else 0.0, + 'credit': -write_off_balance if write_off_balance < 0.0 else 0.0, 'partner_id': self.partner_id.id, 'account_id': write_off_line_vals.get('account_id'), }) @@ -757,16 +766,21 @@ class AccountPayment(models.Model): # This allows to create a new payment with custom 'line_ids'. if writeoff_lines: + counterpart_amount = sum(counterpart_lines.mapped('amount_currency')) writeoff_amount = sum(writeoff_lines.mapped('amount_currency')) - counterpart_amount = counterpart_lines['amount_currency'] - if writeoff_amount > 0.0 and counterpart_amount > 0.0: - sign = 1 - else: + + # To be consistent with the payment_difference made in account.payment.register, + # 'writeoff_amount' needs to be signed regarding the 'amount' field before the write. + # Since the write is already done at this point, we need to base the computation on accounting values. + if (counterpart_amount > 0.0) == (writeoff_amount > 0.0): sign = -1 + else: + sign = 1 + writeoff_amount = abs(writeoff_amount) * sign write_off_line_vals = { 'name': writeoff_lines[0].name, - 'amount': writeoff_amount * sign, + 'amount': writeoff_amount, 'account_id': writeoff_lines[0].account_id.id, } else: diff --git a/addons/account/tests/test_account_payment.py b/addons/account/tests/test_account_payment.py index 772da3dac4f..5ef482db4a4 100644 --- a/addons/account/tests/test_account_payment.py +++ b/addons/account/tests/test_account_payment.py @@ -323,6 +323,206 @@ class TestAccountPayment(AccountTestInvoicingCommon): }, ]) + def test_inbound_payment_sync_writeoff_debit_sign(self): + payment = self.env['account.payment'].create({ + 'amount': 100.0, + 'payment_type': 'inbound', + 'partner_type': 'customer', + }) + + # ==== Edit the account.move.line ==== + + liquidity_lines, counterpart_lines, dummy = payment._seek_for_lines() + payment.move_id.write({ + 'line_ids': [ + (1, liquidity_lines.id, {'debit': 100.0}), + (1, counterpart_lines.id, {'credit': 125.0}), + (0, 0, {'debit': 25.0, 'account_id': self.company_data['default_account_revenue'].id}), + ], + }) + + self.assertRecordValues(payment, [{ + 'payment_type': 'inbound', + 'partner_type': 'customer', + 'amount': 100.0, + }]) + + # ==== Edit the account.payment amount ==== + + payment.write({ + 'partner_type': 'supplier', + 'amount': 100.1, + 'destination_account_id': self.company_data['default_account_payable'].id, + }) + + self.assertRecordValues(payment.line_ids.sorted('balance'), [ + { + 'debit': 0.0, + 'credit': 125.1, + 'account_id': self.company_data['default_account_payable'].id, + }, + { + 'debit': 25.0, + 'credit': 0.0, + 'account_id': self.company_data['default_account_revenue'].id, + }, + { + 'debit': 100.1, + 'credit': 0.0, + 'account_id': self.payment_debit_account_id.id, + }, + ]) + + def test_inbound_payment_sync_writeoff_credit_sign(self): + payment = self.env['account.payment'].create({ + 'amount': 100.0, + 'payment_type': 'inbound', + 'partner_type': 'customer', + }) + + # ==== Edit the account.move.line ==== + + liquidity_lines, counterpart_lines, dummy = payment._seek_for_lines() + payment.move_id.write({ + 'line_ids': [ + (1, liquidity_lines.id, {'debit': 100.0}), + (1, counterpart_lines.id, {'credit': 75.0}), + (0, 0, {'credit': 25.0, 'account_id': self.company_data['default_account_revenue'].id}), + ], + }) + + self.assertRecordValues(payment, [{ + 'payment_type': 'inbound', + 'partner_type': 'customer', + 'amount': 100.0, + }]) + + # ==== Edit the account.payment amount ==== + + payment.write({ + 'partner_type': 'supplier', + 'amount': 100.1, + 'destination_account_id': self.company_data['default_account_payable'].id, + }) + + self.assertRecordValues(payment.line_ids.sorted('balance'), [ + { + 'debit': 0.0, + 'credit': 75.1, + 'account_id': self.company_data['default_account_payable'].id, + }, + { + 'debit': 0.0, + 'credit': 25.0, + 'account_id': self.company_data['default_account_revenue'].id, + }, + { + 'debit': 100.1, + 'credit': 0.0, + 'account_id': self.payment_debit_account_id.id, + }, + ]) + + def test_outbound_payment_sync_writeoff_debit_sign(self): + payment = self.env['account.payment'].create({ + 'amount': 100.0, + 'payment_type': 'outbound', + 'partner_type': 'supplier', + }) + + # ==== Edit the account.move.line ==== + + liquidity_lines, counterpart_lines, dummy = payment._seek_for_lines() + payment.move_id.write({ + 'line_ids': [ + (1, liquidity_lines.id, {'credit': 100.0}), + (1, counterpart_lines.id, {'debit': 75.0}), + (0, 0, {'debit': 25.0, 'account_id': self.company_data['default_account_revenue'].id}), + ], + }) + + self.assertRecordValues(payment, [{ + 'payment_type': 'outbound', + 'partner_type': 'supplier', + 'amount': 100.0, + }]) + + # ==== Edit the account.payment amount ==== + + payment.write({ + 'partner_type': 'customer', + 'amount': 100.1, + 'destination_account_id': self.company_data['default_account_receivable'].id, + }) + + self.assertRecordValues(payment.line_ids.sorted('balance'), [ + { + 'debit': 0.0, + 'credit': 100.1, + 'account_id': self.payment_credit_account_id.id, + }, + { + 'debit': 25.0, + 'credit': 0.0, + 'account_id': self.company_data['default_account_revenue'].id, + }, + { + 'debit': 75.1, + 'credit': 0.0, + 'account_id': self.company_data['default_account_receivable'].id, + }, + ]) + + def test_outbound_payment_sync_writeoff_credit_sign(self): + payment = self.env['account.payment'].create({ + 'amount': 100.0, + 'payment_type': 'outbound', + 'partner_type': 'supplier', + }) + + # ==== Edit the account.move.line ==== + + liquidity_lines, counterpart_lines, dummy = payment._seek_for_lines() + payment.move_id.write({ + 'line_ids': [ + (1, liquidity_lines.id, {'credit': 100.0}), + (1, counterpart_lines.id, {'debit': 125.0}), + (0, 0, {'credit': 25.0, 'account_id': self.company_data['default_account_revenue'].id}), + ], + }) + + self.assertRecordValues(payment, [{ + 'payment_type': 'outbound', + 'partner_type': 'supplier', + 'amount': 100.0, + }]) + + # ==== Edit the account.payment amount ==== + + payment.write({ + 'partner_type': 'customer', + 'amount': 100.1, + 'destination_account_id': self.company_data['default_account_receivable'].id, + }) + + self.assertRecordValues(payment.line_ids.sorted('balance'), [ + { + 'debit': 0.0, + 'credit': 100.1, + 'account_id': self.payment_credit_account_id.id, + }, + { + 'debit': 0.0, + 'credit': 25.0, + 'account_id': self.company_data['default_account_revenue'].id, + }, + { + 'debit': 125.1, + 'credit': 0.0, + 'account_id': self.company_data['default_account_receivable'].id, + }, + ]) + def test_internal_transfer(self): copy_receivable = self.copy_account(self.company_data['default_account_receivable'])