Skip to content
This repository was archived by the owner on Apr 28, 2022. It is now read-only.

Commit 89750da

Browse files
Richard deMeesterPCatinean
authored andcommitted
[FIX] Duplicate variant check Fix.
1) If variant stored has more attributes (e.g. not all required) and a new variant was being proposed, it was matching. Need to reject variants with more attributes as not being a match! 2) Likewise, custom value ids MUST be taken in to account. If a variant had Attr1: Value 1, Attr2: Value X, and a new variant was being checked with Attr1: Value 1, Attr2: Custom, then it was matching and not creating a new variant!
1 parent 4def722 commit 89750da

File tree

1 file changed

+66
-36
lines changed

1 file changed

+66
-36
lines changed

product_configurator/models/product.py

Lines changed: 66 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -219,31 +219,43 @@ def search_variant(self, value_ids, custom_values=None):
219219
220220
:returns: product.product recordset of products matching domain
221221
"""
222+
self.ensure_one()
223+
222224
if custom_values is None:
223225
custom_values = {}
224226
attr_obj = self.env['product.attribute']
225-
for product_tmpl in self:
226-
domain = [('product_tmpl_id', '=', product_tmpl.id)]
227227

228-
for value_id in value_ids:
229-
domain.append(('attribute_value_ids', '=', value_id))
228+
domain = [('product_tmpl_id', '=', self.id)]
230229

231-
attr_search = attr_obj.search([
232-
('search_ok', '=', True),
233-
('custom_type', 'not in', attr_obj._get_nosearch_fields())
234-
])
230+
for value_id in value_ids:
231+
domain.append(('attribute_value_ids', '=', value_id))
235232

236-
for attr_id, value in custom_values.iteritems():
237-
if attr_id not in attr_search.ids:
238-
domain.append(
239-
('value_custom_ids.attribute_id', '!=', int(attr_id)))
240-
else:
241-
domain.append(
242-
('value_custom_ids.attribute_id', '=', int(attr_id)))
243-
domain.append(('value_custom_ids.value', '=', value))
233+
attr_search = attr_obj.search([
234+
('search_ok', '=', True),
235+
('custom_type', 'not in', attr_obj._get_nosearch_fields())
236+
])
244237

245-
products = self.env['product.product'].search(domain)
246-
return products
238+
for attr_id, value in custom_values.iteritems():
239+
if attr_id not in attr_search.ids:
240+
domain.append(
241+
('value_custom_ids.attribute_id', '!=', int(attr_id)))
242+
else:
243+
domain.append(
244+
('value_custom_ids.attribute_id', '=', int(attr_id)))
245+
domain.append(('value_custom_ids.value', '=', value))
246+
247+
products = self.env['product.product'].search(domain)
248+
249+
# At this point, we might have found products with all of the passed
250+
# in values, but it might have more attributes! These are NOT
251+
# matches
252+
more_attrs = products.filtered(
253+
lambda p:
254+
len(p.attribute_value_ids) != len(value_ids) or
255+
len(p.value_custom_ids) != len(custom_values)
256+
)
257+
products -= more_attrs
258+
return products
247259

248260
def get_config_image_obj(self, value_ids, size=None):
249261
"""
@@ -349,13 +361,22 @@ def create_get_variant(self, value_ids, custom_values=None):
349361
if not valid:
350362
raise ValidationError(_('Invalid Configuration'))
351363

352-
duplicates = self.search_variant(value_ids)
364+
duplicates = self.search_variant(value_ids,
365+
custom_values=custom_values)
353366

354-
# Only return duplicates without custom values for now:
355-
if duplicates.filtered(lambda p: not p.value_custom_ids):
367+
# At the moment, I don't have enough confidence with my understanding
368+
# of binary attributes, so will leave these as not matching...
369+
# In theory, they should just work, if they are set to "non search"
370+
# in custom field def!
371+
# TODO: Check the logic with binary attributes
372+
if custom_values:
373+
value_custom_ids = self.encode_custom_values(custom_values)
374+
if any('attachment_ids' in cv[2] for cv in value_custom_ids):
375+
duplicates = False
376+
377+
if duplicates:
356378
return duplicates[0]
357379

358-
# TODO: Handle duplicates with custom values
359380
vals = self.get_variant_vals(value_ids, custom_values)
360381
variant = self.env['product.product'].create(vals)
361382

@@ -521,20 +542,29 @@ def _check_duplicate_product(self):
521542
if not self.config_ok:
522543
return None
523544

524-
# All duplicates with and without custom values
525-
duplicates = self.product_tmpl_id.search_variant(
526-
self.attribute_value_ids.ids).filtered(lambda p: p.id != self.id)
527-
528-
# Prevent duplicates without custom values (only attribute values)
529-
if duplicates.filtered(lambda p: not p.value_custom_ids):
530-
raise ValidationError(
531-
_("Configurable Products cannot have duplicates "
532-
"(identical attribute values)")
533-
)
534-
535-
# TODO: For the future prevent duplicates with identical custom values
536-
# or implement custom values on the order line level since they are
537-
# specific to each order.
545+
# At the moment, I don't have enough confidence with my understanding
546+
# of binary attributes, so will leave these as not matching...
547+
# In theory, they should just work, if they are set to "non search"
548+
# in custom field def!
549+
# TODO: Check the logic with binary attributes
550+
if self.value_custom_ids.filtered(lambda cv: cv.attachment_ids):
551+
pass
552+
else:
553+
custom_values = {
554+
cv.attribute_id.id: cv.value
555+
for cv in self.value_custom_ids
556+
}
557+
558+
duplicates = self.product_tmpl_id.search_variant(
559+
self.attribute_value_ids.ids,
560+
custom_values=custom_values
561+
).filtered(lambda p: p.id != self.id)
562+
563+
if duplicates:
564+
raise ValidationError(
565+
_("Configurable Products cannot have duplicates "
566+
"(identical attribute values)")
567+
)
538568

539569
@api.multi
540570
def _compute_product_price_extra(self):

0 commit comments

Comments
 (0)