From 42cc64b5cee743ad5a817d757a772eebbcc8927c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Theys?= Date: Tue, 21 May 2019 08:44:55 +0000 Subject: [PATCH] [FIX] product: fix possible combination with variant active + archive Before this commit, if multiple variants exist for the same combination it would consider the combination impossible if any of the variants was archived. After this commit, it will consider the combination impossible only if all the corresponding variants are archived. opw-1959317 PR: #32691 --- addons/product/models/product.py | 10 ++++++++++ addons/product/models/product_template.py | 20 ++++++++++--------- .../test_product_attribute_value_config.py | 15 ++++++++++++++ 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/addons/product/models/product.py b/addons/product/models/product.py index 9bccf02fabc..8bd8600f7a0 100644 --- a/addons/product/models/product.py +++ b/addons/product/models/product.py @@ -346,6 +346,16 @@ class ProductProduct(models.Model): product._set_standard_price(vals.get('standard_price') or 0.0) # `_get_variant_id_for_combination` depends on existing variants self.clear_caches() + self.env['product.template'].invalidate_cache( + fnames=[ + 'valid_archived_variant_ids', + 'valid_existing_variant_ids', + 'product_variant_ids', + 'product_variant_id', + 'product_variant_count' + ], + ids=products.mapped('product_tmpl_id').ids + ) return products @api.multi diff --git a/addons/product/models/product_template.py b/addons/product/models/product_template.py index a54ddbce909..5fbe41d8b9b 100644 --- a/addons/product/models/product_template.py +++ b/addons/product/models/product_template.py @@ -830,9 +830,16 @@ class ProductTemplate(models.Model): # combination has different values than the ones configured on the template return False - if not self.has_dynamic_attributes() and not self._get_variant_for_combination(combination): - # the variant has been deleted - return False + variant = self._get_variant_for_combination(combination) + + if self.has_dynamic_attributes(): + if variant and not variant.active: + # dynamic and the variant has been archived + return False + else: + if not variant or not variant.active: + # not dynamic, the variant has been archived or deleted + return False exclusions = self._get_own_attribute_exclusions() if exclusions: @@ -849,11 +856,6 @@ class ProductTemplate(models.Model): if exclusion in combination.ids: return False - filtered_combination = combination._without_no_variant_attributes() - archived_combinations = self._get_archived_combinations() - if archived_combinations and filtered_combination.ids in archived_combinations: - return False - return True @api.multi @@ -887,7 +889,7 @@ class ProductTemplate(models.Model): for pav in attribute_values: domain = expression.AND([[('attribute_value_ids', 'in', pav.id)], domain]) - res = self.env['product.product'].with_context(active_test=False).search(domain) + res = self.env['product.product'].with_context(active_test=False).search(domain, order='active DESC') # The domain above is checking for the `product.attribute.value`, but we # need to make sure it's the same `product.template.attribute.value`. diff --git a/addons/product/tests/test_product_attribute_value_config.py b/addons/product/tests/test_product_attribute_value_config.py index e966adbdbdc..497f6fbeba3 100644 --- a/addons/product/tests/test_product_attribute_value_config.py +++ b/addons/product/tests/test_product_attribute_value_config.py @@ -312,6 +312,21 @@ class TestProductAttributeValueConfig(TestProductAttributeValueSetup): variant.unlink() self.assertFalse(self.computer._is_combination_possible(computer_ssd_256 + computer_ram_8 + computer_hdd_1)) + # CASE: if multiple variants exist for the same combination and at least + # one of them is not archived, the combination is possible + values = self.ssd_256 + self.ram_8 + self.hdd_1 + self.env['product.product'].create({ + 'product_tmpl_id': self.computer.id, + 'attribute_value_ids': [(6, 0, values.ids)], + 'active': False, + }) + self.env['product.product'].create({ + 'product_tmpl_id': self.computer.id, + 'attribute_value_ids': [(6, 0, values.ids)], + 'active': True, + }) + self.assertTrue(self.computer._is_combination_possible(computer_ssd_256 + computer_ram_8 + computer_hdd_1)) + def test_get_first_possible_combination(self): computer_ssd_256 = self._get_product_template_attribute_value(self.ssd_256) computer_ssd_512 = self._get_product_template_attribute_value(self.ssd_512)