[FIX] stock: partial reserve in MTO

- Create a product with -4.0 Units in stock
- Set the Buy and MTO routes, assign a vendor
- Create a SO for 25 Units
- A PO of 25 Units is created => validate and receive products
- Check availability on the picking linked to the SO

Nothing is reserved, while 21 Units could be reserved.

opw-1850688

Co-authored-by: Nicolas Martinelli <nim@odoo.com>
This commit is contained in:
Simon Lejeune
2018-06-14 10:36:57 +02:00
committed by Nicolas Martinelli
co-authored by Nicolas Martinelli
parent caadeeee62
commit d42856f29d
2 changed files with 63 additions and 7 deletions
+11 -6
View File
@@ -865,11 +865,6 @@ class StockMove(models.Model):
package_id=package_id, owner_id=owner_id, strict=strict
)
except UserError:
# If it raises here, it means that the `available_quantity` brought by a done move line
# is not available on the quants itself. This could be the result of an inventory
# adjustment that removed totally of partially `available_quantity`. When this happens, we
# chose to do nothing. This situation could not happen on MTS move, because in this case
# `available_quantity` is directly the quantity on the quants themselves.
taken_quantity = 0
# Find a candidate move line to update or create a new one.
@@ -985,7 +980,17 @@ class StockMove(models.Model):
available_move_lines[(move_line.location_id, move_line.lot_id, move_line.result_package_id, move_line.owner_id)] -= move_line.product_qty
for (location_id, lot_id, package_id, owner_id), quantity in available_move_lines.items():
need = move.product_qty - sum(move.move_line_ids.mapped('product_qty'))
taken_quantity = move._update_reserved_quantity(need, quantity, location_id, lot_id, package_id, owner_id)
# `quantity` is what is brought by chained done move lines. We double check
# here this quantity is available on the quants themselves. If not, this
# could be the result of an inventory adjustment that removed totally of
# partially `quantity`. When this happens, we chose to reserve the maximum
# still available. This situation could not happen on MTS move, because in
# this case `quantity` is directly the quantity on the quants themselves.
available_quantity = self.env['stock.quant']._get_available_quantity(
move.product_id, location_id, lot_id=lot_id, package_id=package_id, owner_id=owner_id, strict=True)
if float_is_zero(available_quantity, precision_rounding=move.product_id.uom_id.rounding):
continue
taken_quantity = move._update_reserved_quantity(need, min(quantity, available_quantity), location_id, lot_id, package_id, owner_id)
if float_is_zero(taken_quantity, precision_rounding=move.product_id.uom_id.rounding):
continue
if need - taken_quantity == 0.0:
+52 -1
View File
@@ -1751,7 +1751,7 @@ class StockMove(TransactionCase):
ml.qty_done = 1
res_dict_for_back_order = picking_pack_cust.button_validate()
backorder_wizard = self.env[(res_dict_for_back_order.get('res_model'))].browse(res_dict_for_back_order.get('res_id'))
backorder_wizard.with_context(debug=True).process()
backorder_wizard.process()
backorder = self.env['stock.picking'].search([('backorder_id', '=', picking_pack_cust.id)])
backordered_move = backorder.move_lines
@@ -1782,6 +1782,57 @@ class StockMove(TransactionCase):
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product2, self.customer_location), 3)
self.assertEqual(self.env['stock.quant']._get_available_quantity(self.product2, self.pack_location), 0)
def test_link_assign_10(self):
""" Test the assignment mechanism with partial availability.
"""
# make some stock:
# stock location: 2.0
# pack location: -1.0
self.env['stock.quant']._update_available_quantity(self.product1, self.stock_location, 2.0)
self.assertEqual(len(self.env['stock.quant']._gather(self.product1, self.stock_location)), 1.0)
move_out = self.env['stock.move'].create({
'name': 'test_link_assign_out',
'location_id': self.pack_location.id,
'location_dest_id': self.customer_location.id,
'product_id': self.product1.id,
'product_uom': self.uom_unit.id,
'product_uom_qty': 1.0,
})
move_out._action_confirm()
move_out._action_assign()
move_out.quantity_done = 1.0
move_out._action_done()
self.assertEqual(len(self.env['stock.quant']._gather(self.product1, self.pack_location)), 1.0)
move_stock_pack = self.env['stock.move'].create({
'name': 'test_link_assign_1_1',
'location_id': self.stock_location.id,
'location_dest_id': self.pack_location.id,
'product_id': self.product1.id,
'product_uom': self.uom_unit.id,
'product_uom_qty': 2.0,
})
move_pack_cust = self.env['stock.move'].create({
'name': 'test_link_assign_1_2',
'location_id': self.pack_location.id,
'location_dest_id': self.customer_location.id,
'product_id': self.product1.id,
'product_uom': self.uom_unit.id,
'product_uom_qty': 2.0,
})
move_stock_pack.write({'move_dest_ids': [(4, move_pack_cust.id, 0)]})
move_pack_cust.write({'move_orig_ids': [(4, move_stock_pack.id, 0)]})
(move_stock_pack + move_pack_cust)._action_confirm()
move_stock_pack._action_assign()
move_stock_pack.quantity_done = 2.0
move_stock_pack._action_done()
self.assertEqual(len(move_pack_cust.move_line_ids), 1)
self.assertAlmostEqual(move_pack_cust.reserved_availability, 1.0)
self.assertEqual(move_pack_cust.state, 'partially_available')
def test_use_unreserved_move_line_1(self):
""" Test that validating a stock move linked to an untracked product reserved by another one
correctly unreserves the other one.