diff --git a/addons/mrp_subcontracting/models/stock_move.py b/addons/mrp_subcontracting/models/stock_move.py index b1157baea26..87f2b3ef3d6 100644 --- a/addons/mrp_subcontracting/models/stock_move.py +++ b/addons/mrp_subcontracting/models/stock_move.py @@ -276,19 +276,9 @@ class StockMove(models.Model): def _prepare_move_split_vals(self, qty): vals = super(StockMove, self)._prepare_move_split_vals(qty) - if self.is_subcontract: - vals['move_orig_ids'] = [] if not self.move_orig_ids else [(4, self.move_orig_ids[-1].id)] vals['location_id'] = self.location_id.id return vals - def _split(self, qty, restrict_partner_id=False): - self.ensure_one() - new_move_vals = super()._split(qty=qty, restrict_partner_id=restrict_partner_id) - # Update the origin moves to remove the split one - if self.move_orig_ids and self.is_subcontract: - self.move_orig_ids = (self.move_orig_ids - self.move_orig_ids[-1]).ids - return new_move_vals - def _should_bypass_reservation(self, forced_location=False): """ If the move is subcontracted then ignore the reservation. """ should_bypass_reservation = super()._should_bypass_reservation(forced_location=forced_location) diff --git a/addons/mrp_subcontracting/tests/test_subcontracting.py b/addons/mrp_subcontracting/tests/test_subcontracting.py index 1048d902197..458e7eaf54a 100644 --- a/addons/mrp_subcontracting/tests/test_subcontracting.py +++ b/addons/mrp_subcontracting/tests/test_subcontracting.py @@ -709,6 +709,66 @@ class TestSubcontractingFlows(TestMrpSubcontractingCommon): self.assertEqual(self.env['mrp.production'].search_count([('bom_id', '=', bom.id)]), 3) + def test_several_backorders_2(self): + # This test ensure that the backorders finished moves are correctly made (Production -> Subcontracting -> Stock) + # When the receipt is done, the Subcontracting location should have 0 quantity of the finished product. + # In more detail, this test checks that everything is done correctly + # when the quantity of the backorder is set on the stock.move.line instead of the stock.move, + # it can for example happens if the finished product is tracked by Serial Number. + + def process_picking_with_backorder(picking, qty): + # Process the picking by putting the given quantity on the stock.move.line + picking.move_line_ids.ensure_one().qty_done = qty + action = picking.button_validate() + if isinstance(action, dict): + wizard = Form(self.env[action['res_model']].with_context(action['context'])).save() + wizard.process() + return picking.backorder_ids + + def check_quants(product, stock_qty, sub_qty, prod_qty): + # Check the quantities of the Stock, Subcontracting and Production locations for the given product + subcontracting_location = self.env.company.subcontracting_location_id + production_location = product.property_stock_production + stock_location = self.env.ref('stock.stock_location_stock') + + self.assertEqual(sub_qty, self.env['stock.quant']._gather(product, subcontracting_location).quantity) + self.assertEqual(stock_qty, self.env['stock.quant']._gather(product, stock_location).quantity) + self.assertEqual(prod_qty, self.env['stock.quant']._gather(product, production_location).quantity) + + in_pck_type = self.env.ref('stock.picking_type_in') + in_pck_type.write({'show_operations': True, 'show_reserved': True}) + + finished = self.env['product.product'].create({'name': 'Finished Product', 'type': 'product'}) + component = self.env['product.product'].create([{'name': 'Component', 'type': 'product'}]) + 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 = in_pck_type + 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 = 6 + picking = picking_form.save() + picking.action_confirm() + + backorder01 = process_picking_with_backorder(picking, 1) + check_quants(product=finished, stock_qty=1, sub_qty=0, prod_qty=-1) + check_quants(product=component, stock_qty=0, sub_qty=-1, prod_qty=1) + + backorder02 = process_picking_with_backorder(backorder01, 2) + check_quants(product=finished, stock_qty=3, sub_qty=0, prod_qty=-3) + check_quants(product=component, stock_qty=0, sub_qty=-3, prod_qty=3) + + process_picking_with_backorder(backorder02, 3) + check_quants(product=finished, stock_qty=6, sub_qty=0, prod_qty=-6) + check_quants(product=component, stock_qty=0, sub_qty=-6, prod_qty=6) + def test_subcontracting_rules_replication(self): """ Test activate/archive subcontracting location rules.""" reference_location_rules = self.env['stock.rule'].search(['|', ('location_src_id', '=', self.env.company.subcontracting_location_id.id), ('location_dest_id', '=', self.env.company.subcontracting_location_id.id)])