From 2283f1105b4158b5155c554f74a0aefad266e79d Mon Sep 17 00:00:00 2001 From: Paul Stroobant Date: Tue, 19 Mar 2024 10:48:25 +0100 Subject: [PATCH] [FIX] project_purchase: split ids when calculating analytic contribution Steps to reproduce issue: 1. Create a Project with an Analytic Account and ensure it is Billable 2. Create a Purchase Order and add a Product 3. Add an Analytic Distribution to the Product with, on one line, the Project Account and an Account from another Plan 4. Confirm the Purchase Order 5. Open the Project's Updates 6. You get the error : > analytic_contribution = pol_read['analytic_distribution'][str(self.analytic_account_id.id)] / 100. > KeyError: '[int]' Explanation: This issue is related to odoo@73fa88c44ae64b2fc93ef1233f1ab8f8dbe2b0cc: the IDs are now stored in a csv string instead of separate values to allow for cross-analytics. In this case, `self.analytic_account_id.id` is not a key but part of a key. The line causing the issue was overlooked during the resolution of the previous one. Suggested fix: Similar lines have been fixed in the previous commit. Applying the same correction solves the issue. https://github.com/odoo/odoo/commit/73fa88c44ae64b2fc93ef1233f1ab8f8dbe2b0cc#diff-7af98465d7e344b935b9f2327a30b2da17a4df73d64bfee5b9b7a497362083e7L48-R59 https://github.com/odoo/odoo/commit/73fa88c44ae64b2fc93ef1233f1ab8f8dbe2b0cc#diff-2f1670bdaecbb290806818cc80aff338e2f956d89f3a71f6c2ed1b9805795fd3L575-R600 opw-3773509 closes odoo/odoo#158325 Signed-off-by: Wala Gauthier (gawa) --- .../models/project_project.py | 6 +++- .../tests/test_project_profitability.py | 33 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/addons/project_purchase/models/project_project.py b/addons/project_purchase/models/project_project.py index 11a2b8ce2f4..640da6112fb 100644 --- a/addons/project_purchase/models/project_project.py +++ b/addons/project_purchase/models/project_project.py @@ -169,7 +169,11 @@ class Project(models.Model): purchase_order_line_invoice_line_ids.extend(pol_read['invoice_lines'].ids) currency = self.env['res.currency'].browse(pol_read['currency_id']).with_prefetch(currency_ids) price_unit = currency._convert(pol_read['price_unit'], self.currency_id, self.company_id) - analytic_contribution = pol_read['analytic_distribution'][str(self.analytic_account_id.id)] / 100. + # an analytic account can appear several time in an analytic distribution with different repartition percentage + analytic_contribution = sum( + percentage for ids, percentage in pol_read['analytic_distribution'].items() + if str(self.analytic_account_id.id) in ids.split(',') + ) / 100. amount_invoiced -= price_unit * pol_read['qty_invoiced'] * analytic_contribution if pol_read['qty_invoiced'] > 0 else 0.0 if pol_read['qty_to_invoice'] > 0: amount_to_invoice -= price_unit * pol_read['qty_to_invoice'] * analytic_contribution diff --git a/addons/project_purchase/tests/test_project_profitability.py b/addons/project_purchase/tests/test_project_profitability.py index 0e6a65d6a7b..8f92b27c79a 100644 --- a/addons/project_purchase/tests/test_project_profitability.py +++ b/addons/project_purchase/tests/test_project_profitability.py @@ -507,3 +507,36 @@ class TestProjectPurchaseProfitability(TestProjectProfitabilityCommon, TestPurch purchase_bill = purchase_order.invoice_ids # get the bill from the purchase purchase_bill.invoice_date = datetime.today() purchase_bill.action_post() + + def test_cross_analytics_contribution(self): + cross_plan = self.env['account.analytic.plan'].create({'name': 'Cross Plan'}) + cross_account = self.env['account.analytic.account'].create({ + 'name': "Cross Analytic Account", + 'plan_id': cross_plan.id, + "company_id": self.env.company.id, + }) + cross_distribution = 42 + + cross_order = self.env['purchase.order'].create({ + 'name': 'Cross Purchase Order', + "partner_id": self.partner_a.id, + "company_id": self.env.company.id, + 'order_line': [ + Command.create({ + 'analytic_distribution': { + f"{self.project.analytic_account_id.id},{cross_account.id}": cross_distribution, + }, + "product_id": self.product_order.id, + "product_qty": 1, + "price_unit": self.product_order.standard_price, + "currency_id": self.env.company.currency_id.id, + }), + ], + }) + + cross_order.button_confirm() + items = self.project._get_profitability_items() + self.assertEqual( + items['costs']['data'][0]['to_bill'], + self.product_order.standard_price *-cross_distribution/100 + )