Merge pull request #3531 from pdvyas/exchange-rate-api

Change currency exchange rate api to fixer.io
diff --git a/erpnext/__version__.py b/erpnext/__version__.py
index ca621e3..b0b41d3 100644
--- a/erpnext/__version__.py
+++ b/erpnext/__version__.py
@@ -1,2 +1,2 @@
 from __future__ import unicode_literals
-__version__ = '5.0.26'
+__version__ = '5.0.29'
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py
index 4e7928d..138cf23 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py
@@ -4,7 +4,7 @@
 from __future__ import unicode_literals
 import frappe
 
-from frappe.utils import flt, fmt_money, getdate, formatdate
+from frappe.utils import flt, fmt_money, getdate, formatdate, cstr
 from frappe import _
 
 from frappe.model.document import Document
@@ -118,7 +118,7 @@
 	bal = flt(frappe.db.sql("""select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))
 		from `tabGL Entry`
 		where against_voucher_type=%s and against_voucher=%s
-		and account = %s and party_type=%s and party=%s""",
+		and account = %s and ifnull(party_type, '')=%s and ifnull(party, '')=%s""",
 		(against_voucher_type, against_voucher, account, party_type, party))[0][0] or 0.0)
 
 	if against_voucher_type == 'Purchase Invoice':
@@ -127,8 +127,9 @@
 		against_voucher_amount = flt(frappe.db.sql("""
 			select sum(ifnull(debit, 0)) - sum(ifnull(credit, 0))
 			from `tabGL Entry` where voucher_type = 'Journal Entry' and voucher_no = %s
-			and account = %s and party_type=%s and party=%s and ifnull(against_voucher, '') = ''""",
-			(against_voucher, account, party_type, party))[0][0])
+			and account = %s and ifnull(party_type, '')=%s and ifnull(party, '')=%s 
+			and ifnull(against_voucher, '') = ''""",
+			(against_voucher, account, cstr(party_type), cstr(party)))[0][0])
 
 		if not against_voucher_amount:
 			frappe.throw(_("Against Journal Entry {0} is already adjusted against some other voucher")
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.json b/erpnext/accounts/doctype/journal_entry/journal_entry.json
index 6eb395d..249fcc4 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.json
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.json
@@ -53,7 +53,7 @@
    "fieldname": "posting_date", 
    "fieldtype": "Date", 
    "in_filter": 1, 
-   "in_list_view": 1, 
+   "in_list_view": 0, 
    "label": "Posting Date", 
    "no_copy": 1, 
    "oldfieldname": "posting_date", 
@@ -445,7 +445,7 @@
  "icon": "icon-file-text", 
  "idx": 1, 
  "is_submittable": 1, 
- "modified": "2015-04-27 20:32:31.655580", 
+ "modified": "2015-06-29 15:28:12.529019", 
  "modified_by": "Administrator", 
  "module": "Accounts", 
  "name": "Journal Entry", 
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index 753fcc3..7bf6c56 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -274,30 +274,28 @@
 				r.append(_('Reference #{0} dated {1}').format(self.cheque_no, formatdate(self.cheque_date)))
 			else:
 				msgprint(_("Please enter Reference date"), raise_exception=frappe.MandatoryError)
-
+				
+		company_currency = get_company_currency(self.company)
+		
 		for d in self.get('accounts'):
 			if d.against_invoice and d.credit:
-				currency = frappe.db.get_value("Sales Invoice", d.against_invoice, "currency")
-
-				r.append(_("{0} against Sales Invoice {1}").format(fmt_money(flt(d.credit), currency = currency), \
+				r.append(_("{0} against Sales Invoice {1}").format(fmt_money(flt(d.credit), currency = company_currency), \
 					d.against_invoice))
 
 			if d.against_sales_order and d.credit:
-				currency = frappe.db.get_value("Sales Order", d.against_sales_order, "currency")
-				r.append(_("{0} against Sales Order {1}").format(fmt_money(flt(d.credit), currency = currency), \
+				r.append(_("{0} against Sales Order {1}").format(fmt_money(flt(d.credit), currency = company_currency), \
 					d.against_sales_order))
 
 			if d.against_voucher and d.debit:
-				bill_no = frappe.db.sql("""select bill_no, bill_date, currency
+				bill_no = frappe.db.sql("""select bill_no, bill_date
 					from `tabPurchase Invoice` where name=%s""", d.against_voucher)
 				if bill_no and bill_no[0][0] and bill_no[0][0].lower().strip() \
 						not in ['na', 'not applicable', 'none']:
-					r.append(_('{0} against Bill {1} dated {2}').format(fmt_money(flt(d.debit), currency=bill_no[0][2]), bill_no[0][0],
+					r.append(_('{0} against Bill {1} dated {2}').format(fmt_money(flt(d.debit), currency=company_currency), bill_no[0][0],
 						bill_no[0][1] and formatdate(bill_no[0][1].strftime('%Y-%m-%d'))))
 
 			if d.against_purchase_order and d.debit:
-				currency = frappe.db.get_value("Purchase Order", d.against_purchase_order, "currency")
-				r.append(_("{0} against Purchase Order {1}").format(fmt_money(flt(d.credit), currency = currency), \
+				r.append(_("{0} against Purchase Order {1}").format(fmt_money(flt(d.credit), currency = company_currency), \
 					d.against_purchase_order))
 
 		if self.user_remark:
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index 3e16a31..d404851 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -224,3 +224,4 @@
 	else
 		cur_frm.pformat.print_heading = __("Purchase Invoice");
 }
+
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
index e192e76..dcbc605 100755
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.json
@@ -926,12 +926,21 @@
    "no_copy": 1, 
    "permlevel": 0, 
    "print_hide": 1
+  }, 
+  {
+   "depends_on": "eval:doc.is_recurring==1", 
+   "fieldname": "recurring_print_format", 
+   "fieldtype": "Link", 
+   "label": "Recurring Print Format", 
+   "options": "Print Format", 
+   "permlevel": 0, 
+   "precision": ""
   }
  ], 
  "icon": "icon-file-text", 
  "idx": 1, 
  "is_submittable": 1, 
- "modified": "2015-06-16 16:46:47.308287", 
+ "modified": "2015-06-22 07:30:06.743438", 
  "modified_by": "Administrator", 
  "module": "Accounts", 
  "name": "Purchase Invoice", 
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 8820c87..660b221 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -88,9 +88,7 @@
 			throw(_("Conversion rate cannot be 0 or 1"))
 
 	def validate_credit_to_acc(self):
-		root_type, account_type = frappe.db.get_value("Account", self.credit_to, ["root_type", "account_type"])
-		if root_type != "Liability":
-			frappe.throw(_("Credit To account must be a liability account"))
+		account_type = frappe.db.get_value("Account", self.credit_to, "account_type")
 		if account_type != "Payable":
 			frappe.throw(_("Credit To account must be a Payable account"))
 
@@ -412,4 +410,4 @@
 				and tabAccount.company = '%(company)s'
 				and tabAccount.%(key)s LIKE '%(txt)s'
 				%(mcond)s""" % {'company': filters['company'], 'key': searchfield,
-			'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype)})
+			'txt': "%%%s%%" % frappe.db.escape(txt), 'mcond':get_match_cond(doctype)})
diff --git a/erpnext/accounts/doctype/sales_invoice/pos.py b/erpnext/accounts/doctype/sales_invoice/pos.py
index 7d5613d..2c5bb12 100644
--- a/erpnext/accounts/doctype/sales_invoice/pos.py
+++ b/erpnext/accounts/doctype/sales_invoice/pos.py
@@ -36,7 +36,7 @@
 			if(locate(%(_name)s, i.item_name), locate(%(_name)s, i.item_name), 99999),
 			if(locate(%(_name)s, i.variant_of), locate(%(_name)s, i.variant_of), 99999),
 			if(locate(%(_name)s, i.item_group), locate(%(_name)s, i.item_group), 99999),"""
-		args["name"] = "%%%s%%" % item
+		args["name"] = "%%%s%%" % frappe.db.escape(item)
 		args["_name"] = item.replace("%", "")
 
 	# locate function is used to sort by closest match from the beginning of the value
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
index b35fa8a..3bb9aa0 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js
@@ -392,8 +392,6 @@
 	}
 }
 
-
-
 cur_frm.set_query("debit_to", function(doc) {
 	return{
 		filters: [
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
index a021be4..045678d 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json
@@ -1228,6 +1228,15 @@
    "read_only": 0
   }, 
   {
+   "depends_on": "eval:doc.is_recurring==1", 
+   "fieldname": "recurring_print_format", 
+   "fieldtype": "Link", 
+   "label": "Recurring Print Format", 
+   "options": "Print Format", 
+   "permlevel": 0, 
+   "precision": ""
+  }, 
+  {
    "fieldname": "against_income_account", 
    "fieldtype": "Small Text", 
    "hidden": 1, 
@@ -1244,7 +1253,7 @@
  "icon": "icon-file-text", 
  "idx": 1, 
  "is_submittable": 1, 
- "modified": "2015-06-16 16:45:06.618286", 
+ "modified": "2015-06-22 06:39:22.072544", 
  "modified_by": "Administrator", 
  "module": "Accounts", 
  "name": "Sales Invoice", 
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index fe5954e..87f723d 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -235,9 +235,7 @@
 			reconcile_against_document(lst)
 
 	def validate_debit_to_acc(self):
-		root_type, account_type = frappe.db.get_value("Account", self.debit_to, ["root_type", "account_type"])
-		if root_type != "Asset":
-			frappe.throw(_("Debit To account must be a liability account"))
+		account_type = frappe.db.get_value("Account", self.debit_to, "account_type")
 		if account_type != "Receivable":
 			frappe.throw(_("Debit To account must be a Receivable account"))
 
@@ -613,7 +611,7 @@
 				and tabAccount.company = '%(company)s'
 				and tabAccount.%(key)s LIKE '%(txt)s'
 				%(mcond)s""" % {'company': filters['company'], 'key': searchfield,
-			'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype)})
+			'txt': "%%%s%%" % frappe.db.escape(txt), 'mcond':get_match_cond(doctype)})
 
 @frappe.whitelist()
 def make_delivery_note(source_name, target_doc=None):
diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py
index 8fc785c..17fe922 100644
--- a/erpnext/accounts/general_ledger.py
+++ b/erpnext/accounts/general_ledger.py
@@ -3,7 +3,7 @@
 
 from __future__ import unicode_literals
 import frappe
-from frappe.utils import flt, cstr
+from frappe.utils import flt, cstr, cint
 from frappe import _
 from frappe.model.meta import get_field_precision
 from erpnext.accounts.utils import validate_expense_against_budget
@@ -82,14 +82,15 @@
 	gle.submit()
 
 def validate_account_for_auto_accounting_for_stock(gl_map):
-	if gl_map[0].voucher_type=="Journal Entry":
-		aii_accounts = [d[0] for d in frappe.db.sql("""select name from tabAccount
-			where account_type = 'Warehouse' and ifnull(warehouse, '')!=''""")]
+	if cint(frappe.db.get_single_value("Accounts Settings", "auto_accounting_for_stock")) \
+		and gl_map[0].voucher_type=="Journal Entry":
+			aii_accounts = [d[0] for d in frappe.db.sql("""select name from tabAccount
+				where account_type = 'Warehouse' and ifnull(warehouse, '')!=''""")]
 
-		for entry in gl_map:
-			if entry.account in aii_accounts:
-				frappe.throw(_("Account: {0} can only be updated via Stock Transactions")
-					.format(entry.account), StockAccountInvalidTransaction)
+			for entry in gl_map:
+				if entry.account in aii_accounts:
+					frappe.throw(_("Account: {0} can only be updated via Stock Transactions")
+						.format(entry.account), StockAccountInvalidTransaction)
 
 def round_off_debit_credit(gl_map):
 	precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"),
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json
index dc1dfa4..f65ba40 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.json
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.json
@@ -868,12 +868,21 @@
    "no_copy": 1, 
    "permlevel": 0, 
    "print_hide": 1
+  }, 
+  {
+   "depends_on": "eval:doc.is_recurring==1", 
+   "fieldname": "recurring_print_format", 
+   "fieldtype": "Link", 
+   "label": "Recurring Print Format", 
+   "options": "Print Format", 
+   "permlevel": 0, 
+   "precision": ""
   }
  ], 
  "icon": "icon-file-text", 
  "idx": 1, 
  "is_submittable": 1, 
- "modified": "2015-06-15 15:38:56.794601", 
+ "modified": "2015-06-22 07:30:36.259753", 
  "modified_by": "Administrator", 
  "module": "Buying", 
  "name": "Purchase Order", 
diff --git a/erpnext/change_log/v5/v5_0_28.md b/erpnext/change_log/v5/v5_0_28.md
new file mode 100644
index 0000000..6ad54e6
--- /dev/null
+++ b/erpnext/change_log/v5/v5_0_28.md
@@ -0,0 +1 @@
+- Open notification of Sales Order and Purchase Order based on whether Invoice is created against them. For eg. If a Sales Order is not Invoiced, it will be considered as open. Previously it was considered open if Delivery Note was created against Sales Order.
diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py
index 898dd23..4f35fea 100644
--- a/erpnext/controllers/queries.py
+++ b/erpnext/controllers/queries.py
@@ -194,7 +194,7 @@
 			and tabBOM.is_active=1
 			and tabBOM.%(key)s like "%(txt)s"
 			%(fcond)s  %(mcond)s
-		limit %(start)s, %(page_len)s """ %  {'key': searchfield, 'txt': "%%%s%%" % txt,
+		limit %(start)s, %(page_len)s """ %  {'key': searchfield, 'txt': "%%%s%%" % frappe.db.escape(txt),
 		'fcond': get_filters_cond(doctype, filters, conditions),
 		'mcond':get_match_cond(doctype), 'start': start, 'page_len': page_len})
 
@@ -207,7 +207,7 @@
 		where `tabProject`.status not in ("Completed", "Cancelled")
 			and %(cond)s `tabProject`.name like "%(txt)s" %(mcond)s
 		order by `tabProject`.name asc
-		limit %(start)s, %(page_len)s """ % {'cond': cond,'txt': "%%%s%%" % txt,
+		limit %(start)s, %(page_len)s """ % {'cond': cond,'txt': "%%%s%%" % frappe.db.escape(txt),
 		'mcond':get_match_cond(doctype),'start': start, 'page_len': page_len})
 
 def get_delivery_notes_to_be_billed(doctype, txt, searchfield, start, page_len, filters):
diff --git a/erpnext/controllers/recurring_document.py b/erpnext/controllers/recurring_document.py
index a46fa32..8c8af23 100644
--- a/erpnext/controllers/recurring_document.py
+++ b/erpnext/controllers/recurring_document.py
@@ -124,7 +124,7 @@
 	frappe.sendmail(new_rv.notification_email_address,
 		subject=  _("New {0}: #{1}").format(new_rv.doctype, new_rv.name),
 		message = _("Please find attached {0} #{1}").format(new_rv.doctype, new_rv.name),
-		attachments = [frappe.attach_print(new_rv.doctype, new_rv.name, file_name=new_rv.name)])
+		attachments = [frappe.attach_print(new_rv.doctype, new_rv.name, file_name=new_rv.name, print_format=new_rv.recurring_print_format)])
 
 def notify_errors(doc, doctype, party, owner):
 	from frappe.utils.user import get_system_managers
diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py
index b523416..12de2e5 100644
--- a/erpnext/crm/doctype/lead/lead.py
+++ b/erpnext/crm/doctype/lead/lead.py
@@ -75,8 +75,7 @@
 		return frappe.db.get_value("Customer", {"lead_name": self.name})
 
 	def has_opportunity(self):
-		return frappe.db.get_value("Opportunity", {"lead": self.name, "docstatus": 1,
-			"status": ["!=", "Lost"]})
+		return frappe.db.get_value("Opportunity", {"lead": self.name, "status": ["!=", "Lost"]})
 
 @frappe.whitelist()
 def make_customer(source_name, target_doc=None):
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index d36f269..d9262d4 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -5,7 +5,7 @@
 app_description = "Open Source Enterprise Resource Planning for Small and Midsized Organizations"
 app_icon = "icon-th"
 app_color = "#e74c3c"
-app_version = "5.0.26"
+app_version = "5.0.29"
 
 error_report_email = "support@erpnext.com"
 
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index c75c2bd..44fb6fd 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -339,6 +339,7 @@
 		events.append({
 			"doctype": "Leave Block List Date",
 			"from_date": block_date.block_date,
+			"to_date": block_date.block_date,
 			"title": _("Leave Blocked") + ": " + block_date.reason,
 			"name": "_" + str(cnt),
 		})
@@ -355,6 +356,7 @@
 			events.append({
 				"doctype": "Holiday",
 				"from_date": holiday.holiday_date,
+				"to_date":  holiday.holiday_date,
 				"title": _("Holiday") + ": " + cstr(holiday.description),
 				"name": holiday.name
 			})
diff --git a/erpnext/manufacturing/doctype/bom/bom.json b/erpnext/manufacturing/doctype/bom/bom.json
index 239df47..67e2b78 100644
--- a/erpnext/manufacturing/doctype/bom/bom.json
+++ b/erpnext/manufacturing/doctype/bom/bom.json
@@ -12,7 +12,7 @@
    "fieldname": "item", 
    "fieldtype": "Link", 
    "in_filter": 1, 
-   "in_list_view": 0, 
+   "in_list_view": 1, 
    "label": "Item", 
    "oldfieldname": "item", 
    "oldfieldtype": "Link", 
@@ -54,7 +54,7 @@
    "fieldname": "is_active", 
    "fieldtype": "Check", 
    "hidden": 0, 
-   "in_list_view": 0, 
+   "in_list_view": 1, 
    "label": "Is Active", 
    "no_copy": 1, 
    "oldfieldname": "is_active", 
@@ -67,7 +67,7 @@
    "default": "1", 
    "fieldname": "is_default", 
    "fieldtype": "Check", 
-   "in_list_view": 0, 
+   "in_list_view": 1, 
    "label": "Is Default", 
    "no_copy": 1, 
    "oldfieldname": "is_default", 
@@ -279,7 +279,7 @@
  "is_submittable": 1, 
  "issingle": 0, 
  "istable": 0, 
- "modified": "2015-03-03 14:22:44.725097", 
+ "modified": "2015-06-26 02:02:30.705279", 
  "modified_by": "Administrator", 
  "module": "Manufacturing", 
  "name": "BOM", 
diff --git a/erpnext/patches/v5_0/update_frozen_accounts_permission_role.py b/erpnext/patches/v5_0/update_frozen_accounts_permission_role.py
index 2f85513..14426f5 100644
--- a/erpnext/patches/v5_0/update_frozen_accounts_permission_role.py
+++ b/erpnext/patches/v5_0/update_frozen_accounts_permission_role.py
@@ -7,6 +7,6 @@
 	account_settings = frappe.get_doc("Accounts Settings")
 
 	if not account_settings.frozen_accounts_modifier and account_settings.bde_auth_role:
-		frappe.db.set_value("Account Settings", None,
+		frappe.db.set_value("Accounts Settings", None,
 			"frozen_accounts_modifier", account_settings.bde_auth_role)
 
diff --git a/erpnext/projects/doctype/task/task.py b/erpnext/projects/doctype/task/task.py
index 42717fd..f5541cc 100644
--- a/erpnext/projects/doctype/task/task.py
+++ b/erpnext/projects/doctype/task/task.py
@@ -141,7 +141,7 @@
 				%(mcond)s
 			order by name
 			limit %(start)s, %(page_len)s """ % {'key': searchfield,
-			'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype),
+			'txt': "%%%s%%" % frappe.db.escape(txt), 'mcond':get_match_cond(doctype),
 			'start': start, 'page_len': page_len})
 
 
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index ca0a6cb..91601a4 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -37,6 +37,16 @@
 		if(this.frm.fields_dict["items"]) {
 			this["items_remove"] = this.calculate_taxes_and_totals;
 		}
+		
+		if(this.frm.fields_dict["recurring_print_format"]) {
+			this.frm.set_query("recurring_print_format", function(doc) {
+				return{
+					filters: [
+						['Print Format', 'doc_type', '=', cur_frm.doctype],
+					]
+				}
+			});
+		}
 	},
 
 	onload_post_render: function() {
@@ -782,3 +792,5 @@
 	cur_frm.cscript.set_dynamic_labels();
 	cur_frm.cscript.calculate_taxes_and_totals();
 })
+
+
diff --git a/erpnext/selling/doctype/sales_order/sales_order.js b/erpnext/selling/doctype/sales_order/sales_order.js
index 7ede9d4..7f0b386 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.js
+++ b/erpnext/selling/doctype/sales_order/sales_order.js
@@ -183,5 +183,3 @@
 		cur_frm.email_doc(frappe.boot.notification_settings.sales_order_message);
 	}
 };
-
-;
diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json
index ad62d57..59f54fb 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.json
+++ b/erpnext/selling/doctype/sales_order/sales_order.json
@@ -1074,13 +1074,22 @@
    "no_copy": 1, 
    "permlevel": 0, 
    "print_hide": 1
+  }, 
+  {
+   "depends_on": "eval:doc.is_recurring==1", 
+   "fieldname": "recurring_print_format", 
+   "fieldtype": "Link", 
+   "label": "Recurring Print Format", 
+   "options": "Print Format", 
+   "permlevel": 0, 
+   "precision": ""
   }
  ], 
  "icon": "icon-file-text", 
  "idx": 1, 
  "is_submittable": 1, 
  "issingle": 0, 
- "modified": "2015-06-15 15:36:38.898462", 
+ "modified": "2015-06-22 07:29:24.379272", 
  "modified_by": "Administrator", 
  "module": "Selling", 
  "name": "Sales Order", 
diff --git a/erpnext/selling/page/sales_browser/sales_browser.js b/erpnext/selling/page/sales_browser/sales_browser.js
index 3b9e25a..98d34be 100644
--- a/erpnext/selling/page/sales_browser/sales_browser.js
+++ b/erpnext/selling/page/sales_browser/sales_browser.js
@@ -122,7 +122,7 @@
 
 		if(me.ctype == "Sales Person") {
 			fields.splice(-1, 0, {fieldtype:'Link', fieldname:'employee', label:__('Employee'),
-				options:'Employee', description: __("Please enter Employee Id of this sales parson")});
+				options:'Employee', description: __("Please enter Employee Id of this sales person")});
 		}
 
 		// the dialog
diff --git a/erpnext/startup/notifications.py b/erpnext/startup/notifications.py
index e847cfa..4190f2d 100644
--- a/erpnext/startup/notifications.py
+++ b/erpnext/startup/notifications.py
@@ -14,7 +14,7 @@
 			"Contact": {"status": "Open"},
 			"Opportunity": {"status": "Open"},
 			"Quotation": {"docstatus": 0},
-			"Sales Order": { "per_delivered": ("<", 100), "status": ("!=", "Stopped"), "docstatus": ("<", 2) },
+			"Sales Order": { "per_billed": ("<", 100), "status": ("!=", "Stopped"), "docstatus": ("<", 2) },
 			"Journal Entry": {"docstatus": 0},
 			"Sales Invoice": { "outstanding_amount": (">", 0), "docstatus": ("<", 2) },
 			"Purchase Invoice": {"docstatus": 0},
@@ -25,7 +25,7 @@
 			"Delivery Note": {"docstatus": 0},
 			"Stock Entry": {"docstatus": 0},
 			"Material Request": {"docstatus": 0},
-			"Purchase Order": { "per_received": ("<", 100), "status": ("!=", "Stopped"), "docstatus": ("<", 2) },
+			"Purchase Order": { "per_billed": ("<", 100), "status": ("!=", "Stopped"), "docstatus": ("<", 2) },
 			"Production Order": { "status": "In Process" },
 			"BOM": {"docstatus": 0},
 			"Timesheet": {"docstatus": 0},
diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json
index 6659da5..8b10319 100644
--- a/erpnext/stock/doctype/item/item.json
+++ b/erpnext/stock/doctype/item/item.json
@@ -707,7 +707,7 @@
    "fieldtype": "Link", 
    "ignore_user_permissions": 1, 
    "label": "Default BOM", 
-   "no_copy": 0, 
+   "no_copy": 1, 
    "oldfieldname": "default_bom", 
    "oldfieldtype": "Link", 
    "options": "BOM", 
@@ -879,7 +879,7 @@
  "icon": "icon-tag", 
  "idx": 1, 
  "max_attachments": 1, 
- "modified": "2015-05-22 02:16:57.435105", 
+ "modified": "2015-06-26 17:20:18.204558", 
  "modified_by": "Administrator", 
  "module": "Stock", 
  "name": "Item", 
diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py
index 0b0246e..bac5441 100644
--- a/erpnext/stock/doctype/serial_no/serial_no.py
+++ b/erpnext/stock/doctype/serial_no/serial_no.py
@@ -180,7 +180,7 @@
 			where fieldname='serial_no' and fieldtype='Text'"""):
 
 			for item in frappe.db.sql("""select name, serial_no from `tab%s`
-				where serial_no like '%%%s%%'""" % (dt[0], old)):
+				where serial_no like '%%%s%%'""" % (dt[0], frappe.db.escape(old))):
 
 				serial_nos = map(lambda i: i==old and new or i, item[1].split('\n'))
 				frappe.db.sql("""update `tab%s` set serial_no = %s
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index d823e7e..813a61b 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -5,7 +5,7 @@
 import frappe
 import frappe.defaults
 
-from frappe.utils import cstr, cint, flt, comma_or, get_datetime
+from frappe.utils import cstr, cint, flt, comma_or, get_datetime, getdate
 
 from frappe import _
 from erpnext.stock.utils import get_incoming_rate
@@ -66,6 +66,7 @@
 		self.validate_valuation_rate()
 		self.set_total_incoming_outgoing_value()
 		self.set_total_amount()
+		self.validate_batch()
 
 	def on_submit(self):
 		self.update_stock_ledger()
@@ -359,8 +360,11 @@
 		if self.purpose == "Subcontract" and self.purchase_order:
 			purchase_order = frappe.get_doc("Purchase Order", self.purchase_order)
 			for se_item in self.items:
-				total_allowed = [d.required_qty for d in purchase_order.supplied_items \
-					if d.rm_item_code == se_item.item_code][0]
+				total_allowed = sum([flt(d.required_qty) for d in purchase_order.supplied_items \
+					if d.rm_item_code == se_item.item_code])
+				if not total_allowed:
+					frappe.throw(_("Item {0} not found in 'Raw Materials Supplied' table in Purchase Order {1}")
+						.format(se_item.item_code, self.purchase_order))
 				total_supplied = frappe.db.sql("""select sum(qty)
 					from `tabStock Entry Detail`, `tabStock Entry`
 					where `tabStock Entry`.purchase_order = %s
@@ -721,6 +725,13 @@
 				mreq_item.warehouse != (item.s_warehouse if self.purpose== "Material Issue" else item.t_warehouse):
 					frappe.throw(_("Item or Warehouse for row {0} does not match Material Request").format(item.idx),
 						frappe.MappingMismatchError)
+						
+	def validate_batch(self):
+		if self.purpose == "Material Transfer for Manufacture":
+			for item in self.get("items"):
+				if item.batch_no:
+					if getdate(self.posting_date) > getdate(frappe.db.get_value("Batch", item.batch_no, "expiry_date")):
+						frappe.throw(_("Batch {0} of Item {1} has expired.").format(item.batch_no, item.item_code))
 
 @frappe.whitelist()
 def get_party_details(ref_dt, ref_dn):
diff --git a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py
index d911975..69e1321 100644
--- a/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py
+++ b/erpnext/stock/report/batch_wise_balance_history/batch_wise_balance_history.py
@@ -54,7 +54,7 @@
 	return frappe.db.sql("""select item_code, batch_no, warehouse,
 		posting_date, actual_qty
 		from `tabStock Ledger Entry`
-		where docstatus < 2 %s order by item_code, warehouse""" %
+		where docstatus < 2 and ifnull(batch_no, '') != '' %s order by item_code, warehouse""" %
 		conditions, as_dict=1)
 
 def get_item_warehouse_batch_map(filters, float_precision):
diff --git a/erpnext/templates/includes/issue_row.html b/erpnext/templates/includes/issue_row.html
index 30b2ab0..16a8f7b 100644
--- a/erpnext/templates/includes/issue_row.html
+++ b/erpnext/templates/includes/issue_row.html
@@ -1,6 +1,6 @@
 <div class="web-list-item">
     <div class="row">
-        <div class="col-sm-8">
+        <div class="col-sm-6">
             <a class="no-decoration" href="/issues?name={{ doc.name }}" no-pjax>
                 {{ doc.subject }}
             </a>
@@ -9,6 +9,11 @@
             <span class="indicator {{ "red" if doc.status=="Open" else "blue" }}">
                 {{ doc.status }}</span>
         </div>
+        <div class="col-sm-2">
+            <a class="text-muted text-right" href="/issues?name={{ doc.name }}" no-pjax>
+                {{ doc.name }}
+            </a>
+        </div>
         <div class="col-sm-2 text-muted text-right small">
             {{ frappe.format_date(doc.creation) }}
         </div>
diff --git a/erpnext/utilities/transaction_base.py b/erpnext/utilities/transaction_base.py
index 60889c5..be74aeb 100644
--- a/erpnext/utilities/transaction_base.py
+++ b/erpnext/utilities/transaction_base.py
@@ -22,16 +22,21 @@
 			self.posting_time = now_datetime().strftime('%H:%M:%S')
 
 	def add_calendar_event(self, opts, force=False):
-		if self.contact_by != cstr(self._prev.contact_by) or \
-				self.contact_date != cstr(self._prev.contact_date) or force:
+		if cstr(self.contact_by) != cstr(self._prev.contact_by) or \
+				cstr(self.contact_date) != cstr(self._prev.contact_date) or force:
 
 			self.delete_events()
 			self._add_calendar_event(opts)
 
 	def delete_events(self):
-		frappe.delete_doc("Event", frappe.db.sql_list("""select name from `tabEvent`
-			where ref_type=%s and ref_name=%s""", (self.doctype, self.name)),
-			ignore_permissions=True)
+		events = frappe.db.sql_list("""select name from `tabEvent`
+			where ref_type=%s and ref_name=%s""", (self.doctype, self.name))
+		if events:
+			frappe.db.sql("delete from `tabEvent` where name in (%s)"
+				.format(", ".join(['%s']*len(events))), tuple(events))
+				
+			frappe.db.sql("delete from `tabEvent Role` where parent in (%s)"
+				.format(", ".join(['%s']*len(events))), tuple(events))
 
 	def _add_calendar_event(self, opts):
 		opts = frappe._dict(opts)
diff --git a/setup.py b/setup.py
index 2cba2e8..ea74fa8 100644
--- a/setup.py
+++ b/setup.py
@@ -1,6 +1,6 @@
 from setuptools import setup, find_packages
 
-version = "5.0.26"
+version = "5.0.29"
 
 with open("requirements.txt", "r") as f:
 	install_requires = f.readlines()