diff --git a/sale_line_reconfigure/controllers/product_configurator.py b/sale_line_reconfigure/controllers/product_configurator.py index cfb97f33..fa725357 100644 --- a/sale_line_reconfigure/controllers/product_configurator.py +++ b/sale_line_reconfigure/controllers/product_configurator.py @@ -27,6 +27,7 @@ class ProductConfiguratorController(product_configurator.ProductConfiguratorCont 'sale_line': sale_line, # get_attribute_exclusions deprecated, use product method 'get_attribute_exclusions': self._get_attribute_exclusions, + # get_attribute_value_defaults deprecated due to ecommerce templates 'get_attribute_value_defaults': self._get_attribute_value_defaults, }) diff --git a/sale_line_reconfigure/models/product.py b/sale_line_reconfigure/models/product.py index 9b1a5c88..39768ab4 100644 --- a/sale_line_reconfigure/models/product.py +++ b/sale_line_reconfigure/models/product.py @@ -1,4 +1,4 @@ -from odoo import fields, models +from odoo import api, fields, models, _ class ProductTemplate(models.Model): @@ -40,6 +40,58 @@ class ProductTemplate(models.Model): return attribute_values + """ + This override will move 'default' attribute values to the top of the possible combinations to allow + reasonable amount of time to get '_get_first_possible_combination' on a VERY large product configuration. + """ + @api.multi + def _get_possible_combinations(self, parent_combination=None, necessary_values=None): + """Generator returning combinations that are possible, following the + sequence of attributes and values. + + See `_is_combination_possible` for what is a possible combination. + + When encountering an impossible combination, try to change the value + of attributes by starting with the further regarding their sequences. + + Ignore attributes that have no values. + + :param parent_combination: combination from which `self` is an + optional or accessory product. + :type parent_combination: recordset `product.template.attribute.value` + + :param necessary_values: values that must be in the returned combination + :type necessary_values: recordset of `product.template.attribute.value` + + :return: the possible combinations + :rtype: generator of recordset of `product.template.attribute.value` + """ + self.ensure_one() + + if not self.active: + return _("The product template is archived so no combination is possible.") + + necessary_values = necessary_values or self.env['product.template.attribute.value'] + necessary_attributes = necessary_values.mapped('attribute_id') + ptal_stack = [self.valid_product_template_attribute_line_ids.filtered(lambda ptal: ptal.attribute_id not in necessary_attributes)] + combination_stack = [necessary_values] + + # keep going while we have attribute lines to test + while len(ptal_stack): + attribute_lines = ptal_stack.pop() + combination = combination_stack.pop() + + if not attribute_lines: + # full combination, if it's possible return it, otherwise skip it + if self._is_combination_possible(combination, parent_combination): + yield(combination) + else: + # we have remaining attribute lines to consider + for ptav in reversed(attribute_lines[0].product_template_value_ids.sorted(lambda l: not l.is_default)): + ptal_stack.append(attribute_lines[1:]) + combination_stack.append(combination + ptav) + + return _("There are no remaining possible combination.") class ProductTemplateAttributeValue(models.Model): _inherit = 'product.template.attribute.value' diff --git a/sale_line_reconfigure/views/sale_product_configurator_templates.xml b/sale_line_reconfigure/views/sale_product_configurator_templates.xml index 184610aa..951f1be4 100644 --- a/sale_line_reconfigure/views/sale_product_configurator_templates.xml +++ b/sale_line_reconfigure/views/sale_product_configurator_templates.xml @@ -8,7 +8,7 @@