From 95705f18aad8359a5ae791b4d08b162334d7de00 Mon Sep 17 00:00:00 2001 From: Mihir Kandoi Date: Mon, 11 May 2026 17:30:57 +0530 Subject: [PATCH] fix: validate variant values (#54831) --- .../doctype/sales_order/test_sales_order.py | 2 +- erpnext/stock/doctype/item/item.py | 38 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 1998dbc4f8e..3dcea77fb5a 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -1619,7 +1619,7 @@ class TestSalesOrder(ERPNextTestSuite): make_item( # template item "Test-WO-Tshirt", { - "has_variant": 1, + "has_variants": 1, "variant_based_on": "Item Attribute", "attributes": [{"attribute": "Test Colour"}], }, diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index e06b6714d5a..21cdad65980 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -223,6 +223,7 @@ class Item(Document): self.validate_warehouse_for_reorder() self.update_bom_item_desc() + self.validate_variant() self.validate_has_variants() self.validate_attributes_in_variants() self.validate_stock_exists_for_template_item() @@ -860,6 +861,43 @@ class Item(Document): enqueue_after_commit=True, ) + def validate_variant(self): + if self.variant_of: + has_variants, based_on = frappe.get_value( + "Item", self.variant_of, ["has_variants", "variant_based_on"] + ) + if not has_variants: + frappe.throw(_("Item {0} is not a template item.").format(frappe.bold(self.variant_of))) + + if based_on == "Item Attribute": + for d in self.attributes: + if not frappe.db.exists( + "Item Variant Attribute", {"attribute": d.attribute, "parent": self.variant_of} + ): + frappe.throw( + _("Attribute {0} is not valid for the selected template.").format( + frappe.bold(d.attribute) + ) + ) + + numeric_values, disabled = frappe.get_value( + "Item Variant Attribute", + {"attribute": d.attribute, "parent": self.variant_of}, + ["numeric_values", "disabled"], + ) + + 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} + ): + frappe.throw( + _("Attribute Value {0} is not valid for the selected attribute {1}.").format( + frappe.bold(d.attribute_value), frappe.bold(d.attribute) + ) + ) + def validate_has_variants(self): if self.is_new(): return