From f5da45537ad43d726d006e3af7db4bb43510dc82 Mon Sep 17 00:00:00 2001 From: Yolann Sabaux Date: Thu, 10 Aug 2023 06:43:07 +0000 Subject: [PATCH] [FIX] account: allows ungrouped batch payment with different payment terms Steps to reproduce: - Create two Bills with different payment terms with one having no "early_discount" such as '30% Now, Balance 60 Days' - Select the Bills and click on Register Payment (make sure the payment is not grouped) Issue: Server Error Cause: We try to Register Payment for all the Bills at once, but the "early_discount" is not defined for all the Bills. So, whenever there is a move with an early discount, the mode is always considered as "early_payment". Therefore, we call `_get_invoice_counterpart_amls_for_early_payment_discount` with an empty list since there is no early discount https://github.com/odoo/odoo/blob/0ffaaebfa5c25c4bf71fb0e02288767dbfac959d/addons/account/wizard/account_payment_register.py#L750-L755 https://github.com/odoo/odoo/blob/0ffaaebfa5c25c4bf71fb0e02288767dbfac959d/addons/account/wizard/account_payment_register.py#L760 Causing the "local variable 'aml' referenced before assignment" error. Solution: We only iterate through moves belonging to the batch. This way, we avoid setting the mode to "early_payment" and entering the confition. opw-3378445 closes odoo/odoo#132113 X-original-commit: 9bba9576d3365500a5c1eda0cfd57457fd999878 Signed-off-by: Laurent Smet (las) Signed-off-by: Yolann Sabaux (yosa) --- .../tests/test_early_payment_discount.py | 90 +++++++++++++++++++ .../wizard/account_payment_register.py | 2 +- 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/addons/account/tests/test_early_payment_discount.py b/addons/account/tests/test_early_payment_discount.py index 2d9ef25a4e7a8..a8de15c7f472f 100644 --- a/addons/account/tests/test_early_payment_discount.py +++ b/addons/account/tests/test_early_payment_discount.py @@ -24,6 +24,17 @@ def setUpClass(cls, chart_template_ref=None): })] }) + cls.pay_term_net_30_days = cls.env['account.payment.term'].create({ + 'name': 'Net 30 days', + 'line_ids': [ + (0, 0, { + 'value_amount': 100, + 'value': 'percent', + 'nb_days': 30, + }), + ], + }) + def assert_tax_totals(self, document, expected_values): main_keys_to_ignore = { 'formatted_amount_total', 'formatted_amount_untaxed', 'display_tax_base', 'subtotals_order'} @@ -691,3 +702,82 @@ def test_mixed_epd_with_rounding_issue(self): }) for price_unit, quantity, taxes in line_create_vals ] }) + + def test_register_payment_batch_with_discount_and_without_discount(self): + """ + Test that a batch payment, that is + - not grouped + - with invoices having different payment terms (1 with discount, 1 without) + -> will not crash + """ + out_invoice_1 = self.env['account.move'].create({ + 'move_type': 'out_invoice', + 'date': '2019-01-01', + 'invoice_date': '2019-01-01', + 'partner_id': self.partner_a.id, + 'currency_id': self.currency_data['currency'].id, + 'invoice_line_ids': [Command.create({'product_id': self.product_a.id, 'price_unit': 1000.0, 'tax_ids': []})], + 'invoice_payment_term_id': self.pay_term_net_30_days.id, + }) + out_invoice_2 = self.env['account.move'].create({ + 'move_type': 'out_invoice', + 'date': '2019-01-01', + 'invoice_date': '2019-01-01', + 'partner_id': self.partner_a.id, + 'currency_id': self.currency_data['currency'].id, + 'invoice_line_ids': [Command.create({'product_id': self.product_a.id, 'price_unit': 2000.0, 'tax_ids': []})], + 'invoice_payment_term_id': self.early_pay_10_percents_10_days.id, + }) + (out_invoice_1 + out_invoice_2).action_post() + active_ids = (out_invoice_1 + out_invoice_2).ids + + payments = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=active_ids).create({ + 'payment_date': '2019-01-01', 'group_payment': False + })._create_payments() + self.assertTrue(all(payments.mapped('is_reconciled'))) + self.assertRecordValues(payments.line_ids.sorted('balance'), [ + {'amount_currency': -2000.0}, + {'amount_currency': -1000.0}, + {'amount_currency': 200.0}, + {'amount_currency': 1000}, + {'amount_currency': 1800}, + ]) + + def test_register_payment_batch_without_discount(self): + """ + Test that a batch payment, that is + - not grouped + - with invoices having the same payment terms (without discount) + -> will not crash + """ + out_invoice_1 = self.env['account.move'].create({ + 'move_type': 'out_invoice', + 'date': '2019-01-01', + 'invoice_date': '2019-01-01', + 'partner_id': self.partner_a.id, + 'currency_id': self.currency_data['currency'].id, + 'invoice_line_ids': [Command.create({'product_id': self.product_a.id, 'price_unit': 1000.0, 'tax_ids': []})], + 'invoice_payment_term_id': self.pay_term_net_30_days.id, + }) + out_invoice_2 = self.env['account.move'].create({ + 'move_type': 'out_invoice', + 'date': '2019-01-01', + 'invoice_date': '2019-01-01', + 'partner_id': self.partner_a.id, + 'currency_id': self.currency_data['currency'].id, + 'invoice_line_ids': [Command.create({'product_id': self.product_a.id, 'price_unit': 2000.0, 'tax_ids': []})], + 'invoice_payment_term_id': self.pay_term_net_30_days.id, + }) + (out_invoice_1 + out_invoice_2).action_post() + active_ids = (out_invoice_1 + out_invoice_2).ids + + payments = self.env['account.payment.register'].with_context(active_model='account.move', active_ids=active_ids).create({ + 'payment_date': '2019-01-01', 'group_payment': False + })._create_payments() + self.assertTrue(all(payments.mapped('is_reconciled'))) + self.assertRecordValues(payments.line_ids.sorted('balance'), [ + {'amount_currency': -2000.0}, + {'amount_currency': -1000.0}, + {'amount_currency': 1000.0}, + {'amount_currency': 2000}, + ]) diff --git a/addons/account/wizard/account_payment_register.py b/addons/account/wizard/account_payment_register.py index 7d89b26520d86..730e303dacd9b 100644 --- a/addons/account/wizard/account_payment_register.py +++ b/addons/account/wizard/account_payment_register.py @@ -500,7 +500,7 @@ def _get_total_amount_using_same_currency(self, batch_result, early_payment_disc self.ensure_one() amount = 0.0 mode = False - moves = self.line_ids.move_id + moves = batch_result['lines'].mapped('move_id') for move in moves: if early_payment_discount and move._is_eligible_for_early_payment_discount(move.currency_id, self.payment_date): amount += move.invoice_payment_term_id._get_amount_due_after_discount(move.amount_total, move.amount_tax)#todo currencies