From 56a4f4beb2a8ccf99697db34e3c75d058d2956ec Mon Sep 17 00:00:00 2001 From: Walid Date: Tue, 5 Sep 2023 17:17:34 +0200 Subject: [PATCH] [FIX] purchase_mrp: split cost in bom line Steps to reproduce: - Create Storable Product "Super Test" with Cost of $1. - Create Storable Product "Pack of Super Test" with Cost of $10. - Create a Kit BoM that produces 1 "Pack of Super Test" from 10 "Super Test". - Ensure product category on both products is set to Automated FIFO Inventory Valuation. - Create a PO for 20 "Pack of Super Test" and confirm. - Process the Delivery and look at inventory valuation. - See that "Super Test" has moved quantity at 200 with Unit Value of 10 each (taken from kit product!). Bug: cost isn't split on the qty of the bom line Fix: take product quantities of the bom into consideration opw-3453703 closes odoo/odoo#134909 X-original-commit: 8e516dccac4ced7e48adfabe756a899784bac9ca Signed-off-by: William Henrotin (whe) Signed-off-by: Walid Hanniche (waha) --- addons/purchase_mrp/models/mrp_bom.py | 4 +-- addons/purchase_mrp/models/stock_move.py | 6 ++-- .../tests/test_purchase_mrp_flow.py | 28 +++++++++++++++++++ 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/addons/purchase_mrp/models/mrp_bom.py b/addons/purchase_mrp/models/mrp_bom.py index 0190cef0a66..ce296a3db42 100644 --- a/addons/purchase_mrp/models/mrp_bom.py +++ b/addons/purchase_mrp/models/mrp_bom.py @@ -32,7 +32,7 @@ class MrpBomLine(models.Model): def _get_cost_share(self): self.ensure_one() if self.cost_share: - return fields.Float.round(self.cost_share / 100, 2) + return self.cost_share / 100 bom = self.bom_id bom_lines_without_cost_share = bom.bom_line_ids.filtered(lambda bl: not bl.cost_share) - return fields.Float.round(1 / len(bom_lines_without_cost_share), 2) + return 1 / len(bom_lines_without_cost_share) diff --git a/addons/purchase_mrp/models/stock_move.py b/addons/purchase_mrp/models/stock_move.py index f9469154f38..68377db0fa1 100644 --- a/addons/purchase_mrp/models/stock_move.py +++ b/addons/purchase_mrp/models/stock_move.py @@ -1,9 +1,8 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from dateutil.relativedelta import relativedelta from odoo import _, models -from odoo.tools.float_utils import float_is_zero +from odoo.tools.float_utils import float_is_zero, float_round from odoo.exceptions import UserError @@ -22,7 +21,8 @@ class StockMove(models.Model): line = self.purchase_line_id kit_price_unit = line._get_gross_price_unit() cost_share = self.bom_line_id._get_cost_share() - return kit_price_unit * cost_share + price_unit_prec = self.env['decimal.precision'].precision_get('Product Price') + return float_round(kit_price_unit * cost_share * line.product_qty / self.product_qty, precision_digits=price_unit_prec) def _get_valuation_price_and_qty(self, related_aml, to_curr): valuation_price_unit_total, valuation_total_qty = super()._get_valuation_price_and_qty(related_aml, to_curr) diff --git a/addons/purchase_mrp/tests/test_purchase_mrp_flow.py b/addons/purchase_mrp/tests/test_purchase_mrp_flow.py index 70f2bfd5cc7..07259cae943 100644 --- a/addons/purchase_mrp/tests/test_purchase_mrp_flow.py +++ b/addons/purchase_mrp/tests/test_purchase_mrp_flow.py @@ -215,6 +215,34 @@ class TestPurchaseMrpFlow(TransactionCase): move_line.qty_done = qty_to_process[comp][0] move._action_done() + def test_kit_component_cost(self): + # Set kit and componnet product to automated FIFO + self.kit_1.categ_id.property_cost_method = 'fifo' + self.kit_1.categ_id.property_valuation = 'real_time' + + self.kit_1.bom_ids.product_qty = 3 + + po = Form(self.env['purchase.order']) + po.partner_id = self.env['res.partner'].create({'name': 'Testy'}) + with po.order_line.new() as line: + line.product_id = self.kit_1 + line.product_qty = 120 + line.price_unit = 1260 + po = po.save() + po.button_confirm() + po.picking_ids.action_set_quantities_to_reservation() + po.picking_ids.button_validate() + + # Unit price equaly dived among bom lines (cost share not set) + # # price further divided by product qty of each component + components = [ + self.component_a, + self.component_b, + self.component_c, + ] + + self.assertEqual(sum([k.standard_price * k.qty_available for k in components]), 120 * 1260) + def test_01_sale_mrp_kit_qty_delivered(self): """ Test that the quantities delivered are correct when a kit with subkits is ordered with multiple backorders and returns