[FIX] account: Fix corner cases of https://github.com/odoo/odoo/pull/70303
Original issue: Create a payment like follow: Payment type: receive money Partner type: customer Destination account: whatever receivable Amount: define an amount (i.e. 90.00) On Save, open the draft jounral entry created. Lower the liquidity or counterpart amount and add a writeoff Go back to the payment, change the amount and save. The journal entry writeoff will swap from debit to credit at every change made to the amount. This occur also when changing currency on the payment opw-2475223 Otherwise, this fix is not covering all cases: inbound with write-off in debit inbound with write-off in credit outbound with write-off in debit outbound with write-off in credit closes odoo/odoo#70903 X-original-commit: 01b9bff35e85fafb1a50bb0819123d186acf4925 Signed-off-by: Laurent Smet <smetl@users.noreply.github.com>
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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'])
|
||||
|
||||
|
||||
Reference in New Issue
Block a user