diff --git a/addons/mrp_subcontracting/models/stock_move.py b/addons/mrp_subcontracting/models/stock_move.py index 8d9e7395f4f..5492302a221 100644 --- a/addons/mrp_subcontracting/models/stock_move.py +++ b/addons/mrp_subcontracting/models/stock_move.py @@ -77,7 +77,7 @@ class StockMove(models.Model): move._auto_record_components(delta_qty) to_set_moves -= move elif float_compare(delta_qty, 0, precision_rounding=move.product_uom.rounding) < 0: - move._reduce_subcontract_order_qty(abs(delta_qty)) + move.with_context(transfer_qty=True)._reduce_subcontract_order_qty(abs(delta_qty)) if to_set_moves: super(StockMove, to_set_moves)._set_quantity() @@ -295,8 +295,17 @@ class StockMove(models.Model): def _reduce_subcontract_order_qty(self, quantity_to_remove): self.ensure_one() productions = self.move_orig_ids.production_id.filtered(lambda p: p.state not in ('done', 'cancel'))[::-1] + wip_production = productions[0] if self._context.get('transfer_qty') and len(productions) > 1 else self.env['mrp.production'] + + # Transfer removed qty to WIP production + if wip_production: + self.env['change.production.qty'].with_context(skip_activity=True).create({ + 'mo_id': wip_production.id, + 'product_qty': wip_production.product_uom_qty + quantity_to_remove + }).change_prod_qty() + # Cancel productions until reach new_quantity - for production in productions: + for production in (productions - wip_production): if quantity_to_remove >= production.product_qty: quantity_to_remove -= production.product_qty production.with_context(skip_activity=True).action_cancel() diff --git a/addons/mrp_subcontracting/tests/test_subcontracting.py b/addons/mrp_subcontracting/tests/test_subcontracting.py index 2f36331cac5..42e2efd1d64 100644 --- a/addons/mrp_subcontracting/tests/test_subcontracting.py +++ b/addons/mrp_subcontracting/tests/test_subcontracting.py @@ -837,6 +837,75 @@ class TestSubcontractingFlows(TestMrpSubcontractingCommon): {'product_qty': 3, 'state': 'cancel'}, ]) + def test_decrease_quantity_done(self): + self.bom.consumption = 'flexible' + supplier_location = self.env.ref('stock.stock_location_suppliers') + + receipt = self.env['stock.picking'].create({ + 'partner_id': self.subcontractor_partner1.id, + 'location_id': supplier_location.id, + 'location_dest_id': self.warehouse.lot_stock_id.id, + 'picking_type_id': self.warehouse.in_type_id.id, + 'move_ids': [(0, 0, { + 'name': self.finished.name, + 'product_id': self.finished.id, + 'product_uom_qty': 10.0, + 'product_uom': self.finished.uom_id.id, + 'location_id': supplier_location.id, + 'location_dest_id': self.warehouse.lot_stock_id.id, + })], + }) + + receipt.action_confirm() + productions = self.env['mrp.production'].search([('product_id', '=', self.finished.id)], order='id') + self.assertRecordValues(productions, [ + {'qty_producing': 0.0, 'product_qty': 10.0, 'state': 'confirmed'}, + ]) + + receipt.move_ids.quantity = 6 + productions = self.env['mrp.production'].search([('product_id', '=', self.finished.id)], order='id') + self.assertEqual(receipt.move_ids.product_uom_qty, 10.0, 'Demand should not be impacted') + self.assertRecordValues(productions, [ + {'qty_producing': 6.0, 'product_qty': 6.0, 'state': 'to_close'}, + {'qty_producing': 4.0, 'product_qty': 4.0, 'state': 'to_close'}, + ]) + + receipt.move_ids.quantity = 9 + productions = self.env['mrp.production'].search([('product_id', '=', self.finished.id)], order='id') + self.assertEqual(receipt.move_ids.product_uom_qty, 10.0, 'Demand should not be impacted') + self.assertRecordValues(productions, [ + {'qty_producing': 6.0, 'product_qty': 6.0, 'state': 'to_close'}, + {'qty_producing': 3.0, 'product_qty': 3.0, 'state': 'to_close'}, + {'qty_producing': 1.0, 'product_qty': 1.0, 'state': 'to_close'}, + ]) + + receipt.move_ids.quantity = 7 + productions = self.env['mrp.production'].search([('product_id', '=', self.finished.id)], order='id') + self.assertEqual(receipt.move_ids.product_uom_qty, 10.0, 'Demand should not be impacted') + self.assertRecordValues(productions, [ + {'qty_producing': 6.0, 'product_qty': 6.0, 'state': 'to_close'}, + {'qty_producing': 1.0, 'product_qty': 1.0, 'state': 'to_close'}, + {'qty_producing': 3.0, 'product_qty': 3.0, 'state': 'to_close'}, + ]) + + receipt.move_ids.quantity = 4 + productions = self.env['mrp.production'].search([('product_id', '=', self.finished.id)], order='id') + self.assertEqual(receipt.move_ids.product_uom_qty, 10.0, 'Demand should not be impacted') + self.assertRecordValues(productions, [ + {'qty_producing': 4.0, 'product_qty': 4.0, 'state': 'to_close'}, + {'qty_producing': 1.0, 'product_qty': 1.0, 'state': 'cancel'}, + {'qty_producing': 6.0, 'product_qty': 6.0, 'state': 'to_close'}, + ]) + + receipt.move_ids.quantity = 0 + productions = self.env['mrp.production'].search([('product_id', '=', self.finished.id)], order='id') + self.assertEqual(receipt.move_ids.product_uom_qty, 10.0, 'Demand should not be impacted') + self.assertRecordValues(productions, [ + {'qty_producing': 4.0, 'product_qty': 4.0, 'state': 'cancel'}, + {'qty_producing': 1.0, 'product_qty': 1.0, 'state': 'cancel'}, + {'qty_producing': 10.0, 'product_qty': 10.0, 'state': 'to_close'}, + ]) + @tagged('post_install', '-at_install') class TestSubcontractingTracking(TransactionCase):