diff --git a/erpnext/controllers/item_variant.py b/erpnext/controllers/item_variant.py index 0ba090956ca..74b7dfb5c24 100644 --- a/erpnext/controllers/item_variant.py +++ b/erpnext/controllers/item_variant.py @@ -209,7 +209,9 @@ def create_variant(item, args, use_template_image=False): variant_attributes = [] for d in template.attributes: - variant_attributes.append({"attribute": d.attribute, "attribute_value": args.get(d.attribute)}) + attribute_value = args.get(_(d.attribute)) or args.get(d.attribute) + if attribute_value: + variant_attributes.append({"attribute": d.attribute, "attribute_value": attribute_value}) variant.set("attributes", variant_attributes) copy_attributes_to_variant(template, variant) @@ -228,6 +230,12 @@ def enqueue_multiple_variant_creation(item, args, use_template_image=False): # There can be innumerable attribute combinations, enqueue if isinstance(args, str): variants = json.loads(args) + else: + variants = args + variants = {key: values for key, values in variants.items() if values} + if not variants: + frappe.throw(_("Please select at least one attribute value")) + total_variants = 1 for key in variants: total_variants *= len(variants[key]) @@ -251,6 +259,7 @@ def create_multiple_variants(item, args, use_template_image=False): count = 0 if isinstance(args, str): args = json.loads(args) + args = {key: values for key, values in args.items() if values} template_item = frappe.get_doc("Item", item) args_set = generate_keyed_value_combinations(args) @@ -285,6 +294,9 @@ def generate_keyed_value_combinations(args): """ # Return empty list if empty + if not args: + return [] + args = {key: values for key, values in args.items() if values} if not args: return [] diff --git a/erpnext/controllers/tests/test_item_variant.py b/erpnext/controllers/tests/test_item_variant.py index 68c8d2cd2c3..eacefbb2806 100644 --- a/erpnext/controllers/tests/test_item_variant.py +++ b/erpnext/controllers/tests/test_item_variant.py @@ -3,7 +3,11 @@ import unittest import frappe -from erpnext.controllers.item_variant import copy_attributes_to_variant, make_variant_item_code +from erpnext.controllers.item_variant import ( + copy_attributes_to_variant, + generate_keyed_value_combinations, + make_variant_item_code, +) from erpnext.stock.doctype.item.test_item import set_item_variant_settings from erpnext.stock.doctype.quality_inspection.test_quality_inspection import ( create_quality_inspection_parameter, @@ -17,6 +21,19 @@ class TestItemVariant(unittest.TestCase): variant = make_item_variant() self.assertEqual(variant.get("quality_inspection_template"), "_Test QC Template") + def test_generate_keyed_value_combinations_ignores_empty_attributes(self): + combinations = generate_keyed_value_combinations( + {"Test Colour": ["Red", "Blue"], "Test Size": ["Small", "Large"], "Test Fit": []} + ) + + self.assertEqual(len(combinations), 4) + self.assertNotIn("Test Fit", combinations[0]) + + single_attribute_combinations = generate_keyed_value_combinations( + {"Test Colour": ["Red", "Blue"], "Test Size": []} + ) + self.assertEqual(single_attribute_combinations, [{"Test Colour": "Red"}, {"Test Colour": "Blue"}]) + def create_variant_with_tables(item, args): if isinstance(args, str): diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js index 5bf0d54ee26..19585b9dabc 100644 --- a/erpnext/stock/doctype/item/item.js +++ b/erpnext/stock/doctype/item/item.js @@ -581,11 +581,10 @@ $.extend(erpnext.item, { default: 0, onchange: function () { let selected_attributes = get_selected_attributes(); - let lengths = []; - Object.keys(selected_attributes).map((key) => { - lengths.push(selected_attributes[key].length); + let lengths = Object.keys(selected_attributes).map((key) => { + return selected_attributes[key].length; }); - if (lengths.includes(0)) { + if (!lengths.length) { me.multiple_variant_dialog.get_primary_btn().html(__("Create Variants")); me.multiple_variant_dialog.disable_primary_action(); } else { @@ -622,7 +621,7 @@ $.extend(erpnext.item, { fieldtype: "HTML", fieldname: "help", options: ``, }, ] @@ -680,6 +679,9 @@ $.extend(erpnext.item, { selected_attributes[attribute_name].push($(opt).attr("data-fieldname")); } }); + if (!selected_attributes[attribute_name].length) { + delete selected_attributes[attribute_name]; + } }); return selected_attributes; diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index b011dcf8fcd..05e8a2f3779 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -855,8 +855,13 @@ class Item(Document): if disabled: frappe.throw(_("Attribute {0} is disabled.").format(frappe.bold(d.attribute))) - if not numeric_values and not frappe.db.exists( - "Item Attribute Value", {"parent": d.attribute, "attribute_value": d.attribute_value} + if ( + not numeric_values + and d.attribute_value + and not frappe.db.exists( + "Item Attribute Value", + {"parent": d.attribute, "attribute_value": d.attribute_value}, + ) ): frappe.throw( _("Attribute Value {0} is not valid for the selected attribute {1}.").format(