From d6455186386ee684368e867e3bb2dafecfb6bfcc Mon Sep 17 00:00:00 2001 From: "Adrien Widart (awt)" Date: Thu, 1 Dec 2022 13:30:38 +0000 Subject: [PATCH] [FIX] stock,{stock,mrp}_account: add SML with kit to draft picking If account is installed, it is not possible to scan a kit and validate the picking To reproduce the issue: (Need stock_barcode_mrp) 1. Create two products P_kit, P_compo: - P_kit: - Barcode: 123 2. Create a kit-type BoM 3. Barcode > Operations > Receipts, Create 4. Scan 123 5. Validate Error: an error message is displayed ("Record does not exist or has been deleted") When validating the receipt, it creates the SML_kit and its SM_kit. Both are in draft state. So, we validate SM_kit. In `/stock_account._action_done`, we add SM_kit to a dict (`valued_moves`) and we then call the `super` method: https://github.com/odoo/odoo/blob/33fa9cff038691a98ca840fe0d72484da16276ba/addons/stock_account/models/stock_move.py#L244-L257 In `/stock._action_done`, because of the state of SM, we confirm it: https://github.com/odoo/odoo/blob/24f2e3f73498e5eb180a6793de6c25efd414aadb/addons/stock/models/stock_move.py#L1517-L1518 And, therefore, we explode SM_kit: https://github.com/odoo/odoo/blob/5f8da70b5b1f313e9b676846e55e84621f55e734/addons/mrp/models/stock_move.py#L239-L240 This creates SM_compo and unlink SM_kit. However, there are two issues: - In `/stock._action_done`, we don't keep any reference to SM_compo. The method will not return it and `/stock_account._action_done` will not create any layer, if needed, for that SM_compo - In `/stock_account._action_done`, we don't consider that SM_kit may have been deleted. As a result, we keep using it: https://github.com/odoo/odoo/blob/33fa9cff038691a98ca840fe0d72484da16276ba/addons/stock_account/models/stock_move.py#L266-L271 This is the reason why an error will be raised OPW-3015933 closes odoo/odoo#108762 closes odoo/odoo#112814 X-original-commit: c78666e3fbd06bc7a7899ccaa6e562bf3072e955 Related: odoo/enterprise#37137 Signed-off-by: Arnold Moyaux (arm) Signed-off-by: William Henrotin (whe) Signed-off-by: Adrien Widart --- .../tests/test_valuation_layers.py | 32 +++++++++++++++++++ addons/stock/models/stock_move.py | 4 +-- addons/stock_account/models/stock_move.py | 3 ++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/addons/mrp_account/tests/test_valuation_layers.py b/addons/mrp_account/tests/test_valuation_layers.py index c61a7c9f966..097625e99a3 100644 --- a/addons/mrp_account/tests/test_valuation_layers.py +++ b/addons/mrp_account/tests/test_valuation_layers.py @@ -316,3 +316,35 @@ class TestMrpValuationStandard(TestMrpValuationCommon): self.assertEqual(self.product1.quantity_svl, 2) self._make_out_move(self.product1, 1) self.assertEqual(self.product1.value_svl, 15) + + def test_validate_draft_kit(self): + """ + Create a draft receipt, add a kit to its move lines and directly + validate it. From client side, such a behaviour is possible with + the Barcode app. + """ + self.component.product_tmpl_id.categ_id.property_cost_method = 'average' + self.product1.type = 'consu' + self.bom.type = 'phantom' + self.component.standard_price = 1424 + + receipt = self.env['stock.picking'].create({ + 'location_id': self.customer_location.id, + 'location_dest_id': self.stock_location.id, + 'picking_type_id': self.picking_type_in.id, + 'move_line_ids': [(0, 0, { + 'product_id': self.product1.id, + 'qty_done': 1, + 'product_uom_id': self.product1.uom_id.id, + 'location_id': self.customer_location.id, + 'location_dest_id': self.stock_location.id, + })] + }) + receipt.button_validate() + + self.assertEqual(receipt.state, 'done') + self.assertRecordValues(receipt.move_ids, [ + {'product_id': self.component.id, 'quantity_done': 1, 'state': 'done'}, + ]) + self.assertEqual(self.component.qty_available, 1) + self.assertEqual(self.component.value_svl, 1424) diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py index 4a690bfb3d0..4e2fe04f84f 100644 --- a/addons/stock/models/stock_move.py +++ b/addons/stock/models/stock_move.py @@ -1761,8 +1761,8 @@ Please change the quantity done or the rounding precision of your unit of measur return extra_move | self def _action_done(self, cancel_backorder=False): - self.filtered(lambda move: move.state == 'draft')._action_confirm() # MRP allows scrapping draft moves - moves = self.exists().filtered(lambda x: x.state not in ('done', 'cancel')) + moves = self.filtered(lambda move: move.state == 'draft')._action_confirm() # MRP allows scrapping draft moves + moves = (self | moves).exists().filtered(lambda x: x.state not in ('done', 'cancel')) moves_ids_todo = OrderedSet() # Cancel moves where necessary ; we should do it before creating the extra moves because diff --git a/addons/stock_account/models/stock_move.py b/addons/stock_account/models/stock_move.py index e6f7725cdca..63b779f17a2 100644 --- a/addons/stock_account/models/stock_move.py +++ b/addons/stock_account/models/stock_move.py @@ -252,6 +252,9 @@ class StockMove(models.Model): res = super(StockMove, self)._action_done(cancel_backorder=cancel_backorder) + # '_action_done' might have deleted some exploded stock moves + valued_moves = {value_type: moves.exists() for value_type, moves in valued_moves.items()} + # '_action_done' might have created an extra move to be valued for move in res - self: for valued_type in self._get_valued_types():