Merge pull request #17475 from netchampfaris/item-variant-attributes-optional

fix: Allow variant attributes to be optional
diff --git a/erpnext/controllers/item_variant.py b/erpnext/controllers/item_variant.py
index e0acd73..631f775 100644
--- a/erpnext/controllers/item_variant.py
+++ b/erpnext/controllers/item_variant.py
@@ -124,16 +124,8 @@
 
 	conditions = " or ".join(conditions)
 
-	# use approximate match and shortlist possible variant matches
-	# it is approximate because we are matching using OR condition
-	# and it need not be exact match at this stage
-	# this uses a simpler query instead of using multiple exists conditions
-	possible_variants = frappe.db.sql_list("""select name from `tabItem` item
-		where variant_of=%s and exists (
-			select name from `tabItem Variant Attribute` iv_attribute
-				where iv_attribute.parent=item.name
-				and ({conditions}) and parent != %s
-		)""".format(conditions=conditions), (template, cstr(variant_item_code)))
+	from erpnext.portal.product_configurator.utils import get_item_codes_by_attributes
+	possible_variants = [i for i in get_item_codes_by_attributes(args, template) if i != variant_item_code]
 
 	for variant in possible_variants:
 		variant = frappe.get_doc("Item", variant)
@@ -317,7 +309,7 @@
 			}, as_dict=True)
 
 		if not item_attribute:
-			return
+			continue
 			# frappe.throw(_('Invalid attribute {0} {1}').format(frappe.bold(attr.attribute),
 			# 	frappe.bold(attr.attribute_value)), title=_('Invalid Attribute'),
 			# 	exc=InvalidItemAttributeValueError)
diff --git a/erpnext/portal/product_configurator/utils.py b/erpnext/portal/product_configurator/utils.py
index 15d5e9f..61c50e5 100644
--- a/erpnext/portal/product_configurator/utils.py
+++ b/erpnext/portal/product_configurator/utils.py
@@ -102,6 +102,9 @@
 	for attribute, values in attribute_filters.items():
 		attribute_values = values
 
+		if not isinstance(attribute_values, list):
+			attribute_values = [attribute_values]
+
 		if not attribute_values: continue
 
 		wheres = []
diff --git a/erpnext/public/js/utils/item_quick_entry.js b/erpnext/public/js/utils/item_quick_entry.js
index 62b82ac..2947d5b 100644
--- a/erpnext/public/js/utils/item_quick_entry.js
+++ b/erpnext/public/js/utils/item_quick_entry.js
@@ -390,15 +390,6 @@
 			}
 		})
 
-		if (mandatory.length) {
-			frappe.msgprint({
-				title: __('Missing Values Required'),
-				message: __('Following fields have missing values:') + '<br><br><ul><li>' + mandatory.join('<li>') + '</ul>',
-				indicator: 'orange'
-			});
-			return {};
-		}
-
 		if (this.is_manufacturer) {
 			$.each(this.manufacturer_fields, function(index, field) {
 				attribute[field.fieldname] = me.dialog.fields_dict[field.fieldname].input.value;
diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js
index 6c30d00..42c84da 100644
--- a/erpnext/stock/doctype/item/item.js
+++ b/erpnext/stock/doctype/item/item.js
@@ -585,7 +585,7 @@
 				"label": row.attribute,
 				"fieldname": row.attribute,
 				"fieldtype": fieldtype,
-				"reqd": 1,
+				"reqd": 0,
 				"description": desc
 			})
 		}
@@ -600,6 +600,7 @@
 			if(!args) return;
 			frappe.call({
 				method:"erpnext.controllers.item_variant.get_variant",
+				btn: d.get_primary_btn(),
 				args: {
 					"template": frm.doc.name,
 					"args": d.get_values()
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index 3e501b4..5d4dbf4 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -800,10 +800,12 @@
 
 	def validate_variant_attributes(self):
 		if self.is_new() and self.variant_of and self.variant_based_on == 'Item Attribute':
+			# remove attributes with no attribute_value set
+			self.attributes = [d for d in self.attributes if cstr(d.attribute_value).strip()]
+
 			args = {}
-			for d in self.attributes:
-				if cstr(d.attribute_value).strip() == '':
-					frappe.throw(_("Please specify Attribute Value for attribute {0}").format(d.attribute))
+			for i, d in enumerate(self.attributes):
+				d.idx = i + 1
 				args[d.attribute] = d.attribute_value
 
 			variant = get_variant(self.variant_of, args, self.name)