diff --git a/addons/mrp_subcontracting/models/stock_picking.py b/addons/mrp_subcontracting/models/stock_picking.py index f49a4b19ad1..c1f0803b43c 100644 --- a/addons/mrp_subcontracting/models/stock_picking.py +++ b/addons/mrp_subcontracting/models/stock_picking.py @@ -38,9 +38,14 @@ class StockPicking(models.Model): for move in self.move_ids.filtered(lambda move: move.is_subcontract): # Auto set qty_producing/lot_producing_id of MO wasn't recorded # manually (if the flexible + record_component or has tracked component) - if any(production._has_been_recorded() for production in move._get_subcontract_production()): + productions = move._get_subcontract_production() + recorded_productions = productions.filtered(lambda p: p._has_been_recorded()) + recorded_qty = sum(recorded_productions.mapped('qty_producing')) + sm_done_qty = sum(productions._get_subcontract_move().mapped('quantity_done')) + rounding = self.env['decimal.precision'].precision_get('Product Unit of Measure') + if float_compare(recorded_qty, sm_done_qty, precision_digits=rounding) >= 0: continue - production = move._get_subcontract_production() + production = productions - recorded_productions if not production: continue if len(production) > 1: diff --git a/addons/mrp_subcontracting/tests/test_subcontracting.py b/addons/mrp_subcontracting/tests/test_subcontracting.py index 27cf0e53a8c..36494fc4b0d 100644 --- a/addons/mrp_subcontracting/tests/test_subcontracting.py +++ b/addons/mrp_subcontracting/tests/test_subcontracting.py @@ -590,6 +590,55 @@ class TestSubcontractingFlows(TestMrpSubcontractingCommon): self.assertEqual(subcontracting_values['bom_cost'], 10) self.assertEqual(report_values['lines']['total'], 20) # 10 For subcontracting + 5 for comp1 + 5 for subcontracting of comp2_bom + def test_several_backorders(self): + def process_picking(picking, qty): + picking.move_ids.quantity_done = qty + action = picking.button_validate() + if isinstance(action, dict): + wizard = Form(self.env[action['res_model']].with_context(action['context'])).save() + wizard.process() + + resupply_route = self.env['stock.route'].search([('name', '=', 'Resupply Subcontractor on Order')]) + finished, component = self.env['product.product'].create([{ + 'name': 'Finished Product', + 'type': 'product', + }, { + 'name': 'Component', + 'type': 'product', + 'route_ids': [(4, resupply_route.id)], + }]) + + bom = self.env['mrp.bom'].create({ + 'product_tmpl_id': finished.product_tmpl_id.id, + 'product_qty': 1.0, + 'type': 'subcontract', + 'subcontractor_ids': [(4, self.subcontractor_partner1.id)], + 'bom_line_ids': [(0, 0, {'product_id': component.id, 'product_qty': 1.0})], + }) + + picking_form = Form(self.env['stock.picking']) + picking_form.picking_type_id = self.env.ref('stock.picking_type_in') + picking_form.partner_id = self.subcontractor_partner1 + with picking_form.move_ids_without_package.new() as move: + move.product_id = finished + move.product_uom_qty = 5 + picking = picking_form.save() + picking.action_confirm() + + supply_picking = self.env['mrp.production'].search([('bom_id', '=', bom.id)]).picking_ids + process_picking(supply_picking, 5) + + process_picking(picking, 1.25) + + backorder01 = picking.backorder_ids + process_picking(backorder01, 1) + + backorder02 = backorder01.backorder_ids + process_picking(backorder02, 0) + self.assertEqual(backorder02.move_ids.quantity_done, 2.75) + + self.assertEqual(self.env['mrp.production'].search_count([('bom_id', '=', bom.id)]), 3) + class TestSubcontractingTracking(TransactionCase): diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py index 745b8276dcc..a439872d01b 100644 --- a/addons/stock/models/stock_move.py +++ b/addons/stock/models/stock_move.py @@ -1416,7 +1416,7 @@ class StockMove(models.Model): move_lines_out_reserved = (reserved_moves_out_siblings | moves_out_siblings_to_consider).mapped('move_line_ids') def _keys_out_groupby(ml): - return (ml.location_id.id, ml.lot_id.id, ml.package_id.id, ml.owner_id.id) + return (ml.location_id, ml.lot_id, ml.package_id, ml.owner_id) grouped_move_lines_out = {} for k, g in groupby(move_lines_out_done, key=_keys_out_groupby): @@ -1428,7 +1428,8 @@ class StockMove(models.Model): grouped_move_lines_out[k] = sum(self.env['stock.move.line'].concat(*g).mapped('reserved_qty')) available_move_lines = {key: grouped_move_lines_in[key] - grouped_move_lines_out.get(key, 0) for key in grouped_move_lines_in} # pop key if the quantity available amount to 0 - return dict((k, v) for k, v in available_move_lines.items() if v) + rounding = move.product_id.uom_id.rounding + return dict((k, v) for k, v in available_move_lines.items() if float_compare(v, 0, precision_rounding=rounding) > 0) StockMove = self.env['stock.move'] assigned_moves_ids = OrderedSet()