[feature] ability to have variants based on manufacturer
diff --git a/erpnext/controllers/item_variant.py b/erpnext/controllers/item_variant.py
index f8c9c0a..53421b7 100644
--- a/erpnext/controllers/item_variant.py
+++ b/erpnext/controllers/item_variant.py
@@ -12,19 +12,42 @@
 class ItemTemplateCannotHaveStock(frappe.ValidationError): pass
 
 @frappe.whitelist()
-def get_variant(template, args, variant=None):
-	"""Validates Attributes and their Values, then looks for an exactly matching Item Variant
+def get_variant(template, args=None, variant=None, manufacturer=None,
+	manufacturer_part_no=None):
+	"""Validates Attributes and their Values, then looks for an exactly
+		matching Item Variant
 
 		:param item: Template Item
 		:param args: A dictionary with "Attribute" as key and "Attribute Value" as value
 	"""
-	if isinstance(args, basestring):
-		args = json.loads(args)
+	item_template = frappe.get_doc('Item', template)
 
-	if not args:
-		frappe.throw(_("Please specify at least one attribute in the Attributes table"))
+	if item_template.variant_based_on=='Manufacturer' and manufacturer:
+		return make_variant_based_on_manufacturer(item_template, manufacturer,
+			manufacturer_part_no)
+	else:
+		if isinstance(args, basestring):
+			args = json.loads(args)
 
-	return find_variant(template, args, variant)
+		if not args:
+			frappe.throw(_("Please specify at least one attribute in the Attributes table"))
+		return find_variant(template, args, variant)
+
+def make_variant_based_on_manufacturer(template, manufacturer, manufacturer_part_no):
+	'''Make and return a new variant based on manufacturer and
+		manufacturer part no'''
+	from frappe.model.naming import append_number_if_name_exists
+
+	variant = frappe.new_doc('Item')
+
+	copy_attributes_to_variant(template, variant)
+
+	variant.manufacturer = manufacturer
+	variant.manufacturer_part_no = manufacturer_part_no
+
+	variant.item_code = append_number_if_name_exists('Item', template.name)
+
+	return variant
 
 def validate_item_variant_attributes(item, args=None):
 	if isinstance(item, basestring):
@@ -131,6 +154,7 @@
 
 	template = frappe.get_doc("Item", item)
 	variant = frappe.new_doc("Item")
+	variant.variant_based_on = 'Item Attribute'
 	variant_attributes = []
 
 	for d in template.attributes:
@@ -147,17 +171,28 @@
 
 def copy_attributes_to_variant(item, variant):
 	from frappe.model import no_value_fields
+
+	# copy non no-copy fields
+
+	exclude_fields = ["item_code", "item_name", "show_in_website"]
+
+	if item.variant_based_on=='Manufacturer':
+		# don't copy manufacturer values if based on part no
+		exclude_fields += ['manufacturer', 'manufacturer_part_no']
+
 	for field in item.meta.fields:
 		if field.fieldtype not in no_value_fields and (not field.no_copy)\
-			and field.fieldname not in ("item_code", "item_name", "show_in_website"):
+			and field.fieldname not in exclude_fields:
 			if variant.get(field.fieldname) != item.get(field.fieldname):
 				variant.set(field.fieldname, item.get(field.fieldname))
 	variant.variant_of = item.name
 	variant.has_variants = 0
-	if variant.attributes:
-		variant.description += "\n"
-		for d in variant.attributes:
-			variant.description += "<p>" + d.attribute + ": " + cstr(d.attribute_value) + "</p>"
+
+	if item.variant_based_on=='Item Attribute':
+		if variant.attributes:
+			variant.description += "\n"
+			for d in variant.attributes:
+				variant.description += "<p>" + d.attribute + ": " + cstr(d.attribute_value) + "</p>"
 
 def make_variant_item_code(template_item_code, variant):
 	"""Uses template's item code and abbreviations to make variant's item code"""
diff --git a/erpnext/docs/assets/img/stock/select-mfg-for-variant.png b/erpnext/docs/assets/img/stock/select-mfg-for-variant.png
new file mode 100644
index 0000000..4da1d6c
--- /dev/null
+++ b/erpnext/docs/assets/img/stock/select-mfg-for-variant.png
Binary files differ
diff --git a/erpnext/docs/assets/img/stock/set-variant-by-mfg.png b/erpnext/docs/assets/img/stock/set-variant-by-mfg.png
new file mode 100644
index 0000000..2eaa8f0
--- /dev/null
+++ b/erpnext/docs/assets/img/stock/set-variant-by-mfg.png
Binary files differ
diff --git a/erpnext/docs/user/manual/en/stock/item/item-variants.md b/erpnext/docs/user/manual/en/stock/item/item-variants.md
index cdca6ed..7514404 100644
--- a/erpnext/docs/user/manual/en/stock/item/item-variants.md
+++ b/erpnext/docs/user/manual/en/stock/item/item-variants.md
@@ -1,15 +1,28 @@
+# Item Variants
+
+### What are Variants?
+
 A Item Variant is a version of a Item, such as differing sizes or differing colours (like a _blue_ t-shirt in size _small_ rather then just a t-shirt).
-Without Item variants, you would have to treat the _small, medium_ and _large_ versions of a t-shirt as three separate Items; 
+Without Item variants, you would have to treat the _small, medium_ and _large_ versions of a t-shirt as three separate Items;
 Item variants let you treat the _small, medium_ and _large_ versions of a t-shirt as variations of the one Item 't-shirt'.
 
+### Using Variants
+
+Variants can be based on two things
+
+1. Item Attributes
+1. Manufacturers
+
+### Variants Based on Item Attributes
+
 To use Item Variants in ERPNext, create an Item and check 'Has Variants'.
 
-* The Item shall then be referred to as a so called 'Template'. Such a Template is not identical to a regular 'Item' any longer. For example it (the Template) can not be used directly in any Transactions (Sales Order, Delivery Note, Purchase Invoice) itself. Only the Variants of an Item (_blue_ t-shirt in size _small)_ can be practically used in such. Therefore it would be ideal to decide whether an item 'Has Variants' or not directly when creating it. 
+* The Item shall then be referred to as a so called 'Template'. Such a Template is not identical to a regular 'Item' any longer. For example it (the Template) can not be used directly in any Transactions (Sales Order, Delivery Note, Purchase Invoice) itself. Only the Variants of an Item (_blue_ t-shirt in size _small)_ can be practically used in such. Therefore it would be ideal to decide whether an item 'Has Variants' or not directly when creating it.
 
 <img class="screenshot" alt="Has Variants" src="{{docs_base_url}}/assets/img/stock/item-has-variants.png">
 
 On selecting 'Has Variants' a table shall appear. Specify the variant attributes for the Item in the table.
-In case the attribute has Numeric Values, you can specify the range and increment values here. 
+In case the attribute has Numeric Values, you can specify the range and increment values here.
 
 <img class="screenshot" alt="Valid Attributes" src="{{docs_base_url}}/assets/img/stock/item-attributes.png">
 
@@ -22,3 +35,17 @@
 <img class="screenshot" alt="Make Variants" src="{{docs_base_url}}/assets/img/stock/make-variant-1.png">
 
 To learn more about setting Attributes Master check [Item Attributes]({{docs_base_url}}/user/manual/en/stock/setup/item-attribute.html)
+
+### Variants Based on Manufacturers
+
+To setup variants based on Manufactueres, in your Item template, set "Variants Based On" as "Manufacturers"
+
+<img class='screenshot' alt='Setup Item Variant by Manufacturer'
+	src='{{docs_base_url}}/assets/img/stock/select-mfg-for-variant.png'>
+
+When you make a new Variant, the system will prompt you to select a Manufacturer. You can also optionally put in a Manufacturer Part Number
+
+<img class='screenshot' alt='Setup Item Variant by Manufacturer'
+	src='{{docs_base_url}}/assets/img/stock/set-variant-by-mfg.png'>
+
+The naming of the variant will be the name (ID) of the template Item with a number suffix. e.g. "ITEM000" will have variant "ITEM000-1"
\ No newline at end of file
diff --git a/erpnext/public/css/erpnext.css b/erpnext/public/css/erpnext.css
index 697c078..a51472f 100644
--- a/erpnext/public/css/erpnext.css
+++ b/erpnext/public/css/erpnext.css
@@ -327,4 +327,3 @@
 body[data-route="pos"] .collapse-btn {
   cursor: pointer;
 }
-
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index 891f37c..f149baf 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -177,11 +177,11 @@
 							fields: [
 								{fieldtype:'Read Only', fieldname:'item_code',
 									label: __('Item Code'), in_list_view:1},
-								{fieldtype:'Link', fieldname:'bom', options: 'BOM',
+								{fieldtype:'Link', fieldname:'bom', options: 'BOM', reqd: 1,
 									label: __('Select BOM'), in_list_view:1, get_query: function(doc) {
 										return {filters: {item: doc.item_code}};
 									}},
-								{fieldtype:'Float', fieldname:'pending_qty',
+								{fieldtype:'Float', fieldname:'pending_qty', reqd: 1,
 									label: __('Qty'), in_list_view:1},
 							],
 							get_data: function() {
diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js
index 7068c99..4920721 100644
--- a/erpnext/stock/doctype/item/item.js
+++ b/erpnext/stock/doctype/item/item.js
@@ -261,6 +261,45 @@
 	make_variant: function(frm) {
 		var fields = []
 
+		if(frm.doc.variant_based_on==="Item Attribute") {
+			erpnext.item.show_modal_for_item_attribute_selection(frm);
+		} else {
+			erpnext.item.show_modal_for_manufacturers(frm);
+		}
+	},
+
+	show_modal_for_manufacturers: function(frm) {
+		var dialog = new frappe.ui.Dialog({
+			fields: [
+				{fieldtype:'Link', options:'Manufacturer',
+					reqd:1, label:'Manufacturer'},
+				{fieldtype:'Data', label:'Manufacturer Part Number',
+					fieldname: 'manufacturer_part_no'},
+			]
+		});
+
+		dialog.set_primary_action(__('Make'), function() {
+			var data = dialog.get_values();
+			if(!data) return;
+
+			// call the server to make the variant
+			data.template = frm.doc.name;
+			frappe.call({
+				method:"erpnext.controllers.item_variant.get_variant",
+				args: data,
+				callback: function(r) {
+					var doclist = frappe.model.sync(r.message);
+					console.log(doclist);
+					dialog.hide();
+					frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
+				}
+			});
+		})
+
+		dialog.show();
+	},
+
+	show_modal_for_item_attribute_selection: function(frm) {
 		for(var i=0;i< frm.doc.attributes.length;i++){
 			var fieldtype, desc;
 			var row = frm.doc.attributes[i];
@@ -371,13 +410,42 @@
 				})
 		});
 	},
-	toggle_attributes: function(frm) {
-		frm.toggle_display("attributes", frm.doc.has_variants || frm.doc.variant_of);
-		frm.fields_dict.attributes.grid.toggle_reqd("attribute_value", frm.doc.variant_of ? 1 : 0);
-		frm.fields_dict.attributes.grid.set_column_disp("attribute_value", frm.doc.variant_of ? 1 : 0);
 
-		frm.toggle_enable("attributes", !frm.doc.variant_of);
-		frm.fields_dict.attributes.grid.toggle_enable("attribute", !frm.doc.variant_of);
-		frm.fields_dict.attributes.grid.toggle_enable("attribute_value", !frm.doc.variant_of);
+	toggle_attributes: function(frm) {
+		if((frm.doc.has_variants || frm.doc.variant_of)
+			&& frm.doc.variant_based_on==='Item Attribute') {
+			frm.toggle_display("attributes", true);
+
+			var grid = frm.fields_dict.attributes.grid;
+
+			if(frm.doc.variant_of) {
+				// variant
+
+				// value column is displayed but not editable
+				grid.set_column_disp("attribute_value", true);
+				grid.toggle_enable("attribute_value", false);
+
+				grid.toggle_enable("attribute", false);
+
+				// can't change attributes since they are
+				// saved when the variant was created
+				frm.toggle_enable("attributes", false);
+			} else {
+				// template - values not required!
+
+				// make the grid editable
+				frm.toggle_enable("attributes", true);
+
+				// value column is hidden
+				grid.set_column_disp("attribute_value", false);
+
+				// enable the grid so you can add more attributes
+				grid.toggle_enable("attribute", true);
+			}
+
+		} else {
+			// nothing to do with attributes, hide it
+			frm.toggle_display("attributes", false);
+		}
 	}
 });
diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json
index 4a5094e..db327cc 100644
--- a/erpnext/stock/doctype/item/item.json
+++ b/erpnext/stock/doctype/item/item.json
@@ -1,5 +1,6 @@
 {
  "allow_copy": 0, 
+ "allow_guest_to_view": 0, 
  "allow_import": 1, 
  "allow_rename": 1, 
  "autoname": "field:item_code", 
@@ -1218,7 +1219,39 @@
    "bold": 0, 
    "collapsible": 0, 
    "columns": 0, 
-   "depends_on": "", 
+   "default": "Item Attribute", 
+   "depends_on": "has_variants", 
+   "fieldname": "variant_based_on", 
+   "fieldtype": "Select", 
+   "hidden": 0, 
+   "ignore_user_permissions": 0, 
+   "ignore_xss_filter": 0, 
+   "in_filter": 0, 
+   "in_global_search": 0, 
+   "in_list_view": 0, 
+   "in_standard_filter": 0, 
+   "label": "Variant Based On", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Item Attribute\nManufacturer", 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 0, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 0, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 0, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
+  }, 
+  {
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "depends_on": "eval:doc.has_variants && doc.variant_based_on==='Item Attribute'", 
    "fieldname": "attributes", 
    "fieldtype": "Table", 
    "hidden": 1, 
@@ -2792,6 +2825,7 @@
    "unique": 0
   }
  ], 
+ "has_web_view": 0, 
  "hide_heading": 0, 
  "hide_toolbar": 0, 
  "icon": "fa fa-tag", 
@@ -2799,12 +2833,11 @@
  "image_field": "image", 
  "image_view": 0, 
  "in_create": 0, 
- "in_dialog": 0, 
  "is_submittable": 0, 
  "issingle": 0, 
  "istable": 0, 
  "max_attachments": 1, 
- "modified": "2017-02-20 13:26:45.446617", 
+ "modified": "2017-03-21 21:03:10.715674", 
  "modified_by": "Administrator", 
  "module": "Stock", 
  "name": "Item", 
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index 0f0205b..4d0c3ac 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -643,7 +643,7 @@
 					.format(self.stock_uom, template_uom))
 
 	def validate_attributes(self):
-		if self.has_variants or self.variant_of:
+		if (self.has_variants or self.variant_of) and self.variant_based_on=='Item Attribute':
 			attributes = []
 			if not self.attributes:
 				frappe.throw(_("Attribute table is mandatory"))
@@ -654,7 +654,7 @@
 					attributes.append(d.attribute)
 
 	def validate_variant_attributes(self):
-		if self.variant_of:
+		if self.variant_of and self.variant_based_on=='Item Attribute':
 			args = {}
 			for d in self.attributes:
 				if not d.attribute_value:
@@ -675,7 +675,7 @@
 		from `tabStock Ledger Entry` where item_code=%s
 			and posting_date > date_sub(curdate(), interval 1 year)
 			group by posting_date''', name))
-	
+
 	for date, count in items.iteritems():
 		timestamp = get_timestamp(date)
 		out.update({ timestamp: count })
diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py
index 15a1118..2a8e434 100644
--- a/erpnext/stock/doctype/item/test_item.py
+++ b/erpnext/stock/doctype/item/test_item.py
@@ -7,7 +7,7 @@
 
 from frappe.test_runner import make_test_records
 from erpnext.controllers.item_variant import (create_variant, ItemVariantExistsError,
-	InvalidItemAttributeValueError)
+	InvalidItemAttributeValueError, get_variant)
 
 from frappe.model.rename_doc import rename_doc
 from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
@@ -167,31 +167,66 @@
 		variant.item_name = "_Test Numeric Variant Large 1.1m"
 		self.assertRaises(InvalidItemAttributeValueError, variant.save)
 
-		variant = create_variant("_Test Numeric Template Item", 
+		variant = create_variant("_Test Numeric Template Item",
 			{"Test Size": "Large", "Test Item Length": 1.5})
 		self.assertEquals(variant.item_code, "_Test Numeric Template Item-L-1.5")
 		variant.item_code = "_Test Numeric Variant-L-1.5"
 		variant.item_name = "_Test Numeric Variant Large 1.5m"
 		variant.save()
-		
-	def test_item_merging(self):		
+
+	def test_item_merging(self):
 		create_item("Test Item for Merging 1")
 		create_item("Test Item for Merging 2")
-		
-		make_stock_entry(item_code="Test Item for Merging 1", target="_Test Warehouse - _TC", 
+
+		make_stock_entry(item_code="Test Item for Merging 1", target="_Test Warehouse - _TC",
 			qty=1, rate=100)
-		make_stock_entry(item_code="Test Item for Merging 2", target="_Test Warehouse 1 - _TC", 
+		make_stock_entry(item_code="Test Item for Merging 2", target="_Test Warehouse 1 - _TC",
 			qty=1, rate=100)
-		
+
 		rename_doc("Item", "Test Item for Merging 1", "Test Item for Merging 2", merge=True)
-		
+
 		self.assertFalse(frappe.db.exists("Item", "Test Item for Merging 1"))
-		
-		self.assertTrue(frappe.db.get_value("Bin", 
+
+		self.assertTrue(frappe.db.get_value("Bin",
 			{"item_code": "Test Item for Merging 2", "warehouse": "_Test Warehouse - _TC"}))
-			
-		self.assertTrue(frappe.db.get_value("Bin", 
-			{"item_code": "Test Item for Merging 2", "warehouse": "_Test Warehouse 1 - _TC"}))		
+
+		self.assertTrue(frappe.db.get_value("Bin",
+			{"item_code": "Test Item for Merging 2", "warehouse": "_Test Warehouse 1 - _TC"}))
+
+	def test_item_variant_by_manufacturer(self):
+		if frappe.db.exists('Item', '_Test Variant Mfg'):
+			frappe.delete_doc('Item', '_Test Variant Mfg')
+		if frappe.db.exists('Item', '_Test Variant Mfg-1'):
+			frappe.delete_doc('Item', '_Test Variant Mfg-1')
+		if frappe.db.exists('Manufacturer', 'MSG1'):
+			frappe.delete_doc('Manufacturer', 'MSG1')
+
+		template = frappe.get_doc(dict(
+			doctype='Item',
+			item_code='_Test Variant Mfg',
+			has_variant=1,
+			item_group='Products',
+			variant_based_on='Manufacturer'
+		)).insert()
+
+		manufacturer = frappe.get_doc(dict(
+			doctype='Manufacturer',
+			short_name='MSG1'
+		)).insert()
+
+		variant = get_variant(template.name, manufacturer=manufacturer.name)
+		self.assertEquals(variant.item_code, '_Test Variant Mfg-1')
+		self.assertEquals(variant.description, '_Test Variant Mfg')
+		self.assertEquals(variant.manufacturer, 'MSG1')
+		variant.insert()
+
+		variant = get_variant(template.name, manufacturer=manufacturer.name,
+			manufacturer_part_no='007')
+		self.assertEquals(variant.item_code, '_Test Variant Mfg-2')
+		self.assertEquals(variant.description, '_Test Variant Mfg')
+		self.assertEquals(variant.manufacturer, 'MSG1')
+		self.assertEquals(variant.manufacturer_part_no, '007')
+
 
 def make_item_variant():
 	if not frappe.db.exists("Item", "_Test Variant Item-S"):
@@ -215,6 +250,5 @@
 		item.item_name = item_code
 		item.description = item_code
 		item.item_group = "All Item Groups"
-		item.is_stock_item = is_stock_item or 1		
+		item.is_stock_item = is_stock_item or 1
 		item.save()
-		
\ No newline at end of file
diff --git a/erpnext/support/doctype/issue/issue.py b/erpnext/support/doctype/issue/issue.py
index a1f8077..8a0be85 100644
--- a/erpnext/support/doctype/issue/issue.py
+++ b/erpnext/support/doctype/issue/issue.py
@@ -63,7 +63,7 @@
 		'no_breadcrumbs': True
 	}
 
-def get_issue_list(doctype, txt, filters, limit_start, limit_page_length=20):
+def get_issue_list(doctype, txt, filters, limit_start, limit_page_length=20, order_by=None):
 	from frappe.www.list import get_list
 	user = frappe.session.user
 	ignore_permissions = False