[FIX] stock: button_validate: forced move lines

When a move line is not linked to a move, it'll be linked to the first
move of the same product at validation time. We slightly improve this
logic by linking it to the first non-completed move. To be completely
correct, we should split the move line if necessary and link it to all
needed moves, but at this time we don't  want to make the logic too
complex.

Use case: create a sale order with three sale order lines of the same
products, use the detailed operations view and add three move lines of
the same products, validate the picking. Before the patch, all move
lines were linked to the first move and thus only the first sale order
line had delivered quantities.

Fixes #25488
opw-1861765
This commit is contained in:
Simon Lejeune
2018-08-09 08:38:17 +02:00
committed by len-odoo
parent d92f17cebe
commit 252bc396b4
2 changed files with 77 additions and 3 deletions
@@ -421,3 +421,76 @@ class TestSaleStock(TestSale):
# check the delivered quantity
self.assertEqual(so1.order_line.qty_delivered, 3.0)
def test_07_forced_qties(self):
""" Make multiple sale order lines of the same product which isn't available in stock. On
the picking, create new move lines (through the detailed operations view). See that the move
lines are correctly dispatched through the moves.
"""
uom_unit = self.env.ref('product.product_uom_unit')
uom_dozen = self.env.ref('product.product_uom_dozen')
item1 = self.products['prod_order']
self.assertEqual(item1.uom_id.id, uom_unit.id)
# sell a dozen
so1 = self.env['sale.order'].create({
'partner_id': self.partner.id,
'order_line': [
(0, 0, {
'name': item1.name,
'product_id': item1.id,
'product_uom_qty': 1,
'product_uom': uom_dozen.id,
'price_unit': item1.list_price,
}),
(0, 0, {
'name': item1.name,
'product_id': item1.id,
'product_uom_qty': 1,
'product_uom': uom_dozen.id,
'price_unit': item1.list_price,
}),
(0, 0, {
'name': item1.name,
'product_id': item1.id,
'product_uom_qty': 1,
'product_uom': uom_dozen.id,
'price_unit': item1.list_price,
}),
],
})
so1.action_confirm()
self.assertEqual(len(so1.picking_ids.move_lines), 3)
so1.picking_ids.write({
'move_line_ids': [
(0, 0, {
'product_id': item1.id,
'product_uom_qty': 0,
'qty_done': 1,
'product_uom_id': uom_dozen.id,
'location_id': so1.picking_ids.location_id.id,
'location_dest_id': so1.picking_ids.location_dest_id.id,
}),
(0, 0, {
'product_id': item1.id,
'product_uom_qty': 0,
'qty_done': 1,
'product_uom_id': uom_dozen.id,
'location_id': so1.picking_ids.location_id.id,
'location_dest_id': so1.picking_ids.location_dest_id.id,
}),
(0, 0, {
'product_id': item1.id,
'product_uom_qty': 0,
'qty_done': 1,
'product_uom_id': uom_dozen.id,
'location_id': so1.picking_ids.location_id.id,
'location_dest_id': so1.picking_ids.location_dest_id.id,
}),
],
})
so1.picking_ids.button_validate()
self.assertEqual(so1.picking_ids.state, 'done')
self.assertEqual(so1.order_line.mapped('qty_delivered'), [1, 1, 1])
+4 -3
View File
@@ -631,8 +631,9 @@ class Picking(models.Model):
# # Link existing moves or add moves when no one is related
for ops in pick.move_line_ids.filtered(lambda x: not x.move_id):
# Search move with this product
moves = pick.move_lines.filtered(lambda x: x.product_id == ops.product_id)
if moves: #could search move that needs it the most (that has some quantities left)
moves = pick.move_lines.filtered(lambda x: x.product_id == ops.product_id)
moves = sorted(moves, key=lambda m: m.quantity_done < m.product_qty, reverse=True)
if moves:
ops.move_id = moves[0].id
else:
new_move = self.env['stock.move'].create({
@@ -802,7 +803,7 @@ class Picking(models.Model):
quantity_done[quant.product_id.id] += quant.qty
for pack in self.mapped('move_line_ids').filtered(lambda x: x.product_id and not x.move_id):
quantity_done.setdefault(pack.product_id.id, 0)
quantity_done[pack.product_id.id] += pack.qty_done
quantity_done[pack.product_id.id] += pack.product_uom_id._compute_quantity(pack.qty_done, pack.product_id.uom_id)
return any(quantity_done[x] < quantity_todo.get(x, 0) for x in quantity_done)
@api.multi