summaryrefslogtreecommitdiff
path: root/addons/account
diff options
context:
space:
mode:
authorLaurent Smet <las@odoo.com>2021-05-14 09:04:22 +0000
committerLaurent Smet <las@odoo.com>2021-05-14 14:23:07 +0000
commit87f6a2fd3f86d13ebe320c058336d752362b8f44 (patch)
tree3d3a8b15a9e263879456ab744f4981b812c18b15 /addons/account
parentdc296afac29a5a716b162ecef7d4a296399c2da3 (diff)
[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#70807 Signed-off-by: Laurent Smet <smetl@users.noreply.github.com>
Diffstat (limited to 'addons/account')
-rw-r--r--addons/account/models/account_payment.py62
-rw-r--r--addons/account/tests/test_account_payment.py230
2 files changed, 208 insertions, 84 deletions
diff --git a/addons/account/models/account_payment.py b/addons/account/models/account_payment.py
index 46f04073bcd..15bd9198373 100644
--- a/addons/account/models/account_payment.py
+++ b/addons/account/models/account_payment.py
@@ -187,23 +187,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:
@@ -236,33 +245,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'),
})
@@ -713,16 +722,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:
+
+ # 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 15bb5ae81cd..b2a0df04492 100644
--- a/addons/account/tests/test_account_payment.py
+++ b/addons/account/tests/test_account_payment.py
@@ -324,93 +324,203 @@ class TestAccountPayment(AccountTestInvoicingCommon):
},
])
- def test_payment_move_sync_writeoff_sign(self):
- copy_receivable = self.copy_account(self.company_data['default_account_receivable'])
+ def test_inbound_payment_sync_writeoff_debit_sign(self):
+ payment = self.env['account.payment'].create({
+ 'amount': 100.0,
+ 'payment_type': 'inbound',
+ 'partner_type': 'customer',
+ })
- pay_form = Form(self.env['account.payment'].with_context(default_journal_id=self.company_data['default_journal_bank'].id))
- pay_form.amount = 50.0
- pay_form.payment_type = 'inbound'
- pay_form.partner_type = 'customer'
- pay_form.destination_account_id = copy_receivable
- payment = pay_form.save()
+ # ==== Edit the account.move.line ====
- expected_payment_values = {
- 'amount': 50.0,
+ liquidity_lines, counterpart_lines, writeoff_lines = 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',
- 'payment_reference': False,
- 'is_reconciled': False,
- 'currency_id': self.company_data['currency'].id,
- 'partner_id': False,
- 'destination_account_id': copy_receivable.id,
- 'payment_method_id': self.env.ref('account.account_payment_method_manual_in').id,
- }
- expected_move_values = {
- 'currency_id': self.company_data['currency'].id,
- 'partner_id': False,
- }
- expected_liquidity_line = {
- 'debit': 50.0,
- 'credit': 0.0,
- 'amount_currency': 50.0,
- 'currency_id': self.company_data['currency'].id,
- 'account_id': self.payment_debit_account_id.id,
- }
- expected_counterpart_line = {
- 'debit': 0.0,
- 'credit': 50.0,
- 'amount_currency': -50.0,
- 'currency_id': self.company_data['currency'].id,
- 'account_id': self.partner_a.property_account_payable_id.id,
- }
+ '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 ====
- move_form = Form(payment.move_id)
- with move_form.line_ids.edit(0) as line_form:
- line_form.currency_id = self.company_data['currency']
- line_form.amount_currency = 100.0
- with move_form.line_ids.edit(1) as line_form:
- line_form.currency_id = self.company_data['currency']
- line_form.amount_currency = -75.0
- line_form.account_id = copy_receivable
- with move_form.line_ids.new() as line_form:
- line_form.currency_id = self.company_data['currency']
- line_form.amount_currency = -25.0
- line_form.account_id = self.company_data['default_account_revenue']
- move_form.save()
+ liquidity_lines, counterpart_lines, writeoff_lines = 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, [{
- **expected_payment_values,
+ 'payment_type': 'inbound',
+ 'partner_type': 'customer',
'amount': 100.0,
}])
# ==== Edit the account.payment amount ====
- pay_form = Form(payment)
- pay_form.partner_type = 'supplier'
- pay_form.amount = 100.1
- pay_form.partner_id = self.partner_a
- payment = pay_form.save()
+ 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'), [
{
- **expected_counterpart_line,
'debit': 0.0,
'credit': 75.1,
- 'amount_currency': -75.1,
+ 'account_id': self.company_data['default_account_payable'].id,
},
{
'debit': 0.0,
'credit': 25.0,
- 'amount_currency': -25.0,
- 'currency_id': self.company_data['currency'].id,
'account_id': self.company_data['default_account_revenue'].id,
},
{
- **expected_liquidity_line,
'debit': 100.1,
'credit': 0.0,
- 'amount_currency': 100.1,
+ '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, writeoff_lines = 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, writeoff_lines = 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,
},
])