From 5a2edc50ea56054db7a43a20dc8e2f102b22356e Mon Sep 17 00:00:00 2001 From: Adrien Widart Date: Thu, 28 Apr 2022 09:05:45 +0000 Subject: [PATCH] [FIX] stock: receive products with detailed operations A recursion error may appear when a user receives a product. To reproduce the issue: 1. Create a tracked-by-usn product P 2. Create an immediate receipt for P 3. In the Detailed Operations wizard, add a line and Confirm Error: An Odoo Server Error is raised (`RecursionError`) [1] When confirming the wizard, a new SML is created. In the creation method, we define the `product_uom_qty` of the associated SM: https://github.com/odoo/odoo/blob/1b1b320c4b8a0c08d156e569216cbea1100fb1bb/addons/stock/models/stock_move_line.py#L294 [2] In the writing method of the SM, because we are defining `product_uom_qty`, we unreserve and assign again the SM: https://github.com/odoo/odoo/blob/1b1b320c4b8a0c08d156e569216cbea1100fb1bb/addons/stock/models/stock_move.py#L606-L607 [3] In the assigning method, because there isn't any need, it quickly lead to https://github.com/odoo/odoo/blob/1b1b320c4b8a0c08d156e569216cbea1100fb1bb/addons/stock/models/stock_move.py#L1487-L1488 i.e., the SM is considered as assigned and flagged to be redirected [4] In the redirection method (`_apply_putaway_strategy`), we define the new destination location of the SML. https://github.com/odoo/odoo/blob/1b1b320c4b8a0c08d156e569216cbea1100fb1bb/addons/stock/models/stock_move_line.py#L230 [5] Because of this, in the writing method of the SML, we define again the `product_uom_qty` of the SM: https://github.com/odoo/odoo/blob/1b1b320c4b8a0c08d156e569216cbea1100fb1bb/addons/stock/models/stock_move_line.py#L461-L462 This brings us back to step 2 => Recursion In the writing method of the SM (step 2), we can prevent the "unreserve & reserve again" step thanks to a key-context: `do_not_unreserve`. OPW-2833951 closes odoo/odoo#90171 X-original-commit: fbc5cf7813c2e9d8a02fe8a73a74bfa32a8f9b96 Signed-off-by: William Henrotin (whe) Signed-off-by: Adrien Widart --- addons/stock/models/stock_move_line.py | 1 + addons/stock/tests/test_stock_flow.py | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/addons/stock/models/stock_move_line.py b/addons/stock/models/stock_move_line.py index c523dd95e7f..dd0635a11f8 100644 --- a/addons/stock/models/stock_move_line.py +++ b/addons/stock/models/stock_move_line.py @@ -208,6 +208,7 @@ class StockMoveLine(models.Model): packaging=self.move_id.product_packaging_id) def _apply_putaway_strategy(self): + self = self.with_context(do_not_unreserve=True) for package, smls in groupby(self, lambda sml: sml.result_package_id): smls = self.env['stock.move.line'].concat(*smls) excluded_smls = smls diff --git a/addons/stock/tests/test_stock_flow.py b/addons/stock/tests/test_stock_flow.py index c9d98ee0d92..44fb39f3c5f 100644 --- a/addons/stock/tests/test_stock_flow.py +++ b/addons/stock/tests/test_stock_flow.py @@ -2220,3 +2220,25 @@ class TestStockFlow(TestStockCommon): self.assertEqual(picking.state, 'cancel') self.assertEqual(move.state, 'cancel') self.assertEqual(scrap.move_id.state, 'done') + + def test_receive_tracked_product(self): + self.productA.tracking = 'serial' + type_in = self.env['stock.picking.type'].browse(self.picking_type_in) + + receipt_form = Form(self.env['stock.picking'].with_context(default_immediate_transfer=True)) + receipt_form.picking_type_id = type_in + with receipt_form.move_ids_without_package.new() as move_line: + move_line.product_id = self.productA + receipt = receipt_form.save() + + move_form = Form(receipt.move_ids, view='stock.view_stock_move_nosuggest_operations') + with move_form.move_line_nosuggest_ids.new() as line: + line.lot_name = "USN01" + move_form.save() + + receipt.button_validate() + quant = self.productA.stock_quant_ids.filtered(lambda q: q.location_id.id == self.stock_location) + + self.assertEqual(receipt.state, 'done') + self.assertEqual(quant.quantity, 1.0) + self.assertEqual(quant.lot_id.name, 'USN01')