[FIX] mrp: generate move_line with same lot

Usecase to reproduce:
- Set a product with the same lot in different locations
- Create a MO that will uses theses products and that require more than one location
- Produce it.
-> Traceback Expected singleton: stock.move.line

It happens because product produce only expect one move line
by lot. Howeever it could exist more than one move line if the
product for a specific lot are shared among multiple under location.

This commit try to fill the move line with the correct quantity
one by one and add the extra in a new move line.
This commit is contained in:
Arnold Moyaux
2017-12-18 11:46:21 +01:00
parent 08bf52f5db
commit 1f860fea38
2 changed files with 80 additions and 11 deletions
+13 -6
View File
@@ -190,12 +190,18 @@ class StockMove(models.Model):
def _generate_consumed_move_line(self, qty_to_add, final_lot, lot=False):
if lot:
ml = self.move_line_ids.filtered(lambda ml: ml.lot_id == lot and not ml.lot_produced_id)
move_lines = self.move_line_ids.filtered(lambda ml: ml.lot_id == lot and not ml.lot_produced_id)
else:
ml = self.move_line_ids.filtered(lambda ml: not ml.lot_id and not ml.lot_produced_id)
if ml:
new_quantity_done = (ml.qty_done + qty_to_add)
if new_quantity_done >= ml.product_uom_qty:
move_lines = self.move_line_ids.filtered(lambda ml: not ml.lot_id and not ml.lot_produced_id)
for ml in move_lines:
rounding = ml.product_uom_id.rounding
if float_compare(qty_to_add, 0, precision_rounding=rounding) <= 0:
break
quantity_to_process = min(qty_to_add, ml.product_uom_qty - ml.qty_done)
qty_to_add -= quantity_to_process
new_quantity_done = (ml.qty_done + quantity_to_process)
if float_compare(new_quantity_done, ml.product_uom_qty, precision_rounding=rounding) >= 0:
ml.write({'qty_done': new_quantity_done, 'lot_produced_id': final_lot.id})
else:
new_qty_reserved = ml.product_uom_qty - new_quantity_done
@@ -204,7 +210,8 @@ class StockMove(models.Model):
'lot_produced_id': final_lot.id}
ml.copy(default=default)
ml.with_context(bypass_reservation_update=True).write({'product_uom_qty': new_qty_reserved, 'qty_done': 0})
else:
if float_compare(qty_to_add, 0, precision_rounding=self.product_uom.rounding) > 0:
vals = {
'move_id': self.id,
'product_id': self.product_id.id,
+67 -5
View File
@@ -276,7 +276,7 @@ class TestMrpOrder(TestMrpCommon):
'final_lot_id': finished_lot.id,
'qty_producing': 48
})
kit_wo.record_production()
self.assertEqual(kit_wo.state, 'done', "Workorder should be in done state.")
@@ -431,9 +431,9 @@ class TestMrpOrder(TestMrpCommon):
""" In previous versions we had rounding and efficiency fields. We check if we can still do the same, but with only the rounding on the UoM"""
self.product_6.uom_id.rounding = 1.0
bom_eff = self.env['mrp.bom'].create({'product_id': self.product_6.id,
'product_tmpl_id': self.product_6.product_tmpl_id.id,
'product_qty': 1,
'product_uom_id': self.product_6.uom_id.id,
'product_tmpl_id': self.product_6.product_tmpl_id.id,
'product_qty': 1,
'product_uom_id': self.product_6.uom_id.id,
'type': 'normal',
'bom_line_ids': [
(0, 0, {'product_id': self.product_2.id, 'product_qty': 2.03}),
@@ -447,7 +447,7 @@ class TestMrpOrder(TestMrpCommon):
#Check the production order has the right quantities
self.assertEqual(production.move_raw_ids[0].product_qty, 41, 'The quantity should be rounded up')
self.assertEqual(production.move_raw_ids[1].product_qty, 84, 'The quantity should be rounded up')
# produce product
produce_wizard = self.env['mrp.product.produce'].with_context({
'active_id': production.id,
@@ -516,3 +516,65 @@ class TestMrpOrder(TestMrpCommon):
}).create({})
self.assertEqual(len(product_produce.produce_line_ids), 1, 'You should have 1 produce lines since one has already be consumed.')
self.assertEqual(product_produce.produce_line_ids[0].lot_id, remaining_lot, 'Wrong lot proposed.')
def test_product_produce_3(self):
""" Check that line are created when the consumed products are
tracked by serial and the lot proposed are correct. """
self.stock_location = self.env.ref('stock.stock_location_stock')
self.stock_shelf_1 = self.env.ref('stock.stock_location_components')
self.stock_shelf_2 = self.env.ref('stock.stock_location_14')
mo, _, p_final, p1, p2 = self.generate_mo(tracking_base_1='lot', qty_base_1=10, qty_final=1)
self.assertEqual(len(mo), 1, 'MO should have been created')
first_lot_for_p1 = self.env['stock.production.lot'].create({
'name': 'lot1',
'product_id': p1.id,
})
second_lot_for_p1 = self.env['stock.production.lot'].create({
'name': 'lot2',
'product_id': p1.id,
})
final_product_lot = self.env['stock.production.lot'].create({
'name': 'lot1',
'product_id': p_final.id,
})
self.env['stock.quant']._update_available_quantity(p1, self.stock_shelf_1, 3, lot_id=first_lot_for_p1)
self.env['stock.quant']._update_available_quantity(p1, self.stock_shelf_2, 3, lot_id=first_lot_for_p1)
self.env['stock.quant']._update_available_quantity(p1, self.stock_location, 8, lot_id=second_lot_for_p1)
self.env['stock.quant']._update_available_quantity(p2, self.stock_location, 5)
mo.action_assign()
product_produce = self.env['mrp.product.produce'].with_context({
'active_id': mo.id,
'active_ids': [mo.id],
}).create({
'product_qty': 1.0,
'lot_id': final_product_lot.id,
})
# product 1 lot 1 shelf1
# product 1 lot 1 shelf2
# product 1 lot 2
self.assertEqual(len(product_produce.produce_line_ids), 3, 'You should have 3 produce lines. lot 1 shelf_1, lot 1 shelf_2, lot2')
for produce_line in product_produce.produce_line_ids:
produce_line.qty_done = produce_line.qty_to_consume + 1
product_produce.do_produce()
move_1 = mo.move_raw_ids.filtered(lambda m: m.product_id == p1)
# qty_done/product_uom_qty lot
# 3/3 lot 1 shelf 1
# 1/1 lot 1 shelf 2
# 2/2 lot 1 shelf 2
# 2/0 lot 1 other
# 5/4 lot 2
ml_to_shelf_1 = move_1.move_line_ids.filtered(lambda ml: ml.lot_id == first_lot_for_p1 and ml.location_id == self.stock_shelf_1)
ml_to_shelf_2 = move_1.move_line_ids.filtered(lambda ml: ml.lot_id == first_lot_for_p1 and ml.location_id == self.stock_shelf_2)
self.assertEqual(sum(ml_to_shelf_1.mapped('qty_done')), 3.0, '3 units should be took from shelf1 as reserved.')
self.assertEqual(sum(ml_to_shelf_2.mapped('qty_done')), 3.0, '3 units should be took from shelf2 as reserved.')
self.assertEqual(move_1.quantity_done, 13, 'You should have used the tem units.')
mo.button_mark_done()
self.assertEqual(mo.state, 'done', "Production order should be in done state.")