diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index 6a8abea1543..d74f849facd 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 639d6a292ec..a2826be91f9 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -202,6 +202,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() @@ -811,6 +812,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