Merge branch 'hotfix'
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index f93c967..7ce7772 100644
--- a/erpnext/__init__.py
+++ b/erpnext/__init__.py
@@ -2,7 +2,7 @@
 from __future__ import unicode_literals
 import frappe
 
-__version__ = '8.0.44'
+__version__ = '8.0.45'
 
 
 def get_default_company(user=None):
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index b48fb20..cada95f 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -78,7 +78,7 @@
 					},
 					get_query_filters: {
 						docstatus: 1,
-						status: ["!=", "Closed"],
+						status: ["not in", ["Closed", "Completed"]],
 						company: me.frm.doc.company,
 						is_return: 0
 					}
diff --git a/erpnext/accounts/doctype/sales_invoice/pos.py b/erpnext/accounts/doctype/sales_invoice/pos.py
index a899cde..0f0569a 100644
--- a/erpnext/accounts/doctype/sales_invoice/pos.py
+++ b/erpnext/accounts/doctype/sales_invoice/pos.py
@@ -35,6 +35,7 @@
 		'item_groups': get_item_groups(pos_profile),
 		'customers': customers,
 		'address': get_customers_address(customers),
+		'contacts': get_contacts(customers),
 		'serial_no_data': get_serial_no_data(pos_profile, doc.company),
 		'batch_no_data': get_batch_no_data(),
 		'tax_data': get_item_tax_data(),
@@ -160,7 +161,7 @@
 		item_group_dict[data.name] = [data.lft, data.rgt]
 	return item_group_dict
 
-def get_customers_list(pos_profile):
+def get_customers_list(pos_profile={}):
 	cond = "1=1"
 	customer_groups = []
 	if pos_profile.get('customer_groups'):
@@ -170,7 +171,7 @@
 		cond = "customer_group in (%s)"%(', '.join(['%s']*len(customer_groups)))
 
 	return frappe.db.sql(""" select name, customer_name, customer_group,
-		territory from tabCustomer where disabled = 0
+		territory, customer_pos_id from tabCustomer where disabled = 0
 		and {cond}""".format(cond=cond), tuple(customer_groups), as_dict=1) or {}
 
 def get_customers_address(customers):
@@ -183,13 +184,29 @@
 			email_id, phone, fax, pincode from `tabAddress` where is_primary_address =1 and name in
 			(select parent from `tabDynamic Link` where link_doctype = 'Customer' and link_name = %s
 			and parenttype = 'Address')""", data.name, as_dict=1)
-		if address:
-			address_data = address[0]
-			address_data.update({'full_name': data.customer_name})
-			customer_address[data.name] = address_data
+		address_data = {}
+		if address: address_data = address[0]
+
+		address_data.update({'full_name': data.customer_name, 'customer_pos_id': data.customer_pos_id})
+		customer_address[data.name] = address_data
 
 	return customer_address
 
+def get_contacts(customers):
+	customer_contact = {}
+	if isinstance(customers, basestring):
+		customers = [frappe._dict({'name': customers})]
+
+	for data in customers:
+		contact = frappe.db.sql(""" select email_id, phone from `tabContact` 
+			where is_primary_contact =1 and name in
+			(select parent from `tabDynamic Link` where link_doctype = 'Customer' and link_name = %s
+			and parenttype = 'Contact')""", data.name, as_dict=1)
+		if contact: 
+			customer_contact[data.name] = contact[0]
+
+	return customer_contact
+
 def get_child_nodes(group_type, root):
 	lft, rgt = frappe.db.get_value(group_type, root, ["lft", "rgt"])
 	return frappe.db.sql(""" Select name, lft, rgt from `tab{tab}` where
@@ -294,7 +311,7 @@
 	if isinstance(customers_list, basestring):
 		customers_list = json.loads(customers_list)
 
-	customers = make_customer_and_address(customers_list)
+	customers_list = make_customer_and_address(customers_list)
 	name_list = []
 	for docs in doc_list:
 		for name, doc in docs.items():
@@ -303,6 +320,7 @@
 				si_doc = frappe.new_doc('Sales Invoice')
 				si_doc.offline_pos_name = name
 				si_doc.update(doc)
+				si_doc.customer = get_customer_id(doc)
 				si_doc.due_date = doc.get('posting_date')
 				submit_invoice(si_doc, name, doc)
 				name_list.append(name)
@@ -310,30 +328,54 @@
 				name_list.append(name)
 
 	email_queue = make_email_queue(email_queue_list)
+	customers = get_customers_list()
 	return {
 		'invoice': name_list,
 		'email_queue': email_queue,
-		'customers': customers
+		'customers': customers_list,
+		'synced_customers_list': customers,
+		'synced_address': get_customers_address(customers),
+		'synced_contacts': get_contacts(customers)
 	}
 
 def validate_records(doc):
 	validate_item(doc)
 
-def make_customer_and_address(customers):
-	customer_list = []
-	for name, data in customers.items():
-		if not frappe.db.exists('Customer', name):
-			name = add_customer(name)
-		data = json.loads(data)
-		make_contact(data, name)
-		make_address(data, name)
-		customer_list.append(name)
-	frappe.db.commit()
-	return customer_list
+def get_customer_id(doc, customer=None):
+	cust_id = None
+	if doc.get('customer_pos_id'):
+		cust_id = frappe.db.get_value('Customer',
+			{'customer_pos_id': doc.get('customer_pos_id')}, 'name')
 
-def add_customer(name):
+	if not cust_id:
+		customer = customer or doc.get('customer')
+		if frappe.db.exists('Customer', customer):
+			cust_id = customer
+		else:
+			cust_id = add_customer(doc)
+
+	return cust_id
+
+def make_customer_and_address(customers):
+	customers_list = []
+	for customer, data in customers.items():
+		data = json.loads(data)
+		cust_id = get_customer_id(data, customer)
+		if not cust_id:
+			cust_id = add_customer(data)
+		else:
+			frappe.db.set_value("Customer", cust_id, "customer_name", data.get('full_name'))
+
+		make_contact(data, cust_id)
+		make_address(data, cust_id)
+		customers_list.append(customer)
+	frappe.db.commit()
+	return customers_list
+
+def add_customer(data):
 	customer_doc = frappe.new_doc('Customer')
-	customer_doc.customer_name = name
+	customer_doc.customer_name = data.get('full_name') or data.get('customer')
+	customer_doc.customer_pos_id = data.get('customer_pos_id')
 	customer_doc.customer_type = 'Company'
 	customer_doc.customer_group = frappe.db.get_single_value('Selling Settings', 'customer_group')
 	customer_doc.territory = frappe.db.get_single_value('Selling Settings', 'territory')
@@ -348,6 +390,7 @@
 			{'link_doctype': 'Customer', 'link_name': customer, 'parenttype': 'Contact'}, 'parent')
 
 		args = {
+			'first_name': args.get('full_name'),
 			'email_id': args.get('email_id'),
 			'phone': args.get('phone')
 		}
@@ -357,8 +400,8 @@
 			doc = frappe.get_doc('Contact', name)
 
 		doc.update(args)
+		doc.is_primary_contact = 1
 		if not name:
-			doc.first_name = customer
 			doc.append('links',{
 				'link_doctype': 'Customer',
 				'link_name': customer
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 4b1837d..ab49fc0 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -243,7 +243,6 @@
 				(not self.project and not data.sales_invoice) or \
 				(not sales_invoice and data.sales_invoice == self.name):
 				data.sales_invoice = sales_invoice
-				if self.project: return
 
 	def on_update(self):
 		self.set_paid_amount()
@@ -483,13 +482,14 @@
 			self.set('packed_items', [])
 
 	def set_billing_hours_and_amount(self):
-		for timesheet in self.timesheets:
-			ts_doc = frappe.get_doc('Timesheet', timesheet.time_sheet)
-			if not timesheet.billing_hours and ts_doc.total_billable_hours:
-				timesheet.billing_hours = ts_doc.total_billable_hours
+		if not self.project:
+			for timesheet in self.timesheets:
+				ts_doc = frappe.get_doc('Timesheet', timesheet.time_sheet)
+				if not timesheet.billing_hours and ts_doc.total_billable_hours:
+					timesheet.billing_hours = ts_doc.total_billable_hours
 
-			if not timesheet.billing_amount and ts_doc.total_billable_amount:
-				timesheet.billing_amount = ts_doc.total_billable_amount
+				if not timesheet.billing_amount and ts_doc.total_billable_amount:
+					timesheet.billing_amount = ts_doc.total_billable_amount
 
 	def update_timesheet_billing_for_project(self):
 		if not self.timesheets and self.project:
diff --git a/erpnext/accounts/page/pos/pos.js b/erpnext/accounts/page/pos/pos.js
index 223e915..4494110 100644
--- a/erpnext/accounts/page/pos/pos.js
+++ b/erpnext/accounts/page/pos/pos.js
@@ -20,6 +20,7 @@
 erpnext.pos.PointOfSale = erpnext.taxes_and_totals.extend({
 	init: function (wrapper) {
 		this.page_len = 20;
+		this.freeze = false;
 		this.page = wrapper.page;
 		this.wrapper = $(wrapper).find('.page-content');
 		this.set_indicator();
@@ -72,6 +73,7 @@
 	onload: function () {
 		var me = this;
 		this.get_data_from_server(function () {
+			me.make_control();
 			me.create_new();
 		});
 	},
@@ -96,7 +98,6 @@
 		this.page.add_menu_item(__("Sync Master Data"), function () {
 			me.get_data_from_server(function () {
 				me.load_data(false);
-				me.make_customer();
 				me.make_item_list();
 				me.set_missing_values();
 			})
@@ -311,6 +312,7 @@
 		this.serial_no_data = r.message.serial_no_data;
 		this.batch_no_data = r.message.batch_no_data;
 		this.tax_data = r.message.tax_data;
+		this.contacts = r.message.contacts;
 		this.address = r.message.address || {};
 		this.price_list_data = r.message.price_list_data;
 		this.bin_data = r.message.bin_data;
@@ -320,7 +322,6 @@
 		this.default_customer = r.message.default_customer || null;
 		this.print_settings = locals[":Print Settings"]["Print Settings"];
 		this.letter_head = (this.pos_profile_data.length > 0) ? frappe.boot.letter_heads[this.pos_profile_data[letter_head]] : {};
-		this.make_control()
 	},
 
 	save_previous_entry: function () {
@@ -403,6 +404,7 @@
 		this.frm = {}
 		this.frm.doc = this.doc
 		this.set_transaction_defaults("Customer");
+		this.frm.doc["allow_user_to_edit_rate"] = this.pos_profile_data["allow_user_to_edit_rate"] ? true : false,
 		this.wrapper.html(frappe.render_template("pos", this.frm.doc));
 		this.make_search();
 		this.make_customer();
@@ -707,15 +709,28 @@
 				autoFirst: true,
 				list: [],
 				filter: function (item, input) {
-					var value = item.value.toLowerCase();
-					if (value.indexOf('is_action') !== -1 ||
-						value.indexOf(input.toLowerCase()) !== -1) {
+					if (item.value.includes('is_action')) {
 						return true;
 					}
+
+					input = input.toLowerCase();
+					item = this.get_item(item.value);
+					var searchtext =
+						Object.keys(item)
+							.filter(key => ['customer_name', 'customer_group', 'value', 'label', 'email_id', 'phone'].includes(key))
+							.map(key => item[key])
+							.join(" ")
+							.toLowerCase();
+
+					return searchtext.includes(input)
 				},
 				item: function (item, input) {
-					var d = item;
+					var d = this.get_item(item.value);
 					var html = "<span>" + __(d.label || d.value) + "</span>";
+					if(d.customer_name) {
+						html += '<br><span class="text-muted ellipsis">' + __(d.customer_name) + '</span>';
+					}
+
 					return $('<li></li>')
 						.data('item.autocomplete', d)
 						.html('<a><p>' + html + '</p></a>')
@@ -723,28 +738,12 @@
 				}
 			});
 
-		this.customers_mapper = this.customers.map(function (c) {
-			return {
-				label: c.name,
-				value: c.name,
-				customer_group: c.customer_group,
-				territory: c.territory
-			}
-		});
-
-		this.customers_mapper.push({
-			label: "<span class='text-primary link-option'>"
-			+ "<i class='fa fa-plus' style='margin-right: 5px;'></i> "
-			+ __("Create a new Customer")
-			+ "</span>",
-			value: 'is_action',
-			action: me.add_customer
-		});
+		this.prepare_customer_mapper()
 		this.autocomplete_customers();
 
 		this.party_field.$input
 			.on('input', function (e) {
-				me.party_field.awesomeplete.list = this.customers_mapper;
+				me.party_field.awesomeplete.list = me.customers_mapper;
 			})
 			.on('awesomplete-select', function (e) {
 				var customer = me.party_field.awesomeplete
@@ -784,6 +783,32 @@
 			});
 	},
 
+	prepare_customer_mapper: function() {
+		var me = this;
+
+		this.customers_mapper = this.customers.map(function (c) {
+			contact = me.contacts[c.name];
+			return {
+				label: c.name,
+				value: c.name,
+				customer_name: c.customer_name,
+				customer_group: c.customer_group,
+				territory: c.territory,
+				phone: contact ? contact["phone"] : '',
+				email_id: contact ? contact["email_id"] : ''
+			}
+		});
+
+		this.customers_mapper.push({
+			label: "<span class='text-primary link-option'>"
+			+ "<i class='fa fa-plus' style='margin-right: 5px;'></i> "
+			+ __("Create a new Customer")
+			+ "</span>",
+			value: 'is_action',
+			action: me.add_customer
+		});
+	},
+
 	autocomplete_customers: function() {
 		this.party_field.awesomeplete.list = this.customers_mapper;
 	},
@@ -871,10 +896,15 @@
 					"label": __("ZIP Code"),
 					"fieldname": "pincode",
 					"fieldtype": "Data"
+				},
+				{
+					"label": __("Customer POS Id"),
+					"fieldname": "customer_pos_id",
+					"fieldtype": "Data",
+					"hidden": 1
 				}
 			]
 		})
-
 		this.customer_doc.show()
 		this.render_address_data()
 
@@ -887,12 +917,19 @@
 
 	render_address_data: function() {
 		var me = this;
-		this.address_data = this.address[this.frm.doc.customer];
-		this.customer_doc.set_values(this.address_data)
+		this.address_data = this.address[this.frm.doc.customer] || {};
+		if(!this.address_data.email_id || !this.address_data.phone) {
+			this.address_data = this.contacts[this.frm.doc.customer];
+		}
 
+		this.customer_doc.set_values(this.address_data)
 		if(!this.customer_doc.fields_dict.full_name.$input.val()) {
 			this.customer_doc.set_value("full_name", this.frm.doc.customer)
 		}
+
+		if(!this.customer_doc.fields_dict.customer_pos_id.value) {
+			this.customer_doc.set_value("customer_pos_id", $.now())
+		}
 	},
 
 	get_address_from_localstorage: function() {
@@ -902,6 +939,7 @@
 
 	make_offline_customer: function(new_customer) {
 		this.frm.doc.customer = this.frm.doc.customer || this.customer_doc.get_values().full_name;
+		this.frm.doc.customer_pos_id = this.customer_doc.fields_dict.customer_pos_id.value;
 		this.customer_details = this.get_customers_details();
 		this.customer_details[this.frm.doc.customer] = this.get_prompt_details();
 		this.party_field.$input.val(this.frm.doc.customer);
@@ -923,12 +961,13 @@
 			});
 		}
 
-		this.address[this.frm.doc.customer] = this.customer_doc.get_values();
+		this.address[this.frm.doc.customer] = JSON.parse(this.get_prompt_details())
 	},
 
 	get_prompt_details: function() {
 		this.prompt_details = this.customer_doc.get_values();
 		this.prompt_details['country'] = this.pos_profile_data.country;
+		this.prompt_details['customer_pos_id'] = this.customer_doc.fields_dict.customer_pos_id.value;
 		return JSON.stringify(this.prompt_details)
 	},
 
@@ -942,26 +981,6 @@
 		this.numeric_keypad.show();
 	},
 
-	get_customers: function (key) {
-		var me = this;
-		key = key.toLowerCase().trim()
-		var re = new RegExp('%', 'g');
-		var reg = new RegExp(key.replace(re, '\\w*\\s*[a-zA-Z0-9]*'))
-
-		if (key) {
-			return $.grep(this.customers, function (data) {
-				if (reg.test(data.name.toLowerCase())
-					|| reg.test(data.customer_name.toLowerCase())
-					|| (data.customer_group && reg.test(data.customer_group.toLowerCase()))) {
-					return data
-				}
-			})
-		} else {
-			customers = this.customers.sort(function (a, b) { return a.idx < b.idx })
-			return customers.slice(0, 20)
-		}
-	},
-
 	make_item_list: function () {
 		var me = this;
 		if (!this.price_list) {
@@ -1180,6 +1199,7 @@
 		this.child_doc = this.get_child_item(this.item_code);
 		$(this.wrapper).find('.selected-item').empty();
 		if(this.child_doc.length) {
+			this.child_doc[0]["allow_user_to_edit_rate"] = this.pos_profile_data["allow_user_to_edit_rate"] ? true : false,
 			this.selected_row = $(frappe.render_template("pos_selected_item", this.child_doc[0]))
 			$(this.wrapper).find('.selected-item').html(this.selected_row)
 		}
@@ -1388,7 +1408,6 @@
 				actual_qty: me.actual_qty_dict[d.item_code] || 0.0,
 				projected_qty: d.projected_qty,
 				rate: format_currency(d.rate, me.frm.doc.currency),
-				enabled: me.pos_profile_data["allow_user_to_edit_rate"] ? true : false,
 				amount: format_currency(d.amount, me.frm.doc.currency),
 				selected_class: (me.item_code == d.item_code) ? "active" : ""
 			})).appendTo($items);
@@ -1608,8 +1627,11 @@
 		this.si_docs = this.get_submitted_invoice() || [];
 		this.email_queue_list = this.get_email_queue() || {};
 		this.customers_list = this.get_customers_details() || {};
+		if(this.customer_doc) {
+			this.freeze = this.customer_doc.display
+		}
 
-		if (this.si_docs.length || this.email_queue_list || this.customers_list) {
+		if ((this.si_docs.length || this.email_queue_list || this.customers_list) && !this.freeze) {
 			frappe.call({
 				method: "erpnext.accounts.doctype.sales_invoice.pos.make_invoice",
 				args: {
@@ -1619,12 +1641,17 @@
 				},
 				callback: function (r) {
 					if (r.message) {
+						me.customers = r.message.synced_customers_list;
+						me.address = r.message.synced_address;
+						me.contacts = r.message.synced_contacts;
 						me.removed_items = r.message.invoice;
 						me.removed_email = r.message.email_queue
 						me.removed_customers = r.message.customers
 						me.remove_doc_from_localstorage();
 						me.remove_email_queue_from_localstorage();
 						me.remove_customer_from_localstorage();
+						me.prepare_customer_mapper()
+						me.autocomplete_customers()
 					}
 				}
 			})
diff --git a/erpnext/accounts/print_format/point_of_sale/point_of_sale.json b/erpnext/accounts/print_format/point_of_sale/point_of_sale.json
index b413321..28c853c 100644
--- a/erpnext/accounts/print_format/point_of_sale/point_of_sale.json
+++ b/erpnext/accounts/print_format/point_of_sale/point_of_sale.json
@@ -7,10 +7,10 @@
  "docstatus": 0, 
  "doctype": "Print Format", 
  "font": "Default", 
- "html": "<style>\n\t.print-format table, .print-format tr, \n\t.print-format td, .print-format div, .print-format p {\n\t\tfont-family: Monospace;\n\t\tline-height: 200%;\n\t\tvertical-align: middle;\n\t}\n\t@media screen {\n\t\t.print-format {\n\t\t\twidth: 4in;\n\t\t\tpadding: 0.25in;\n\t\t\tmin-height: 8in;\n\t\t}\n\t}\n</style>\n\n<p class=\"text-center\">\n\t{{ company }}<br>\n\t{{  __(\"POS No : \") }} {{ offline_pos_name }}<br>\n</p>\n<p>\n\t<b>{{ __(\"Date\") }}:</b> {{ dateutil.global_date_format(posting_date) }}<br>\n</p>\n\n<hr>\n<table class=\"table table-condensed cart no-border\">\n\t<thead>\n\t\t<tr>\n\t\t\t<th width=\"50%\">{{ __(\"Item\") }}</b></th>\n\t\t\t<th width=\"25%\" class=\"text-right\">{{ __(\"Qty\") }}</th>\n\t\t\t<th width=\"25%\" class=\"text-right\">{{ __(\"Amount\") }}</th>\n\t\t</tr>\n\t</thead>\n\t<tbody>\n\t\t{% for item in items %}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t{{ item.item_name }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">{{ format_number(item.qty, null,precision(\"difference\")) }}<br>@ {{ format_currency(item.rate, currency) }}</td>\n\t\t\t<td class=\"text-right\">{{ format_currency(item.amount, currency) }}</td>\n\t\t</tr>\n\t\t{% endfor %}\n\t</tbody>\n</table>\n\n<table class=\"table table-condensed no-border\">\n\t<tbody>\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ __(\"Net Total\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(total, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{% for row in taxes %}\n\t\t{% if not row.included_in_print_rate %}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ row.description }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(row.tax_amount, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{% endif %}\n\t\t{% endfor %}\n\t\t{% if discount_amount %}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t{{ __(\"Discount\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(discount_amount, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{% endif %}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ __(\"Grand Total\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(grand_total, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ __(\"Paid Amount\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(paid_amount, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t</tbody>\n</table>\n\n\n<hr>\n<p>{{ terms }}</p>\n<p class=\"text-center\">{{ __(\"Thank you, please visit again.\") }}</p>", 
+ "html": "<style>\n\t.print-format table, .print-format tr, \n\t.print-format td, .print-format div, .print-format p {\n\t\tfont-family: Monospace;\n\t\tline-height: 200%;\n\t\tvertical-align: middle;\n\t}\n\t@media screen {\n\t\t.print-format {\n\t\t\twidth: 4in;\n\t\t\tpadding: 0.25in;\n\t\t\tmin-height: 8in;\n\t\t}\n\t}\n</style>\n\n<p class=\"text-center\">\n\t{{ company }}<br>\n\t{{  __(\"POS No : \") }} {{ offline_pos_name }}<br>\n</p>\n<p>\n\t<b>{{ __(\"Customer\") }}:</b> {{ customer }}<br>\n</p>\n\n<p>\n\t<b>{{ __(\"Date\") }}:</b> {{ dateutil.global_date_format(posting_date) }}<br>\n</p>\n\n<hr>\n<table class=\"table table-condensed cart no-border\">\n\t<thead>\n\t\t<tr>\n\t\t\t<th width=\"50%\">{{ __(\"Item\") }}</b></th>\n\t\t\t<th width=\"25%\" class=\"text-right\">{{ __(\"Qty\") }}</th>\n\t\t\t<th width=\"25%\" class=\"text-right\">{{ __(\"Amount\") }}</th>\n\t\t</tr>\n\t</thead>\n\t<tbody>\n\t\t{% for item in items %}\n\t\t<tr>\n\t\t\t<td>\n\t\t\t\t{{ item.item_name }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">{{ format_number(item.qty, null,precision(\"difference\")) }}<br>@ {{ format_currency(item.rate, currency) }}</td>\n\t\t\t<td class=\"text-right\">{{ format_currency(item.amount, currency) }}</td>\n\t\t</tr>\n\t\t{% endfor %}\n\t</tbody>\n</table>\n\n<table class=\"table table-condensed no-border\">\n\t<tbody>\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ __(\"Net Total\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(total, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{% for row in taxes %}\n\t\t{% if not row.included_in_print_rate %}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 70%\">\n\t\t\t\t{{ row.description }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(row.tax_amount, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{% endif %}\n\t\t{% endfor %}\n\t\t{% if discount_amount %}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t{{ __(\"Discount\") }}\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(discount_amount, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t{% endif %}\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ __(\"Grand Total\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(grand_total, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t\t<tr>\n\t\t\t<td class=\"text-right\" style=\"width: 75%\">\n\t\t\t\t<b>{{ __(\"Paid Amount\") }}</b>\n\t\t\t</td>\n\t\t\t<td class=\"text-right\">\n\t\t\t\t{{ format_currency(paid_amount, currency) }}\n\t\t\t</td>\n\t\t</tr>\n\t</tbody>\n</table>\n\n\n<hr>\n<p>{{ terms }}</p>\n<p class=\"text-center\">{{ __(\"Thank you, please visit again.\") }}</p>", 
  "idx": 0, 
  "line_breaks": 0, 
- "modified": "2017-04-19 13:28:05.129504", 
+ "modified": "2017-05-19 14:36:04.740728", 
  "modified_by": "Administrator", 
  "module": "Accounts", 
  "name": "Point of Sale", 
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index 62d0d5a..9906893 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -33,7 +33,9 @@
 		if args.get("party_type") == "Supplier":
 			columns += [_("Bill No") + "::80", _("Bill Date") + ":Date:80"]
 
-		for label in ("Invoiced Amount", "Paid Amount", "Outstanding Amount"):
+		credit_or_debit_note = "Credit Note" if args.get("party_type") == "Customer" else "Debit Note"
+
+		for label in ("Invoiced Amount", "Paid Amount", credit_or_debit_note, "Outstanding Amount"):
 			columns.append({
 				"label": label,
 				"fieldtype": "Currency",
@@ -95,13 +97,14 @@
 			self.filters["company"] = frappe.db.get_single_value('Global Defaults', 'default_company')
 
 		company_currency = frappe.db.get_value("Company", self.filters.get("company"), "default_currency")
+		
+		return_entries = self.get_return_entries(args.get("party_type"))
 
 		data = []
 		for gle in self.get_entries_till(self.filters.report_date, args.get("party_type")):
 			if self.is_receivable_or_payable(gle, dr_or_cr, future_vouchers):
-				outstanding_amount = flt(self.get_outstanding_amount(gle, 
-					self.filters.report_date, dr_or_cr), currency_precision)
-					
+				outstanding_amount, credit_note_amount = self.get_outstanding_amount(gle, 
+					self.filters.report_date, dr_or_cr, return_entries, currency_precision)
 				if abs(outstanding_amount) > 0.1/10**currency_precision:
 					row = [gle.posting_date, gle.party]
 
@@ -123,8 +126,8 @@
 
 					# invoiced and paid amounts
 					invoiced_amount = gle.get(dr_or_cr) if (gle.get(dr_or_cr) > 0) else 0
-					paid_amt = invoiced_amount - outstanding_amount
-					row += [invoiced_amount, paid_amt, outstanding_amount]
+					paid_amt = invoiced_amount - outstanding_amount - credit_note_amount
+					row += [invoiced_amount, paid_amt, credit_note_amount, outstanding_amount]
 
 					# ageing data
 					entry_date = due_date if self.filters.ageing_based_on == "Due Date" else gle.posting_date
@@ -132,7 +135,8 @@
 						cint(self.filters.range3), self.age_as_on, entry_date, outstanding_amount)
 
 					# issue 6371-Ageing buckets should not have amounts if due date is not reached
-					if self.filters.ageing_based_on == "Due Date" and getdate(due_date) > getdate(self.filters.report_date):
+					if self.filters.ageing_based_on == "Due Date" \
+							and getdate(due_date) > getdate(self.filters.report_date):
 						row[-1]=row[-2]=row[-3]=row[-4]=0
 
 					if self.filters.get(scrub(args.get("party_type"))):
@@ -175,14 +179,28 @@
 			# entries adjusted with future vouchers
 			((gle.against_voucher_type, gle.against_voucher) in future_vouchers)
 		)
+		
+	def get_return_entries(self, party_type):
+		doctype = "Sales Invoice" if party_type=="Customer" else "Purchase Invoice"
+		return [d.name for d in frappe.get_all(doctype, filters={"is_return": 1, "docstatus": 1})]	
 
-	def get_outstanding_amount(self, gle, report_date, dr_or_cr):
-		payment_amount = 0.0
+	def get_outstanding_amount(self, gle, report_date, dr_or_cr, return_entries, currency_precision):
+		payment_amount, credit_note_amount = 0.0, 0.0
+		reverse_dr_or_cr = "credit" if dr_or_cr=="debit" else "debit"
+		
 		for e in self.get_gl_entries_for(gle.party, gle.party_type, gle.voucher_type, gle.voucher_no):
 			if getdate(e.posting_date) <= report_date and e.name!=gle.name:
-				payment_amount += (flt(e.credit if gle.party_type == "Customer" else e.debit) - flt(e.get(dr_or_cr)))
-
-		return flt(gle.get(dr_or_cr)) - flt(gle.credit if gle.party_type == "Customer" else gle.debit) - payment_amount
+				amount = flt(e.get(reverse_dr_or_cr)) - flt(e.get(dr_or_cr))
+				if e.voucher_no not in return_entries:
+					payment_amount += amount
+				else:
+					credit_note_amount += amount
+					
+		outstanding_amount = flt((flt(gle.get(dr_or_cr)) - flt(gle.get(reverse_dr_or_cr)) \
+			- payment_amount - credit_note_amount), currency_precision)
+		credit_note_amount = flt(credit_note_amount, currency_precision)
+		
+		return outstanding_amount, credit_note_amount
 
 	def get_party_name(self, party_type, party_name):
 		return self.get_party_map(party_type).get(party_name, {}).get("customer_name" if party_type == "Customer" else "supplier_name") or ""
diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py
index 42327b9..2f54fc0 100644
--- a/erpnext/controllers/status_updater.py
+++ b/erpnext/controllers/status_updater.py
@@ -85,6 +85,16 @@
 		["Completed", "eval:self.per_billed == 100 and self.docstatus == 1"],
 		["Cancelled", "eval:self.docstatus==2"],
 		["Closed", "eval:self.status=='Closed'"],
+	],
+	"Material Request": [
+		["Draft", None],
+		["Stopped", "eval:self.status == 'Stopped'"],
+		["Cancelled", "eval:self.docstatus == 2"],
+		["Pending", "eval:self.status != 'Stopped' and self.per_ordered == 0 and self.docstatus == 1"],
+		["Partially Ordered", "eval:self.status != 'Stopped' and self.per_ordered < 100 and self.per_ordered > 0 and self.docstatus == 1"],
+		["Ordered", "eval:self.status != 'Stopped' and self.per_ordered == 100 and self.docstatus == 1 and self.material_request_type == 'Purchase'"],
+		["Transferred", "eval:self.status != 'Stopped' and self.per_ordered == 100 and self.docstatus == 1 and self.material_request_type == 'Material Transfer'"],
+		["Issued", "eval:self.status != 'Stopped' and self.per_ordered == 100 and self.docstatus == 1 and self.material_request_type == 'Material Issue'"]
 	]
 }
 
@@ -127,7 +137,8 @@
 					self.status = s[0]
 					break
 
-			if self.status != _status and self.status not in ("Submitted", "Cancelled"):
+			if self.status != _status and self.status not in ("Cancelled", "Partially Ordered",
+																"Ordered", "Issued", "Transferred"):
 				self.add_comment("Label", _(self.status))
 
 			if update:
diff --git a/erpnext/hr/doctype/salary_slip/salary_slip.py b/erpnext/hr/doctype/salary_slip/salary_slip.py
index e18fc27..1cee022 100644
--- a/erpnext/hr/doctype/salary_slip/salary_slip.py
+++ b/erpnext/hr/doctype/salary_slip/salary_slip.py
@@ -91,7 +91,7 @@
 			frappe.throw(_("Name error: {0}".format(err)))
 		except SyntaxError as err:
 			frappe.throw(_("Syntax error in formula or condition: {0}".format(err)))
-		except Exception, e:
+		except Exception as e:
 			frappe.throw(_("Error in formula or condition: {0}".format(e)))
 			raise
 
@@ -330,11 +330,18 @@
 			frappe.throw(_("Please set the Date Of Joining for employee {0}").format(frappe.bold(self.employee_name)))
 
 		for d in self.get(component_type):
-			if self.salary_structure and ((cint(d.depends_on_lwp) == 1 and not self.salary_slip_based_on_timesheet) or\
-			getdate(self.start_date) < joining_date or getdate(self.end_date) > relieving_date):
+			if (self.salary_structure and
+				cint(d.depends_on_lwp) and
+				(not
+				    self.salary_slip_based_on_timesheet or
+					getdate(self.start_date) < joining_date or
+					getdate(self.end_date) > relieving_date
+				)):
 
-				d.amount = rounded((flt(d.default_amount) * flt(self.payment_days)
-					/ cint(self.total_working_days)), self.precision("amount", component_type))
+				d.amount = rounded(
+					(flt(d.default_amount) * flt(self.payment_days)
+					/ cint(self.total_working_days)), self.precision("amount", component_type)
+				)
 			elif not self.payment_days and not self.salary_slip_based_on_timesheet:
 				d.amount = 0
 			elif not d.amount:
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 853efa1..7dc7e3c 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -397,3 +397,5 @@
 erpnext.patches.v8_0.fix_status_for_invoices_with_negative_outstanding
 erpnext.patches.v8_0.make_payments_table_blank_for_non_pos_invoice
 erpnext.patches.v8_0.delete_schools_depricated_doctypes
+erpnext.patches.v8_0.update_customer_pos_id
+erpnext.patches.v8_0.rename_items_in_status_field_of_material_request
diff --git a/erpnext/patches/v8_0/rename_items_in_status_field_of_material_request.py b/erpnext/patches/v8_0/rename_items_in_status_field_of_material_request.py
new file mode 100644
index 0000000..5ad862a
--- /dev/null
+++ b/erpnext/patches/v8_0/rename_items_in_status_field_of_material_request.py
@@ -0,0 +1,25 @@
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+	frappe.db.sql(
+		"""
+		UPDATE `tabMaterial Request`
+			SET status = CASE
+							WHEN docstatus = 2 THEN 'Cancelled'
+							WHEN docstatus = 0 THEN 'Draft'
+							ELSE CASE
+								WHEN status = 'Stopped' THEN 'Stopped'
+								WHEN status != 'Stopped' AND per_ordered = 0 THEN 'Pending'
+								WHEN per_ordered < 100 AND per_ordered > 0 AND status != 'Stopped'
+									THEN 'Partially Ordered'
+								WHEN per_ordered = 100 AND material_request_type = 'Purchase'
+									AND status != 'Stopped' THEN 'Ordered'
+								WHEN per_ordered = 100 AND material_request_type = 'Material Transfer'
+									AND status != 'Stopped' THEN 'Transferred'
+								WHEN per_ordered = 100 AND material_request_type = 'Material Issue'
+									AND status != 'Stopped' THEN 'Issued'
+							END
+			END
+		"""
+	)
\ No newline at end of file
diff --git a/erpnext/patches/v8_0/update_customer_pos_id.py b/erpnext/patches/v8_0/update_customer_pos_id.py
new file mode 100644
index 0000000..a772ae9
--- /dev/null
+++ b/erpnext/patches/v8_0/update_customer_pos_id.py
@@ -0,0 +1,9 @@
+# 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():
+	frappe.reload_doctype("Customer")
+	frappe.db.sql(""" update `tabCustomer` set customer_pos_id = name """)
\ No newline at end of file
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index dc1db35..1437ee9 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -606,7 +606,7 @@
 		this.frm.doc.change_amount = 0.0;
 		this.frm.doc.base_change_amount = 0.0;
 		if(this.frm.doc.paid_amount > this.frm.doc.grand_total && !this.frm.doc.is_return) {
-			var payment_types = $.map(cur_frm.doc.payments, function(d) { return d.type });
+			var payment_types = $.map(this.frm.doc.payments, function(d) { return d.type });
 			if (in_list(payment_types, 'Cash')) {
 				this.frm.doc.change_amount = flt(this.frm.doc.paid_amount - this.frm.doc.grand_total +
 					this.frm.doc.write_off_amount, precision("change_amount"));
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 6206b28..b508fcb 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -98,6 +98,13 @@
 
 			frm.cscript.calculate_taxes_and_totals();
 		});
+
+		var me = this;
+		if(this.frm.fields_dict["items"].grid.get_field('batch_no')) {
+			this.frm.set_query("batch_no", "items", function(doc, cdt, cdn) {
+				return me.set_query_for_batch(doc, cdt, cdn)
+			});
+		}
 	},
 	onload: function() {
 		var me = this;
@@ -1129,4 +1136,32 @@
 
 		return method
 	},
+
+	set_query_for_batch: function(doc, cdt, cdn) {
+		// Show item's batches in the dropdown of batch no
+
+		var me = this;
+		var item = frappe.get_doc(cdt, cdn);
+
+		if(!item.item_code) {
+			frappe.throw(__("Please enter Item Code to get batch no"));
+		} else if (doc.doctype == "Purchase Receipt" || 
+			(doc.doctype == "Purchase Invoice" && doc.update_stock)) {
+
+			return {
+				filters: {'item': item.item_code}
+			}
+		} else {
+			filters = {
+				'item_code': item.item_code,
+				'posting_date': me.frm.doc.posting_date || frappe.datetime.nowdate(),
+			}
+			if(item.warehouse) filters["warehouse"] = item.warehouse
+
+			return {
+				query : "erpnext.controllers.queries.get_batch_no",
+				filters: filters
+			}
+		}
+	},
 });
diff --git a/erpnext/public/js/pos/pos.html b/erpnext/public/js/pos/pos.html
index 6065e60..485a945 100644
--- a/erpnext/public/js/pos/pos.html
+++ b/erpnext/public/js/pos/pos.html
@@ -73,7 +73,7 @@
 						{% for(var j=i*3; j
 						<(i+1)*3; j++) { %} <button type="button" class="btn btn-default numeric-keypad" val="{{j+1}}">{{j+1}}</button>
 							{% } %}
-							<button type="button" id="pos-item-{{ chartData[i].toLowerCase() }}" class="btn text-center btn-default numeric-keypad pos-operation">{{ __(chartData[i]) }}</button>
+							<button type="button" {% if(!allow_user_to_edit_rate && chartData[i] == __("Price")) { %} disabled {% } %} id="pos-item-{{ chartData[i].toLowerCase() }}" class="btn text-center btn-default numeric-keypad pos-operation">{{ __(chartData[i]) }}</button>
 				</div>
 				{% } %}
 				<div class="row text-right">
diff --git a/erpnext/public/js/pos/pos_selected_item.html b/erpnext/public/js/pos/pos_selected_item.html
index a4bc49d..64f8c16 100644
--- a/erpnext/public/js/pos/pos_selected_item.html
+++ b/erpnext/public/js/pos/pos_selected_item.html
@@ -13,7 +13,7 @@
 	</div>
 	<div class="pos-list-row">
 		<div class="cell">{{ __("Price") }}:</div>
-		<input type="tel" class="form-control cell pos-item-price" value="{%= rate %}"/>
+		<input type="tel" class="form-control cell pos-item-price" {% if !allow_user_to_edit_rate %} disabled {% endif %} value="{%= rate %}"/>
 	</div> 
 	<div class="pos-list-row">
 		<div class="cell">{{ __("Amount") }}:</div>
diff --git a/erpnext/schools/doctype/assessment_plan/assessment_plan.js b/erpnext/schools/doctype/assessment_plan/assessment_plan.js
index 3c9ab80..abdb0c8 100644
--- a/erpnext/schools/doctype/assessment_plan/assessment_plan.js
+++ b/erpnext/schools/doctype/assessment_plan/assessment_plan.js
@@ -6,7 +6,17 @@
 cur_frm.add_fetch("supervisor", "instructor_name", "supervisor_name");
 
 frappe.ui.form.on("Assessment Plan", {
-        refresh: function(frm) {
+    onload: function(frm) {
+        frm.set_query("assessment_group", function(doc, cdt, cdn) {
+            return{
+                filters: {
+                    'is_group': 0
+                }
+            }
+        });
+    },
+
+    refresh: function(frm) {
         if (frm.doc.docstatus == 1) {
             frm.add_custom_button(__("Assessment Result"), function() {
                 frappe.route_options = {
diff --git a/erpnext/schools/doctype/assessment_plan/assessment_plan.json b/erpnext/schools/doctype/assessment_plan/assessment_plan.json
index 697a0d4..e2ac321 100644
--- a/erpnext/schools/doctype/assessment_plan/assessment_plan.json
+++ b/erpnext/schools/doctype/assessment_plan/assessment_plan.json
@@ -3,7 +3,7 @@
  "allow_guest_to_view": 0, 
  "allow_import": 1, 
  "allow_rename": 0, 
- "autoname": "field:assessment_name", 
+ "autoname": "ASP.#####", 
  "beta": 0, 
  "creation": "2015-11-12 16:34:34.658092", 
  "custom": 0, 
@@ -38,7 +38,7 @@
    "read_only": 0, 
    "remember_last_selected_value": 0, 
    "report_hide": 0, 
-   "reqd": 1, 
+   "reqd": 0, 
    "search_index": 0, 
    "set_only_once": 0, 
    "unique": 0
@@ -633,7 +633,7 @@
  "istable": 0, 
  "max_attachments": 0, 
  "menu_index": 0, 
- "modified": "2017-05-02 12:54:11.991616", 
+ "modified": "2017-06-05 23:40:30.434741", 
  "modified_by": "Administrator", 
  "module": "Schools", 
  "name": "Assessment Plan", 
@@ -667,6 +667,7 @@
  "show_name_in_global_search": 0, 
  "sort_field": "modified", 
  "sort_order": "DESC", 
+ "title_field": "assessment_name", 
  "track_changes": 0, 
  "track_seen": 0
 }
\ No newline at end of file
diff --git a/erpnext/schools/doctype/assessment_plan/assessment_plan.py b/erpnext/schools/doctype/assessment_plan/assessment_plan.py
index 7f83c01..f988886 100644
--- a/erpnext/schools/doctype/assessment_plan/assessment_plan.py
+++ b/erpnext/schools/doctype/assessment_plan/assessment_plan.py
@@ -36,4 +36,4 @@
 		for d in self.assessment_criteria:
 			max_score += d.maximum_score
 		if self.maximum_assessment_score != max_score:
-			frappe.throw(_("Sum of Scores of Assessment Criteria needs to be {0}.".format(self.maximum_assessment_score)))
\ No newline at end of file
+			frappe.throw(_("Sum of Scores of Assessment Criteria needs to be {0}.".format(self.maximum_assessment_score)))
diff --git a/erpnext/schools/doctype/program_enrollment/program_enrollment.json b/erpnext/schools/doctype/program_enrollment/program_enrollment.json
index a07b3ee..f2bc416 100644
--- a/erpnext/schools/doctype/program_enrollment/program_enrollment.json
+++ b/erpnext/schools/doctype/program_enrollment/program_enrollment.json
@@ -325,8 +325,129 @@
    "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
+   "collapsible": 1, 
+   "collapsible_depends_on": "vehicle_no", 
+   "columns": 0, 
+   "fieldname": "transportation", 
+   "fieldtype": "Section Break", 
+   "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": "Transportation", 
+   "length": 0, 
+   "no_copy": 0, 
+   "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_bulk_edit": 0, 
+   "allow_on_submit": 1, 
+   "bold": 0, 
    "collapsible": 0, 
    "columns": 0, 
+   "fieldname": "mode_of_transportation", 
+   "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": "Mode of Transportation", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "\nSchool Bus\nPublic Transport\nSelf-Driving Vehicle\nPick/Drop by Guardian", 
+   "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_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "column_break_13", 
+   "fieldtype": "Column Break", 
+   "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, 
+   "length": 0, 
+   "no_copy": 0, 
+   "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_bulk_edit": 0, 
+   "allow_on_submit": 1, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "vehicle_no", 
+   "fieldtype": "Data", 
+   "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": "Vehicle/Bus Number", 
+   "length": 0, 
+   "no_copy": 0, 
+   "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_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 1, 
+   "columns": 0, 
    "fieldname": "enrolled_courses", 
    "fieldtype": "Section Break", 
    "hidden": 0, 
@@ -416,7 +537,7 @@
    "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
-   "collapsible": 0, 
+   "collapsible": 1, 
    "columns": 0, 
    "fieldname": "section_break_7", 
    "fieldtype": "Section Break", 
@@ -547,7 +668,7 @@
  "istable": 0, 
  "max_attachments": 0, 
  "menu_index": 0, 
- "modified": "2017-04-24 18:22:43.567607", 
+ "modified": "2017-06-02 15:29:05.812335", 
  "modified_by": "Administrator", 
  "module": "Schools", 
  "name": "Program Enrollment", 
diff --git a/erpnext/schools/doctype/student_attendance_tool/student_attendance_tool.js b/erpnext/schools/doctype/student_attendance_tool/student_attendance_tool.js
index 6f8c6cd..8fe8f8c 100644
--- a/erpnext/schools/doctype/student_attendance_tool/student_attendance_tool.js
+++ b/erpnext/schools/doctype/student_attendance_tool/student_attendance_tool.js
@@ -3,6 +3,16 @@
 frappe.provide("schools")
 
 frappe.ui.form.on('Student Attendance Tool', {
+	onload: function(frm) {
+		frm.set_query("student_group", function() {
+			return {
+				"filters": {
+					"group_based_on": frm.doc.group_based_on
+				}
+			};
+		});
+	},
+
 	refresh: function(frm) {
 		frm.disable_save();
 	},
diff --git a/erpnext/schools/doctype/student_attendance_tool/student_attendance_tool.json b/erpnext/schools/doctype/student_attendance_tool/student_attendance_tool.json
index 291e027..265ac8c 100644
--- a/erpnext/schools/doctype/student_attendance_tool/student_attendance_tool.json
+++ b/erpnext/schools/doctype/student_attendance_tool/student_attendance_tool.json
@@ -50,6 +50,39 @@
    "bold": 0, 
    "collapsible": 0, 
    "columns": 0, 
+   "default": "Batch", 
+   "depends_on": "eval:doc.based_on == \"Student Group\"", 
+   "fieldname": "group_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": "Group Based On", 
+   "length": 0, 
+   "no_copy": 0, 
+   "options": "Batch\nCourse\nActivity", 
+   "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_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
    "fieldname": "column_break_2", 
    "fieldtype": "Column Break", 
    "hidden": 0, 
@@ -240,7 +273,7 @@
  "issingle": 1, 
  "istable": 0, 
  "max_attachments": 0, 
- "modified": "2017-05-01 15:09:55.740005", 
+ "modified": "2017-06-05 23:16:43.127216", 
  "modified_by": "Administrator", 
  "module": "Schools", 
  "name": "Student Attendance Tool", 
diff --git a/erpnext/schools/report/student_and_guardian_contact_details/student_and_guardian_contact_details.py b/erpnext/schools/report/student_and_guardian_contact_details/student_and_guardian_contact_details.py
index 2e59d61..f191022 100644
--- a/erpnext/schools/report/student_and_guardian_contact_details/student_and_guardian_contact_details.py
+++ b/erpnext/schools/report/student_and_guardian_contact_details/student_and_guardian_contact_details.py
@@ -22,13 +22,14 @@
 	if not student_list:
 		return  columns, []
 
+	group_roll_no_map = get_student_roll_no(academic_year, program, student_batch_name)
 	student_map = get_student_details(student_list)
 	guardian_map = get_guardian_map(student_list)
 
 	for d in program_enrollments:
 		student_details = student_map.get(d.student)
-		row = [d.student, d.student_name, student_details.get("student_mobile_number"), student_details.get("student_email_id"),
-				student_details.get("address")]
+		row = [group_roll_no_map.get(d.student), d.student, d.student_name, student_details.get("student_mobile_number"),\
+				student_details.get("student_email_id"), student_details.get("address")]
 
 		student_guardians = guardian_map.get(d.student)
 
@@ -44,7 +45,8 @@
 
 
 def get_columns():
-	columns = [ 
+	columns = [
+		_(" Group Roll No") + "::60",  
 		_("Student ID") + ":Link/Student:90", 
 		_("Student Name") + "::150", 
 		_("Student Mobile No.") + "::110",
@@ -93,4 +95,13 @@
 		guardian["email_address"] = guardian_email_id.get(guardian.guardian)
 		guardian_map.setdefault(guardian.parent, []).append(guardian)
 
-	return guardian_map
\ No newline at end of file
+	return guardian_map
+
+def get_student_roll_no(academic_year, program, batch):
+	student_group = frappe.get_all("Student Group",
+		filters={"academic_year":academic_year, "program":program, "batch":batch})
+	if student_group:
+		roll_no_dict = dict(frappe.db.sql('''select student, group_roll_number from `tabStudent Group Student` where parent=%s''',
+			(student_group[0].name)))
+		return roll_no_dict
+	return {}
diff --git a/erpnext/selling/doctype/customer/customer.json b/erpnext/selling/doctype/customer/customer.json
index 4ae4738..8157013 100644
--- a/erpnext/selling/doctype/customer/customer.json
+++ b/erpnext/selling/doctype/customer/customer.json
@@ -1,5 +1,6 @@
 {
  "allow_copy": 0, 
+ "allow_guest_to_view": 0, 
  "allow_import": 1, 
  "allow_rename": 1, 
  "autoname": "naming_series:", 
@@ -14,6 +15,7 @@
  "engine": "InnoDB", 
  "fields": [
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -44,6 +46,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -73,6 +76,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 1, 
    "collapsible": 0, 
@@ -103,6 +107,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -134,6 +139,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -165,6 +171,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -194,6 +201,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -222,6 +230,7 @@
    "width": "50%"
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -254,6 +263,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -286,6 +296,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -315,6 +326,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -345,6 +357,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 1, 
@@ -374,6 +387,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -403,6 +417,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -432,6 +447,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -460,6 +476,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -490,6 +507,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -520,6 +538,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -548,6 +567,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -576,6 +596,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -604,6 +625,7 @@
    "width": "50%"
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -633,6 +655,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 1, 
@@ -662,6 +685,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -693,6 +717,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 1, 
@@ -723,6 +748,7 @@
    "width": "50%"
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -753,6 +779,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -784,6 +811,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -815,6 +843,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 1, 
@@ -846,6 +875,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -877,6 +907,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -906,6 +937,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 1, 
@@ -937,6 +969,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -968,6 +1001,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -998,6 +1032,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 1, 
@@ -1028,6 +1063,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -1057,8 +1093,39 @@
    "search_index": 0, 
    "set_only_once": 0, 
    "unique": 0
+  }, 
+  {
+   "allow_bulk_edit": 0, 
+   "allow_on_submit": 0, 
+   "bold": 0, 
+   "collapsible": 0, 
+   "columns": 0, 
+   "fieldname": "customer_pos_id", 
+   "fieldtype": "Data", 
+   "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": "Customer POS id", 
+   "length": 0, 
+   "no_copy": 1, 
+   "permlevel": 0, 
+   "precision": "", 
+   "print_hide": 1, 
+   "print_hide_if_no_value": 0, 
+   "read_only": 1, 
+   "remember_last_selected_value": 0, 
+   "report_hide": 1, 
+   "reqd": 0, 
+   "search_index": 0, 
+   "set_only_once": 0, 
+   "unique": 0
   }
  ], 
+ "has_web_view": 0, 
  "hide_heading": 0, 
  "hide_toolbar": 0, 
  "icon": "fa fa-user", 
@@ -1066,12 +1133,11 @@
  "image_field": "image", 
  "image_view": 0, 
  "in_create": 0, 
- "in_dialog": 0, 
  "is_submittable": 0, 
  "issingle": 0, 
  "istable": 0, 
  "max_attachments": 0, 
- "modified": "2017-02-20 13:21:53.659049", 
+ "modified": "2017-06-05 13:58:19.258783", 
  "modified_by": "Administrator", 
  "module": "Selling", 
  "name": "Customer", 
diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js
index 1fcf334..6233f05 100644
--- a/erpnext/selling/sales_common.js
+++ b/erpnext/selling/sales_common.js
@@ -73,34 +73,6 @@
 				return me.set_query_for_batch(doc, cdt, cdn)
 			});
 		}
-
-		if(this.frm.fields_dict["items"].grid.get_field('batch_no')) {
-			this.frm.set_query("batch_no", "items", function(doc, cdt, cdn) {
-				return me.set_query_for_batch(doc, cdt, cdn)
-			});
-		}
-	},
-
-	set_query_for_batch: function(doc, cdt, cdn) {
-		// Show item's batches in the dropdown of batch no
-
-		var me = this;
-		var item = frappe.get_doc(cdt, cdn);
-
-		if(!item.item_code) {
-			frappe.throw(__("Please enter Item Code to get batch no"));
-		} else {
-			filters = {
-				'item_code': item.item_code,
-				'posting_date': me.frm.doc.posting_date || frappe.datetime.nowdate(),
-			}
-			if(item.warehouse) filters["warehouse"] = item.warehouse
-
-			return {
-				query : "erpnext.controllers.queries.get_batch_no",
-				filters: filters
-			}
-		}
 	},
 
 	refresh: function() {
diff --git a/erpnext/stock/doctype/material_request/material_request.json b/erpnext/stock/doctype/material_request/material_request.json
index 2ab0907..fc174a4 100644
--- a/erpnext/stock/doctype/material_request/material_request.json
+++ b/erpnext/stock/doctype/material_request/material_request.json
@@ -1,5 +1,6 @@
 {
  "allow_copy": 0, 
+ "allow_guest_to_view": 0, 
  "allow_import": 1, 
  "allow_rename": 0, 
  "autoname": "naming_series:", 
@@ -12,6 +13,7 @@
  "editable_grid": 0, 
  "fields": [
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -41,6 +43,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 1, 
    "bold": 0, 
    "collapsible": 0, 
@@ -71,6 +74,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -100,6 +104,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -127,6 +132,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -158,6 +164,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -191,6 +198,7 @@
    "width": "150px"
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -225,6 +233,7 @@
    "width": "150px"
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -255,6 +264,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -286,6 +296,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 1, 
@@ -316,6 +327,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -344,6 +356,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -377,6 +390,7 @@
    "width": "100px"
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -407,6 +421,7 @@
    "width": "50%"
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -425,7 +440,7 @@
    "no_copy": 1, 
    "oldfieldname": "status", 
    "oldfieldtype": "Select", 
-   "options": "\nDraft\nSubmitted\nStopped\nCancelled", 
+   "options": "\nDraft\nSubmitted\nStopped\nCancelled\nPending\nPartially Ordered\nOrdered\nIssued\nTransferred", 
    "permlevel": 0, 
    "print_hide": 1, 
    "print_hide_if_no_value": 0, 
@@ -440,6 +455,7 @@
    "width": "100px"
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -471,6 +487,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 1, 
@@ -500,6 +517,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 1, 
    "bold": 0, 
    "collapsible": 0, 
@@ -531,6 +549,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 1, 
    "bold": 0, 
    "collapsible": 0, 
@@ -560,6 +579,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 1, 
@@ -591,6 +611,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -622,6 +643,7 @@
    "unique": 0
   }, 
   {
+   "allow_bulk_edit": 0, 
    "allow_on_submit": 0, 
    "bold": 0, 
    "collapsible": 0, 
@@ -652,19 +674,19 @@
    "unique": 0
   }
  ], 
+ "has_web_view": 0, 
  "hide_heading": 0, 
  "hide_toolbar": 0, 
  "icon": "fa fa-ticket", 
  "idx": 70, 
  "image_view": 0, 
  "in_create": 0, 
- "in_dialog": 0, 
  "is_submittable": 1, 
  "issingle": 0, 
  "istable": 0, 
  "max_attachments": 0, 
  "menu_index": 0, 
- "modified": "2017-02-20 13:29:56.743544", 
+ "modified": "2017-05-31 15:06:44.611826", 
  "modified_by": "Administrator", 
  "module": "Stock", 
  "name": "Material Request", 
diff --git a/erpnext/stock/doctype/material_request/material_request.py b/erpnext/stock/doctype/material_request/material_request.py
index 82c4c19..65263a0 100644
--- a/erpnext/stock/doctype/material_request/material_request.py
+++ b/erpnext/stock/doctype/material_request/material_request.py
@@ -70,7 +70,9 @@
 			self.status = "Draft"
 
 		from erpnext.controllers.status_updater import validate_status
-		validate_status(self.status, ["Draft", "Submitted", "Stopped", "Cancelled"])
+		validate_status(self.status, ["Draft", "Submitted", "Stopped", "Cancelled", "Pending",
+										"Partially Ordered", "Ordered", "Issued", "Transferred"]
+						)
 
 		validate_for_items(self)
 
@@ -91,9 +93,20 @@
 		self.title = ', '.join(items)
 
 	def on_submit(self):
-		frappe.db.set(self, 'status', 'Submitted')
+		# frappe.db.set(self, 'status', 'Submitted')
 		self.update_requested_qty()
 
+	def before_save(self):
+		self.set_status(update=True)
+
+	def before_submit(self):
+		self.set_status(update=True)
+
+	def before_cancel(self):
+		# if MRQ is already closed, no point saving the document
+		check_for_closed_status(self.doctype, self.name)
+		self.set_status(update=True, status='Cancelled')
+
 	def check_modified_date(self):
 		mod_db = frappe.db.sql("""select modified from `tabMaterial Request` where name = %s""",
 			self.name)
@@ -105,16 +118,36 @@
 
 	def update_status(self, status):
 		self.check_modified_date()
-		frappe.db.set(self, 'status', cstr(status))
+		self.status_can_change(status)
+		self.set_status(update=True, status=status)
 		self.update_requested_qty()
 
+	def status_can_change(self, status):
+		"""
+		validates that `status` is acceptable for the present controller status
+		and throws an Exception if otherwise.
+		"""
+		if self.status and self.status == 'Cancelled':
+			# cancelled documents cannot change
+			if status != self.status:
+				frappe.throw(
+					_("{0} {1} is cancelled so the action cannot be completed").
+						format(_(self.doctype), self.name),
+					frappe.InvalidStatusError
+				)
+
+		elif self.status and self.status == 'Draft':
+			# draft document to pending only
+			if status != 'Pending':
+				frappe.throw(
+					_("{0} {1} has not been submitted so the action cannot be completed").
+						format(_(self.doctype), self.name),
+					frappe.InvalidStatusError
+				)
+
 	def on_cancel(self):
-		check_for_closed_status(self.doctype, self.name)
-
 		self.update_requested_qty()
 
-		frappe.db.set(self,'status','Cancelled')
-
 	def update_completed_qty(self, mr_items=None, update_modified=True):
 		if self.material_request_type == "Purchase":
 			return
diff --git a/erpnext/stock/doctype/material_request/test_material_request.py b/erpnext/stock/doctype/material_request/test_material_request.py
index 8f43acd..c3a2137 100644
--- a/erpnext/stock/doctype/material_request/test_material_request.py
+++ b/erpnext/stock/doctype/material_request/test_material_request.py
@@ -98,6 +98,94 @@
 		se.insert()
 		se.submit()
 
+	def test_cannot_stop_cancelled_material_request(self):
+		mr = frappe.copy_doc(test_records[0])
+		mr.insert()
+		mr.submit()
+
+		mr.load_from_db()
+		mr.cancel()
+		self.assertRaises(frappe.ValidationError, mr.update_status, 'Stopped')
+
+	def test_mr_changes_from_stopped_to_pending_after_reopen(self):
+		mr = frappe.copy_doc(test_records[0])
+		mr.insert()
+		mr.submit()
+		self.assertEqual('Pending', mr.status)
+
+		mr.update_status('Stopped')
+		self.assertEqual('Stopped', mr.status)
+
+		mr.update_status('Submitted')
+		self.assertEqual('Pending', mr.status)
+
+	def test_cannot_submit_cancelled_mr(self):
+		mr = frappe.copy_doc(test_records[0])
+		mr.insert()
+		mr.submit()
+		mr.load_from_db()
+		mr.cancel()
+		self.assertRaises(frappe.ValidationError, mr.submit)
+
+	def test_mr_changes_from_pending_to_cancelled_after_cancel(self):
+		mr = frappe.copy_doc(test_records[0])
+		mr.insert()
+		mr.submit()
+		mr.cancel()
+		self.assertEqual('Cancelled', mr.status)
+
+	def test_cannot_change_cancelled_mr(self):
+		mr = frappe.copy_doc(test_records[0])
+		mr.insert()
+		mr.submit()
+		mr.load_from_db()
+		mr.cancel()
+
+		self.assertRaises(frappe.InvalidStatusError, mr.update_status, 'Draft')
+		self.assertRaises(frappe.InvalidStatusError, mr.update_status, 'Stopped')
+		self.assertRaises(frappe.InvalidStatusError, mr.update_status, 'Ordered')
+		self.assertRaises(frappe.InvalidStatusError, mr.update_status, 'Issued')
+		self.assertRaises(frappe.InvalidStatusError, mr.update_status, 'Transferred')
+		self.assertRaises(frappe.InvalidStatusError, mr.update_status, 'Pending')
+
+	def test_cannot_submit_deleted_material_request(self):
+		mr = frappe.copy_doc(test_records[0])
+		mr.insert()
+		mr.delete()
+
+		self.assertRaises(frappe.ValidationError, mr.submit)
+
+	def test_cannot_delete_submitted_mr(self):
+		mr = frappe.copy_doc(test_records[0])
+		mr.insert()
+		mr.submit()
+
+		self.assertRaises(frappe.ValidationError, mr.delete)
+
+	def test_stopped_mr_changes_to_pending_after_reopen(self):
+		mr = frappe.copy_doc(test_records[0])
+		mr.insert()
+		mr.submit()
+		mr.load_from_db()
+
+		mr.update_status('Stopped')
+		mr.update_status('Submitted')
+		self.assertEqual(mr.status, 'Pending')
+
+	def test_pending_mr_changes_to_stopped_after_stop(self):
+		mr = frappe.copy_doc(test_records[0])
+		mr.insert()
+		mr.submit()
+		mr.load_from_db()
+
+		mr.update_status('Stopped')
+		self.assertEqual(mr.status, 'Stopped')
+
+	def test_cannot_stop_unsubmitted_mr(self):
+		mr = frappe.copy_doc(test_records[0])
+		mr.insert()
+		self.assertRaises(frappe.InvalidStatusError, mr.update_status, 'Stopped')
+
 	def test_completed_qty_for_purchase(self):
 		existing_requested_qty_item1 = self._get_requested_qty("_Test Item Home Desktop 100", "_Test Warehouse - _TC")
 		existing_requested_qty_item2 = self._get_requested_qty("_Test Item Home Desktop 200", "_Test Warehouse - _TC")
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
index 5c97e7c..b4cfcaa 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.js
@@ -145,17 +145,6 @@
 	}
 }
 
-cur_frm.fields_dict['items'].grid.get_field('batch_no').get_query= function(doc, cdt, cdn) {
-	var d = locals[cdt][cdn];
-	if(d.item_code) {
-		return {
-			filters: {'item': d.item_code}
-		}
-	}
-	else
-		msgprint(__("Please enter Item Code."));
-}
-
 cur_frm.cscript.select_print_heading = function(doc, cdt, cdn) {
 	if(doc.select_print_heading)
 		cur_frm.pformat.print_heading = doc.select_print_heading;
diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py
index 03d4d73..8420c9b 100644
--- a/erpnext/stock/doctype/serial_no/serial_no.py
+++ b/erpnext/stock/doctype/serial_no/serial_no.py
@@ -160,7 +160,7 @@
 	def after_rename(self, old, new, merge=False):
 		"""rename serial_no text fields"""
 		for dt in frappe.db.sql("""select parent from tabDocField
-			where fieldname='serial_no' and fieldtype='Text'"""):
+			where fieldname='serial_no' and fieldtype in ('Text', 'Small Text')"""):
 
 			for item in frappe.db.sql("""select name, serial_no from `tab%s`
 				where serial_no like '%%%s%%'""" % (dt[0], frappe.db.escape(old))):