[FIX] purchase_mrp: calculate valuation unit_cost correctly
commit that introduced the issue : https://github.com/odoo/odoo/commit/8e516dccac4ced7e48adfabe756a899784bac9ca Issue: ====== valuation unit cost is wrong when we do backorder with real time unit price computation Steps to reproduce the issue: ============================= - Create a kit with 2 components with product quntity to produce = 3 - Put qty = 2 for the first component and qty = 1 for the second component - Assign product category to the kit product and the components as fifo one with automatec price computation - Create a purchase order with 30 quantity of the kit and price unit = 90 - confirm order and go to receipt - Confirm 4 qty for the first component and 2 qty for the second. - Create backorder - Go to the confirmed receipt and go to valuation - You will see that the total sum corresponds to the price of all the products and not only the confirmed ones. Solution: ========= We need to use the bom quantities and not the order line to get the unit_cost of each component. opw-3790132 closes odoo/odoo#158788 X-original-commit: a72232694f68a810986e5c1c24fd0394d058af41 Signed-off-by: William Henrotin (whe) <whe@odoo.com> Signed-off-by: Mahdi Cheikh Rouhou (macr) <macr@odoo.com>
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user