diff --git a/erpnext/patches.txt b/erpnext/patches.txt index b15ed408fb..2955740d9b 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -190,4 +190,4 @@ erpnext.patches.v5_4.fix_missing_item_images 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 455aae6cb3..0000000000 --- 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 0000000000..baffc48825 --- /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 0000000000..800d9382a9 --- /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()