diff --git a/addons/mrp/models/mrp_production.py b/addons/mrp/models/mrp_production.py index 37a7436333b..9713ed31031 100644 --- a/addons/mrp/models/mrp_production.py +++ b/addons/mrp/models/mrp_production.py @@ -1836,19 +1836,19 @@ class MrpProduction(models.Model): product_uom = initial_move.product_id.uom_id if not initial_move.picked: for move_line in initial_move.move_line_ids: - available_qty = move_line.product_uom_id._compute_quantity(move_line.quantity, product_uom) - if float_compare(available_qty, 0, precision_rounding=move_line.product_uom_id.rounding) <= 0: + available_qty = move_line.product_uom_id._compute_quantity(move_line.quantity, product_uom, rounding_method="HALF-UP") + if float_compare(available_qty, 0, precision_rounding=product_uom.rounding) <= 0: continue ml_by_move.append((available_qty, move_line, move_line.copy_data()[0])) moves = list(initial_move | backorder_moves) move = moves and moves.pop(0) - move_qty_to_reserve = move.product_qty + move_qty_to_reserve = move.product_qty # Product UoM for index, (quantity, move_line, ml_vals) in enumerate(ml_by_move): taken_qty = min(quantity, move_qty_to_reserve) - taken_qty_uom = product_uom._compute_quantity(taken_qty, move_line.product_uom_id) + taken_qty_uom = product_uom._compute_quantity(taken_qty, move_line.product_uom_id, rounding_method="HALF-UP") if float_is_zero(taken_qty_uom, precision_rounding=move_line.product_uom_id.rounding): continue move_line.write({ @@ -1867,7 +1867,7 @@ class MrpProduction(models.Model): while float_compare(quantity, 0, precision_rounding=product_uom.rounding) > 0 and move: # Do not create `stock.move.line` if there is no initial demand on `stock.move` taken_qty = min(move_qty_to_reserve, quantity) - taken_qty_uom = product_uom._compute_quantity(taken_qty, move_line.product_uom_id) + taken_qty_uom = product_uom._compute_quantity(taken_qty, move_line.product_uom_id, rounding_method="HALF-UP") if move == initial_move: move_line.quantity += taken_qty_uom elif not float_is_zero(taken_qty_uom, precision_rounding=move_line.product_uom_id.rounding): diff --git a/addons/mrp/tests/test_backorder.py b/addons/mrp/tests/test_backorder.py index 35c2f261830..1a883ca92c1 100644 --- a/addons/mrp/tests/test_backorder.py +++ b/addons/mrp/tests/test_backorder.py @@ -322,6 +322,35 @@ class TestMrpProductionBackorder(TestMrpCommon): # 300 Grams consumed and 700 reserved self.assertAlmostEqual(self.env['stock.quant']._gather(product_component, self.stock_location).reserved_quantity, 0.7) + def test_rounding_backorder(self): + """test backorder component rounding doesn't introduce reservation issues""" + production, _, _, p1, p2 = self.generate_mo(qty_final=5, qty_base_1=1, qty_base_2=1) + + self.env['stock.quant']._update_available_quantity(p1, self.stock_location, 100) + self.env['stock.quant']._update_available_quantity(p2, self.stock_location, 100) + + production.action_assign() + + production_form = Form(production) + production_form.qty_producing = 3.1 + production = production_form.save() + + details_operation_form = Form(production.move_raw_ids.filtered(lambda m: m.product_id == p1), view=self.env.ref('stock.view_stock_move_operations')) + with details_operation_form.move_line_ids.edit(0) as ml: + ml.quantity = 3.09 + + details_operation_form.save() + + action = production.button_mark_done() + backorder_form = Form(self.env['mrp.production.backorder'].with_context(**action['context'])) + backorder_form.save().action_backorder() + backorder = production.procurement_group_id.mrp_production_ids[-1] + # 3.09 consumed and 1.9 reserved + self.assertAlmostEqual(self.env['stock.quant']._gather(p1, self.stock_location).reserved_quantity, 1.9) + self.assertAlmostEqual(backorder.move_raw_ids.filtered(lambda m: m.product_id == p1).move_line_ids.quantity, 1.9) + + # Make sure we don't have an unreserve errors + backorder.do_unreserve() def test_tracking_backorder_series_serial_1(self): """ Create a MO of 4 tracked products (serial) with pbm_sam.