diff --git a/addons/purchase_mrp/models/stock_move.py b/addons/purchase_mrp/models/stock_move.py index 8f2efcfdb3e..737e922e69a 100644 --- a/addons/purchase_mrp/models/stock_move.py +++ b/addons/purchase_mrp/models/stock_move.py @@ -19,12 +19,24 @@ class StockMove(models.Model): if self.product_id == self.purchase_line_id.product_id or not self.bom_line_id or self._should_ignore_pol_price(): return super()._get_price_unit() line = self.purchase_line_id + # price_unit here with uom of product kit_price_unit = line._get_gross_price_unit() + bom_line = self.bom_line_id + bom = bom_line.bom_id if line.currency_id != self.company_id.currency_id: kit_price_unit = line.currency_id._convert(kit_price_unit, self.company_id.currency_id, self.company_id, fields.Date.context_today(self), round=False) cost_share = self.bom_line_id._get_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) + uom_factor = 1.0 + kit_product = bom.product_id or bom.product_tmpl_id + + # Convert uom from product_uom to bom_uom for kit product + uom_factor = bom.product_uom_id._compute_quantity(uom_factor, kit_product.uom_id) + + # Convert uom from bom_line_uom to product_uom for bom_line + uom_factor = bom_line.product_id.uom_id._compute_quantity(uom_factor, bom_line.product_uom_id) + + return float_round(kit_price_unit * cost_share * uom_factor * bom.product_qty / bom_line.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 b23c0e13712..f0dfa3fbc08 100644 --- a/addons/purchase_mrp/tests/test_purchase_mrp_flow.py +++ b/addons/purchase_mrp/tests/test_purchase_mrp_flow.py @@ -931,3 +931,54 @@ class TestPurchaseMrpFlow(AccountTestInvoicingCommon): report_values = self.env['report.mrp.report_bom_structure']._get_report_data(bom_id=bom.id) line_values = report_values['lines']['components'][0] self.assertEqual(line_values['availability_state'], 'expected', 'The first component should be expected as there is an incoming PO.') + + def test_valuation_with_backorder(self): + fifo_category = self.env['product.category'].create({ + 'name': 'FIFO', + 'property_cost_method': 'fifo', + 'property_valuation': 'real_time' + }) + kit, cmp1, cmp2 = self.env['product.product'].create([{ + 'name': name, + 'standard_price': 0, + 'type': 'product', + 'categ_id': fifo_category.id, + } for name in ['Kit', 'Cmp1', 'Cmp2']]) + kit.uom_id = self.uom_gm.id + cmp1.uom_id = self.uom_gm.id + cmp2.uom_id = self.uom_kg.id + + self.env['mrp.bom'].create({ + 'product_uom_id': self.uom_kg.id, + 'product_qty': 3, + 'product_tmpl_id': kit.product_tmpl_id.id, + 'type': 'phantom', + 'bom_line_ids': [ + (0, 0, {'product_id': cmp1.id, 'product_qty': 2, 'product_uom_id': self.uom_kg.id}), + (0, 0, {'product_id': cmp2.id, 'product_qty': 1, 'product_uom_id': self.uom_gm.id})] + }) + + po_form = Form(self.env['purchase.order']) + partner = self.env['res.partner'].create({'name': 'My Test Partner'}) + po_form.partner_id = partner + with po_form.order_line.new() as pol_form: + pol_form.product_id = kit + pol_form.product_qty = 30 + pol_form.product_uom = self.uom_kg + pol_form.price_unit = 90000 + pol_form.taxes_id.clear() + po = po_form.save() + po.button_confirm() + + receipt = po.picking_ids + receipt.move_line_ids[0].qty_done = 4 + receipt.move_line_ids[1].qty_done = 2 + action = receipt.button_validate() + wizard = Form(self.env[action['res_model']].with_context(action['context'])).save() + wizard.process() + # Price Unit for 1 gm of the kit = 90000/1000 = 90 + # unit_cost for cmp1 = 90 *1000* 3 / 2 / 2 / 1000 = 67.5 + # unit_cost for cmp2 = 90 *1000* 3 / 2 / 1 * 1000 = 135000000 + svl = po.picking_ids[0].move_ids.stock_valuation_layer_ids + self.assertEqual(svl[0].unit_cost, 67.5) + self.assertEqual(svl[1].unit_cost, 135000000)