[fix] [patch] Item Template Attributes - migration from v4 and v5
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index b15ed40..2955740 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -190,4 +190,4 @@
erpnext.patches.v5_4.stock_entry_additional_costs
erpnext.patches.v5_4.cleanup_journal_entry #2015-08-14
execute:frappe.db.sql("update `tabProduction Order` pro set description = (select description from tabItem where name=pro.production_item) where ifnull(description, '') = ''")
-erpnext.patches.v5_4.item_template
+erpnext.patches.v5_7.item_template_attribtues
diff --git a/erpnext/patches/v5_4/item_template.py b/erpnext/patches/v5_4/item_template.py
deleted file mode 100644
index 455aae6..0000000
--- a/erpnext/patches/v5_4/item_template.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
-# License: GNU General Public License v3. See license.txt
-
-from __future__ import unicode_literals
-import frappe
-
-def execute():
- item_attribute = {}
- for d in frappe.db.sql("""select DISTINCT va.attribute, i.variant_of from `tabVariant Attribute` va, `tabItem` i \
- where va.parent = i.name""", as_dict=1):
- item_attribute.setdefault(d.variant_of, []).append({"attribute": d.attribute})
-
- for item, attributes in item_attribute.items():
- template = frappe.get_doc("Item", item)
- template.set('attributes', attributes)
- template.save()
-
- frappe.delete_doc("DocType", "Manage Variants")
- frappe.delete_doc("DocType", "Manage Variants Item")
\ No newline at end of file
diff --git a/erpnext/patches/v5_7/__init__.py b/erpnext/patches/v5_7/__init__.py
new file mode 100644
index 0000000..baffc48
--- /dev/null
+++ b/erpnext/patches/v5_7/__init__.py
@@ -0,0 +1 @@
+from __future__ import unicode_literals
diff --git a/erpnext/patches/v5_7/item_template_attributes.py b/erpnext/patches/v5_7/item_template_attributes.py
new file mode 100644
index 0000000..800d938
--- /dev/null
+++ b/erpnext/patches/v5_7/item_template_attributes.py
@@ -0,0 +1,112 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+import MySQLdb
+
+def execute():
+ """
+ Structure History:
+ 1. Item and Item Attribute
+ 2. Item, Variant Attribute, Manage Variants and Manage Variant Items
+ 3. Item, Variant Attribute (latest)
+ """
+ frappe.db.reload_doctype("Item")
+ frappe.db.reload_doctype("Variant Attribute")
+
+ variant_templates = frappe.get_all("Item", filters={"has_variants": 1}, limit_page_length=1)
+ if not variant_templates:
+ # database does not have items that have variants
+ # so no point in running the patch
+ return
+
+ variant_attributes = frappe.get_all("Variant Attribute", fields=["*"], limit_page_length=1)
+
+ if variant_attributes:
+ # manage variant patch is already applied
+ migrate_manage_variants()
+
+ else:
+ # old structure based on "Item Variant" table
+ try:
+ migrate_item_variants()
+
+ except MySQLdb.ProgrammingError:
+ print "`tabItem Variant` not found"
+
+def migrate_manage_variants():
+ item_attribute = {}
+ for d in frappe.db.sql("""select DISTINCT va.attribute, i.variant_of from `tabVariant Attribute` va, `tabItem` i \
+ where va.parent = i.name""", as_dict=1):
+ item_attribute.setdefault(d.variant_of, []).append({"attribute": d.attribute})
+
+ for item, attributes in item_attribute.items():
+ template = frappe.get_doc("Item", item)
+ template.set('attributes', attributes)
+ template.save()
+
+ frappe.delete_doc("DocType", "Manage Variants")
+ frappe.delete_doc("DocType", "Manage Variants Item")
+
+# patch old style
+def migrate_item_variants():
+ for item in frappe.get_all("Item", filters={"has_variants": 1}):
+ all_variants = frappe.get_all("Item", filters={"variant_of": item.name}, fields=["name", "description"])
+ item_attributes = frappe.db.sql("""select distinct item_attribute, item_attribute_value
+ from `tabItem Attribute` where parent=%s""", item.name)
+
+ attribute_value_options = {}
+ for attribute, value in item_attributes:
+ attribute_value_options.setdefault(attribute, []).append(value)
+
+ save_attributes_in_template(item, attribute_value_options)
+
+ possible_combinations = get_possible_combinations(attribute_value_options)
+
+ for variant in all_variants:
+ for combination in possible_combinations:
+ match = True
+ for attribute, value in combination.items():
+ if "{0}: {1}".format(attribute, value) not in variant.description:
+ match = False
+ break
+
+ if match:
+ # found the right variant
+ save_attributes_in_variant(variant, combination)
+ break
+
+ frappe.delete_doc("DocType", "Item Attribute")
+
+def save_attributes_in_template(item, attribute_value_options):
+ # store attribute in Variant Attribute table for template
+ template = frappe.get_doc("Item", item)
+ template.set("attributes", [{"attribute": attribute} for attribute in attribute_value_options.keys()])
+ template.save()
+
+def get_possible_combinations(attribute_value_options):
+ possible_combinations = []
+
+ for attribute, values in attribute_value_options.items():
+ if not possible_combinations:
+ for v in values:
+ possible_combinations.append({attribute: v})
+
+ else:
+ for v in values:
+ for combination in possible_combinations:
+ combination[attribute] = v
+
+ return possible_combinations
+
+def save_attributes_in_variant(variant, combination):
+ # add data into attributes table
+ variant_item = frappe.get_doc("Item", variant.name)
+ variant_item.set("attributes", [])
+ for attribute, value in combination.items():
+ variant_item.append("attributes", {
+ "attribute": attribute,
+ "attribute_value": value
+ })
+ variant_item.save()