Merge pull request #1844 from anandpdoshi/anand-wip

Serial No Validation in Stock Entry, Warehouse query fix
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 847e09e..aba7a88 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -424,8 +424,7 @@
 
 	def get_stock_items(self):
 		stock_items = []
-		item_codes = list(set(item.item_code for item in
-			self.get(self.fname)))
+		item_codes = list(set(item.item_code for item in self.get(self.fname)))
 		if item_codes:
 			stock_items = [r[0] for r in frappe.db.sql("""select name
 				from `tabItem` where name in (%s) and is_stock_item='Yes'""" % \
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index d310347..83cec98 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -275,6 +275,16 @@
 			and voucher_no=%s""", (self.doctype, self.name)):
 				self.make_gl_entries()
 
+	def get_serialized_items(self):
+		serialized_items = []
+		item_codes = list(set([d.item_code for d in self.get(self.fname)]))
+		if item_codes:
+			serialized_items = frappe.db.sql_list("""select name from `tabItem`
+				where has_serial_no='Yes' and name in ({})""".format(", ".join(["%s"]*len(item_codes))),
+				tuple(item_codes))
+
+		return serialized_items
+
 def update_gl_entries_after(posting_date, posting_time, warehouse_account=None, for_items=None):
 	def _delete_gl_entries(voucher_type, voucher_no):
 		frappe.db.sql("""delete from `tabGL Entry`
diff --git a/erpnext/public/js/controllers/stock_controller.js b/erpnext/public/js/controllers/stock_controller.js
index 97bcb6c..1b472f1 100644
--- a/erpnext/public/js/controllers/stock_controller.js
+++ b/erpnext/public/js/controllers/stock_controller.js
@@ -13,14 +13,19 @@
 
 	setup_warehouse_query: function() {
 		var me = this;
+		var warehouse_query_method = function() {
+			return erpnext.queries.warehouse(me.frm.doc);
+		};
 
 		var _set_warehouse_query = function(doctype, parentfield) {
 			var warehouse_link_fields = frappe.meta.get_docfields(doctype, me.frm.doc.name,
 				{"fieldtype": "Link", "options": "Warehouse"});
 			$.each(warehouse_link_fields, function(i, df) {
-				me.frm.set_query(df.fieldname, parentfield, function() {
-					return erpnext.queries.warehouse(me.frm.doc);
-				})
+				if(parentfield) {
+					me.frm.set_query(df.fieldname, parentfield, warehouse_query_method);
+				} else {
+					me.frm.set_query(df.fieldname, warehouse_query_method);
+				}
 			});
 		};
 
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.js b/erpnext/stock/doctype/delivery_note/delivery_note.js
index 10fe650..d2e60eb 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.js
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.js
@@ -12,6 +12,7 @@
 {% include 'accounts/doctype/sales_invoice/pos.js' %}
 
 frappe.provide("erpnext.stock");
+frappe.provide("erpnext.stock.delivery_note");
 erpnext.stock.DeliveryNoteController = erpnext.selling.SellingController.extend({
 	refresh: function(doc, dt, dn) {
 		this._super();
@@ -40,7 +41,7 @@
 			cur_frm.add_custom_button(__('Make Packing Slip'), cur_frm.cscript['Make Packing Slip']);
 		}
 
-		set_print_hide(doc, dt, dn);
+		erpnext.stock.delivery_note.set_print_hide(doc, dt, dn);
 
 		// unhide expense_account and cost_center is auto_accounting_for_stock enabled
 		var aii_enabled = cint(sys_defaults.auto_accounting_for_stock)
@@ -124,7 +125,7 @@
 	})
 }
 
-var set_print_hide= function(doc, cdt, cdn){
+erpnext.stock.delivery_note.set_print_hide = function(doc, cdt, cdn){
 	var dn_fields = frappe.meta.docfield_map['Delivery Note'];
 	var dn_item_fields = frappe.meta.docfield_map['Delivery Note Item'];
 	var dn_fields_copy = dn_fields;
@@ -147,7 +148,7 @@
 }
 
 cur_frm.cscript.print_without_amount = function(doc, cdt, cdn) {
-	set_print_hide(doc, cdt, cdn);
+	erpnext.stock.delivery_note.set_print_hide(doc, cdt, cdn);
 }
 
 
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 125a293..a7e007a 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -77,6 +77,7 @@
 
 	def validate_item(self):
 		stock_items = self.get_stock_items()
+		serialized_items = self.get_serialized_items()
 		for item in self.get("mtn_details"):
 			if item.item_code not in stock_items:
 				frappe.throw(_("{0} is not a stock Item").format(item.item_code))
@@ -88,6 +89,12 @@
 				item.conversion_factor = 1
 			if not item.transfer_qty:
 				item.transfer_qty = item.qty * item.conversion_factor
+			if (self.purpose in ("Material Transfer", "Sales Return", "Purchase Return")
+				and not item.serial_no
+				and item.item_code in serialized_items):
+				frappe.throw(_("Row #{0}: Please specify Serial No for Item {1}").format(item.idx, item.item_code),
+					frappe.MandatoryError)
+
 
 	def validate_warehouse(self, pro_obj):
 		"""perform various (sometimes conditional) validations on warehouse"""