Files
suite/sale_line_reconfigure/models/product.py
Jared Kipe d0e4def77a IMP sale_line_reconfigure Get _get_first_possible_combination faster by ordering by 'is_default'
This improves the performance greatly in ecommerce if you have MANY combinations and an exclusion on a high up attribute (as it will 'fail' potentially millions of combinations before coming to something that 'is_default' would have given you already).
2019-10-28 09:38:46 -07:00

100 lines
4.2 KiB
Python

from odoo import api, fields, models, _
class ProductTemplate(models.Model):
_inherit = 'product.template'
def get_default_attribute_values(self, so_line):
product = None
if so_line:
product = so_line.product_id
attribute_values = self.env['product.attribute.value'].browse()
for attribute_line in self.attribute_line_ids:
attribute = attribute_line.attribute_id
attribute_line_values = attribute_line.product_template_value_ids
# Product Values
if product:
product_values = product.attribute_value_ids.filtered(lambda v: v.attribute_id == attribute)
if product_values:
attribute_values += product_values
continue
so_line_values = so_line.product_no_variant_attribute_value_ids.filtered(
lambda v: v.attribute_id == attribute)
if so_line_values:
attribute_values += so_line_values.mapped('product_attribute_value_id')
continue
default_value = self.env['product.template.attribute.value'].search([
('product_tmpl_id', '=', self.id),
('attribute_id', '=', attribute.id),
('is_default', '=', True),
], limit=1)
if default_value:
attribute_values += default_value.mapped('product_attribute_value_id')
continue
# First value
attribute_values += attribute_line_values[0].product_attribute_value_id
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'
is_default = fields.Boolean(string='Use as Default', copy=False)