From 994aef18c52a5f5d100c8e595fe0943e6d6236c2 Mon Sep 17 00:00:00 2001 From: "Gauthier Wala (gawa)" Date: Thu, 4 Apr 2024 16:13:49 +0200 Subject: [PATCH] [FIX] account: analytic_distribution on counterpart of transfer To reproduce: - Create 2 lines with the same balance but only one has an analytic_distribution (of 100% on an analytic account). - Create a transfer of accounts for these => The counterpart has a distribution of 100% or no distribution. Indeed, we simply put the distribution of the last line. It makes no sense: analytic "balance" is generated and does not reflect the transfer move. We should make a prorata of the distributions of the lines to transfer. closes odoo/odoo#161982 X-original-commit: dcfe607d48021902c88b79a571a15559434d1592 Signed-off-by: Laurent Smet (las) Signed-off-by: Wala Gauthier (gawa) --- addons/account/tests/test_transfer_wizard.py | 67 +++++++++++++++++++ .../wizard/account_automatic_entry_wizard.py | 27 ++++++-- 2 files changed, 90 insertions(+), 4 deletions(-) diff --git a/addons/account/tests/test_transfer_wizard.py b/addons/account/tests/test_transfer_wizard.py index 8ba220f313d..d35748bc77b 100644 --- a/addons/account/tests/test_transfer_wizard.py +++ b/addons/account/tests/test_transfer_wizard.py @@ -192,6 +192,23 @@ class TestTransferWizard(AccountTestInvoicingCommon): }) cls.move_2.action_post() + analytic_plan_1, analytic_plan_2 = cls.env['account.analytic.plan'].create([ + {'name': 'Plan Test 1'}, + {'name': 'Plan Test 2'}, + ]) + cls.analytic_account_1, cls.analytic_account_2 = cls.env['account.analytic.account'].create([ + { + 'name': 'test_analytic_account_1', + 'plan_id': analytic_plan_1.id, + 'code': 'TESTEUH1' + }, + { + 'name': 'test_analytic_account_2', + 'plan_id': analytic_plan_2.id, + 'code': 'TESTEUH2' + }, + ]) + @freeze_time('2024-03-13') def test_transfer_default_tax(self): """ Make sure default taxes on accounts are not computed on transfer moves @@ -438,3 +455,53 @@ class TestTransferWizard(AccountTestInvoicingCommon): self.assertRecordValues(destination_line, [ {'account_id': self.accounts[0].id, 'amount_currency': 0.0, 'currency_id': self.test_currency_1.id, 'balance': -1000} ]) + + def test_transfer_wizard_analytic(self): + """ Tests that the analytic distribution is transmitted when doing a transfer with the wizard """ + invoice = self.env['account.move'].create([ + { + 'move_type': 'out_invoice', + 'partner_id': self.partner_a.id, + 'invoice_date': '2017-01-01', + 'journal_id': self.company_data['default_journal_sale'].id, + 'invoice_line_ids': [ + Command.create({ + 'quantity': 1, + 'price_unit': 1000.0, + 'account_id': self.company_data['default_account_revenue'].id, + 'analytic_distribution': {self.analytic_account_1.id: 100}, + }), + Command.create({ + 'quantity': 1, + 'price_unit': 2000.0, + 'account_id': self.company_data['default_account_revenue'].id, + 'analytic_distribution': {self.analytic_account_1.id: 50, self.analytic_account_2.id: 50}, + }), + Command.create({ + 'quantity': 1, + 'price_unit': 1000.0, + 'account_id': self.company_data['default_account_revenue'].id, + 'analytic_distribution': False, + }), + ], + } + ]) + invoice.action_post() + wizard = self.env['account.automatic.entry.wizard'].with_context( + active_model='account.move.line', + active_ids=invoice.invoice_line_ids.ids + ).create({ + 'action': 'change_account', + 'date': '2018-01-01', + 'journal_id': self.journal.id, + 'destination_account_id': self.receivable_account.id, + }) + + transfer_move = self.env['account.move'].browse(wizard.do_action()['res_id']) + + self.assertRecordValues(transfer_move.line_ids, [ + {'balance': -4000, 'analytic_distribution': {str(self.analytic_account_1.id): 50, str(self.analytic_account_2.id): 25}}, + {'balance': 1000, 'analytic_distribution': {str(self.analytic_account_1.id): 100}}, + {'balance': 2000, 'analytic_distribution': {str(self.analytic_account_1.id): 50, str(self.analytic_account_2.id): 50}}, + {'balance': 1000, 'analytic_distribution': False}, + ]) diff --git a/addons/account/wizard/account_automatic_entry_wizard.py b/addons/account/wizard/account_automatic_entry_wizard.py index f91d597f162..1aa9c634a1f 100644 --- a/addons/account/wizard/account_automatic_entry_wizard.py +++ b/addons/account/wizard/account_automatic_entry_wizard.py @@ -161,6 +161,7 @@ class AutomaticEntryWizard(models.TransientModel): # Group data from selected move lines counterpart_balances = defaultdict(lambda: defaultdict(lambda: 0)) + counterpart_distribution_amount = defaultdict(lambda: defaultdict(lambda: {})) grouped_source_lines = defaultdict(lambda: self.env['account.move.line']) for line in self.move_line_ids.filtered(lambda x: x.account_id != self.destination_account_id): @@ -171,9 +172,17 @@ class AutomaticEntryWizard(models.TransientModel): counterpart_currency = self.destination_account_id.currency_id counterpart_amount_currency = self.company_id.currency_id._convert(line.balance, self.destination_account_id.currency_id, self.company_id, line.date) - counterpart_balances[(line.partner_id, counterpart_currency)]['amount_currency'] += counterpart_amount_currency - counterpart_balances[(line.partner_id, counterpart_currency)]['balance'] += line.balance - counterpart_balances[(line.partner_id, counterpart_currency)]['analytic_distribution'] = line.analytic_distribution + grouping_key = (line.partner_id, counterpart_currency) + + counterpart_balances[grouping_key]['amount_currency'] += counterpart_amount_currency + counterpart_balances[grouping_key]['balance'] += line.balance + if line.analytic_distribution: + for account_id, distribution in line.analytic_distribution.items(): + # For the counterpart, we will need to make a prorata of the different distribution of the lines + # This computes the total balance for each analytic account, for each counterpart line to generate + distribution_values = counterpart_distribution_amount[grouping_key] + distribution_values[account_id] = (line.balance * distribution + distribution_values.get(account_id, 0) * 100) / 100 + counterpart_balances[grouping_key]['analytic_distribution'] = counterpart_distribution_amount[grouping_key] or {} grouped_source_lines[( line.partner_id, line.currency_id, @@ -186,6 +195,16 @@ class AutomaticEntryWizard(models.TransientModel): source_accounts = self.move_line_ids.mapped('account_id') counterpart_label = len(source_accounts) == 1 and _("Transfer from %s", source_accounts.display_name) or _("Transfer counterpart") + # We divide the amount for each account by the total balance to reflect the lines counter-parted + analytic_distribution = { + account_id: ( + 100 + if counterpart_currency.is_zero(counterpart_vals['balance']) + else 100 * distribution_amount / counterpart_vals['balance'] + ) + for account_id, distribution_amount in counterpart_vals['analytic_distribution'].items() + } + if not counterpart_currency.is_zero(counterpart_vals['amount_currency']) or not self.company_id.currency_id.is_zero(counterpart_vals['balance']): line_vals.append({ 'name': counterpart_label, @@ -195,7 +214,7 @@ class AutomaticEntryWizard(models.TransientModel): 'partner_id': counterpart_partner.id or None, 'amount_currency': counterpart_currency.round((counterpart_vals['balance'] < 0 and -1 or 1) * abs(counterpart_vals['amount_currency'])) or 0, 'currency_id': counterpart_currency.id, - 'analytic_distribution': counterpart_vals['analytic_distribution'], + 'analytic_distribution': analytic_distribution, }) # Generate change_account lines' vals