[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) <whe@odoo.com>
Signed-off-by: Adrien Widart <awt@odoo.com>
This commit is contained in:
Adrien Widart
2022-04-29 18:22:06 +02:00
parent 769230a80d
commit 5a2edc50ea
2 changed files with 23 additions and 0 deletions
+1
View File
@@ -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
+22
View File
@@ -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')