Ported v3 fixes to v4

Commit range: webnotes/erpnext@e4b72df2f4bd7272c42e90f6faec3c27aa763b82..webnotes/erpnext@85441b0180f84246259d5a0ab4e3bcbf29355efe
diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py
index 502a484..fb44694 100644
--- a/erpnext/accounts/doctype/account/account.py
+++ b/erpnext/accounts/doctype/account/account.py
@@ -3,7 +3,7 @@
 
 from __future__ import unicode_literals
 import frappe
-from frappe.utils import flt, cstr, cint
+from frappe.utils import flt, cstr, cint, getdate, add_days, formatdate
 from frappe import msgprint, throw, _
 from frappe.model.document import Document
 
@@ -151,6 +151,27 @@
 				and not self.get_authorized_user():
 			throw(_("{0} Credit limit {0} crossed").format(_(credit_limit_from), credit_limit))
 
+	def validate_due_date(self, posting_date, due_date):
+		credit_days = (self.credit_days or frappe.db.get_value("Company", self.company, "credit_days"))
+		if credit_days is None:
+			return
+
+		posting_date, due_date = getdate(posting_date), getdate(due_date)
+		diff = (due_date - posting_date).days
+
+		if diff < 0:
+			frappe.throw(_("Due Date cannot be before Posting Date"))
+		elif diff > credit_days:
+			is_credit_controller = frappe.db.get_value("Accounts Settings", None,
+				"credit_controller") in frappe.user.get_roles()
+
+			if is_credit_controller:
+				msgprint(_("Note: Due Date exceeds the allowed credit days by {0} day(s)").format(
+					diff - credit_days))
+			else:
+				max_due_date = formatdate(add_days(posting_date, credit_days))
+				frappe.throw(_("Due Date cannot be after {0}").format(max_due_date))
+
 	def validate_trash(self):
 		"""checks gl entries and if child exists"""
 		if not self.parent_account:
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py
index 93d1ae3..2390e77 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py
@@ -25,8 +25,7 @@
 		validate_balance_type(self.account, adv_adj)
 
 		# Update outstanding amt on against voucher
-		if self.against_voucher and self.against_voucher_type != "POS" \
-			and update_outstanding == 'Yes':
+		if self.against_voucher and update_outstanding == 'Yes':
 				update_outstanding_amt(self.account, self.against_voucher_type,
 					self.against_voucher)
 
diff --git a/erpnext/accounts/doctype/journal_voucher/journal_voucher.py b/erpnext/accounts/doctype/journal_voucher/journal_voucher.py
index 223be3c..94882e2 100644
--- a/erpnext/accounts/doctype/journal_voucher/journal_voucher.py
+++ b/erpnext/accounts/doctype/journal_voucher/journal_voucher.py
@@ -212,7 +212,7 @@
 			self.is_approving_authority = 0
 
 			# Fetch credit controller role
-			approving_authority = frappe.db.get_value("Global Defaults", None,
+			approving_authority = frappe.db.get_value("Accounts Settings", None,
 				"credit_controller")
 
 			# Check logged-in user is authorized
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 36514ff..b9dda02 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -50,6 +50,7 @@
 		self.validate_with_previous_doc()
 		self.validate_uom_is_integer("uom", "qty")
 		self.set_aging_date()
+		frappe.get_doc("Account", self.credit_to).validate_due_date(self.posting_date, self.due_date)
 		self.set_against_expense_account()
 		self.validate_write_off_account()
 		self.update_valuation_rate("entries")
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index c4ef3e7..ca73518 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -138,7 +138,7 @@
 		wrapper.load_from_db()
 
 		expected_values = [
-			["_Test FG Item", 90, 7059],
+			["_Test FG Item", 90, 59],
 			["_Test Item Home Desktop 200", 135, 177]
 		]
 		for i, item in enumerate(wrapper.get("entries")):
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index eeb2425..fcb4728 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -23,7 +23,7 @@
 			// show debit_to in print format
 			this.frm.set_df_property("debit_to", "print_hide", 0);
 		}
-		
+
 		// toggle to pos view if is_pos is 1 in user_defaults
 		if ((cint(frappe.defaults.get_user_defaults("is_pos"))===1 || this.frm.doc.is_pos)) {
 			if(this.frm.doc.__islocal && !this.frm.doc.amended_from && !this.frm.doc.customer) {
@@ -34,14 +34,14 @@
 				});
 			}
 		}
-		
+
 		// if document is POS then change default print format to "POS Invoice"
 		if(cur_frm.doc.is_pos && cur_frm.doc.docstatus===1) {
 			locals.DocType[cur_frm.doctype].default_print_format = "POS Invoice";
 			cur_frm.setup_print_layout();
 		}
 	},
-	
+
 	refresh: function(doc, dt, dn) {
 		this._super();
 
@@ -59,7 +59,7 @@
 				};
 				frappe.set_route("query-report", "General Ledger");
 			}, "icon-table");
-			
+
 			var percent_paid = cint(flt(doc.grand_total - doc.outstanding_amount) / flt(doc.grand_total) * 100);
 			cur_frm.dashboard.add_progress(percent_paid + "% Paid", percent_paid);
 
@@ -69,10 +69,10 @@
 				// show Make Delivery Note button only if Sales Invoice is not created from Delivery Note
 				var from_delivery_note = false;
 				from_delivery_note = cur_frm.doc.entries
-					.some(function(item) { 
-						return item.delivery_note ? true : false; 
+					.some(function(item) {
+						return item.delivery_note ? true : false;
 					});
-				
+
 				if(!from_delivery_note)
 					cur_frm.appframe.add_primary_action(__('Make Delivery'), cur_frm.cscript['Make Delivery Note'])
 			}
@@ -89,7 +89,7 @@
 	},
 
 	sales_order_btn: function() {
-		this.$sales_order_btn = cur_frm.appframe.add_primary_action(__('From Sales Order'), 
+		this.$sales_order_btn = cur_frm.appframe.add_primary_action(__('From Sales Order'),
 			function() {
 				frappe.model.map_current_doc({
 					method: "erpnext.selling.doctype.sales_order.sales_order.make_sales_invoice",
@@ -106,7 +106,7 @@
 	},
 
 	delivery_note_btn: function() {
-		this.$delivery_note_btn = cur_frm.appframe.add_primary_action(__('From Delivery Note'), 
+		this.$delivery_note_btn = cur_frm.appframe.add_primary_action(__('From Delivery Note'),
 			function() {
 				frappe.model.map_current_doc({
 					method: "erpnext.stock.doctype.delivery_note.delivery_note.make_sales_invoice",
@@ -124,11 +124,11 @@
 				});
 			});
 	},
-	
+
 	tc_name: function() {
 		this.get_terms();
 	},
-	
+
 	is_pos: function(callback_fn) {
 		cur_frm.cscript.hide_fields(this.frm.doc);
 		if(cint(this.frm.doc.is_pos)) {
@@ -146,7 +146,7 @@
 							me.set_default_values();
 							me.set_dynamic_labels();
 							me.calculate_taxes_and_totals();
-							
+
 							if(callback_fn) callback_fn();
 						}
 					}
@@ -154,11 +154,11 @@
 			}
 		}
 	},
-	
+
 	customer: function() {
 		if(this.frm.updating_party_details)
 			return;
-		erpnext.utils.get_party_details(this.frm, 
+		erpnext.utils.get_party_details(this.frm,
 			"erpnext.accounts.party.get_party_details", {
 				posting_date: this.frm.doc.posting_date,
 				party: this.frm.doc.customer,
@@ -167,42 +167,42 @@
 				price_list: this.frm.doc.selling_price_list,
 			})
 	},
-	
+
 	debit_to: function() {
 		this.customer();
 	},
-	
+
 	allocated_amount: function() {
 		this.calculate_total_advance("Sales Invoice", "advance_adjustment_details");
 		this.frm.refresh_fields();
 	},
-	
+
 	write_off_outstanding_amount_automatically: function() {
 		if(cint(this.frm.doc.write_off_outstanding_amount_automatically)) {
 			frappe.model.round_floats_in(this.frm.doc, ["grand_total", "paid_amount"]);
 			// this will make outstanding amount 0
-			this.frm.set_value("write_off_amount", 
-				flt(this.frm.doc.grand_total - this.frm.doc.paid_amount), 
+			this.frm.set_value("write_off_amount",
+				flt(this.frm.doc.grand_total - this.frm.doc.paid_amount),
 				precision("write_off_amount"));
 		}
-		
-		this.calculate_outstanding_amount();
+
+		this.calculate_outstanding_amount(false);
 		this.frm.refresh_fields();
 	},
-	
+
 	write_off_amount: function() {
 		this.write_off_outstanding_amount_automatically();
 	},
-	
+
 	paid_amount: function() {
 		this.write_off_outstanding_amount_automatically();
 	},
-	
+
 	entries_add: function(doc, cdt, cdn) {
 		var row = frappe.get_doc(cdt, cdn);
 		this.frm.script_manager.copy_from_first_row("entries", row, ["income_account", "cost_center"]);
 	},
-	
+
 	set_dynamic_labels: function() {
 		this._super();
 		this.hide_fields(this.frm.doc);
@@ -224,9 +224,9 @@
 	'gross_profit_percent', 'get_advances_received',
 	'advance_adjustment_details', 'sales_partner', 'commission_rate',
 	'total_commission', 'advances'];
-	
+
 	item_flds_normal = ['sales_order', 'delivery_note']
-	
+
 	if(cint(doc.is_pos) == 1) {
 		hide_field(par_flds);
 		unhide_field('payments_section');
@@ -239,15 +239,15 @@
 		}
 		cur_frm.fields_dict['entries'].grid.set_column_disp(item_flds_normal, true);
 	}
-	
+
 	item_flds_stock = ['serial_no', 'batch_no', 'actual_qty', 'expense_account', 'warehouse']
 	cur_frm.fields_dict['entries'].grid.set_column_disp(item_flds_stock,
 		(cint(doc.update_stock)==1 ? true : false));
-	
+
 	// India related fields
 	if (frappe.boot.sysdefaults.country == 'India') unhide_field(['c_form_applicable', 'c_form_no']);
 	else hide_field(['c_form_applicable', 'c_form_no']);
-	
+
 	cur_frm.refresh_fields();
 }
 
@@ -305,7 +305,7 @@
 			'group_or_ledger': 'Ledger',
 			'company': doc.company
 		}
-	}	
+	}
 }
 
 cur_frm.fields_dict.write_off_account.get_query = function(doc) {
@@ -326,7 +326,7 @@
 			'group_or_ledger': 'Ledger',
 			'company': doc.company
 		}
-	}	
+	}
 }
 
 //project name
@@ -335,7 +335,7 @@
 	return{
 		query: "erpnext.controllers.queries.get_project_name",
 		filters: {'customer': doc.customer}
-	}	
+	}
 }
 
 // Income Account in Details Table
@@ -365,10 +365,10 @@
 // -----------------------------
 cur_frm.fields_dict["entries"].grid.get_field("cost_center").get_query = function(doc) {
 	return {
-		filters: { 
+		filters: {
 			'company': doc.company,
 			'group_or_ledger': 'Ledger'
-		}	
+		}
 	}
 }
 
@@ -396,12 +396,12 @@
 		var owner_email = doc.owner=="Administrator"
 			? frappe.user_info("Administrator").email
 			: doc.owner;
-		
+
 		doc.notification_email_address = $.map([cstr(owner_email),
 			cstr(doc.contact_email)], function(v) { return v || null; }).join(", ");
 		doc.repeat_on_day_of_month = frappe.datetime.str_to_obj(doc.posting_date).getDate();
 	}
-		
+
 	refresh_many(["notification_email_address", "repeat_on_day_of_month"]);
 }
 
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 5d42459..514f719 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -65,6 +65,7 @@
 			self.is_opening = 'No'
 
 		self.set_aging_date()
+		frappe.get_doc("Account", self.debit_to).validate_due_date(self.posting_date, self.due_date)
 		self.set_against_income_account()
 		self.validate_c_form()
 		self.validate_time_logs_are_submitted()
@@ -464,6 +465,10 @@
 			make_gl_entries(gl_entries, cancel=(self.docstatus == 2),
 				update_outstanding=update_outstanding, merge_entries=False)
 
+			if update_outstanding == "No":
+				from erpnext.accounts.doctype.gl_entry.gl_entry import update_outstanding_amt
+				update_outstanding_amt(self.debit_to, self.doctype, self.name)
+
 			if repost_future_gle and cint(self.update_stock) \
 				and cint(frappe.defaults.get_global_default("auto_accounting_for_stock")):
 					items, warehouse_account = self.get_items_and_warehouse_accounts()
diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py
index d321d00..25ea78f 100644
--- a/erpnext/accounts/general_ledger.py
+++ b/erpnext/accounts/general_ledger.py
@@ -10,7 +10,7 @@
 
 class StockAccountInvalidTransaction(frappe.ValidationError): pass
 
-def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True, 
+def make_gl_entries(gl_map, cancel=False, adv_adj=False, merge_entries=True,
 		update_outstanding='Yes'):
 	if gl_map:
 		if not cancel:
@@ -18,11 +18,11 @@
 			save_entries(gl_map, adv_adj, update_outstanding)
 		else:
 			delete_gl_entries(gl_map, adv_adj=adv_adj, update_outstanding=update_outstanding)
-		
+
 def process_gl_map(gl_map, merge_entries=True):
 	if merge_entries:
 		gl_map = merge_similar_entries(gl_map)
-	
+
 	for entry in gl_map:
 		# toggle debit, credit if negative entry
 		if flt(entry.debit) < 0:
@@ -33,11 +33,11 @@
 			entry.credit = 0.0
 
 	return gl_map
-		
+
 def merge_similar_entries(gl_map):
 	merged_gl_map = []
 	for entry in gl_map:
-		# if there is already an entry in this account then just add it 
+		# if there is already an entry in this account then just add it
 		# to that entry
 		same_head = check_if_in_list(entry, merged_gl_map)
 		if same_head:
@@ -45,7 +45,7 @@
 			same_head.credit = flt(same_head.credit) + flt(entry.credit)
 		else:
 			merged_gl_map.append(entry)
-			 
+
 	# filter zero debit and credit entries
 	merged_gl_map = filter(lambda x: flt(x.debit)!=0 or flt(x.credit)!=0, merged_gl_map)
 	return merged_gl_map
@@ -61,20 +61,20 @@
 
 def save_entries(gl_map, adv_adj, update_outstanding):
 	validate_account_for_auto_accounting_for_stock(gl_map)
-	
+
 	total_debit = total_credit = 0.0
 	for entry in gl_map:
 		make_entry(entry, adv_adj, update_outstanding)
 		# check against budget
 		validate_expense_against_budget(entry)
-		
+
 
 		# update total debit / credit
 		total_debit += flt(entry.debit)
 		total_credit += flt(entry.credit)
-		
+
 	validate_total_debit_credit(total_debit, total_credit)
-	
+
 def make_entry(args, adv_adj, update_outstanding):
 	args.update({"doctype": "GL Entry"})
 	gle = frappe.get_doc(args)
@@ -82,45 +82,44 @@
 	gle.insert()
 	gle.run_method("on_update_with_args", adv_adj, update_outstanding)
 	gle.submit()
-	
+
 def validate_total_debit_credit(total_debit, total_credit):
 	if abs(total_debit - total_credit) > 0.005:
 		frappe.throw(_("Debit and Credit not equal for this voucher: Diff (Debit) is ") +
 		 	cstr(total_debit - total_credit))
-			
+
 def validate_account_for_auto_accounting_for_stock(gl_map):
 	if gl_map[0].voucher_type=="Journal Voucher":
-		aii_accounts = [d[0] for d in frappe.db.sql("""select name from tabAccount 
+		aii_accounts = [d[0] for d in frappe.db.sql("""select name from tabAccount
 			where account_type = 'Warehouse' and ifnull(master_name, '')!=''""")]
-		
+
 		for entry in gl_map:
 			if entry.account in aii_accounts:
-				frappe.throw(_("Account") + ": " + entry.account + 
-					_(" can only be debited/credited through Stock transactions"), 
+				frappe.throw(_("Account") + ": " + entry.account +
+					_(" can only be debited/credited through Stock transactions"),
 					StockAccountInvalidTransaction)
-	
-		
-def delete_gl_entries(gl_entries=None, voucher_type=None, voucher_no=None, 
+
+
+def delete_gl_entries(gl_entries=None, voucher_type=None, voucher_no=None,
 		adv_adj=False, update_outstanding="Yes"):
-	
+
 	from erpnext.accounts.doctype.gl_entry.gl_entry import validate_balance_type, \
 		check_freezing_date, update_outstanding_amt, validate_frozen_account
-		
+
 	if not gl_entries:
-		gl_entries = frappe.db.sql("""select * from `tabGL Entry` 
+		gl_entries = frappe.db.sql("""select * from `tabGL Entry`
 			where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no), as_dict=True)
 	if gl_entries:
 		check_freezing_date(gl_entries[0]["posting_date"], adv_adj)
-	
-	frappe.db.sql("""delete from `tabGL Entry` where voucher_type=%s and voucher_no=%s""", 
+
+	frappe.db.sql("""delete from `tabGL Entry` where voucher_type=%s and voucher_no=%s""",
 		(voucher_type or gl_entries[0]["voucher_type"], voucher_no or gl_entries[0]["voucher_no"]))
-	
+
 	for entry in gl_entries:
 		validate_frozen_account(entry["account"], adv_adj)
 		validate_balance_type(entry["account"], adv_adj)
 		validate_expense_against_budget(entry)
-		
-		if entry.get("against_voucher") and entry.get("against_voucher_type") != "POS" \
-			and update_outstanding == 'Yes':
-				update_outstanding_amt(entry["account"], entry.get("against_voucher_type"), 
-					entry.get("against_voucher"), on_cancel=True)
\ No newline at end of file
+
+		if entry.get("against_voucher") and update_outstanding == 'Yes':
+				update_outstanding_amt(entry["account"], entry.get("against_voucher_type"),
+					entry.get("against_voucher"), on_cancel=True)
diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py
index 408f434..b876a2b 100644
--- a/erpnext/controllers/queries.py
+++ b/erpnext/controllers/queries.py
@@ -36,10 +36,11 @@
 				or employee_name like "%(txt)s")
 			%(mcond)s
 		order by
-			case when name like "%(txt)s" then 0 else 1 end,
-			case when employee_name like "%(txt)s" then 0 else 1 end,
-			name
+			if(locate("%(_txt)s", name), locate("%(_txt)s", name), 99999),
+			if(locate("%(_txt)s", employee_name), locate("%(_txt)s", item_name), 99999),
+			name, employee_name
 		limit %(start)s, %(page_len)s""" % {'key': searchfield, 'txt': "%%%s%%" % txt,
+		'_txt': txt.replace("%", ""),
 		'mcond':get_match_cond(doctype), 'start': start, 'page_len': page_len})
 
  # searches for leads which are not converted
@@ -52,11 +53,12 @@
 				or company_name like "%(txt)s")
 			%(mcond)s
 		order by
-			case when name like "%(txt)s" then 0 else 1 end,
-			case when lead_name like "%(txt)s" then 0 else 1 end,
-			case when company_name like "%(txt)s" then 0 else 1 end,
-			lead_name asc
+			if(locate("%(_txt)s", name), locate("%(_txt)s", name), 99999),
+			if(locate("%(_txt)s", lead_name), locate("%(_txt)s", name), 99999),
+			if(locate("%(_txt)s", company_name), locate("%(_txt)s", name), 99999),
+			name, lead_name
 		limit %(start)s, %(page_len)s""" % {'key': searchfield, 'txt': "%%%s%%" % txt,
+		'_txt': txt.replace("%", ""),
 		'mcond':get_match_cond(doctype), 'start': start, 'page_len': page_len})
 
  # searches for customer
@@ -76,11 +78,12 @@
 				or customer_name like "%(txt)s")
 			%(mcond)s
 		order by
-			case when name like "%(txt)s" then 0 else 1 end,
-			case when customer_name like "%(txt)s" then 0 else 1 end,
+			if(locate("%(_txt)s", name), locate("%(_txt)s", name), 99999),
+			if(locate("%(_txt)s", customer_name), locate("%(_txt)s", name), 99999),
 			name, customer_name
 		limit %(start)s, %(page_len)s""" % {'field': fields,'key': searchfield,
-		'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype),
+		'txt': "%%%s%%" % txt, '_txt': txt.replace("%", ""),
+		'mcond':get_match_cond(doctype),
 		'start': start, 'page_len': page_len})
 
 # searches for supplier
@@ -98,11 +101,12 @@
 				or supplier_name like "%(txt)s")
 			%(mcond)s
 		order by
-			case when name like "%(txt)s" then 0 else 1 end,
-			case when supplier_name like "%(txt)s" then 0 else 1 end,
+			if(locate("%(_txt)s", name), locate("%(_txt)s", name), 99999),
+			if(locate("%(_txt)s", supplier_name), locate("%(_txt)s", name), 99999),
 			name, supplier_name
 		limit %(start)s, %(page_len)s """ % {'field': fields,'key': searchfield,
-		'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype), 'start': start,
+		'txt': "%%%s%%" % txt, '_txt': txt.replace("%", ""),
+		'mcond':get_match_cond(doctype), 'start': start,
 		'page_len': page_len})
 
 def tax_account_query(doctype, txt, searchfield, start, page_len, filters):
@@ -141,12 +145,17 @@
 			and (tabItem.`{key}` LIKE %(txt)s
 				or tabItem.item_name LIKE %(txt)s)
 			{fcond} {mcond}
+		order by
+			if(locate(%(_txt)s, name), locate(%(_txt)s, name), 99999),
+			if(locate(%(_txt)s, item_name), locate(%(_txt)s, item_name), 99999),
+			name, item_name
 		limit %(start)s, %(page_len)s """.format(key=searchfield,
 			fcond=get_filters_cond(doctype, filters, conditions),
 			mcond=get_match_cond(doctype)),
 			{
 				"today": nowdate(),
 				"txt": "%%%s%%" % txt,
+				"_txt": txt.replace("%", ""),
 				"start": start,
 				"page_len": page_len
 			})
diff --git a/erpnext/manufacturing/doctype/production_order/production_order.py b/erpnext/manufacturing/doctype/production_order/production_order.py
index edcb25d..5c617fd 100644
--- a/erpnext/manufacturing/doctype/production_order/production_order.py
+++ b/erpnext/manufacturing/doctype/production_order/production_order.py
@@ -6,10 +6,10 @@
 
 from frappe.utils import cstr, flt, nowdate
 from frappe import _
+from frappe.model.document import Document
 
 class OverProductionError(frappe.ValidationError): pass
-
-from frappe.model.document import Document
+class StockOverProductionError(frappe.ValidationError): pass
 
 class ProductionOrder(Document):
 
@@ -89,21 +89,41 @@
 		frappe.msgprint(_("Production Order status is {0}").format(status))
 
 
-	def update_status(self, status):
-		if status == 'Stopped':
-			frappe.db.set(self, 'status', cstr(status))
-		else:
-			if flt(self.qty) == flt(self.produced_qty):
-				frappe.db.set(self, 'status', 'Completed')
-			if flt(self.qty) > flt(self.produced_qty):
-				frappe.db.set(self, 'status', 'In Process')
-			if flt(self.produced_qty) == 0:
-				frappe.db.set(self, 'status', 'Submitted')
+	def update_status(self, status=None):
+		if not status:
+			status = self.status
 
+		if status != 'Stopped':
+			stock_entries = frappe._dict(frappe.db.sql("""select purpose, sum(fg_completed_qty)
+				from `tabStock Entry` where production_order=%s and docstatus=1
+				group by purpose""", self.name))
+
+			status = "Submitted"
+			if stock_entries:
+				status = "In Process"
+				produced_qty = stock_entries.get("Manufacture/Repack")
+				if flt(produced_qty) == flt(self.qty):
+					status = "Completed"
+
+		if status != self.status:
+			self.db_set("status", status)
+
+	def update_produced_qty(self):
+		produced_qty = frappe.db.sql("""select sum(fg_completed_qty)
+			from `tabStock Entry` where production_order=%s and docstatus=1
+			and purpose='Manufacture/Repack'""", self.name)
+		produced_qty = flt(produced_qty[0][0]) if produced_qty else 0
+
+		if produced_qty > self.qty:
+			frappe.throw(_("Cannot manufacture more than the planned Quantity to Manufacture ({0}) in Production Order: {1}").format(self.qty, self.name), StockOverProductionError)
+
+		self.db_set("produced_qty", produced_qty)
 
 	def on_submit(self):
 		if not self.wip_warehouse:
-			frappe.throw(_("WIP Warehouse required before Submit"))
+			frappe.throw(_("Work-in-Progress Warehouse is required before Submit"))
+		if not self.fg_warehouse:
+			frappe.throw(_("For Warehouse is required before Submit"))
 		frappe.db.set(self,'status', 'Submitted')
 		self.update_planned_qty(self.qty)
 
diff --git a/erpnext/manufacturing/doctype/production_order/test_production_order.py b/erpnext/manufacturing/doctype/production_order/test_production_order.py
index 9bc001d..125a016 100644
--- a/erpnext/manufacturing/doctype/production_order/test_production_order.py
+++ b/erpnext/manufacturing/doctype/production_order/test_production_order.py
@@ -49,7 +49,7 @@
 		return pro_doc.name
 
 	def test_over_production(self):
-		from erpnext.stock.doctype.stock_entry.stock_entry import StockOverProductionError
+		from erpnext.manufacturing.doctype.production_order.production_order import StockOverProductionError
 		pro_order = self.test_planned_qty()
 
 		stock_entry = make_stock_entry(pro_order, "Manufacture/Repack")
diff --git a/erpnext/public/js/queries.js b/erpnext/public/js/queries.js
index ec38d63..117e192 100644
--- a/erpnext/public/js/queries.js
+++ b/erpnext/public/js/queries.js
@@ -24,8 +24,10 @@
 		return { query: "erpnext.controllers.queries.account_query" };
 	},
 
-	item: function() {
-		return { query: "erpnext.controllers.queries.item_query" };
+	item: function(filters) {
+		var args = { query: "erpnext.controllers.queries.item_query" };
+		if(filters) args["filters"] = filters;
+		return args;
 	},
 
 	bom: function() {
@@ -38,25 +40,25 @@
 
 	customer_filter: function(doc) {
 		if(!doc.customer) {
-			frappe.throw(__("Please specify a") + " " + 
+			frappe.throw(__("Please specify a") + " " +
 				__(frappe.meta.get_label(doc.doctype, "customer", doc.name)));
 		}
-		
+
 		return { filters: { customer: doc.customer } };
 	},
 
 	supplier_filter: function(doc) {
 		if(!doc.supplier) {
-			frappe.throw(__("Please specify a") + " " + 
+			frappe.throw(__("Please specify a") + " " +
 				__(frappe.meta.get_label(doc.doctype, "supplier", doc.name)));
 		}
-		
+
 		return { filters: { supplier: doc.supplier } };
 	},
 
 	lead_filter: function(doc) {
 		if(!doc.lead) {
-			frappe.throw(__("Please specify a") + " " + 
+			frappe.throw(__("Please specify a") + " " +
 				__(frappe.meta.get_label(doc.doctype, "lead", doc.name)));
 		}
 
@@ -66,4 +68,4 @@
 	not_a_group_filter: function() {
 		return { filters: { is_group: "No" } };
 	},
-});
\ No newline at end of file
+});
diff --git a/erpnext/public/js/transaction.js b/erpnext/public/js/transaction.js
index 5d43ad4..4aaa138 100644
--- a/erpnext/public/js/transaction.js
+++ b/erpnext/public/js/transaction.js
@@ -189,7 +189,7 @@
 	},
 
 	validate: function() {
-		this.calculate_taxes_and_totals();
+		this.calculate_taxes_and_totals(false);
 	},
 
 	company: function() {
@@ -299,7 +299,8 @@
 		this.calculate_taxes_and_totals();
 	},
 
-	tax_rate: function(doc, cdt, cdn) {
+	// tax rate
+	rate: function(doc, cdt, cdn) {
 		this.calculate_taxes_and_totals();
 	},
 
@@ -372,7 +373,6 @@
 		var on_previous_row_error = function(row_range) {
 			var msg = __("For row {0} in {1}. To include {2} in Item rate, rows {3} must also be included",
 				[tax.idx, __(tax.doctype), tax.charge_type, row_range])
-
 			frappe.throw(msg);
 		};
 
@@ -680,14 +680,14 @@
 		});
 	},
 
-	calculate_total_advance: function(parenttype, advance_parentfield) {
+	calculate_total_advance: function(parenttype, advance_parentfield, update_paid_amount) {
 		if(this.frm.doc.doctype == parenttype && this.frm.doc.docstatus < 2) {
 			var advance_doclist = this.frm.doc[advance_parentfield] || [];
 			this.frm.doc.total_advance = flt(frappe.utils.sum(
 				$.map(advance_doclist, function(adv) { return adv.allocated_amount })
 			), precision("total_advance"));
 
-			this.calculate_outstanding_amount();
+			this.calculate_outstanding_amount(update_paid_amount);
 		}
 	},
 
diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js
index a89aaef..1e9643a 100644
--- a/erpnext/selling/sales_common.js
+++ b/erpnext/selling/sales_common.js
@@ -235,9 +235,9 @@
 		}
 	},
 
-	calculate_taxes_and_totals: function() {
+	calculate_taxes_and_totals: function(update_paid_amount) {
 		this._super();
-		this.calculate_total_advance("Sales Invoice", "advance_adjustment_details");
+		this.calculate_total_advance("Sales Invoice", "advance_adjustment_details", update_paid_amount);
 		this.calculate_commission();
 		this.calculate_contribution();
 
@@ -398,7 +398,7 @@
 		return grand_total_for_discount_amount;
 	},
 
-	calculate_outstanding_amount: function() {
+	calculate_outstanding_amount: function(update_paid_amount) {
 		// NOTE:
 		// paid_amount and write_off_amount is only for POS Invoice
 		// total_advance is only for non POS Invoice
@@ -408,7 +408,9 @@
 			var total_amount_to_pay = this.frm.doc.grand_total - this.frm.doc.write_off_amount
 				- this.frm.doc.total_advance;
 			if(this.frm.doc.is_pos) {
-				if(!this.frm.doc.paid_amount) this.frm.doc.paid_amount = flt(total_amount_to_pay);
+				if(!this.frm.doc.paid_amount || update_paid_amount===undefined || update_paid_amount) {
+					this.frm.doc.paid_amount = flt(total_amount_to_pay);
+				}
 			} else {
 				this.frm.doc.paid_amount = 0
 			}
diff --git a/erpnext/stock/doctype/landed_cost_wizard/landed_cost_wizard.py b/erpnext/stock/doctype/landed_cost_wizard/landed_cost_wizard.py
index b1a67e2..f71c827 100644
--- a/erpnext/stock/doctype/landed_cost_wizard/landed_cost_wizard.py
+++ b/erpnext/stock/doctype/landed_cost_wizard/landed_cost_wizard.py
@@ -58,13 +58,14 @@
 					ch.rate = amt
 					ch.tax_amount = amt
 					ch.docstatus = 1
-					ch.save(1)
+					ch.db_insert()
 				else:	# overwrite if exists
 					matched_row[0].rate = amt
 					matched_row[0].tax_amount = amt
 					matched_row[0].cost_center = lc.cost_center
 
 			pr_doc.run_method("validate")
+			pr_doc._validate_mandatory()
 			for d in pr_doc.get_all_children():
 				d.db_update()
 
diff --git a/erpnext/stock/doctype/serial_no/serial_no.js b/erpnext/stock/doctype/serial_no/serial_no.js
index 67eb779..10b20f9 100644
--- a/erpnext/stock/doctype/serial_no/serial_no.js
+++ b/erpnext/stock/doctype/serial_no/serial_no.js
@@ -8,3 +8,9 @@
 cur_frm.add_fetch("item_code", "description", "description")
 cur_frm.add_fetch("item_code", "item_group", "item_group")
 cur_frm.add_fetch("item_code", "brand", "brand")
+
+cur_frm.cscript.onload = function() {
+	cur_frm.set_query("item_code", function() {
+		return erpnext.queries.item({"is_stock_item": "Yes", "has_serial_no": "Yes"})
+	});
+}
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 66716a7..74c5a3f 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -18,7 +18,6 @@
 class StockOverReturnError(frappe.ValidationError): pass
 class IncorrectValuationRateError(frappe.ValidationError): pass
 class DuplicateEntryForProductionOrderError(frappe.ValidationError): pass
-class StockOverProductionError(frappe.ValidationError): pass
 
 from erpnext.controllers.stock_controller import StockController
 
@@ -314,24 +313,11 @@
 		if self.production_order:
 			pro_doc = frappe.get_doc("Production Order", self.production_order)
 			_validate_production_order(pro_doc)
-			self.update_produced_qty(pro_doc)
+			pro_doc.run_method("update_status")
 			if self.purpose == "Manufacture/Repack":
+				pro_doc.run_method("update_produced_qty")
 				self.update_planned_qty(pro_doc)
 
-	def update_produced_qty(self, pro_doc):
-		if self.purpose == "Manufacture/Repack":
-			produced_qty = flt(pro_doc.produced_qty) + \
-				(self.docstatus==1 and 1 or -1 ) * flt(self.fg_completed_qty)
-
-			if produced_qty > flt(pro_doc.qty):
-				frappe.throw(_("Production Order") + ": " + self.production_order + "\n" +
-					_("Total Manufactured Qty can not be greater than Planned qty to manufacture")
-					+ "(%s/%s)" % (produced_qty, flt(pro_doc.qty)), StockOverProductionError)
-
-			status = 'Completed' if flt(produced_qty) >= flt(pro_doc.qty) else 'In Process'
-			frappe.db.sql("""update `tabProduction Order` set status=%s, produced_qty=%s
-				where name=%s""", (status, produced_qty, self.production_order))
-
 	def update_planned_qty(self, pro_doc):
 		from erpnext.stock.utils import update_bin
 		update_bin({
diff --git a/erpnext/support/doctype/customer_issue/customer_issue.js b/erpnext/support/doctype/customer_issue/customer_issue.js
index 422ec98..74ff7d7 100644
--- a/erpnext/support/doctype/customer_issue/customer_issue.js
+++ b/erpnext/support/doctype/customer_issue/customer_issue.js
@@ -3,20 +3,20 @@
 
 frappe.provide("erpnext.support");
 
-frappe.ui.form.on_change("Customer Issue", "customer", function(frm) { 
+frappe.ui.form.on_change("Customer Issue", "customer", function(frm) {
 	erpnext.utils.get_party_details(frm) });
-frappe.ui.form.on_change("Customer Issue", "customer_address", 
+frappe.ui.form.on_change("Customer Issue", "customer_address",
 	erpnext.utils.get_address_display);
-frappe.ui.form.on_change("Customer Issue", "contact_person", 
-	erpnext.utils.get_contact_details);	
+frappe.ui.form.on_change("Customer Issue", "contact_person",
+	erpnext.utils.get_contact_details);
 
 erpnext.support.CustomerIssue = frappe.ui.form.Controller.extend({
 	refresh: function() {
 		if((cur_frm.doc.status=='Open' || cur_frm.doc.status == 'Work In Progress')) {
 			cur_frm.add_custom_button(__('Make Maintenance Visit'), this.make_maintenance_visit)
 		}
-	}, 
-		
+	},
+
 	make_maintenance_visit: function() {
 		frappe.model.open_mapped_doc({
 			method: "erpnext.support.doctype.customer_issue.customer_issue.make_maintenance_visit",
@@ -28,8 +28,8 @@
 $.extend(cur_frm.cscript, new erpnext.support.CustomerIssue({frm: cur_frm}));
 
 cur_frm.cscript.onload = function(doc,cdt,cdn){
-	if(!doc.status) 
-		set_multiple(dt,dn,{status:'Open'}); 
+	if(!doc.status)
+		set_multiple(dt,dn,{status:'Open'});
 }
 
 cur_frm.fields_dict['customer_address'].get_query = function(doc, cdt, cdn) {
@@ -66,7 +66,6 @@
 cur_frm.add_fetch('serial_no', 'amc_expiry_date', 'amc_expiry_date');
 cur_frm.add_fetch('serial_no', 'customer', 'customer');
 cur_frm.add_fetch('serial_no', 'customer_name', 'customer_name');
-cur_frm.add_fetch('serial_no', 'delivery_address', 'customer_address');
 cur_frm.add_fetch('item_code', 'item_name', 'item_name');
 cur_frm.add_fetch('item_code', 'description', 'description');
 
@@ -74,14 +73,14 @@
 	if(doc.serial_no) {
 		return{
 			filters:{ 'serial_no': doc.serial_no}
-		}		
+		}
 	}
 	else{
 		return{
 			filters:[
 				['Item', 'docstatus', '!=', 2]
 			]
-		}		
+		}
 	}
 }