[FIX] mrp: orderpoint for manufacture not trigger twice

Usecase to reproduce:
With BoM structure
- Product A (RR 1-20)
	|
	Product B (MTO)
		|
		Product C (RR 5-50)
			|
			Product D (Buy)

Launch the RR. The MO are:
Current Behavior
- Product A 20
- Product B 20
- Product C 50
- Product C 70

Expected Behavior
- Product A 20
- Product B 20
- Product C 50

It happens because the MO are created as draft during the
`_run_manufacture` and are confirm at the end of
`_procure_orderpoint_confirm` in '_post_process_scheduler`.

However at the first MO for product A, it creates a MO for product B
and since it consumes product c, it checks if the orderpoint should be
trigger. MO for product C still "draft" and the orderpoint forecast is
now -20, so it will create a new procurement for product C with 70 units

To fix it we take the MO draft linked to the orderpoint for the
forecasted quantity.

closes odoo/odoo#89079

X-original-commit: 199a0dd0f013655a3c2345a41bc7c721e09bfc68
Signed-off-by: Arnold Moyaux <arm@odoo.com>
Signed-off-by: William Henrotin (whe) <whe@odoo.com>
This commit is contained in:
Arnold Moyaux
2022-04-20 10:33:00 +02:00
parent b893695bf9
commit cf9ff8e41a
2 changed files with 94 additions and 1 deletions
+14 -1
View File
@@ -50,7 +50,8 @@ class StockWarehouseOrderpoint(models.Model):
for orderpoint in self
if orderpoint.product_id in bom_kits
}
res = super(StockWarehouseOrderpoint, self.filtered(lambda p: p not in bom_kit_orderpoints))._quantity_in_progress()
orderpoints_without_kit = self - self.env['stock.warehouse.orderpoint'].concat(*bom_kit_orderpoints.keys())
res = super(StockWarehouseOrderpoint, orderpoints_without_kit)._quantity_in_progress()
for orderpoint in bom_kit_orderpoints:
dummy, bom_sub_lines = bom_kit_orderpoints[orderpoint].explode(orderpoint.product_id, 1)
ratios_qty_available = []
@@ -73,6 +74,18 @@ class StockWarehouseOrderpoint(models.Model):
# (the quantity if we have received all in-progress components) - (the quantity using only available components)
product_qty = min(ratios_total or [0]) - min(ratios_qty_available or [0])
res[orderpoint.id] = orderpoint.product_id.uom_id._compute_quantity(product_qty, orderpoint.product_uom, round=False)
bom_manufacture = self.env['mrp.bom']._bom_find(orderpoints_without_kit.product_id, bom_type='normal')
bom_manufacture = self.env['mrp.bom'].concat(*bom_manufacture.values())
productions_group = self.env['mrp.production'].read_group(
[('bom_id', 'in', bom_manufacture.ids), ('state', '=', 'draft'), ('orderpoint_id', 'in', orderpoints_without_kit.ids)],
['orderpoint_id', 'product_qty', 'product_uom_id'],
['orderpoint_id', 'product_uom_id'], lazy=False)
for p in productions_group:
uom = self.env['uom.uom'].browse(p['product_uom_id'][0])
orderpoint = self.env['stock.warehouse.orderpoint'].browse(p['orderpoint_id'][0])
res[orderpoint.id] += uom._compute_quantity(
p['product_qty'], orderpoint.product_uom, round=False)
return res
def _get_qty_multiple_to_order(self):
+80
View File
@@ -596,3 +596,83 @@ class TestProcurement(TestMrpCommon):
self.assertEqual(manufacturing_order.product_qty, 10, 'The demand on the initial manufacturing order should not have been increased.')
manufacturing_orders = self.env['mrp.production'].search([('product_id', '=', product.id)])
self.assertEqual(len(manufacturing_orders), 2, 'A new MO should have been created for missing demand.')
def test_rr_with_dependance_between_bom(self):
self.warehouse = self.env.ref('stock.warehouse0')
route_mto = self.warehouse.mto_pull_id.route_id
route_mto.active = True
route_manufacture = self.warehouse.manufacture_pull_id.route_id
product_1 = self.env['product.product'].create({
'name': 'Product A',
'type': 'product',
'route_ids': [(6, 0, [route_manufacture.id])]
})
product_2 = self.env['product.product'].create({
'name': 'Product B',
'type': 'product',
'route_ids': [(6, 0, [route_manufacture.id, route_mto.id])]
})
product_3 = self.env['product.product'].create({
'name': 'Product B',
'type': 'product',
'route_ids': [(6, 0, [route_manufacture.id])]
})
product_4 = self.env['product.product'].create({
'name': 'Product C',
'type': 'consu',
})
op1 = self.env['stock.warehouse.orderpoint'].create({
'name': 'Product A',
'location_id': self.warehouse.lot_stock_id.id,
'product_id': product_1.id,
'product_min_qty': 1,
'product_max_qty': 20,
})
op2 = self.env['stock.warehouse.orderpoint'].create({
'name': 'Product B',
'location_id': self.warehouse.lot_stock_id.id,
'product_id': product_3.id,
'product_min_qty': 5,
'product_max_qty': 50,
})
self.env['mrp.bom'].create({
'product_id': product_1.id,
'product_tmpl_id': product_1.product_tmpl_id.id,
'product_uom_id': self.uom_unit.id,
'product_qty': 1,
'consumption': 'flexible',
'type': 'normal',
'bom_line_ids': [(0, 0, {'product_id': product_2.id, 'product_qty': 1})]
})
self.env['mrp.bom'].create({
'product_id': product_2.id,
'product_tmpl_id': product_2.product_tmpl_id.id,
'product_uom_id': self.uom_unit.id,
'product_qty': 1,
'consumption': 'flexible',
'type': 'normal',
'bom_line_ids': [(0, 0, {'product_id': product_3.id, 'product_qty': 1})]
})
self.env['mrp.bom'].create({
'product_id': product_3.id,
'product_tmpl_id': product_3.product_tmpl_id.id,
'product_uom_id': self.uom_unit.id,
'product_qty': 1,
'consumption': 'flexible',
'type': 'normal',
'bom_line_ids': [(0, 0, {'product_id': product_4.id, 'product_qty': 1})]
})
(op1 | op2)._procure_orderpoint_confirm()
mo1 = self.env['mrp.production'].search([('product_id', '=', product_1.id)])
mo3 = self.env['mrp.production'].search([('product_id', '=', product_3.id)])
self.assertEqual(len(mo1), 1)
self.assertEqual(len(mo3), 1)
self.assertEqual(mo1.product_qty, 20)
self.assertEqual(mo3.product_qty, 50)