From b4e11b7dc547a318e809a16ac75a47087b18a17f Mon Sep 17 00:00:00 2001 From: "Nathan Marotte (nama)" Date: Fri, 17 Sep 2021 08:07:14 +0000 Subject: [PATCH] [FIX] sale_stock_margin: Traceback after reset to quotation avco kit SO Issue: With margin enabled and avco for stock valuation, after confirming a SO with a product variant which is a bom kit, when we try to change the variant, there is a traceback Steps to reproduce : 1) Install Stock, Accounting, MRP, Sale, 2) Enable Margins in settings 3) Configure a Product Category with costing method AVCO 4) Configure a Product with 2 variants and that product category 5) [Important: KIT] Create 2 BoM, one for each variant and set those BoM to KIT 6) Create a SO for that product and one variant 7) Confirm the SO, cancel it, and set to quotation 8) Edit the SO and change the variant, save -> Traceback Side-Note: This issue is due to the fact that we iterate over the stock_moves to find the quantity of the BoM, but that stock_move correspond to confirming at step 7, when we change the variant at step 8, the stock move has not changed, so still contains the previous bom_line_id with the quantity, but this doesn't reflect with the new state of the SO which is for a different variant. For me since the stock move is canceled, it should be taken into consideration when computing the average price but I might be wrong, it's up to the reviewer to decide if it makes sense opw-2639093 closes odoo/odoo#77606 X-original-commit: c0d4ed5ac641d339a6cd4e23db9667048d35360d Signed-off-by: William Henrotin --- addons/mrp_account/models/product.py | 2 + .../sale_mrp/tests/test_sale_mrp_kit_bom.py | 65 +++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/addons/mrp_account/models/product.py b/addons/mrp_account/models/product.py index 118ee6a436e..6d1f1fb1000 100644 --- a/addons/mrp_account/models/product.py +++ b/addons/mrp_account/models/product.py @@ -57,6 +57,8 @@ class ProductProduct(models.Model): bom_lines = {line: data for line, data in bom_lines} value = 0 for move in stock_moves: + if move.state == 'cancel': + continue bom_line = move.bom_line_id if bom_line: bom_line_data = bom_lines[bom_line] diff --git a/addons/sale_mrp/tests/test_sale_mrp_kit_bom.py b/addons/sale_mrp/tests/test_sale_mrp_kit_bom.py index c58eaadd9b1..f321f5a5abb 100644 --- a/addons/sale_mrp/tests/test_sale_mrp_kit_bom.py +++ b/addons/sale_mrp/tests/test_sale_mrp_kit_bom.py @@ -166,3 +166,68 @@ class TestSaleMrpKitBom(TransactionCase): cogs_aml = amls.filtered(lambda aml: aml.account_id == self.expense_account) self.assertAlmostEqual(cogs_aml.debit, 2.53) self.assertEqual(cogs_aml.credit, 0) + + def test_reset_avco_kit(self): + """ + Test a specific use case : One product with 2 variant, each variant has its own BoM with either component_1 or + component_2. Create a SO for one of the variant, confirm, cancel, reset to draft and then change the product of + the SO -> There should be no traceback + """ + component_1 = self.env['product.product'].create({'name': 'compo 1'}) + component_2 = self.env['product.product'].create({'name': 'compo 2'}) + + product_category = self.env['product.category'].create({ + 'name': 'test avco kit', + 'property_cost_method': 'average' + }) + attributes = self.env['product.attribute'].create({'name': 'Legs'}) + steel_legs = self.env['product.attribute.value'].create({'attribute_id': attributes.id, 'name': 'Steel'}) + aluminium_legs = self.env['product.attribute.value'].create( + {'attribute_id': attributes.id, 'name': 'Aluminium'}) + + product = self.env['product.product'].create({ + 'name': 'test product', + 'categ_id': product_category.id, + 'attribute_line_ids': [(0, 0, { + 'attribute_id': attributes.id, + 'value_ids': [(6, 0, [steel_legs.id, aluminium_legs.id])] + })] + }) + product_variant_ids = product.product_variant_ids.search([('id', '!=', product.id)]) + product_variant_ids[0].categ_id.property_cost_method = 'average' + product_variant_ids[1].categ_id.property_cost_method = 'average' + # BoM 1 with component_1 + self.env['mrp.bom'].create({ + 'product_id': product_variant_ids[0].id, + 'product_tmpl_id': product_variant_ids[0].product_tmpl_id.id, + 'product_qty': 1.0, + 'consumption': 'flexible', + 'type': 'phantom', + 'bom_line_ids': [(0, 0, {'product_id': component_1.id, 'product_qty': 1})] + }) + # BoM 2 with component_2 + self.env['mrp.bom'].create({ + 'product_id': product_variant_ids[1].id, + 'product_tmpl_id': product_variant_ids[1].product_tmpl_id.id, + 'product_qty': 1.0, + 'consumption': 'flexible', + 'type': 'phantom', + 'bom_line_ids': [(0, 0, {'product_id': component_2.id, 'product_qty': 1})] + }) + partner = self.env['res.partner'].create({'name': 'Testing Man'}) + so = self.env['sale.order'].create({ + 'partner_id': partner.id, + }) + # Create the order line + self.env['sale.order.line'].create({ + 'name': "Order line", + 'product_id': product_variant_ids[0].id, + 'order_id': so.id, + }) + so.action_confirm() + so.action_cancel() + so.action_draft() + with Form(so) as so_form: + with so_form.order_line.edit(0) as order_line_change: + # The actual test, there should be no traceback here + order_line_change.product_id = product_variant_ids[1]