manage variants new doctype created
diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js
index 5da3d35..9db24f1 100644
--- a/erpnext/stock/doctype/item/item.js
+++ b/erpnext/stock/doctype/item/item.js
@@ -5,40 +5,6 @@
 
 frappe.ui.form.on("Item", {
 	onload: function(frm) {
-		var df = frappe.meta.get_docfield("Item Variant", "item_attribute_value");
-		df.on_make = function(field) {
-			$(field.input_area).addClass("ui-front");
-			field.$input.autocomplete({
-				minLength: 0,
-				minChars: 0,
-				source: function(request, response) {
-					frappe.call({
-						method:"frappe.client.get_list",
-						args:{
-							doctype:"Item Attribute Value",
-							filters: [
-								["parent","=", field.doc.item_attribute],
-								["attribute_value", "like", request.term + "%"]
-							],
-							fields: ["attribute_value"]
-						},
-						callback: function(r) {
-							response($.map(r.message, function(d) { return d.attribute_value; }));
-						}
-					});
-				},
-				select: function(event, ui) {
-					field.$input.val(ui.item.value);
-					field.$input.trigger("change");
-				},
-				focus: function( event, ui ) {
-					if(ui.item.action) {
-						return false;
-					}
-				},
-			});
-		}
-
 		erpnext.item.setup_queries(frm);
 	},
 
@@ -64,6 +30,10 @@
 			frm.add_custom_button(__("Show Variants"), function() {
 				frappe.set_route("List", "Item", {"variant_of": frm.doc.name});
 			}, "icon-list", "btn-default");
+			frm.add_custom_button(__("Manage Variants"), function() {
+				frappe.route_options = {"item": frm.doc.name };
+				new_doc("Manage Variants");
+			});
 		}
 		if (frm.doc.variant_of) {
 			frm.set_intro(__("This Item is a Variant of {0} (Template). Attributes will be copied over from the template unless 'No Copy' is set", [frm.doc.variant_of]), true);
@@ -114,6 +84,7 @@
 			method: "copy_specification_from_item_group"
 		});
 	},
+	
 	is_stock_item: function(frm) {
 		erpnext.item.toggle_reqd(frm);
 	}
diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json
index 8b10319..6ff8ac3 100644
--- a/erpnext/stock/doctype/item/item.json
+++ b/erpnext/stock/doctype/item/item.json
@@ -186,16 +186,6 @@
    "read_only": 0
   }, 
   {
-   "depends_on": "has_variants", 
-   "description": "A new variant (Item) will be created for each attribute value combination", 
-   "fieldname": "variants", 
-   "fieldtype": "Table", 
-   "label": "Variants", 
-   "options": "Item Variant", 
-   "permlevel": 0, 
-   "precision": ""
-  }, 
-  {
    "fieldname": "inventory", 
    "fieldtype": "Section Break", 
    "label": "Inventory", 
@@ -877,7 +867,7 @@
   }
  ], 
  "icon": "icon-tag", 
- "idx": 1, 
+ "idx": 1,
  "max_attachments": 1, 
  "modified": "2015-06-26 17:20:18.204558", 
  "modified_by": "Administrator", 
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index aa463ee..77bcb4d 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -12,8 +12,6 @@
 import copy
 
 class WarehouseNotSet(frappe.ValidationError): pass
-class DuplicateVariant(frappe.ValidationError): pass
-class ItemTemplateCannotHaveStock(frappe.ValidationError): pass
 
 class Item(WebsiteGenerator):
 	website = frappe._dict(
@@ -63,7 +61,6 @@
 		self.cant_change()
 		self.validate_reorder_level()
 		self.validate_warehouse_for_reorder()
-		self.validate_variants()
 		self.update_item_desc()
 		self.synced_with_hub = 0
 
@@ -77,7 +74,6 @@
 		invalidate_cache_for_item(self)
 		self.validate_name_with_item_group()
 		self.update_item_price()
-		self.sync_variants()
 
 	def get_context(self, context):
 		context["parent_groups"] = get_parent_item_groups(self.item_group) + \
@@ -133,43 +129,6 @@
 			if not matched:
 				frappe.throw(_("Default Unit of Measure can not be changed directly because you have already made some transaction(s) with another UOM. To change default UOM, use 'UOM Replace Utility' tool under Stock module."))
 
-	def validate_variants(self):
-		self.validate_variants_are_unique()
-		self.validate_stock_for_template_must_be_zero()
-
-	def validate_stock_for_template_must_be_zero(self):
-		if self.has_variants:
-			stock_in = frappe.db.sql_list("""select warehouse from tabBin
-				where item_code=%s and ifnull(actual_qty, 0) > 0""", self.name)
-			if stock_in:
-				frappe.throw(_("Item Template cannot have stock and varaiants. Please remove stock from warehouses {0}").format(", ".join(stock_in)),
-					ItemTemplateCannotHaveStock)
-
-	def validate_variants_are_unique(self):
-		if not self.has_variants:
-			self.variants = []
-			return
-
-		if self.variants:
-			if self.variant_of:
-				frappe.throw(_("Item cannot be a variant of a variant"))
-	
-			variants, attributes = [], {}
-			for d in self.variants:
-				key = (d.item_attribute, d.item_attribute_value)
-				if key in variants:
-					frappe.throw(_("{0} {1} is entered more than once in Item Variants table")
-						.format(d.item_attribute, d.item_attribute_value), DuplicateVariant)
-				variants.append(key)
-
-				attributes.setdefault(d.item_attribute, [t.attribute_value for t in frappe.db.get_all("Item Attribute Value",
-					fields=["attribute_value"],	filters={"parent": d.item_attribute })])
-				
-				if d.item_attribute_value not in attributes.get(d.item_attribute):
-					frappe.throw(_("Attribute value {0} does not exist in Item Attribute Master.").format(d.item_attribute_value))
-		else:
-			frappe.throw(_("Please enter atleast one attribute row in Item Variants table"))
-
 	def sync_variants(self):
 		variant_item_codes = self.get_variant_item_codes()
 
@@ -460,9 +419,11 @@
 	def update_item_desc(self):
 		if frappe.db.get_value('BOM',self.name, 'description') != self.description:
 			frappe.db.sql("""update `tabBOM` set description = %s where item = %s and docstatus < 2""",(self.description, self.name))
-			frappe.db.sql("""update `tabBOM Item` set description = %s where item_code = %s and docstatus < 2""",(self.description, self.name))
-			frappe.db.sql("""update `tabBOM Explosion Item` set description = %s where item_code = %s and docstatus < 2""",(self.description, self.name))
-
+			frappe.db.sql("""update `tabBOM Item` set description = %s where 
+				item_code = %s and docstatus < 2""",(self.description, self.name))
+			frappe.db.sql("""update `tabBOM Explosion Item` set description = %s where 
+				item_code = %s and docstatus < 2""",(self.description, self.name))
+	
 def validate_end_of_life(item_code, end_of_life=None, verbose=1):
 	if not end_of_life:
 		end_of_life = frappe.db.get_value("Item", item_code, "end_of_life")
@@ -567,3 +528,4 @@
 
 	if doc.get("old_item_group") and doc.get("old_item_group") != doc.item_group:
 		invalidate_cache_for(doc, doc.old_item_group)
+
diff --git a/erpnext/stock/doctype/manage_variants/__init__.py b/erpnext/stock/doctype/manage_variants/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/stock/doctype/manage_variants/__init__.py
diff --git a/erpnext/stock/doctype/manage_variants/manage_variants.js b/erpnext/stock/doctype/manage_variants/manage_variants.js
new file mode 100644
index 0000000..f579897
--- /dev/null
+++ b/erpnext/stock/doctype/manage_variants/manage_variants.js
@@ -0,0 +1,44 @@
+// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+// License: GNU General Public License v3. See license.txt
+
+frappe.ui.form.on("Manage Variants", {
+	onload: function(frm) {
+		var df = frappe.meta.get_docfield("Variant Attribute", "attribute_value");
+		df.on_make = function(field) {
+			field.$input.autocomplete({
+				minLength: 0,
+				minChars: 0,
+				source: function(request, response) {
+					frappe.call({
+						method:"frappe.client.get_list",
+						args:{
+							doctype:"Variant Attribute",
+							filters: [
+								["parent","=", field.doc.attribute],
+								["attribute_value", "like", request.term + "%"]
+							],
+							fields: ["attribute_value"]
+						},
+						callback: function(r) {
+							response($.map(r.message, function(d) { return d.attribute_value; }));
+						}
+					});
+				},
+				select: function(event, ui) {
+					field.$input.val(ui.item.value);
+					field.$input.trigger("change");
+				},
+				focus: function( event, ui ) {
+					if(ui.manage_variants.action) {
+						return false;
+					}
+				},
+			});
+		}
+	},
+
+	refresh: function(frm) {
+		frm.disable_save();
+	}
+	
+});
diff --git a/erpnext/stock/doctype/manage_variants/manage_variants.json b/erpnext/stock/doctype/manage_variants/manage_variants.json
new file mode 100644
index 0000000..b00266a
--- /dev/null
+++ b/erpnext/stock/doctype/manage_variants/manage_variants.json
@@ -0,0 +1,101 @@
+{
+ "allow_copy": 0, 
+ "allow_import": 0, 
+ "allow_rename": 0, 
+ "creation": "2015-05-19 05:39:59.345901", 
+ "custom": 0, 
+ "docstatus": 0, 
+ "doctype": "DocType", 
+ "document_type": "", 
+ "fields": [
+  {
+   "fieldname": "item", 
+   "fieldtype": "Link", 
+   "label": "Item", 
+   "options": "Item", 
+   "permlevel": 0, 
+   "precision": ""
+  }, 
+  {
+   "allow_on_submit": 0, 
+   "fieldname": "attributes", 
+   "fieldtype": "Table", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "in_filter": 0, 
+   "in_list_view": 0, 
+   "label": "Attributes", 
+   "no_copy": 0, 
+   "options": "Variant Attribute", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "read_only": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0
+  }, 
+  {
+   "fieldname": "generate_combinations", 
+   "fieldtype": "Button", 
+   "label": "Generate Combinations", 
+   "options": "generate_combinations", 
+   "permlevel": 0, 
+   "precision": ""
+  }, 
+  {
+   "fieldname": "section_break_4", 
+   "fieldtype": "Section Break", 
+   "permlevel": 0, 
+   "precision": ""
+  }, 
+  {
+   "fieldname": "variants", 
+   "fieldtype": "Table", 
+   "label": "Variants", 
+   "options": "Variant Item", 
+   "permlevel": 0, 
+   "precision": ""
+  }, 
+  {
+   "fieldname": "create_variants", 
+   "fieldtype": "Button", 
+   "label": "Create Variants", 
+   "permlevel": 0, 
+   "precision": ""
+  }
+ ], 
+ "hide_heading": 0, 
+ "hide_toolbar": 0, 
+ "in_create": 1, 
+ "in_dialog": 0, 
+ "is_submittable": 0, 
+ "issingle": 1, 
+ "istable": 0, 
+ "modified": "2015-05-20 18:00:48.331950", 
+ "modified_by": "Administrator", 
+ "module": "Stock", 
+ "name": "Manage Variants", 
+ "name_case": "", 
+ "owner": "Administrator", 
+ "permissions": [
+  {
+   "create": 1, 
+   "delete": 1, 
+   "email": 1, 
+   "export": 0, 
+   "permlevel": 0, 
+   "print": 1, 
+   "read": 1, 
+   "report": 0, 
+   "role": "Material Master Manager", 
+   "share": 1, 
+   "write": 1
+  }
+ ], 
+ "read_only": 1, 
+ "read_only_onload": 0, 
+ "sort_field": "modified", 
+ "sort_order": "DESC"
+}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/manage_variants/manage_variants.py b/erpnext/stock/doctype/manage_variants/manage_variants.py
new file mode 100644
index 0000000..4169cae
--- /dev/null
+++ b/erpnext/stock/doctype/manage_variants/manage_variants.py
@@ -0,0 +1,77 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+from frappe.model.document import Document
+import copy
+
+class DuplicateAttribute(frappe.ValidationError): pass
+class ItemTemplateCannotHaveStock(frappe.ValidationError): pass
+
+class ManageVariants(Document):
+	
+	def generate_combinations(self):
+		self.validate_attributes()
+		self.validate_template_item()
+		self.validate_stock_for_template_must_be_zero()
+		self.validate_attributes_are_unique()
+		self.get_variant_item_codes()
+	
+	def validate_attributes(self):
+		if not self.attributes:
+			frappe.throw("Enter atleast one Attribute & its Value in Attribute table.")
+	
+	def validate_template_item(self):
+		template_item = frappe.get_doc("Item", self.item)
+		if not template_item.has_variants:
+			frappe.throw(_("Selected Item cannot have Variants."))
+			
+		if template_item.variant_of:
+			frappe.throw(_("Item cannot be a variant of a variant"))
+		
+	def validate_stock_for_template_must_be_zero(self):
+		stock_in = frappe.db.sql_list("""select warehouse from tabBin
+			where item_code=%s and ifnull(actual_qty, 0) > 0""", self.item)
+		if stock_in:
+			frappe.throw(_("Item Template cannot have stock and varaiants. Please remove \
+				stock from warehouses {0}").format(", ".join(stock_in)), ItemTemplateCannotHaveStock)
+
+	def validate_attributes_are_unique(self):
+			attributes = []
+			for d in self.attributes:
+				key = (d.attribute, d.attribute_value)
+				if key in attributes:
+					frappe.throw(_("{0} {1} is entered more than once in Attributes table")
+						.format(d.attribute, d.attribute_value), DuplicateAttribute)
+				attributes.append(key)
+				
+	def get_variant_item_codes(self):
+		"""Get all possible suffixes for variants"""
+		variant_dict = {}
+		variant_item_codes = []
+
+		for d in self.attributes:
+			variant_dict.setdefault(d.attribute, []).append(d.attribute_value)
+
+		all_attributes = [d.name for d in frappe.get_all("Item Attribute", order_by = "priority asc")]
+
+		# sort attributes by their priority
+		attributes = filter(None, map(lambda d: d if d in variant_dict else None, all_attributes))
+
+		def add_attribute_suffixes(item_code, my_attributes, attributes):
+			attr = frappe.get_doc("Item Attribute", attributes[0])
+			for value in attr.item_attribute_values:
+				if value.attribute_value in variant_dict[attr.name]:
+					_my_attributes = copy.deepcopy(my_attributes)
+					_my_attributes.append([attr.name, value.attribute_value])
+					if len(attributes) > 1:
+						add_attribute_suffixes(item_code + "-" + value.abbr, _my_attributes, attributes[1:])
+					else:
+						variant_item_codes.append(item_code + "-" + value.abbr)
+
+		add_attribute_suffixes(self.item, [], attributes)
+
+		print variant_item_codes
\ No newline at end of file
diff --git a/erpnext/stock/doctype/variant_attribute/__init__.py b/erpnext/stock/doctype/variant_attribute/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/stock/doctype/variant_attribute/__init__.py
diff --git a/erpnext/stock/doctype/variant_attribute/variant_attribute.json b/erpnext/stock/doctype/variant_attribute/variant_attribute.json
new file mode 100644
index 0000000..5ab3d73
--- /dev/null
+++ b/erpnext/stock/doctype/variant_attribute/variant_attribute.json
@@ -0,0 +1,78 @@
+{
+ "allow_copy": 0, 
+ "allow_import": 1, 
+ "allow_rename": 0, 
+ "autoname": "", 
+ "creation": "2015-05-19 05:12:30.344797", 
+ "custom": 0, 
+ "docstatus": 0, 
+ "doctype": "DocType", 
+ "document_type": "Other", 
+ "fields": [
+  {
+   "allow_on_submit": 0, 
+   "fieldname": "attribute", 
+   "fieldtype": "Link", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "in_filter": 0, 
+   "in_list_view": 1, 
+   "label": "Attribute", 
+   "no_copy": 0, 
+   "options": "Item Attribute", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "read_only": 0, 
+   "report_hide": 0, 
+   "reqd": 1, 
+   "search_index": 0, 
+   "set_only_once": 0
+  }, 
+  {
+   "fieldname": "column_break_2", 
+   "fieldtype": "Column Break", 
+   "permlevel": 0, 
+   "precision": ""
+  }, 
+  {
+   "allow_on_submit": 0, 
+   "fieldname": "attribute_value", 
+   "fieldtype": "Data", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "in_filter": 0, 
+   "in_list_view": 1, 
+   "label": "Attribute Value", 
+   "no_copy": 0, 
+   "options": "", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "read_only": 0, 
+   "report_hide": 0, 
+   "reqd": 1, 
+   "search_index": 0, 
+   "set_only_once": 0
+  }
+ ], 
+ "hide_heading": 0, 
+ "hide_toolbar": 0, 
+ "icon": "", 
+ "in_create": 0, 
+ "in_dialog": 0, 
+ "is_submittable": 0, 
+ "issingle": 0, 
+ "istable": 1, 
+ "modified": "2015-05-20 06:16:16.803578", 
+ "modified_by": "Administrator", 
+ "module": "Stock", 
+ "name": "Variant Attribute", 
+ "name_case": "", 
+ "owner": "Administrator", 
+ "permissions": [], 
+ "read_only": 0, 
+ "read_only_onload": 0, 
+ "sort_field": "modified", 
+ "sort_order": "DESC"
+}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/variant_attribute/variant_attribute.py b/erpnext/stock/doctype/variant_attribute/variant_attribute.py
new file mode 100644
index 0000000..9c35732
--- /dev/null
+++ b/erpnext/stock/doctype/variant_attribute/variant_attribute.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+
+class VariantAttribute(Document):
+	pass
diff --git a/erpnext/stock/doctype/variant_item/__init__.py b/erpnext/stock/doctype/variant_item/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/stock/doctype/variant_item/__init__.py
diff --git a/erpnext/stock/doctype/variant_item/variant_item.json b/erpnext/stock/doctype/variant_item/variant_item.json
new file mode 100644
index 0000000..8e1c862
--- /dev/null
+++ b/erpnext/stock/doctype/variant_item/variant_item.json
@@ -0,0 +1,90 @@
+{
+ "allow_copy": 0, 
+ "allow_import": 1, 
+ "allow_rename": 0, 
+ "autoname": "", 
+ "creation": "2015-05-19 05:55:31.155672", 
+ "custom": 0, 
+ "docstatus": 0, 
+ "doctype": "DocType", 
+ "document_type": "Other", 
+ "fields": [
+  {
+   "allow_on_submit": 0, 
+   "fieldname": "varient", 
+   "fieldtype": "Data", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "in_filter": 0, 
+   "in_list_view": 1, 
+   "label": "Variant", 
+   "no_copy": 0, 
+   "options": "", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "read_only": 1, 
+   "report_hide": 0, 
+   "reqd": 1, 
+   "search_index": 0, 
+   "set_only_once": 0
+  }, 
+  {
+   "allow_on_submit": 0, 
+   "fieldname": "column_break_2", 
+   "fieldtype": "Column Break", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "in_filter": 0, 
+   "in_list_view": 0, 
+   "no_copy": 0, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "read_only": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0
+  }, 
+  {
+   "allow_on_submit": 0, 
+   "fieldname": "item_code", 
+   "fieldtype": "Data", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "in_filter": 0, 
+   "in_list_view": 1, 
+   "label": "Item Code", 
+   "no_copy": 0, 
+   "options": "", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "read_only": 0, 
+   "report_hide": 0, 
+   "reqd": 1, 
+   "search_index": 0, 
+   "set_only_once": 0
+  }
+ ], 
+ "hide_heading": 0, 
+ "hide_toolbar": 0, 
+ "icon": "", 
+ "in_create": 0, 
+ "in_dialog": 0, 
+ "is_submittable": 0, 
+ "issingle": 0, 
+ "istable": 1, 
+ "modified": "2015-05-20 18:20:10.555404", 
+ "modified_by": "Administrator", 
+ "module": "Stock", 
+ "name": "Variant Item", 
+ "name_case": "", 
+ "owner": "Administrator", 
+ "permissions": [], 
+ "read_only": 0, 
+ "read_only_onload": 0, 
+ "sort_field": "modified", 
+ "sort_order": "DESC"
+}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/variant_item/variant_item.py b/erpnext/stock/doctype/variant_item/variant_item.py
new file mode 100644
index 0000000..4aa4ed8
--- /dev/null
+++ b/erpnext/stock/doctype/variant_item/variant_item.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe.model.document import Document
+
+class VariantItem(Document):
+	pass