Merge branch 'develop' into woocommerce-shipping
diff --git a/.travis.yml b/.travis.yml
index 213445b..77d427e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,6 +1,5 @@
-dist: trusty
-
 language: python
+dist: trusty
 
 git:
   depth: 1
@@ -14,21 +13,10 @@
 
 jobs:
   include:
-  - name: "Python 2.7 Server Side Test"
-    python: 2.7
-    script: bench --site test_site run-tests --app erpnext --coverage
-
   - name: "Python 3.6 Server Side Test"
     python: 3.6
     script: bench --site test_site run-tests --app erpnext --coverage
 
-  - name: "Python 2.7 Patch Test"
-    python: 2.7
-    before_script:
-      - wget http://build.erpnext.com/20171108_190013_955977f8_database.sql.gz
-      - bench --site test_site --force restore ~/frappe-bench/20171108_190013_955977f8_database.sql.gz
-    script: bench --site test_site migrate
-
   - name: "Python 3.6 Patch Test"
     python: 3.6
     before_script:
@@ -40,8 +28,7 @@
   - cd ~
   - nvm install 10
 
-  - git clone https://github.com/frappe/bench --depth 1
-  - pip install -e ./bench
+  - pip install frappe-bench
 
   - git clone https://github.com/frappe/frappe --branch $TRAVIS_BRANCH --depth 1
   - bench init --skip-assets --frappe-path ~/frappe --python $(which python) frappe-bench
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index 786b9cf..38d8a62 100644
--- a/erpnext/__init__.py
+++ b/erpnext/__init__.py
@@ -5,7 +5,7 @@
 from erpnext.hooks import regional_overrides
 from frappe.utils import getdate
 
-__version__ = '12.0.0-dev'
+__version__ = '13.0.0-dev'
 
 def get_default_company(user=None):
 	'''Get default company for user'''
diff --git a/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py b/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py
index c3e2f7d..39bf4b0 100644
--- a/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py
+++ b/erpnext/accounts/dashboard_chart_source/account_balance_timeline/account_balance_timeline.py
@@ -6,7 +6,7 @@
 from frappe import _
 from frappe.utils import add_to_date, date_diff, getdate, nowdate, get_last_day, formatdate, get_link_to_form
 from erpnext.accounts.report.general_ledger.general_ledger import execute
-from frappe.core.page.dashboard.dashboard import cache_source, get_from_date_from_timespan
+from frappe.utils.dashboard import cache_source, get_from_date_from_timespan
 from frappe.desk.doctype.dashboard_chart.dashboard_chart import get_period_ending
 
 from frappe.utils.nestedset import get_descendants_of
@@ -14,7 +14,7 @@
 @frappe.whitelist()
 @cache_source
 def get(chart_name = None, chart = None, no_cache = None, filters = None, from_date = None,
-	to_date = None, timespan = None, time_interval = None):
+	to_date = None, timespan = None, time_interval = None, heatmap_year = None):
 	if chart_name:
 		chart = frappe.get_doc('Dashboard Chart', chart_name)
 	else:
diff --git a/erpnext/accounts/dashboard_fixtures.py b/erpnext/accounts/dashboard_fixtures.py
new file mode 100644
index 0000000..cdd1661
--- /dev/null
+++ b/erpnext/accounts/dashboard_fixtures.py
@@ -0,0 +1,127 @@
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+from erpnext import get_default_company
+
+import frappe
+import json
+
+
+def get_data():
+	data = frappe._dict({
+		"dashboards": [],
+		"charts": []
+	})
+	company = get_company_for_dashboards()
+	if company:
+		company_doc = frappe.get_doc("Company", company)
+		data.dashboards = get_dashboards()
+		data.charts = get_charts(company_doc)
+	return data
+
+def get_dashboards():
+	return [{
+		"name": "Accounts",
+		"dashboard_name": "Accounts",
+		"charts": [
+			{ "chart": "Outgoing Bills (Sales Invoice)" },
+			{ "chart": "Incoming Bills (Purchase Invoice)" },
+			{ "chart": "Bank Balance" },
+			{ "chart": "Income" },
+			{ "chart": "Expenses" }
+		]
+	}]
+
+def get_charts(company):
+	income_account = company.default_income_account or get_account("Income Account", company.name)
+	expense_account = company.default_expense_account or get_account("Expense Account", company.name)
+	bank_account = company.default_bank_account or get_account("Bank", company.name)
+
+	return [
+		{
+			"doctype": "Dashboard Chart",
+			"time_interval": "Quarterly",
+			"name": "Income",
+			"chart_name": "Income",
+			"timespan": "Last Year",
+			"color": None,
+			"filters_json": json.dumps({"company": company.name, "account": income_account}),
+			"source": "Account Balance Timeline",
+			"chart_type": "Custom",
+			"timeseries": 1,
+			"owner": "Administrator",
+			"type": "Line"
+		},
+		{
+			"doctype": "Dashboard Chart",
+			"time_interval": "Quarterly",
+			"name": "Expenses",
+			"chart_name": "Expenses",
+			"timespan": "Last Year",
+			"color": None,
+			"filters_json": json.dumps({"company": company.name, "account": expense_account}),
+			"source": "Account Balance Timeline",
+			"chart_type": "Custom",
+			"timeseries": 1,
+			"owner": "Administrator",
+			"type": "Line"
+		},
+		{
+			"doctype": "Dashboard Chart",
+			"time_interval": "Quarterly",
+			"name": "Bank Balance",
+			"chart_name": "Bank Balance",
+			"timespan": "Last Year",
+			"color": "#ffb868",
+			"filters_json": json.dumps({"company": company.name, "account": bank_account}),
+			"source": "Account Balance Timeline",
+			"chart_type": "Custom",
+			"timeseries": 1,
+			"owner": "Administrator",
+			"type": "Line"
+		},
+		{
+			"doctype": "Dashboard Chart",
+			"time_interval": "Monthly",
+			"name": "Incoming Bills (Purchase Invoice)",
+			"chart_name": "Incoming Bills (Purchase Invoice)",
+			"timespan": "Last Year",
+			"color": "#a83333",
+			"value_based_on": "base_grand_total",
+			"filters_json": json.dumps({}),
+			"chart_type": "Sum",
+			"timeseries": 1,
+			"based_on": "posting_date",
+			"owner": "Administrator",
+			"document_type": "Purchase Invoice",
+			"type": "Bar"
+		},
+		{
+			"doctype": "Dashboard Chart",
+			"time_interval": "Monthly",
+			"name": "Outgoing Bills (Sales Invoice)",
+			"chart_name": "Outgoing Bills (Sales Invoice)",
+			"timespan": "Last Year",
+			"color": "#7b933d",
+			"value_based_on": "base_grand_total",
+			"filters_json": json.dumps({}),
+			"chart_type": "Sum",
+			"timeseries": 1,
+			"based_on": "posting_date",
+			"owner": "Administrator",
+			"document_type": "Sales Invoice",
+			"type": "Bar"
+		}
+	]
+
+def get_account(account_type, company):
+	accounts = frappe.get_list("Account", filters={"account_type": account_type, "company": company})
+	if accounts:
+		return accounts[0].name
+
+def get_company_for_dashboards():
+	company = get_default_company()
+	if not company:
+		company_list = frappe.get_list("Company")
+		if company_list:
+			company = company_list[0].name
+	return company
diff --git a/erpnext/accounts/deferred_revenue.py b/erpnext/accounts/deferred_revenue.py
index b0210e5..b57e678 100644
--- a/erpnext/accounts/deferred_revenue.py
+++ b/erpnext/accounts/deferred_revenue.py
@@ -185,7 +185,7 @@
 			total_days, total_booking_days, account_currency)
 
 		make_gl_entries(doc, credit_account, debit_account, against,
-			amount, base_amount, end_date, project, account_currency, item.cost_center, item.name, deferred_process)
+			amount, base_amount, end_date, project, account_currency, item.cost_center, item, deferred_process)
 
 		# Returned in case of any errors because it tries to submit the same record again and again in case of errors
 		if frappe.flags.deferred_accounting_error:
@@ -222,7 +222,7 @@
 		doc.submit()
 
 def make_gl_entries(doc, credit_account, debit_account, against,
-	amount, base_amount, posting_date, project, account_currency, cost_center, voucher_detail_no, deferred_process=None):
+	amount, base_amount, posting_date, project, account_currency, cost_center, item, deferred_process=None):
 	# GL Entry for crediting the amount in the deferred expense
 	from erpnext.accounts.general_ledger import make_gl_entries
 
@@ -236,12 +236,12 @@
 			"credit": base_amount,
 			"credit_in_account_currency": amount,
 			"cost_center": cost_center,
-			"voucher_detail_no": voucher_detail_no,
+			"voucher_detail_no": item.name,
 			'posting_date': posting_date,
 			'project': project,
 			'against_voucher_type': 'Process Deferred Accounting',
 			'against_voucher': deferred_process
-		}, account_currency)
+		}, account_currency, item=item)
 	)
 	# GL Entry to debit the amount from the expense
 	gl_entries.append(
@@ -251,12 +251,12 @@
 			"debit": base_amount,
 			"debit_in_account_currency": amount,
 			"cost_center": cost_center,
-			"voucher_detail_no": voucher_detail_no,
+			"voucher_detail_no": item.name,
 			'posting_date': posting_date,
 			'project': project,
 			'against_voucher_type': 'Process Deferred Accounting',
 			'against_voucher': deferred_process
-		}, account_currency)
+		}, account_currency, item=item)
 	)
 
 	if gl_entries:
diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
index 7a85bfb..894ec5b 100644
--- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
+++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.py
@@ -162,9 +162,9 @@
 
 def get_doctypes_with_dimensions():
 	doclist = ["GL Entry", "Sales Invoice", "Purchase Invoice", "Payment Entry", "Asset",
-		"Expense Claim", "Stock Entry", "Budget", "Payroll Entry", "Delivery Note", "Sales Invoice Item", "Purchase Invoice Item",
-		"Purchase Order Item", "Journal Entry Account", "Material Request Item", "Delivery Note Item", "Purchase Receipt Item",
-		"Stock Entry Detail", "Payment Entry Deduction", "Sales Taxes and Charges", "Purchase Taxes and Charges", "Shipping Rule",
+		"Expense Claim", "Expense Claim Detail", "Expense Taxes and Charges", "Stock Entry", "Budget", "Payroll Entry", "Delivery Note",
+		"Sales Invoice Item", "Purchase Invoice Item", "Purchase Order Item", "Journal Entry Account", "Material Request Item", "Delivery Note Item",
+		"Purchase Receipt Item", "Stock Entry Detail", "Payment Entry Deduction", "Sales Taxes and Charges", "Purchase Taxes and Charges", "Shipping Rule",
 		"Landed Cost Item", "Asset Value Adjustment", "Loyalty Program", "Fee Schedule", "Fee Structure", "Stock Reconciliation",
 		"Travel Request", "Fees", "POS Profile", "Opening Invoice Creation Tool", "Opening Invoice Creation Tool Item", "Subscription",
 		"Subscription Plan"]
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py
index efab580..291aff3 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py
@@ -112,8 +112,8 @@
 			from tabAccount where name=%s""", self.account, as_dict=1)[0]
 
 		if ret.is_group==1:
-			frappe.throw(_("{0} {1}: Account {2} cannot be a Group")
-				.format(self.voucher_type, self.voucher_no, self.account))
+			frappe.throw(_('''{0} {1}: Account {2} is a Group Account and group accounts cannot be used in
+				transactions''').format(self.voucher_type, self.voucher_no, self.account))
 
 		if ret.docstatus==2:
 			frappe.throw(_("{0} {1}: Account {2} is inactive")
diff --git a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py
index 39fc203..594b4d4 100644
--- a/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py
+++ b/erpnext/accounts/doctype/invoice_discounting/invoice_discounting.py
@@ -8,6 +8,7 @@
 from frappe.utils import flt, getdate, nowdate, add_days
 from erpnext.controllers.accounts_controller import AccountsController
 from erpnext.accounts.general_ledger import make_gl_entries
+from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
 
 class InvoiceDiscounting(AccountsController):
 	def validate(self):
@@ -81,10 +82,15 @@
 	def make_gl_entries(self):
 		company_currency = frappe.get_cached_value('Company',  self.company, "default_currency")
 
+
 		gl_entries = []
+		invoice_fields = ["debit_to", "party_account_currency", "conversion_rate", "cost_center"]
+		accounting_dimensions = get_accounting_dimensions()
+
+		invoice_fields.extend(accounting_dimensions)
+
 		for d in self.invoices:
-			inv = frappe.db.get_value("Sales Invoice", d.sales_invoice,
-				["debit_to", "party_account_currency", "conversion_rate", "cost_center"], as_dict=1)
+			inv = frappe.db.get_value("Sales Invoice", d.sales_invoice, invoice_fields, as_dict=1)
 
 			if d.outstanding_amount:
 				outstanding_in_company_currency = flt(d.outstanding_amount * inv.conversion_rate,
@@ -102,7 +108,7 @@
 					"cost_center": inv.cost_center,
 					"against_voucher": d.sales_invoice,
 					"against_voucher_type": "Sales Invoice"
-				}, inv.party_account_currency))
+				}, inv.party_account_currency, item=inv))
 
 				gl_entries.append(self.get_gl_dict({
 					"account": self.accounts_receivable_credit,
@@ -115,7 +121,7 @@
 					"cost_center": inv.cost_center,
 					"against_voucher": d.sales_invoice,
 					"against_voucher_type": "Sales Invoice"
-				}, ar_credit_account_currency))
+				}, ar_credit_account_currency, item=inv))
 
 		make_gl_entries(gl_entries, cancel=(self.docstatus == 2), update_outstanding='No')
 
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index 83c670e..d2245d6 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -86,7 +86,7 @@
 		self.update_payment_schedule(cancel=1)
 		self.set_payment_req_status()
 		self.set_status()
-	
+
 	def set_payment_req_status(self):
 		from erpnext.accounts.doctype.payment_request.payment_request import update_payment_req_status
 		update_payment_req_status(self, None)
@@ -280,7 +280,7 @@
 				outstanding_amount, is_return = frappe.get_cached_value(d.reference_doctype, d.reference_name, ["outstanding_amount", "is_return"])
 				if outstanding_amount <= 0 and not is_return:
 					no_oustanding_refs.setdefault(d.reference_doctype, []).append(d)
-		
+
 		for k, v in no_oustanding_refs.items():
 			frappe.msgprint(_("{} - {} now have {} as they had no outstanding amount left before submitting the Payment Entry.<br><br>\
 					If this is undesirable please cancel the corresponding Payment Entry.")
@@ -451,8 +451,6 @@
 				frappe.throw(_("Reference No and Reference Date is mandatory for Bank transaction"))
 
 	def set_remarks(self):
-		if self.remarks: return
-
 		if self.payment_type=="Internal Transfer":
 			remarks = [_("Amount {0} {1} transferred from {2} to {3}")
 				.format(self.paid_from_account_currency, self.paid_amount, self.paid_from, self.paid_to)]
@@ -506,7 +504,7 @@
 				"against": against_account,
 				"account_currency": self.party_account_currency,
 				"cost_center": self.cost_center
-			})
+			}, item=self)
 
 			dr_or_cr = "credit" if erpnext.get_party_account_type(self.party_type) == 'Receivable' else "debit"
 
@@ -550,7 +548,7 @@
 					"credit_in_account_currency": self.paid_amount,
 					"credit": self.base_paid_amount,
 					"cost_center": self.cost_center
-				})
+				}, item=self)
 			)
 		if self.payment_type in ("Receive", "Internal Transfer"):
 			gl_entries.append(
@@ -561,7 +559,7 @@
 					"debit_in_account_currency": self.received_amount,
 					"debit": self.base_received_amount,
 					"cost_center": self.cost_center
-				})
+				}, item=self)
 			)
 
 	def add_deductions_gl_entries(self, gl_entries):
diff --git a/erpnext/accounts/doctype/payment_order/payment_order.py b/erpnext/accounts/doctype/payment_order/payment_order.py
index 3f3174a..7ecdc41 100644
--- a/erpnext/accounts/doctype/payment_order/payment_order.py
+++ b/erpnext/accounts/doctype/payment_order/payment_order.py
@@ -80,7 +80,7 @@
 			paid_amt += d.amount
 
 	je.append('accounts', {
-		'account': doc.references[0].account,
+		'account': doc.account,
 		'credit_in_account_currency': paid_amt
 	})
 
diff --git a/erpnext/accounts/doctype/payment_request/payment_request.json b/erpnext/accounts/doctype/payment_request/payment_request.json
index 97ae5ff..7508683 100644
--- a/erpnext/accounts/doctype/payment_request/payment_request.json
+++ b/erpnext/accounts/doctype/payment_request/payment_request.json
@@ -1,4 +1,5 @@
 {
+ "actions": [],
  "autoname": "naming_series:",
  "creation": "2015-12-15 22:23:24.745065",
  "doctype": "DocType",
@@ -210,13 +211,14 @@
    "label": "IBAN"
   },
   {
-   "fetch_from": "bank_account.branch_code",
+   "fetch_from": "bank.branch_code",
+   "fetch_if_empty": 1,
    "fieldname": "branch_code",
    "fieldtype": "Read Only",
    "label": "Branch Code"
   },
   {
-   "fetch_from": "bank_account.swift_number",
+   "fetch_from": "bank.swift_number",
    "fieldname": "swift_number",
    "fieldtype": "Read Only",
    "label": "SWIFT Number"
@@ -348,7 +350,8 @@
   }
  ],
  "is_submittable": 1,
- "modified": "2020-03-28 16:07:31.960798",
+ "links": [],
+ "modified": "2020-05-08 10:23:02.815237",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Payment Request",
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
index 19f571f..4d9053a 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
@@ -99,7 +99,7 @@
 				self.same_item = 1
 
 	def validate_max_discount(self):
-		if self.rate_or_discount == "Discount Percentage" and self.items:
+		if self.rate_or_discount == "Discount Percentage" and self.get("items"):
 			for d in self.items:
 				max_discount = frappe.get_cached_value("Item", d.item_code, "max_discount")
 				if max_discount and flt(self.discount_percentage) > flt(max_discount):
diff --git a/erpnext/accounts/doctype/pricing_rule/utils.py b/erpnext/accounts/doctype/pricing_rule/utils.py
index b358f56..cb05481 100644
--- a/erpnext/accounts/doctype/pricing_rule/utils.py
+++ b/erpnext/accounts/doctype/pricing_rule/utils.py
@@ -4,13 +4,19 @@
 # For license information, please see license.txt
 
 from __future__ import unicode_literals
-import frappe, copy, json
-from frappe import throw, _
+
+import copy
+import json
+
 from six import string_types
-from frappe.utils import flt, cint, get_datetime, get_link_to_form, today
+
+import frappe
 from erpnext.setup.doctype.item_group.item_group import get_child_item_groups
 from erpnext.stock.doctype.warehouse.warehouse import get_child_warehouses
 from erpnext.stock.get_item_details import get_conversion_factor
+from frappe import _, throw
+from frappe.utils import cint, flt, get_datetime, get_link_to_form, getdate, today
+
 
 class MultiplePricingRuleConflict(frappe.ValidationError): pass
 
@@ -502,18 +508,16 @@
 	return list(set(apply_on_data))
 
 def validate_coupon_code(coupon_name):
-	from frappe.utils import today,getdate
-	coupon=frappe.get_doc("Coupon Code",coupon_name)
+	coupon = frappe.get_doc("Coupon Code", coupon_name)
+
 	if coupon.valid_from:
-		if coupon.valid_from > getdate(today()) :
-			frappe.throw(_("Sorry,coupon code validity has not started"))
+		if coupon.valid_from > getdate(today()):
+			frappe.throw(_("Sorry, this coupon code's validity has not started"))
 	elif coupon.valid_upto:
-		if coupon.valid_upto < getdate(today()) :
-			frappe.throw(_("Sorry,coupon code validity has expired"))
-	elif coupon.used>=coupon.maximum_use:
-		frappe.throw(_("Sorry,coupon code are exhausted"))
-	else:
-		return
+		if coupon.valid_upto < getdate(today()):
+			frappe.throw(_("Sorry, this coupon code's validity has expired"))
+	elif coupon.used >= coupon.maximum_use:
+		frappe.throw(_("Sorry, this coupon code is no longer valid"))
 
 def update_coupon_code_count(coupon_name,transaction_type):
 	coupon=frappe.get_doc("Coupon Code",coupon_name)
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 3aa24df..aa1d5b5 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -460,7 +460,7 @@
 					"against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
 					"against_voucher_type": self.doctype,
 					"cost_center": self.cost_center
-				}, self.party_account_currency)
+				}, self.party_account_currency, item=self)
 			)
 
 	def make_item_gl_entries(self, gl_entries):
@@ -841,7 +841,7 @@
 					"against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
 					"against_voucher_type": self.doctype,
 					"cost_center": self.cost_center
-				}, self.party_account_currency)
+				}, self.party_account_currency, item=self)
 			)
 
 			gl_entries.append(
@@ -852,7 +852,7 @@
 					"credit_in_account_currency": self.base_paid_amount \
 						if bank_account_currency==self.company_currency else self.paid_amount,
 					"cost_center": self.cost_center
-				}, bank_account_currency)
+				}, bank_account_currency, item=self)
 			)
 
 	def make_write_off_gl_entry(self, gl_entries):
@@ -873,7 +873,7 @@
 					"against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
 					"against_voucher_type": self.doctype,
 					"cost_center": self.cost_center
-				}, self.party_account_currency)
+				}, self.party_account_currency, item=self)
 			)
 			gl_entries.append(
 				self.get_gl_dict({
@@ -883,7 +883,7 @@
 					"credit_in_account_currency": self.base_write_off_amount \
 						if write_off_account_currency==self.company_currency else self.write_off_amount,
 					"cost_center": self.cost_center or self.write_off_cost_center
-				})
+				}, item=self)
 			)
 
 	def make_gle_for_rounding_adjustment(self, gl_entries):
@@ -902,8 +902,7 @@
 					"debit_in_account_currency": self.rounding_adjustment,
 					"debit": self.base_rounding_adjustment,
 					"cost_center": self.cost_center or round_off_cost_center,
-				}
-			))
+				}, item=self))
 
 	def on_cancel(self):
 		super(PurchaseInvoice, self).on_cancel()
@@ -1021,6 +1020,40 @@
 
 		# calculate totals again after applying TDS
 		self.calculate_taxes_and_totals()
+	
+	def set_status(self, update=False, status=None, update_modified=True):
+		if self.is_new():
+			if self.get('amended_from'):
+				self.status = 'Draft'
+			return
+
+		precision = self.precision("outstanding_amount")
+		outstanding_amount = flt(self.outstanding_amount, precision)
+		due_date = getdate(self.due_date)
+		nowdate = getdate()
+
+		if not status:
+			if self.docstatus == 2:
+				status = "Cancelled"
+			elif self.docstatus == 1:
+				if outstanding_amount > 0 and due_date < nowdate:
+					self.status = "Overdue"
+				elif outstanding_amount > 0 and due_date >= nowdate:
+					self.status = "Unpaid"
+				#Check if outstanding amount is 0 due to debit note issued against invoice
+				elif outstanding_amount <= 0 and self.is_return == 0 and frappe.db.get_value('Purchase Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1}):
+					self.status = "Debit Note Issued"
+				elif self.is_return == 1:
+					self.status = "Return"
+				elif outstanding_amount<=0:
+					self.status = "Paid"
+				else:
+					self.status = "Submitted"
+			else:
+				self.status = "Draft"
+
+		if update:
+			self.db_set('status', self.status, update_modified = update_modified)
 
 def get_list_context(context=None):
 	from erpnext.controllers.website_list_for_contact import get_list_context
diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
index e41ad42..6170005 100644
--- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py
@@ -86,6 +86,8 @@
 		pe.submit()
 
 		pi_doc = frappe.get_doc('Purchase Invoice', pi_doc.name)
+		pi_doc.load_from_db()
+		self.assertTrue(pi_doc.status, "Paid")
 
 		self.assertRaises(frappe.LinkExistsError, pi_doc.cancel)
 		unlink_payment_on_cancel_of_invoice()
@@ -203,7 +205,9 @@
 
 		pi.insert()
 		pi.submit()
+		pi.load_from_db()
 
+		self.assertTrue(pi.status, "Unpaid")
 		self.check_gle_for_pi(pi.name)
 
 	def check_gle_for_pi(self, pi):
@@ -234,6 +238,9 @@
 
 		pi = frappe.copy_doc(test_records[0])
 		pi.insert()
+		pi.load_from_db()
+
+		self.assertTrue(pi.status, "Draft")
 		pi.naming_series = 'TEST-'
 
 		self.assertRaises(frappe.CannotChangeConstantError, pi.save)
@@ -248,6 +255,8 @@
 		pi.get("taxes").pop(1)
 		pi.insert()
 		pi.submit()
+		pi.load_from_db()
+		self.assertTrue(pi.status, "Unpaid")
 
 		gl_entries = frappe.db.sql("""select account, debit, credit
 			from `tabGL Entry` where voucher_type='Purchase Invoice' and voucher_no=%s
@@ -599,6 +608,11 @@
 		# return entry
 		pi1 = make_purchase_invoice(is_return=1, return_against=pi.name, qty=-2, rate=50, update_stock=1)
 
+		pi.load_from_db()
+		self.assertTrue(pi.status, "Debit Note Issued")
+		pi1.load_from_db()
+		self.assertTrue(pi1.status, "Return")
+
 		actual_qty_2 = get_qty_after_transaction()
 		self.assertEqual(actual_qty_1 - 2, actual_qty_2)
 
@@ -771,6 +785,8 @@
 		from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import get_outstanding_amount
 
 		pi = make_purchase_invoice(item_code = "_Test Item", qty = (5 * -1), rate=500, is_return = 1)
+		pi.load_from_db()
+		self.assertTrue(pi.status, "Return")
 
 		outstanding_amount = get_outstanding_amount(pi.doctype,
 			pi.name, "Creditors - _TC", pi.supplier, "Supplier")
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 3b0fade..05b85da 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -791,7 +791,7 @@
 					"against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
 					"against_voucher_type": self.doctype,
 					"cost_center": self.cost_center
-				}, self.party_account_currency)
+				}, self.party_account_currency, item=self)
 			)
 
 	def make_tax_gl_entries(self, gl_entries):
@@ -808,7 +808,7 @@
 							tax.precision("base_tax_amount_after_discount_amount")) if account_currency==self.company_currency else
 							flt(tax.tax_amount_after_discount_amount, tax.precision("tax_amount_after_discount_amount"))),
 						"cost_center": tax.cost_center
-					}, account_currency)
+					}, account_currency, item=tax)
 				)
 
 	def make_item_gl_entries(self, gl_entries):
@@ -828,7 +828,7 @@
 
 					for gle in fixed_asset_gl_entries:
 						gle["against"] = self.customer
-						gl_entries.append(self.get_gl_dict(gle))
+						gl_entries.append(self.get_gl_dict(gle, item=item))
 
 					asset.db_set("disposal_date", self.posting_date)
 					asset.set_status("Sold" if self.docstatus==1 else None)
@@ -866,7 +866,7 @@
 					"against_voucher": self.return_against if cint(self.is_return) else self.name,
 					"against_voucher_type": self.doctype,
 					"cost_center": self.cost_center
-				})
+				}, item=self)
 			)
 			gl_entries.append(
 				self.get_gl_dict({
@@ -875,7 +875,7 @@
 					"against": self.customer,
 					"debit": self.loyalty_amount,
 					"remark": "Loyalty Points redeemed by the customer"
-				})
+				}, item=self)
 			)
 
 	def make_pos_gl_entries(self, gl_entries):
@@ -896,7 +896,7 @@
 							"against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
 							"against_voucher_type": self.doctype,
 							"cost_center": self.cost_center
-						}, self.party_account_currency)
+						}, self.party_account_currency, item=self)
 					)
 
 					payment_mode_account_currency = get_account_currency(payment_mode.account)
@@ -909,7 +909,7 @@
 								if payment_mode_account_currency==self.company_currency \
 								else payment_mode.amount,
 							"cost_center": self.cost_center
-						}, payment_mode_account_currency)
+						}, payment_mode_account_currency, item=self)
 					)
 
 	def make_gle_for_change_amount(self, gl_entries):
@@ -927,7 +927,7 @@
 						"against_voucher": self.return_against if cint(self.is_return) and self.return_against else self.name,
 						"against_voucher_type": self.doctype,
 						"cost_center": self.cost_center
-					}, self.party_account_currency)
+					}, self.party_account_currency, item=self)
 				)
 
 				gl_entries.append(
@@ -936,7 +936,7 @@
 						"against": self.customer,
 						"credit": self.base_change_amount,
 						"cost_center": self.cost_center
-					})
+					}, item=self)
 				)
 			else:
 				frappe.throw(_("Select change amount account"), title="Mandatory Field")
@@ -960,7 +960,7 @@
 					"against_voucher": self.return_against if cint(self.is_return) else self.name,
 					"against_voucher_type": self.doctype,
 					"cost_center": self.cost_center
-				}, self.party_account_currency)
+				}, self.party_account_currency, item=self)
 			)
 			gl_entries.append(
 				self.get_gl_dict({
@@ -971,7 +971,7 @@
 						self.precision("base_write_off_amount")) if write_off_account_currency==self.company_currency
 						else flt(self.write_off_amount, self.precision("write_off_amount"))),
 					"cost_center": self.cost_center or self.write_off_cost_center or default_cost_center
-				}, write_off_account_currency)
+				}, write_off_account_currency, item=self)
 			)
 
 	def make_gle_for_rounding_adjustment(self, gl_entries):
@@ -988,8 +988,7 @@
 					"credit": flt(self.base_rounding_adjustment,
 						self.precision("base_rounding_adjustment")),
 					"cost_center": self.cost_center or round_off_cost_center,
-				}
-			))
+				}, item=self))
 
 	def update_billing_status_in_dn(self, update_modified=True):
 		updated_delivery_notes = []
diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
index dd6b4fd..87fe371 100644
--- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
+++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py
@@ -58,7 +58,7 @@
 				"rate": tax_rate_detail.tax_withholding_rate,
 				"threshold": tax_rate_detail.single_threshold,
 				"cumulative_threshold": tax_rate_detail.cumulative_threshold,
-				"description": tax_withholding.category_name
+				"description": tax_withholding.category_name if tax_withholding.category_name else tax_withholding_category
 			})
 
 def get_tax_withholding_rates(tax_withholding, fiscal_year):
@@ -162,8 +162,7 @@
 		debit_note_amount = get_debit_note_amount(suppliers, year_start_date, year_end_date)
 		supplier_credit_amount -= debit_note_amount
 
-		if ((tax_details.get('threshold', 0) and supplier_credit_amount >= tax_details.threshold)
-			or (tax_details.get('cumulative_threshold', 0) and supplier_credit_amount >= tax_details.cumulative_threshold)):
+		if supplier_credit_amount >= tax_details.get('threshold', 0) or supplier_credit_amount >= tax_details.get('cumulative_threshold', 0):
 
 			if ldc and is_valid_certificate(ldc.valid_from, ldc.valid_upto, posting_date, tds_deducted, net_total,
 				ldc.certificate_limit):
@@ -225,4 +224,4 @@
 			certificate_limit > deducted_amount):
 		valid = True
 
-	return valid
\ No newline at end of file
+	return valid
diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py
index fb1a4f4..bfe35ab 100644
--- a/erpnext/accounts/general_ledger.py
+++ b/erpnext/accounts/general_ledger.py
@@ -297,7 +297,8 @@
 			fields = ["*"],
 			filters = {
 				"voucher_type": voucher_type,
-				"voucher_no": voucher_no
+				"voucher_no": voucher_no,
+				"is_cancelled": 0
 			})
 
 	if gl_entries:
diff --git a/erpnext/accounts/report/budget_variance_report/budget_variance_report.py b/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
index 39e218b..49c1d0f 100644
--- a/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
+++ b/erpnext/accounts/report/budget_variance_report/budget_variance_report.py
@@ -2,16 +2,19 @@
 # License: GNU General Public License v3. See license.txt
 
 from __future__ import unicode_literals
+import datetime
+from six import iteritems
+
 import frappe
 from frappe import _
-from frappe.utils import flt
-from frappe.utils import formatdate
+from frappe.utils import flt, formatdate
+
 from erpnext.controllers.trends import get_period_date_ranges, get_period_month_ranges
 
-from six import iteritems
-from pprint import pprint
+
 def execute(filters=None):
-	if not filters: filters = {}
+	if not filters:
+		filters = {}
 
 	columns = get_columns(filters)
 	if filters.get("budget_against_filter"):
@@ -43,20 +46,25 @@
 
 						period_data[0] += last_total
 
-						if(filters.get("show_cumulative")):
+						if filters.get("show_cumulative"):
 							last_total = period_data[0] - period_data[1]
 
 						period_data[2] = period_data[0] - period_data[1]
 						row += period_data
 				totals[2] = totals[0] - totals[1]
-				if filters["period"] != "Yearly" :
+				if filters["period"] != "Yearly":
 					row += totals
 				data.append(row)
 
 	return columns, data
 
+
 def get_columns(filters):
-	columns = [_(filters.get("budget_against")) + ":Link/%s:150"%(filters.get("budget_against")), _("Account") + ":Link/Account:150"]
+	columns = [
+		_(filters.get("budget_against"))
+		+ ":Link/%s:150" % (filters.get("budget_against")),
+		_("Account") + ":Link/Account:150"
+	]
 
 	group_months = False if filters["period"] == "Monthly" else True
 
@@ -65,84 +73,181 @@
 	for year in fiscal_year:
 		for from_date, to_date in get_period_date_ranges(filters["period"], year[0]):
 			if filters["period"] == "Yearly":
-				labels = [_("Budget") + " " + str(year[0]), _("Actual ") + " " + str(year[0]), _("Variance ") + " " + str(year[0])]
+				labels = [
+					_("Budget") + " " + str(year[0]),
+					_("Actual ") + " " + str(year[0]),
+					_("Variance ") + " " + str(year[0])
+				]
 				for label in labels:
-					columns.append(label+":Float:150")
+					columns.append(label + ":Float:150")
 			else:
-				for label in [_("Budget") + " (%s)" + " " + str(year[0]), _("Actual") + " (%s)" + " " + str(year[0]), _("Variance") + " (%s)" + " " + str(year[0])]:
+				for label in [
+					_("Budget") + " (%s)" + " " + str(year[0]),
+					_("Actual") + " (%s)" + " " + str(year[0]),
+					_("Variance") + " (%s)" + " " + str(year[0])
+				]:
 					if group_months:
-						label = label % (formatdate(from_date, format_string="MMM") + "-" + formatdate(to_date, format_string="MMM"))
+						label = label % (
+							formatdate(from_date, format_string="MMM")
+							+ "-"
+							+ formatdate(to_date, format_string="MMM")
+						)
 					else:
 						label = label % formatdate(from_date, format_string="MMM")
 
-					columns.append(label+":Float:150")
+					columns.append(label + ":Float:150")
 
-	if filters["period"] != "Yearly" :
-		return columns + [_("Total Budget") + ":Float:150", _("Total Actual") + ":Float:150",
-			_("Total Variance") + ":Float:150"]
+	if filters["period"] != "Yearly":
+		return columns + [
+			_("Total Budget") + ":Float:150",
+			_("Total Actual") + ":Float:150",
+			_("Total Variance") + ":Float:150"
+		]
 	else:
 		return columns
 
+
 def get_cost_centers(filters):
-	cond = "and 1=1"
+	order_by = ""
 	if filters.get("budget_against") == "Cost Center":
-		cond = "order by lft"
+		order_by = "order by lft"
 
 	if filters.get("budget_against") in ["Cost Center", "Project"]:
-		return frappe.db.sql_list("""select name from `tab{tab}` where company=%s
-			{cond}""".format(tab=filters.get("budget_against"), cond=cond), filters.get("company"))
+		return frappe.db.sql_list(
+			"""
+				select
+					name
+				from
+					`tab{tab}`
+				where
+					company = %s
+				{order_by}
+			""".format(tab=filters.get("budget_against"), order_by=order_by),
+			filters.get("company"))
 	else:
-		return frappe.db.sql_list("""select name from `tab{tab}`""".format(tab=filters.get("budget_against"))) #nosec
+		return frappe.db.sql_list(
+			"""
+				select
+					name
+				from
+					`tab{tab}`
+			""".format(tab=filters.get("budget_against")))  # nosec
 
-#Get dimension & target details
+
+# Get dimension & target details
 def get_dimension_target_details(filters):
+	budget_against = frappe.scrub(filters.get("budget_against"))
 	cond = ""
 	if filters.get("budget_against_filter"):
-		cond += " and b.{budget_against} in (%s)".format(budget_against = \
-			frappe.scrub(filters.get('budget_against'))) % ', '.join(['%s']* len(filters.get('budget_against_filter')))
+		cond += """ and b.{budget_against} in (%s)""".format(
+			budget_against=budget_against) % ", ".join(["%s"] * len(filters.get("budget_against_filter")))
 
-	return frappe.db.sql("""
-			select b.{budget_against} as budget_against, b.monthly_distribution, ba.account, ba.budget_amount,b.fiscal_year
-			from `tabBudget` b, `tabBudget Account` ba
-			where b.name=ba.parent and b.docstatus = 1 and b.fiscal_year between %s and %s
-			and b.budget_against = %s and b.company=%s {cond} order by b.fiscal_year
-		""".format(budget_against=filters.get("budget_against").replace(" ", "_").lower(), cond=cond),
-		tuple([filters.from_fiscal_year,filters.to_fiscal_year,filters.budget_against, filters.company] + filters.get('budget_against_filter')), 
-		as_dict=True)
+	return frappe.db.sql(
+		"""
+			select
+				b.{budget_against} as budget_against,
+				b.monthly_distribution,
+				ba.account,
+				ba.budget_amount,
+				b.fiscal_year
+			from
+				`tabBudget` b,
+				`tabBudget Account` ba
+			where
+				b.name = ba.parent
+				and b.docstatus = 1
+				and b.fiscal_year between %s and %s
+				and b.budget_against = %s
+				and b.company = %s
+				{cond}
+			order by
+				b.fiscal_year
+		""".format(
+			budget_against=budget_against,
+			cond=cond,
+		),
+		tuple(
+			[
+				filters.from_fiscal_year,
+				filters.to_fiscal_year,
+				filters.budget_against,
+				filters.company,
+			]
+			+ filters.get("budget_against_filter")
+		), as_dict=True)
 
 
-#Get target distribution details of accounts of cost center
+# Get target distribution details of accounts of cost center
 def get_target_distribution_details(filters):
 	target_details = {}
-	for d in frappe.db.sql("""select md.name, mdp.month, mdp.percentage_allocation
-		from `tabMonthly Distribution Percentage` mdp, `tabMonthly Distribution` md
-		where mdp.parent=md.name and md.fiscal_year between %s and %s order by md.fiscal_year""",(filters.from_fiscal_year, filters.to_fiscal_year), as_dict=1):
-			target_details.setdefault(d.name, {}).setdefault(d.month, flt(d.percentage_allocation))
+	for d in frappe.db.sql(
+		"""
+			select
+				md.name,
+				mdp.month,
+				mdp.percentage_allocation
+			from
+				`tabMonthly Distribution Percentage` mdp,
+				`tabMonthly Distribution` md
+			where
+				mdp.parent = md.name
+				and md.fiscal_year between %s and %s
+			order by
+				md.fiscal_year
+		""",
+		(filters.from_fiscal_year, filters.to_fiscal_year), as_dict=1):
+		target_details.setdefault(d.name, {}).setdefault(
+			d.month, flt(d.percentage_allocation)
+		)
 
 	return target_details
 
-#Get actual details from gl entry
+# Get actual details from gl entry
 def get_actual_details(name, filters):
-	cond = "1=1"
-	budget_against=filters.get("budget_against").replace(" ", "_").lower()
+	budget_against = frappe.scrub(filters.get("budget_against"))
+	cond = ""
 
 	if filters.get("budget_against") == "Cost Center":
 		cc_lft, cc_rgt = frappe.db.get_value("Cost Center", name, ["lft", "rgt"])
-		cond = "lft>='{lft}' and rgt<='{rgt}'".format(lft = cc_lft, rgt=cc_rgt)
+		cond = """
+				and lft >= "{lft}"
+				and rgt <= "{rgt}"
+			""".format(lft=cc_lft, rgt=cc_rgt)
 
-	ac_details = frappe.db.sql("""select gl.account, gl.debit, gl.credit,gl.fiscal_year,
-		MONTHNAME(gl.posting_date) as month_name, b.{budget_against} as budget_against
-		from `tabGL Entry` gl, `tabBudget Account` ba, `tabBudget` b
-		where
-			b.name = ba.parent
-			and b.docstatus = 1
-			and ba.account=gl.account
-			and b.{budget_against} = gl.{budget_against}
-			and gl.fiscal_year between %s and %s
-			and b.{budget_against}=%s
-			and exists(select name from `tab{tab}` where name=gl.{budget_against} and {cond}) group by gl.name order by gl.fiscal_year
-	""".format(tab = filters.budget_against, budget_against = budget_against, cond = cond,from_year=filters.from_fiscal_year,to_year=filters.to_fiscal_year),
-	(filters.from_fiscal_year, filters.to_fiscal_year, name), as_dict=1)
+	ac_details = frappe.db.sql(
+		"""
+			select
+				gl.account,
+				gl.debit,
+				gl.credit,
+				gl.fiscal_year,
+				MONTHNAME(gl.posting_date) as month_name,
+				b.{budget_against} as budget_against
+			from
+				`tabGL Entry` gl,
+				`tabBudget Account` ba,
+				`tabBudget` b
+			where
+				b.name = ba.parent
+				and b.docstatus = 1
+				and ba.account=gl.account
+				and b.{budget_against} = gl.{budget_against}
+				and gl.fiscal_year between %s and %s
+				and b.{budget_against} = %s
+				and exists(
+					select
+						name
+					from
+						`tab{tab}`
+					where
+						name = gl.{budget_against}
+						{cond}
+				)
+				group by
+					gl.name
+				order by gl.fiscal_year
+		""".format(tab=filters.budget_against, budget_against=budget_against, cond=cond),
+		(filters.from_fiscal_year, filters.to_fiscal_year, name), as_dict=1)
 
 	cc_actual_details = {}
 	for d in ac_details:
@@ -151,7 +256,6 @@
 	return cc_actual_details
 
 def get_dimension_account_month_map(filters):
-	import datetime
 	dimension_target_details = get_dimension_target_details(filters)
 	tdd = get_target_distribution_details(filters)
 
@@ -161,28 +265,43 @@
 		actual_details = get_actual_details(ccd.budget_against, filters)
 
 		for month_id in range(1, 13):
-			month = datetime.date(2013, month_id, 1).strftime('%B')
-			cam_map.setdefault(ccd.budget_against, {}).setdefault(ccd.account, {}).setdefault(ccd.fiscal_year,{})\
-				.setdefault(month, frappe._dict({
-					"target": 0.0, "actual": 0.0
-				}))
+			month = datetime.date(2013, month_id, 1).strftime("%B")
+			cam_map.setdefault(ccd.budget_against, {}).setdefault(
+				ccd.account, {}
+			).setdefault(ccd.fiscal_year, {}).setdefault(
+				month, frappe._dict({"target": 0.0, "actual": 0.0})
+			)
 
 			tav_dict = cam_map[ccd.budget_against][ccd.account][ccd.fiscal_year][month]
-			month_percentage = tdd.get(ccd.monthly_distribution, {}).get(month, 0) \
-				if ccd.monthly_distribution else 100.0/12
+			month_percentage = (
+				tdd.get(ccd.monthly_distribution, {}).get(month, 0)
+				if ccd.monthly_distribution
+				else 100.0 / 12
+			)
 
 			tav_dict.target = flt(ccd.budget_amount) * month_percentage / 100
 
 			for ad in actual_details.get(ccd.account, []):
-				if ad.month_name == month:
-						tav_dict.actual += flt(ad.debit) - flt(ad.credit)
+				if ad.month_name == month and ad.fiscal_year == ccd.fiscal_year:
+					tav_dict.actual += flt(ad.debit) - flt(ad.credit)
 
 	return cam_map
 
+
 def get_fiscal_years(filters):
 
-	fiscal_year = frappe.db.sql("""select name from `tabFiscal Year` where
-	name between %(from_fiscal_year)s and %(to_fiscal_year)s""",
-	{'from_fiscal_year': filters["from_fiscal_year"], 'to_fiscal_year': filters["to_fiscal_year"]})
+	fiscal_year = frappe.db.sql(
+		"""
+			select
+				name
+			from
+				`tabFiscal Year`
+			where
+				name between %(from_fiscal_year)s and %(to_fiscal_year)s
+		""",
+		{
+			"from_fiscal_year": filters["from_fiscal_year"],
+			"to_fiscal_year": filters["to_fiscal_year"]
+		})
 
 	return fiscal_year
diff --git a/erpnext/accounts/report/general_ledger/general_ledger.js b/erpnext/accounts/report/general_ledger/general_ledger.js
index 1188bea..2aecd6b 100644
--- a/erpnext/accounts/report/general_ledger/general_ledger.js
+++ b/erpnext/accounts/report/general_ledger/general_ledger.js
@@ -53,7 +53,7 @@
 			"label": __("Voucher No"),
 			"fieldtype": "Data",
 			on_change: function() {
-				frappe.query_report.set_filter_value('group_by', "");
+				frappe.query_report.set_filter_value('group_by', "Group by Voucher (Consolidated)");
 			}
 		},
 		{
diff --git a/erpnext/accounts/report/gross_and_net_profit_report/gross_and_net_profit_report.py b/erpnext/accounts/report/gross_and_net_profit_report/gross_and_net_profit_report.py
index 1c45810..714e48d 100644
--- a/erpnext/accounts/report/gross_and_net_profit_report/gross_and_net_profit_report.py
+++ b/erpnext/accounts/report/gross_and_net_profit_report/gross_and_net_profit_report.py
@@ -9,8 +9,8 @@
 import copy
 
 def execute(filters=None):
-	period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year,
-		filters.periodicity, filters.accumulated_values, filters.company)
+	period_list = get_period_list(filters.from_fiscal_year, filters.to_fiscal_year, filters.period_start_date,
+		filters.period_end_date, filters.filter_based_on, filters.periodicity, filters.accumulated_values, filters.company)
 
 	columns, data = [], []
 
diff --git a/erpnext/accounts/report/trial_balance/trial_balance.js b/erpnext/accounts/report/trial_balance/trial_balance.js
index 622bab6..07752e1 100644
--- a/erpnext/accounts/report/trial_balance/trial_balance.js
+++ b/erpnext/accounts/report/trial_balance/trial_balance.js
@@ -46,7 +46,7 @@
 				"default": frappe.defaults.get_user_default("year_end_date"),
 			},
 			{
-				"fieldname":"cost_center",
+				"fieldname": "cost_center",
 				"label": __("Cost Center"),
 				"fieldtype": "Link",
 				"options": "Cost Center",
@@ -61,7 +61,13 @@
 				}
 			},
 			{
-				"fieldname":"finance_book",
+				"fieldname": "project",
+				"label": __("Project"),
+				"fieldtype": "Link",
+				"options": "Project"
+			},
+			{
+				"fieldname": "finance_book",
 				"label": __("Finance Book"),
 				"fieldtype": "Link",
 				"options": "Finance Book",
@@ -97,7 +103,7 @@
 	}
 
 	erpnext.dimension_filters.forEach((dimension) => {
-		frappe.query_reports["Trial Balance"].filters.splice(5, 0 ,{
+		frappe.query_reports["Trial Balance"].filters.splice(6, 0 ,{
 			"fieldname": dimension["fieldname"],
 			"label": __(dimension["label"]),
 			"fieldtype": "Link",
diff --git a/erpnext/accounts/report/trial_balance/trial_balance.py b/erpnext/accounts/report/trial_balance/trial_balance.py
index d783241..8bd4399 100644
--- a/erpnext/accounts/report/trial_balance/trial_balance.py
+++ b/erpnext/accounts/report/trial_balance/trial_balance.py
@@ -69,6 +69,10 @@
 	gl_entries_by_account = {}
 
 	opening_balances = get_opening_balances(filters)
+
+	#add filter inside list so that the query in financial_statements.py doesn't break
+	filters.project = [filters.project]
+
 	set_gl_entries_by_account(filters.company, filters.from_date,
 		filters.to_date, min_lft, max_rgt, filters, gl_entries_by_account, ignore_closing_entries=not flt(filters.with_period_closing_entry))
 
@@ -102,6 +106,9 @@
 		additional_conditions += """ and cost_center in (select name from `tabCost Center`
 			where lft >= %s and rgt <= %s)""" % (lft, rgt)
 
+	if filters.project:
+		additional_conditions += " and project = %(project)s"
+
 	if filters.finance_book:
 		fb_conditions = " AND finance_book = %(finance_book)s"
 		if filters.include_default_book_entries:
@@ -116,6 +123,7 @@
 		"from_date": filters.from_date,
 		"report_type": report_type,
 		"year_start_date": filters.year_start_date,
+		"project": filters.project,
 		"finance_book": filters.finance_book,
 		"company_fb": frappe.db.get_value("Company", filters.company, 'default_finance_book')
 	}
diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py
index a3200d5..505ba4c 100644
--- a/erpnext/assets/doctype/asset/asset.py
+++ b/erpnext/assets/doctype/asset/asset.py
@@ -125,7 +125,7 @@
 
 		if self.available_for_use_date and getdate(self.available_for_use_date) < getdate(self.purchase_date):
 			frappe.throw(_("Available-for-use Date should be after purchase date"))
-	
+
 	def validate_gross_and_purchase_amount(self):
 		if self.gross_purchase_amount and self.gross_purchase_amount != self.purchase_receipt_amount:
 			frappe.throw(_("Gross Purchase Amount should be {} to purchase amount of one single Asset. {}\
@@ -455,7 +455,7 @@
 			for d in self.get('finance_books'):
 				if d.finance_book == self.default_finance_book:
 					return cint(d.idx) - 1
-	
+
 	def validate_make_gl_entry(self):
 		purchase_document = self.get_purchase_document()
 		asset_bought_with_invoice = purchase_document == self.purchase_invoice
@@ -487,14 +487,14 @@
 		purchase_document = self.purchase_invoice if asset_bought_with_invoice else self.purchase_receipt
 
 		return purchase_document
-	
+
 	def get_asset_accounts(self):
 		fixed_asset_account = get_asset_category_account('fixed_asset_account', asset=self.name,
 					asset_category = self.asset_category, company = self.company)
 
 		cwip_account = get_asset_account("capital_work_in_progress_account",
 			self.name, self.asset_category, self.company)
-		
+
 		return fixed_asset_account, cwip_account
 
 	def make_gl_entries(self):
@@ -513,7 +513,7 @@
 				"credit": self.purchase_receipt_amount,
 				"credit_in_account_currency": self.purchase_receipt_amount,
 				"cost_center": self.cost_center
-			}))
+			}, item=self))
 
 			gl_entries.append(self.get_gl_dict({
 				"account": fixed_asset_account,
@@ -523,7 +523,7 @@
 				"debit": self.purchase_receipt_amount,
 				"debit_in_account_currency": self.purchase_receipt_amount,
 				"cost_center": self.cost_center
-			}))
+			}, item=self))
 
 		if gl_entries:
 			from erpnext.accounts.general_ledger import make_gl_entries
diff --git a/erpnext/assets/doctype/location/location.json b/erpnext/assets/doctype/location/location.json
index 6a35130..f56fd05 100644
--- a/erpnext/assets/doctype/location/location.json
+++ b/erpnext/assets/doctype/location/location.json
@@ -141,7 +141,7 @@
  ],
  "is_tree": 1,
  "links": [],
- "modified": "2020-03-18 18:00:08.885805",
+ "modified": "2020-05-08 16:11:11.375701",
  "modified_by": "Administrator",
  "module": "Assets",
  "name": "Location",
@@ -221,7 +221,6 @@
   }
  ],
  "quick_entry": 1,
- "restrict_to_domain": "Agriculture",
  "show_name_in_global_search": 1,
  "sort_field": "modified",
  "sort_order": "DESC",
diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js
index 16061c6..1b8b404 100644
--- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js
+++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.js
@@ -18,6 +18,10 @@
 	refresh: function() {
 		var me = this;
 		this._super();
+
+		if (this.frm.doc.__islocal && !this.frm.doc.valid_till) {
+			this.frm.set_value('valid_till', frappe.datetime.add_months(this.frm.doc.transaction_date, 1));
+		}
 		if (this.frm.doc.docstatus === 1) {
 			cur_frm.add_custom_button(__("Purchase Order"), this.make_purchase_order,
 				__('Create'));
diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json
index 82fc628..3bc441a 100644
--- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json
+++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.json
@@ -13,9 +13,10 @@
   "supplier",
   "supplier_name",
   "column_break1",
-  "transaction_date",
-  "amended_from",
   "company",
+  "transaction_date",
+  "valid_till",
+  "amended_from",
   "address_section",
   "supplier_address",
   "contact_person",
@@ -791,13 +792,18 @@
    "options": "Opportunity",
    "print_hide": 1,
    "read_only": 1
+  },
+  {
+   "fieldname": "valid_till",
+   "fieldtype": "Date",
+   "label": "Valid Till"
   }
  ],
  "icon": "fa fa-shopping-cart",
  "idx": 29,
  "is_submittable": 1,
  "links": [],
- "modified": "2019-12-30 19:17:28.208693",
+ "modified": "2020-04-15 11:44:52.958022",
  "modified_by": "Administrator",
  "module": "Buying",
  "name": "Supplier Quotation",
diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py
index 5b4356a..baf2457 100644
--- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py
+++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation.py
@@ -4,7 +4,7 @@
 from __future__ import unicode_literals
 import frappe
 from frappe import _
-from frappe.utils import flt, nowdate, add_days
+from frappe.utils import flt, nowdate, add_days, getdate
 from frappe.model.mapper import get_mapped_doc
 
 from erpnext.controllers.buying_controller import BuyingController
@@ -28,6 +28,7 @@
 		validate_for_items(self)
 		self.validate_with_previous_doc()
 		self.validate_uom_is_integer("uom", "qty")
+		self.validate_valid_till()
 
 	def on_submit(self):
 		frappe.db.set(self, "status", "Submitted")
@@ -52,6 +53,11 @@
 				"is_child_table": True
 			}
 		})
+
+	def validate_valid_till(self):
+		if self.valid_till and getdate(self.valid_till) < getdate(self.transaction_date):
+			frappe.throw(_("Valid till Date cannot be before Transaction Date"))
+
 	def update_rfq_supplier_status(self, include_me):
 		rfq_list = set([])
 		for item in self.items:
@@ -158,3 +164,11 @@
 	}, target_doc)
 
 	return doclist
+
+def set_expired_status():
+	frappe.db.sql("""
+		UPDATE
+			`tabSupplier Quotation` SET `status` = 'Expired'
+		WHERE
+			`status` not in ('Cancelled', 'Stopped') AND `valid_till` < %s
+		""", (nowdate()))
\ No newline at end of file
diff --git a/erpnext/buying/doctype/supplier_quotation/supplier_quotation_list.js b/erpnext/buying/doctype/supplier_quotation/supplier_quotation_list.js
index 9555439..9f4fece 100644
--- a/erpnext/buying/doctype/supplier_quotation/supplier_quotation_list.js
+++ b/erpnext/buying/doctype/supplier_quotation/supplier_quotation_list.js
@@ -5,6 +5,8 @@
 			return [__("Ordered"), "green", "status,=,Ordered"];
 		} else if(doc.status==="Rejected") {
 			return [__("Lost"), "darkgrey", "status,=,Lost"];
+		} else if(doc.status==="Expired") {
+			return [__("Expired"), "darkgrey", "status,=,Expired"];
 		}
 	}
 };
diff --git a/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.js b/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.js
index 3d05612..a76ffee 100644
--- a/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.js
+++ b/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.js
@@ -5,20 +5,18 @@
 	filters: [
 		{
 			fieldtype: "Link",
-			label: __("Supplier Quotation"),
-			options: "Supplier Quotation",
-			fieldname: "supplier_quotation",
-			default: "",
-			get_query: () => {
-				return { filters: { "docstatus": ["<", 2] } }
-			}
+			label: __("Company"),
+			options: "Company",
+			fieldname: "company",
+			default: frappe.defaults.get_user_default("Company"),
+			"reqd": 1
 		},
 		{
 			reqd: 1,
 			default: "",
 			options: "Item",
 			label: __("Item"),
-			fieldname: "item",
+			fieldname: "item_code",
 			fieldtype: "Link",
 			get_query: () => {
 				let quote = frappe.query_report.get_filter_value('supplier_quotation');
@@ -37,8 +35,37 @@
 					}
 				}
 			}
+		},
+		{
+			fieldname: "supplier",
+			label: __("Supplier"),
+			fieldtype: "MultiSelectList",
+			get_data: function(txt) {
+				return frappe.db.get_link_options('Supplier', txt);
+			}
+		},
+		{
+			fieldtype: "Link",
+			label: __("Supplier Quotation"),
+			options: "Supplier Quotation",
+			fieldname: "supplier_quotation",
+			default: "",
+			get_query: () => {
+				return { filters: { "docstatus": ["<", 2] } }
+			}
+		},
+		{
+			fieldtype: "Link",
+			label: __("Request for Quotation"),
+			options: "Request for Quotation",
+			fieldname: "request_for_quotation",
+			default: "",
+			get_query: () => {
+				return { filters: { "docstatus": ["<", 2] } }
+			}
 		}
 	],
+
 	onload: (report) => {
 		// Create a button for setting the default supplier
 		report.page.add_inner_button(__("Select Default Supplier"), () => {
@@ -102,6 +129,4 @@
 		});
 		dialog.show();
 	}
-}
-
-
+}
\ No newline at end of file
diff --git a/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.py b/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.py
index 5aff6ba..a33867a 100644
--- a/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.py
+++ b/erpnext/buying/report/quoted_item_comparison/quoted_item_comparison.py
@@ -2,103 +2,180 @@
 # For license information, please see license.txt
 
 from __future__ import unicode_literals
-from erpnext.setup.utils import get_exchange_rate
-from frappe.utils import flt, cint
 import frappe
+from frappe.utils import flt, cint
+from frappe import _
+from collections import defaultdict
+from erpnext.setup.utils import get_exchange_rate
 
 def execute(filters=None):
-	qty_list = get_quantity_list(filters.item)
-	data = get_quote_list(filters.item, qty_list)
-	columns = get_columns(qty_list)
-	return columns, data
-	
-def get_quote_list(item, qty_list):
-	out = []
-	if not item:
+	if not filters:
+		return [], []
+
+	conditions = get_conditions(filters)
+	supplier_quotation_data = get_data(filters, conditions)
+	columns = get_columns()
+
+	data, chart_data = prepare_data(supplier_quotation_data)
+
+	return columns, data, None, chart_data
+
+def get_conditions(filters):
+	conditions = ""
+	if filters.get("supplier_quotation"):
+		conditions += " AND sqi.parent = %(supplier_quotation)s"
+
+	if filters.get("request_for_quotation"):
+		conditions += " AND sqi.request_for_quotation = %(request_for_quotation)s"
+
+	if filters.get("supplier"):
+		conditions += " AND sq.supplier in %(supplier)s"
+	return conditions
+
+def get_data(filters, conditions):
+	if not filters.get("item_code"):
 		return []
 
-	suppliers = []
-	price_data = []
-	company_currency = frappe.db.get_default("currency")
-	float_precision = cint(frappe.db.get_default("float_precision")) or 2 
-	# Get the list of suppliers
-	for root in frappe.db.sql("""select parent, qty, rate from `tabSupplier Quotation Item`
-		where item_code=%s and docstatus < 2""", item, as_dict=1):
-		for splr in frappe.db.sql("""select supplier from `tabSupplier Quotation`
-			where name =%s and docstatus < 2""", root.parent, as_dict=1):
-			ip = frappe._dict({
-				"supplier": splr.supplier,
-				"qty": root.qty,
-				"parent": root.parent,
-				"rate": root.rate
-			})
-			price_data.append(ip)
-			suppliers.append(splr.supplier)
+	supplier_quotation_data = frappe.db.sql("""SELECT
+		sqi.parent, sqi.qty, sqi.rate, sqi.uom, sqi.request_for_quotation,
+		sq.supplier
+		FROM
+			`tabSupplier Quotation Item` sqi,
+			`tabSupplier Quotation` sq
+		WHERE
+			sqi.item_code = %(item_code)s
+			AND sqi.parent = sq.name
+			AND sqi.docstatus < 2
+			AND sq.company = %(company)s
+			AND sq.status != 'Expired'
+			{0}""".format(conditions), filters, as_dict=1)
 
-	#Add a row for each supplier
-	for root in set(suppliers):
-		supplier_currency = frappe.db.get_value("Supplier", root, "default_currency")
+	return supplier_quotation_data
+
+def prepare_data(supplier_quotation_data):
+	out, suppliers, qty_list = [], [], []
+	supplier_wise_map = defaultdict(list)
+	supplier_qty_price_map = {}
+
+	company_currency = frappe.db.get_default("currency")
+	float_precision = cint(frappe.db.get_default("float_precision")) or 2
+
+	for data in supplier_quotation_data:
+		supplier = data.get("supplier")
+		supplier_currency = frappe.db.get_value("Supplier", data.get("supplier"), "default_currency")
+
 		if supplier_currency:
 			exchange_rate = get_exchange_rate(supplier_currency, company_currency)
 		else:
 			exchange_rate = 1
 
-		row = frappe._dict({
-			"supplier_name": root
-		})
-		for col in qty_list:
-			# Get the quantity for this row
-			for item_price in price_data:
-				if str(item_price.qty) == col.key and item_price.supplier == root:
-					row[col.key] = flt(item_price.rate * exchange_rate, float_precision)
-					row[col.key + "QUOTE"] = item_price.parent
-					break
-				else:
-					row[col.key] = ""
-					row[col.key + "QUOTE"] = ""
-		out.append(row)
-			
-	return out
-	
-def get_quantity_list(item):
-	out = []
-	
-	if item:
-		qty_list = frappe.db.sql("""select distinct qty from `tabSupplier Quotation Item`
-			where ifnull(item_code,'')=%s and docstatus < 2 order by qty""", item, as_dict=1)
+		row = {
+			"quotation": data.get("parent"),
+			"qty": data.get("qty"),
+			"price": flt(data.get("rate") * exchange_rate, float_precision),
+			"uom": data.get("uom"),
+			"request_for_quotation": data.get("request_for_quotation"),
+		}
 
-		for qt in qty_list:
-			col = frappe._dict({
-				"key": str(qt.qty),
-				"label": "Qty: " + str(int(qt.qty))
-			})
-			out.append(col)
+		# map for report view of form {'supplier1':[{},{},...]}
+		supplier_wise_map[supplier].append(row)
 
-	return out
-	
-def get_columns(qty_list):
+		# map for chart preparation of the form {'supplier1': {'qty': 'price'}}
+		if not supplier in supplier_qty_price_map:
+			supplier_qty_price_map[supplier] = {}
+		supplier_qty_price_map[supplier][row["qty"]] = row["price"]
+
+		suppliers.append(supplier)
+		qty_list.append(data.get("qty"))
+
+	suppliers = list(set(suppliers))
+	qty_list = list(set(qty_list))
+
+	# final data format for report view
+	for supplier in suppliers:
+		supplier_wise_map[supplier][0].update({"supplier_name": supplier})
+		for entry in supplier_wise_map[supplier]:
+			out.append(entry)
+
+	chart_data = prepare_chart_data(suppliers, qty_list, supplier_qty_price_map)
+
+	return out, chart_data
+
+def prepare_chart_data(suppliers, qty_list, supplier_qty_price_map):
+	data_points_map = {}
+	qty_list.sort()
+
+	# create qty wise values map of the form {'qty1':[value1, value2]}
+	for supplier in suppliers:
+		entry = supplier_qty_price_map[supplier]
+		for qty in qty_list:
+			if not qty in data_points_map:
+				data_points_map[qty] = []
+			if qty in entry:
+				data_points_map[qty].append(entry[qty])
+			else:
+				data_points_map[qty].append(None)
+
+	dataset = []
+	for qty in qty_list:
+		datapoints = {
+			"name": _("Price for Qty ") + str(qty),
+			"values": data_points_map[qty]
+		}
+		dataset.append(datapoints)
+
+	chart_data = {
+		"data": {
+			"labels": suppliers,
+			"datasets": dataset
+		},
+		"type": "bar"
+	}
+
+	return chart_data
+
+def get_columns():
 	columns = [{
 		"fieldname": "supplier_name",
-		"label": "Supplier",
+		"label": _("Supplier"),
 		"fieldtype": "Link",
 		"options": "Supplier",
 		"width": 200
-	}]
-
-	for qty in qty_list:
-		columns.append({
-			"fieldname": qty.key,
-			"label": qty.label,
-			"fieldtype": "Currency",
-			"options": "currency",
-			"width": 80
-		})
-		columns.append({
-			"fieldname": qty.key + "QUOTE",
-			"label": "Quotation",
-			"fieldtype": "Link",
-			"options": "Supplier Quotation",
-			"width": 90
-		})
+	},
+	{
+		"fieldname": "quotation",
+		"label": _("Supplier Quotation"),
+		"fieldtype": "Link",
+		"options": "Supplier Quotation",
+		"width": 200
+	},
+	{
+		"fieldname": "qty",
+		"label": _("Quantity"),
+		"fieldtype": "Float",
+		"width": 80
+	},
+	{
+		"fieldname": "price",
+		"label": _("Price"),
+		"fieldtype": "Currency",
+		"options": "Company:company:default_currency",
+		"width": 110
+	},
+	{
+		"fieldname": "uom",
+		"label": _("UOM"),
+		"fieldtype": "Link",
+		"options": "UOM",
+		"width": 90
+	},
+	{
+		"fieldname": "request_for_quotation",
+		"label": _("Request for Quotation"),
+		"fieldtype": "Link",
+		"options": "Request for Quotation",
+		"width": 200
+	}
+	]
 
 	return columns
\ No newline at end of file
diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py
index de76e45..b465a10 100644
--- a/erpnext/controllers/status_updater.py
+++ b/erpnext/controllers/status_updater.py
@@ -69,17 +69,6 @@
 		["Cancelled", "eval:self.docstatus==2"],
 		["Closed", "eval:self.status=='Closed'"],
 	],
-	"Purchase Invoice": [
-		["Draft", None],
-		["Submitted", "eval:self.docstatus==1"],
-		["Paid", "eval:self.outstanding_amount==0 and self.docstatus==1"],
-		["Return", "eval:self.is_return==1 and self.docstatus==1"],
-		["Debit Note Issued",
-			"eval:self.outstanding_amount <= 0 and self.docstatus==1 and self.is_return==0 and get_value('Purchase Invoice', {'is_return': 1, 'return_against': self.name, 'docstatus': 1})"],
-		["Unpaid", "eval:self.outstanding_amount > 0 and getdate(self.due_date) >= getdate(nowdate()) and self.docstatus==1"],
-		["Overdue", "eval:self.outstanding_amount > 0 and getdate(self.due_date) < getdate(nowdate()) and self.docstatus==1"],
-		["Cancelled", "eval:self.docstatus==2"],
-	],
 	"Material Request": [
 		["Draft", None],
 		["Stopped", "eval:self.status == 'Stopped'"],
diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py
index 74b3582..ec7d14d 100644
--- a/erpnext/crm/doctype/lead/lead.py
+++ b/erpnext/crm/doctype/lead/lead.py
@@ -153,7 +153,7 @@
 		if not self.lead_name:
 			self.set_lead_name()
 
-		names = self.lead_name.split(" ")
+		names = self.lead_name.strip().split(" ")
 		if len(names) > 1:
 			first_name, last_name = names[0], " ".join(names[1:])
 		else:
diff --git a/erpnext/crm/doctype/linkedin_settings/linkedin_settings.js b/erpnext/crm/doctype/linkedin_settings/linkedin_settings.js
index 50b98e9..263005e 100644
--- a/erpnext/crm/doctype/linkedin_settings/linkedin_settings.js
+++ b/erpnext/crm/doctype/linkedin_settings/linkedin_settings.js
@@ -62,6 +62,8 @@
 				callback : function(r) {
 					window.location.href = r.message;
 				}
+			}).fail(function() {
+				frappe.dom.unfreeze();
 			});
 		}
 	},
diff --git a/erpnext/crm/doctype/linkedin_settings/linkedin_settings.py b/erpnext/crm/doctype/linkedin_settings/linkedin_settings.py
index 5df35df..377e061 100644
--- a/erpnext/crm/doctype/linkedin_settings/linkedin_settings.py
+++ b/erpnext/crm/doctype/linkedin_settings/linkedin_settings.py
@@ -15,7 +15,7 @@
 		params = urlencode({
 			"response_type":"code",
 			"client_id": self.consumer_key,
-			"redirect_uri": get_site_url(frappe.local.site) + "/?cmd=erpnext.crm.doctype.linkedin_settings.linkedin_settings.callback",
+			"redirect_uri": "{0}/api/method/erpnext.crm.doctype.linkedin_settings.linkedin_settings.callback?".format(frappe.utils.get_url()),
 			"scope": "r_emailaddress w_organization_social r_basicprofile r_liteprofile r_organization_social rw_organization_admin w_member_social"
 		})
 
@@ -30,7 +30,7 @@
 			"code": code,
 			"client_id": self.consumer_key,
 			"client_secret": self.get_password(fieldname="consumer_secret"),
-			"redirect_uri": get_site_url(frappe.local.site) + "/?cmd=erpnext.crm.doctype.linkedin_settings.linkedin_settings.callback",
+			"redirect_uri": "{0}/api/method/erpnext.crm.doctype.linkedin_settings.linkedin_settings.callback?".format(frappe.utils.get_url()),
 		}
 		headers = {
 			"Content-Type": "application/x-www-form-urlencoded"
@@ -154,7 +154,7 @@
 
 		return response
 
-@frappe.whitelist()
+@frappe.whitelist(allow_guest=True)
 def callback(code=None, error=None, error_description=None):
 	if not error:
 		linkedin_settings = frappe.get_doc("LinkedIn Settings")
diff --git a/erpnext/crm/doctype/twitter_settings/twitter_settings.js b/erpnext/crm/doctype/twitter_settings/twitter_settings.js
index b55946a..f6f431c 100644
--- a/erpnext/crm/doctype/twitter_settings/twitter_settings.js
+++ b/erpnext/crm/doctype/twitter_settings/twitter_settings.js
@@ -47,6 +47,8 @@
 				callback : function(r) {
 					window.location.href = r.message;
 				}
+			}).fail(function() {
+				frappe.dom.unfreeze();
 			});
 		}
 	},
diff --git a/erpnext/crm/doctype/twitter_settings/twitter_settings.json b/erpnext/crm/doctype/twitter_settings/twitter_settings.json
index f92e7f0..36776e5 100644
--- a/erpnext/crm/doctype/twitter_settings/twitter_settings.json
+++ b/erpnext/crm/doctype/twitter_settings/twitter_settings.json
@@ -11,8 +11,8 @@
   "consumer_key",
   "column_break_5",
   "consumer_secret",
-  "oauth_token",
-  "oauth_secret",
+  "access_token",
+  "access_token_secret",
   "session_status"
  ],
  "fields": [
@@ -42,20 +42,6 @@
    "reqd": 1
   },
   {
-   "fieldname": "oauth_token",
-   "fieldtype": "Data",
-   "hidden": 1,
-   "label": "OAuth Token",
-   "read_only": 1
-  },
-  {
-   "fieldname": "oauth_secret",
-   "fieldtype": "Password",
-   "hidden": 1,
-   "label": "OAuth Token Secret",
-   "read_only": 1
-  },
-  {
    "fieldname": "column_break_5",
    "fieldtype": "Column Break"
   },
@@ -72,12 +58,26 @@
    "label": "Session Status",
    "options": "Expired\nActive",
    "read_only": 1
+  },
+  {
+   "fieldname": "access_token",
+   "fieldtype": "Data",
+   "hidden": 1,
+   "label": "Access Token",
+   "read_only": 1
+  },
+  {
+   "fieldname": "access_token_secret",
+   "fieldtype": "Data",
+   "hidden": 1,
+   "label": "Access Token Secret",
+   "read_only": 1
   }
  ],
  "image_field": "profile_pic",
  "issingle": 1,
  "links": [],
- "modified": "2020-04-21 22:06:43.726798",
+ "modified": "2020-05-13 17:50:47.934776",
  "modified_by": "Administrator",
  "module": "CRM",
  "name": "Twitter Settings",
diff --git a/erpnext/crm/doctype/twitter_settings/twitter_settings.py b/erpnext/crm/doctype/twitter_settings/twitter_settings.py
index 64f53b5..976a23d 100644
--- a/erpnext/crm/doctype/twitter_settings/twitter_settings.py
+++ b/erpnext/crm/doctype/twitter_settings/twitter_settings.py
@@ -12,13 +12,12 @@
 
 class TwitterSettings(Document):
 	def get_authorize_url(self):
-		callback_url = "{0}/?cmd=erpnext.crm.doctype.twitter_settings.twitter_settings.callback".format(frappe.utils.get_url())
+		callback_url = "{0}/api/method/erpnext.crm.doctype.twitter_settings.twitter_settings.callback?".format(frappe.utils.get_url())
 		auth = tweepy.OAuthHandler(self.consumer_key, self.get_password(fieldname="consumer_secret"), callback_url)
-
 		try:
 			redirect_url = auth.get_authorization_url()
 			return redirect_url
-		except:
+		except tweepy.TweepError as e:
 			frappe.msgprint(_("Error! Failed to get request token."))
 			frappe.throw(_('Invalid {0} or {1}').format(frappe.bold("Consumer Key"), frappe.bold("Consumer Secret Key")))
 
@@ -32,13 +31,13 @@
 
 		try:
 			auth.get_access_token(oauth_verifier)
-			api = self.get_api()
+			api = self.get_api(auth.access_token, auth.access_token_secret)
 			user = api.me()
 			profile_pic = (user._json["profile_image_url"]).replace("_normal","")
 
 			frappe.db.set_value(self.doctype, self.name, {
-				"oauth_token" : auth.access_token,
-				"oauth_secret" : auth.access_token_secret,
+				"access_token" : auth.access_token,
+				"access_token_secret" : auth.access_token_secret,
 				"account_name" : user._json["screen_name"],
 				"profile_pic" : profile_pic,
 				"session_status" : "Active"
@@ -50,11 +49,11 @@
 			frappe.msgprint(_("Error! Failed to get access token."))
 			frappe.throw(_('Invalid Consumer Key or Consumer Secret Key'))
 
-	def get_api(self):
+	def get_api(self, access_token, access_token_secret):
 		# authentication of consumer key and secret 
 		auth = tweepy.OAuthHandler(self.consumer_key, self.get_password(fieldname="consumer_secret")) 
 		# authentication of access token and secret 
-		auth.set_access_token(self.oauth_token, self.get_password(fieldname="oauth_secret")) 
+		auth.set_access_token(access_token, access_token_secret) 
 
 		return tweepy.API(auth)
 
@@ -68,13 +67,13 @@
 	
 	def upload_image(self, media):
 		media = get_file_path(media)
-		api = self.get_api()
+		api = self.get_api(self.access_token, self.access_token_secret)
 		media = api.media_upload(media)
 
 		return media.media_id
 
 	def send_tweet(self, text, media_id=None):
-		api = self.get_api()
+		api = self.get_api(self.access_token, self.access_token_secret)
 		try:
 			if media_id:
 				response = api.update_status(status = text, media_ids = [media_id])
@@ -91,8 +90,12 @@
 				frappe.db.commit()
 			frappe.throw(content["message"],title="Twitter Error {0} {1}".format(e.response.status_code, e.response.reason))
 
-@frappe.whitelist()
-def callback(oauth_token, oauth_verifier):
-	twitter_settings = frappe.get_single("Twitter Settings")
-	twitter_settings.get_access_token(oauth_token,oauth_verifier)
-	frappe.db.commit()
+@frappe.whitelist(allow_guest=True)
+def callback(oauth_token = None, oauth_verifier = None):
+	if oauth_token and oauth_verifier:
+		twitter_settings = frappe.get_single("Twitter Settings")
+		twitter_settings.get_access_token(oauth_token,oauth_verifier)
+		frappe.db.commit()
+	else:
+		frappe.local.response["type"] = "redirect"
+		frappe.local.response["location"] = get_url_to_form("Twitter Settings","Twitter Settings")
diff --git a/erpnext/crm/utils.py b/erpnext/crm/utils.py
index 38bf79e..95b19ec 100644
--- a/erpnext/crm/utils.py
+++ b/erpnext/crm/utils.py
@@ -19,6 +19,5 @@
 					mobile_no = primary_mobile_nos[0]
 
 			lead = frappe.get_doc("Lead", contact_lead)
-			lead.phone = phone
-			lead.mobile_no = mobile_no
-			lead.save()
+			lead.db_set("phone", phone)
+			lead.db_set("mobile_no", mobile_no)
diff --git a/erpnext/education/doctype/assessment_plan/assessment_plan.json b/erpnext/education/doctype/assessment_plan/assessment_plan.json
index bc39464..95ed853 100644
--- a/erpnext/education/doctype/assessment_plan/assessment_plan.json
+++ b/erpnext/education/doctype/assessment_plan/assessment_plan.json
@@ -1,790 +1,207 @@
 {
- "allow_copy": 0,
- "allow_guest_to_view": 0,
+ "actions": [],
  "allow_import": 1,
- "allow_rename": 0,
  "autoname": "EDU-ASP-.YYYY.-.#####",
- "beta": 0,
  "creation": "2015-11-12 16:34:34.658092",
- "custom": 0,
- "docstatus": 0,
  "doctype": "DocType",
  "document_type": "Setup",
- "editable_grid": 0,
  "engine": "InnoDB",
+ "field_order": [
+  "student_group",
+  "assessment_name",
+  "assessment_group",
+  "grading_scale",
+  "column_break_2",
+  "course",
+  "program",
+  "academic_year",
+  "academic_term",
+  "section_break_5",
+  "schedule_date",
+  "room",
+  "examiner",
+  "examiner_name",
+  "column_break_4",
+  "from_time",
+  "to_time",
+  "supervisor",
+  "supervisor_name",
+  "section_break_20",
+  "maximum_assessment_score",
+  "assessment_criteria",
+  "amended_from"
+ ],
  "fields": [
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "student_group",
    "fieldtype": "Link",
-   "hidden": 0,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
    "in_global_search": 1,
    "in_list_view": 1,
    "in_standard_filter": 1,
    "label": "Student Group",
-   "length": 0,
-   "no_copy": 0,
    "options": "Student Group",
-   "permlevel": 0,
-   "precision": "",
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 0,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 1,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "reqd": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "assessment_name",
    "fieldtype": "Data",
-   "hidden": 0,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
    "in_global_search": 1,
-   "in_list_view": 0,
-   "in_standard_filter": 0,
-   "label": "Assessment Name",
-   "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,
-   "translatable": 0,
-   "unique": 0
+   "label": "Assessment Name"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "assessment_group",
    "fieldtype": "Link",
-   "hidden": 0,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
-   "in_global_search": 0,
-   "in_list_view": 0,
    "in_standard_filter": 1,
    "label": "Assessment Group",
-   "length": 0,
-   "no_copy": 0,
    "options": "Assessment Group",
-   "permlevel": 0,
-   "precision": "",
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 0,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 1,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "reqd": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fetch_from": "course.default_grading_scale",
+   "fetch_if_empty": 1,
    "fieldname": "grading_scale",
    "fieldtype": "Link",
-   "hidden": 0,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
-   "in_global_search": 0,
-   "in_list_view": 0,
    "in_standard_filter": 1,
    "label": "Grading Scale",
-   "length": 0,
-   "no_copy": 0,
    "options": "Grading Scale",
-   "permlevel": 0,
-   "precision": "",
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 0,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 1,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "reqd": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "column_break_2",
-   "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,
-   "translatable": 0,
-   "unique": 0
+   "fieldtype": "Column Break"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fetch_from": "student_group.course",
+   "fetch_if_empty": 1,
    "fieldname": "course",
    "fieldtype": "Link",
-   "hidden": 0,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
    "in_global_search": 1,
-   "in_list_view": 0,
    "in_standard_filter": 1,
    "label": "Course",
-   "length": 0,
-   "no_copy": 0,
    "options": "Course",
-   "permlevel": 0,
-   "precision": "",
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 0,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 1,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "reqd": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fetch_from": "student_group.program",
    "fieldname": "program",
    "fieldtype": "Link",
-   "hidden": 0,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
    "in_global_search": 1,
-   "in_list_view": 0,
-   "in_standard_filter": 0,
    "label": "Program",
-   "length": 0,
-   "no_copy": 0,
-   "options": "Program",
-   "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,
-   "translatable": 0,
-   "unique": 0
+   "options": "Program"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fetch_from": "student_group.academic_year",
    "fieldname": "academic_year",
    "fieldtype": "Link",
-   "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": "Academic Year",
-   "length": 0,
-   "no_copy": 0,
-   "options": "Academic Year",
-   "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,
-   "translatable": 0,
-   "unique": 0
+   "options": "Academic Year"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fetch_from": "student_group.academic_term",
    "fieldname": "academic_term",
    "fieldtype": "Link",
-   "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": "Academic Term",
-   "length": 0,
-   "no_copy": 0,
-   "options": "Academic Term",
-   "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,
-   "translatable": 0,
-   "unique": 0
+   "options": "Academic Term"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "collapsible_depends_on": "",
-   "columns": 0,
-   "depends_on": "",
    "fieldname": "section_break_5",
    "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": "Schedule",
-   "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,
-   "translatable": 0,
-   "unique": 0
+   "label": "Schedule"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "default": "Today",
    "fieldname": "schedule_date",
    "fieldtype": "Date",
-   "hidden": 0,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
-   "in_global_search": 0,
    "in_list_view": 1,
-   "in_standard_filter": 0,
    "label": "Schedule Date",
-   "length": 0,
    "no_copy": 1,
-   "permlevel": 0,
-   "precision": "",
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 0,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 1,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "reqd": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "room",
    "fieldtype": "Link",
-   "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": "Room",
-   "length": 0,
-   "no_copy": 0,
-   "options": "Room",
-   "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,
-   "translatable": 0,
-   "unique": 0
+   "options": "Room"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "examiner",
    "fieldtype": "Link",
-   "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": "Examiner",
-   "length": 0,
-   "no_copy": 0,
-   "options": "Instructor",
-   "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,
-   "translatable": 0,
-   "unique": 0
+   "options": "Instructor"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fetch_from": "examiner.instructor_name",
    "fieldname": "examiner_name",
    "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": "Examiner Name",
-   "length": 0,
-   "no_copy": 0,
-   "permlevel": 0,
-   "precision": "",
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 1,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 0,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "read_only": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "column_break_4",
-   "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,
-   "translatable": 0,
-   "unique": 0
+   "fieldtype": "Column Break"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "from_time",
    "fieldtype": "Time",
-   "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": "From Time",
-   "length": 0,
    "no_copy": 1,
-   "permlevel": 0,
-   "precision": "",
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 0,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 1,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "reqd": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "to_time",
    "fieldtype": "Time",
-   "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": "To Time",
-   "length": 0,
    "no_copy": 1,
-   "permlevel": 0,
-   "precision": "",
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 0,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 1,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "reqd": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "supervisor",
    "fieldtype": "Link",
-   "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": "Supervisor",
-   "length": 0,
-   "no_copy": 0,
-   "options": "Instructor",
-   "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,
-   "translatable": 0,
-   "unique": 0
+   "options": "Instructor"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fetch_from": "supervisor.instructor_name",
    "fieldname": "supervisor_name",
    "fieldtype": "Data",
-   "hidden": 0,
-   "ignore_user_permissions": 0,
-   "ignore_xss_filter": 0,
-   "in_filter": 0,
    "in_global_search": 1,
-   "in_list_view": 0,
-   "in_standard_filter": 0,
    "label": "Supervisor Name",
-   "length": 0,
-   "no_copy": 0,
-   "permlevel": 0,
-   "precision": "",
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 1,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 0,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "read_only": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "section_break_20",
    "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": "Evaluate",
-   "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,
-   "translatable": 0,
-   "unique": 0
+   "label": "Evaluate"
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "maximum_assessment_score",
    "fieldtype": "Float",
-   "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": "Maximum Assessment Score",
-   "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": 1,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "reqd": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "assessment_criteria",
    "fieldtype": "Table",
-   "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": "Assessment Criteria",
-   "length": 0,
-   "no_copy": 0,
    "options": "Assessment Plan Criteria",
-   "permlevel": 0,
-   "precision": "",
-   "print_hide": 0,
-   "print_hide_if_no_value": 0,
-   "read_only": 0,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 1,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "reqd": 1
   },
   {
-   "allow_bulk_edit": 0,
-   "allow_in_quick_entry": 0,
-   "allow_on_submit": 0,
-   "bold": 0,
-   "collapsible": 0,
-   "columns": 0,
    "fieldname": "amended_from",
    "fieldtype": "Link",
-   "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": "Amended From",
-   "length": 0,
    "no_copy": 1,
    "options": "Assessment Plan",
-   "permlevel": 0,
    "print_hide": 1,
-   "print_hide_if_no_value": 0,
-   "read_only": 1,
-   "remember_last_selected_value": 0,
-   "report_hide": 0,
-   "reqd": 0,
-   "search_index": 0,
-   "set_only_once": 0,
-   "translatable": 0,
-   "unique": 0
+   "read_only": 1
   }
  ],
- "has_web_view": 0,
- "hide_heading": 0,
- "hide_toolbar": 0,
- "idx": 0,
- "image_view": 0,
- "in_create": 0,
  "is_submittable": 1,
- "issingle": 0,
- "istable": 0,
- "max_attachments": 0,
- "menu_index": 0,
- "modified": "2018-08-30 00:48:03.475522",
+ "links": [],
+ "modified": "2020-05-09 14:56:26.746988",
  "modified_by": "Administrator",
  "module": "Education",
  "name": "Assessment Plan",
- "name_case": "",
  "owner": "Administrator",
  "permissions": [
   {
@@ -794,28 +211,17 @@
    "delete": 1,
    "email": 1,
    "export": 1,
-   "if_owner": 0,
-   "import": 0,
-   "permlevel": 0,
    "print": 1,
    "read": 1,
    "report": 1,
    "role": "Academics User",
-   "set_user_permissions": 0,
    "share": 1,
    "submit": 1,
    "write": 1
   }
  ],
- "quick_entry": 0,
- "read_only": 0,
- "read_only_onload": 0,
  "restrict_to_domain": "Education",
- "show_name_in_global_search": 0,
  "sort_field": "modified",
  "sort_order": "DESC",
- "title_field": "assessment_name",
- "track_changes": 0,
- "track_seen": 0,
- "track_views": 0
+ "title_field": "assessment_name"
 }
\ No newline at end of file
diff --git a/erpnext/education/doctype/education_settings/education_settings.json b/erpnext/education/doctype/education_settings/education_settings.json
index 967a030..0e548db 100644
--- a/erpnext/education/doctype/education_settings/education_settings.json
+++ b/erpnext/education/doctype/education_settings/education_settings.json
@@ -1,4 +1,5 @@
 {
+ "actions": [],
  "creation": "2017-04-05 13:33:04.519313",
  "doctype": "DocType",
  "editable_grid": 1,
@@ -42,12 +43,14 @@
    "fieldtype": "Column Break"
   },
   {
+   "default": "0",
    "description": "For Batch based Student Group, the Student Batch will be validated for every Student from the Program Enrollment.",
    "fieldname": "validate_batch",
    "fieldtype": "Check",
    "label": "Validate Batch for Students in Student Group"
   },
   {
+   "default": "0",
    "description": "For Course based Student Group, the Course will be validated for every Student from the enrolled Courses in Program Enrollment.",
    "fieldname": "validate_course",
    "fieldtype": "Check",
@@ -74,13 +77,13 @@
   {
    "fieldname": "web_academy_settings_section",
    "fieldtype": "Section Break",
-   "label": "LMS Settings"
+   "label": "Learning Management System Settings"
   },
   {
    "depends_on": "eval: doc.enable_lms",
    "fieldname": "portal_title",
    "fieldtype": "Data",
-   "label": "LMS Title"
+   "label": "Learning Management System Title"
   },
   {
    "depends_on": "eval: doc.enable_lms",
@@ -89,9 +92,10 @@
    "label": "Description"
   },
   {
+   "default": "0",
    "fieldname": "enable_lms",
    "fieldtype": "Check",
-   "label": "Enable LMS"
+   "label": "Enable Learning Management System"
   },
   {
    "default": "0",
@@ -102,7 +106,8 @@
   }
  ],
  "issingle": 1,
- "modified": "2019-05-13 18:36:13.127563",
+ "links": [],
+ "modified": "2020-05-07 19:18:10.639356",
  "modified_by": "Administrator",
  "module": "Education",
  "name": "Education Settings",
@@ -141,4 +146,4 @@
  "sort_field": "modified",
  "sort_order": "DESC",
  "track_changes": 1
-}
+}
\ No newline at end of file
diff --git a/erpnext/education/doctype/fees/fees.py b/erpnext/education/doctype/fees/fees.py
index f0d60fa..25d67d2 100644
--- a/erpnext/education/doctype/fees/fees.py
+++ b/erpnext/education/doctype/fees/fees.py
@@ -98,14 +98,16 @@
 			"debit_in_account_currency": self.grand_total,
 			"against_voucher": self.name,
 			"against_voucher_type": self.doctype
-		})
+		}, item=self)
+
 		fee_gl_entry = self.get_gl_dict({
 			"account": self.income_account,
 			"against": self.student,
 			"credit": self.grand_total,
 			"credit_in_account_currency": self.grand_total,
 			"cost_center": self.cost_center
-		})
+		}, item=self)
+
 		from erpnext.accounts.general_ledger import make_gl_entries
 		make_gl_entries([student_gl_entries, fee_gl_entry], cancel=(self.docstatus == 2),
 			update_outstanding="Yes", merge_entries=False)
diff --git a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
index b4a5bd1..a706223 100644
--- a/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
+++ b/erpnext/erpnext_integrations/doctype/plaid_settings/plaid_settings.py
@@ -209,7 +209,7 @@
 			result.append(new_transaction.name)
 
 		except Exception:
-			frappe.throw(frappe.get_traceback())
+			frappe.throw(title=_('Bank transaction creation error'))
 
 	return result
 
diff --git a/erpnext/healthcare/dashboard_fixtures.py b/erpnext/healthcare/dashboard_fixtures.py
new file mode 100644
index 0000000..fc3d62f
--- /dev/null
+++ b/erpnext/healthcare/dashboard_fixtures.py
@@ -0,0 +1,41 @@
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+
+import frappe
+import json
+
+
+def get_data():
+	return frappe._dict({
+		"dashboards": get_dashboards(),
+		"charts": get_charts(),
+	})
+
+def get_dashboards():
+	return [{
+		"name": "Healthcare",
+		"dashboard_name": "Healthcare",
+		"charts": [
+			{ "chart": "Patient Appointments" }
+		]
+	}]
+
+def get_charts():
+	return [
+			{
+				"doctype": "Dashboard Chart",
+				"time_interval": "Daily",
+				"name": "Patient Appointments",
+				"chart_name": "Patient Appointments",
+				"timespan": "Last Month",
+				"color": "#77ecca",
+				"filters_json": json.dumps({}),
+				"chart_type": "Count",
+				"timeseries": 1,
+				"based_on": "appointment_datetime",
+				"owner": "Administrator",
+				"document_type": "Patient Appointment",
+				"type": "Line",
+				"width": "Half"
+			}
+		]
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 6b198e7..ab161aa 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -308,7 +308,8 @@
 		"erpnext.crm.doctype.email_campaign.email_campaign.send_email_to_leads_or_contacts",
 		"erpnext.crm.doctype.email_campaign.email_campaign.set_email_campaign_status",
 		"erpnext.selling.doctype.quotation.quotation.set_expired_status",
-		"erpnext.healthcare.doctype.patient_appointment.patient_appointment.update_appointment_status"
+		"erpnext.healthcare.doctype.patient_appointment.patient_appointment.update_appointment_status",
+		"erpnext.buying.doctype.supplier_quotation.supplier_quotation.set_expired_status"
 	],
 	"daily_long": [
 		"erpnext.setup.doctype.email_digest.email_digest.send",
diff --git a/erpnext/hr/doctype/employee_other_income/employee_other_income.json b/erpnext/hr/doctype/employee_other_income/employee_other_income.json
index 2dd6c10..8abfe1e 100644
--- a/erpnext/hr/doctype/employee_other_income/employee_other_income.json
+++ b/erpnext/hr/doctype/employee_other_income/employee_other_income.json
@@ -76,25 +76,15 @@
  ],
  "is_submittable": 1,
  "links": [],
- "modified": "2020-03-19 18:06:45.361830",
+ "modified": "2020-05-14 17:17:38.883126",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "Employee Other Income",
  "owner": "Administrator",
  "permissions": [
   {
-   "create": 1,
-   "delete": 1,
-   "email": 1,
-   "export": 1,
-   "print": 1,
-   "read": 1,
-   "report": 1,
-   "role": "System Manager",
-   "share": 1,
-   "write": 1
-  },
-  {
+   "amend": 1,
+   "cancel": 1,
    "create": 1,
    "delete": 1,
    "email": 1,
@@ -104,9 +94,12 @@
    "report": 1,
    "role": "HR Manager",
    "share": 1,
+   "submit": 1,
    "write": 1
   },
   {
+   "amend": 1,
+   "cancel": 1,
    "create": 1,
    "delete": 1,
    "email": 1,
@@ -116,9 +109,12 @@
    "report": 1,
    "role": "HR User",
    "share": 1,
+   "submit": 1,
    "write": 1
   },
   {
+   "amend": 1,
+   "cancel": 1,
    "create": 1,
    "delete": 1,
    "email": 1,
@@ -128,6 +124,7 @@
    "report": 1,
    "role": "Employee",
    "share": 1,
+   "submit": 1,
    "write": 1
   }
  ],
diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.py b/erpnext/hr/doctype/expense_claim/expense_claim.py
index ac1bfa1..ea469b8 100644
--- a/erpnext/hr/doctype/expense_claim/expense_claim.py
+++ b/erpnext/hr/doctype/expense_claim/expense_claim.py
@@ -116,8 +116,9 @@
 					"party_type": "Employee",
 					"party": self.employee,
 					"against_voucher_type": self.doctype,
-					"against_voucher": self.name
-				})
+					"against_voucher": self.name,
+					"cost_center": self.cost_center
+				}, item=self)
 			)
 
 		# expense entries
@@ -129,7 +130,7 @@
 					"debit_in_account_currency": data.sanctioned_amount,
 					"against": self.employee,
 					"cost_center": data.cost_center
-				})
+				}, item=data)
 			)
 
 		for data in self.advances:
@@ -157,7 +158,7 @@
 					"credit": self.grand_total,
 					"credit_in_account_currency": self.grand_total,
 					"against": self.employee
-				})
+				}, item=self)
 			)
 
 			gl_entry.append(
@@ -170,7 +171,7 @@
 					"debit_in_account_currency": self.grand_total,
 					"against_voucher": self.name,
 					"against_voucher_type": self.doctype,
-				})
+				}, item=self)
 			)
 
 		return gl_entry
@@ -187,7 +188,7 @@
 					"cost_center": self.cost_center,
 					"against_voucher_type": self.doctype,
 					"against_voucher": self.name
-				})
+				}, item=tax)
 			)
 
 	def validate_account_details(self):
diff --git a/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.json b/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.json
index 16e9eef..3cce50e 100644
--- a/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.json
+++ b/erpnext/hr/doctype/expense_claim_detail/expense_claim_detail.json
@@ -13,9 +13,11 @@
   "description",
   "section_break_6",
   "amount",
-  "cost_center",
   "column_break_8",
-  "sanctioned_amount"
+  "sanctioned_amount",
+  "accounting_dimensions_section",
+  "cost_center",
+  "dimension_col_break"
  ],
  "fields": [
   {
@@ -104,12 +106,21 @@
    "fieldtype": "Link",
    "label": "Cost Center",
    "options": "Cost Center"
+  },
+  {
+   "fieldname": "accounting_dimensions_section",
+   "fieldtype": "Section Break",
+   "label": "Accounting Dimensions"
+  },
+  {
+   "fieldname": "dimension_col_break",
+   "fieldtype": "Column Break"
   }
  ],
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2019-12-11 13:42:33.233432",
+ "modified": "2020-05-11 18:54:35.601592",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "Expense Claim Detail",
diff --git a/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.json b/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.json
index d68caf1..885e3ee 100644
--- a/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.json
+++ b/erpnext/hr/doctype/expense_taxes_and_charges/expense_taxes_and_charges.json
@@ -8,14 +8,16 @@
  "engine": "InnoDB",
  "field_order": [
   "account_head",
-  "cost_center",
   "rate",
   "col_break1",
   "description",
   "section_break_6",
   "tax_amount",
   "column_break_8",
-  "total"
+  "total",
+  "accounting_dimensions_section",
+  "cost_center",
+  "dimension_col_break"
  ],
  "fields": [
   {
@@ -91,11 +93,20 @@
   {
    "fieldname": "column_break_8",
    "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "accounting_dimensions_section",
+   "fieldtype": "Section Break",
+   "label": "Accounting Dimensions"
+  },
+  {
+   "fieldname": "dimension_col_break",
+   "fieldtype": "Column Break"
   }
  ],
  "istable": 1,
  "links": [],
- "modified": "2020-03-11 13:25:06.721917",
+ "modified": "2020-05-11 19:01:26.611758",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "Expense Taxes and Charges",
diff --git a/erpnext/hr/doctype/hr_settings/hr_settings.json b/erpnext/hr/doctype/hr_settings/hr_settings.json
index 9161ed8..ebf8723 100644
--- a/erpnext/hr/doctype/hr_settings/hr_settings.json
+++ b/erpnext/hr/doctype/hr_settings/hr_settings.json
@@ -13,12 +13,12 @@
   "stop_birthday_reminders",
   "expense_approver_mandatory_in_expense_claim",
   "payroll_settings",
-  "payroll_based_on", 
-  "max_working_hours_against_timesheet", 
+  "payroll_based_on",
+  "max_working_hours_against_timesheet",
   "include_holidays_in_total_working_days",
   "disable_rounded_total",
   "column_break_11",
-  "daily_wages_fraction_for_half_day", 
+  "daily_wages_fraction_for_half_day",
   "email_salary_slip_to_employee",
   "encrypt_salary_slips_in_emails",
   "password_policy",
@@ -191,7 +191,7 @@
    "default": "Leave",
    "fieldname": "payroll_based_on",
    "fieldtype": "Select",
-   "label": "Calculate Working Days in Payroll based on",
+   "label": "Calculate Payroll Working Days Based On",
    "options": "Leave\nAttendance"
   },
   {
@@ -206,7 +206,7 @@
  "idx": 1,
  "issingle": 1,
  "links": [],
- "modified": "2020-04-13 21:20:59.382394",
+ "modified": "2020-05-11 13:02:51.274347",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "HR Settings",
diff --git a/erpnext/hr/doctype/leave_application/leave_application.py b/erpnext/hr/doctype/leave_application/leave_application.py
index 47b1bb7..d2620be 100755
--- a/erpnext/hr/doctype/leave_application/leave_application.py
+++ b/erpnext/hr/doctype/leave_application/leave_application.py
@@ -549,7 +549,7 @@
 
 	return _get_remaining_leaves(total_leaves, allocation.to_date)
 
-def get_leaves_for_period(employee, leave_type, from_date, to_date):
+def get_leaves_for_period(employee, leave_type, from_date, to_date, do_not_skip_expired_leaves=False):
 	leave_entries = get_leave_entries(employee, leave_type, from_date, to_date)
 	leave_days = 0
 
@@ -559,8 +559,8 @@
 		if  inclusive_period and leave_entry.transaction_type == 'Leave Encashment':
 			leave_days += leave_entry.leaves
 
-		elif inclusive_period and leave_entry.transaction_type == 'Leave Allocation' \
-			and leave_entry.is_expired and not skip_expiry_leaves(leave_entry, to_date):
+		elif inclusive_period and leave_entry.transaction_type == 'Leave Allocation' and leave_entry.is_expired \
+			and (do_not_skip_expired_leaves or not skip_expiry_leaves(leave_entry, to_date)):
 			leave_days += leave_entry.leaves
 
 		elif leave_entry.transaction_type == 'Leave Application':
diff --git a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
index 9ed58c9..63559c4 100644
--- a/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
+++ b/erpnext/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
@@ -88,32 +88,40 @@
 	}, fieldname=['name'])
 
 def process_expired_allocation():
-	''' Check if a carry forwarded allocation has expired and create a expiry ledger entry '''
+	''' Check if a carry forwarded allocation has expired and create a expiry ledger entry
+		Case 1: carry forwarded expiry period is set for the leave type,
+			create a separate leave expiry entry against each entry of carry forwarded and non carry forwarded leaves
+		Case 2: leave type has no specific expiry period for carry forwarded leaves
+			and there is no carry forwarded leave allocation, create a single expiry against the remaining leaves.
+	'''
 
 	# fetch leave type records that has carry forwarded leaves expiry
 	leave_type_records = frappe.db.get_values("Leave Type", filters={
 			'expire_carry_forwarded_leaves_after_days': (">", 0)
 		}, fieldname=['name'])
 
-	leave_type = [record[0] for record in leave_type_records]
+	leave_type = [record[0] for record in leave_type_records] or ['']
 
-	expired_allocation = frappe.db.sql_list("""SELECT name
-		FROM `tabLeave Ledger Entry`
-		WHERE
-			`transaction_type`='Leave Allocation'
-			AND `is_expired`=1""")
-
-	expire_allocation = frappe.get_all("Leave Ledger Entry",
-		fields=['leaves', 'to_date', 'employee', 'leave_type', 'is_carry_forward', 'transaction_name as name', 'transaction_type'],
-		filters={
-			'to_date': ("<", today()),
-			'transaction_type': 'Leave Allocation',
-			'transaction_name': ('not in', expired_allocation)
-		},
-		or_filters={
-			'is_carry_forward': 0,
-			'leave_type': ('in', leave_type)
-		})
+	# fetch non expired leave ledger entry of transaction_type allocation
+	expire_allocation = frappe.db.sql("""
+		SELECT
+			leaves, to_date, employee, leave_type,
+			is_carry_forward, transaction_name as name, transaction_type
+		FROM `tabLeave Ledger Entry` l
+		WHERE (NOT EXISTS
+			(SELECT name
+				FROM `tabLeave Ledger Entry`
+				WHERE
+					transaction_name = l.transaction_name
+					AND transaction_type = 'Leave Allocation'
+					AND name<>l.name
+					AND docstatus = 1
+					AND (
+						is_carry_forward=l.is_carry_forward
+						OR (is_carry_forward = 0 AND leave_type not in %s)
+			)))
+			AND transaction_type = 'Leave Allocation'
+			AND to_date < %s""", (leave_type, today()), as_dict=1)
 
 	if expire_allocation:
 		create_expiry_ledger_entry(expire_allocation)
@@ -133,6 +141,7 @@
 			'employee': allocation.employee,
 			'leave_type': allocation.leave_type,
 			'to_date': ('<=', allocation.to_date),
+			'docstatus': 1
 		}, fieldname=['SUM(leaves)'])
 
 @frappe.whitelist()
@@ -159,7 +168,8 @@
 def expire_carried_forward_allocation(allocation):
 	''' Expires remaining leaves in the on carried forward allocation '''
 	from erpnext.hr.doctype.leave_application.leave_application import get_leaves_for_period
-	leaves_taken = get_leaves_for_period(allocation.employee, allocation.leave_type, allocation.from_date, allocation.to_date)
+	leaves_taken = get_leaves_for_period(allocation.employee, allocation.leave_type,
+		allocation.from_date, allocation.to_date, do_not_skip_expired_leaves=True)
 	leaves = flt(allocation.leaves) + flt(leaves_taken)
 
 	# allow expired leaves entry to be created
diff --git a/erpnext/hr/doctype/upload_attendance/upload_attendance.py b/erpnext/hr/doctype/upload_attendance/upload_attendance.py
index f75bb41..61faea1 100644
--- a/erpnext/hr/doctype/upload_attendance/upload_attendance.py
+++ b/erpnext/hr/doctype/upload_attendance/upload_attendance.py
@@ -145,7 +145,7 @@
 
 	def remove_holidays(rows):
 		rows = [ row for row in rows if row[4] != "Holiday"]
-		return
+		return rows
 
 	from frappe.modules import scrub
 
diff --git a/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py b/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py
index d98ed1b..82ed277 100644
--- a/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py
+++ b/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py
@@ -215,7 +215,7 @@
 def get_employee_details(group_by, company):
 	emp_map = {}
 	query = """select name, employee_name, designation, department, branch, company,
-		holiday_list from `tabEmployee` where company = '%s' """ % frappe.db.escape(company)
+		holiday_list from `tabEmployee` where company = %s """ % frappe.db.escape(company)
 
 	if group_by:
 		group_by = group_by.lower()
diff --git a/erpnext/loan_management/doctype/loan/loan.py b/erpnext/loan_management/doctype/loan/loan.py
index c550d49..76e10e5 100644
--- a/erpnext/loan_management/doctype/loan/loan.py
+++ b/erpnext/loan_management/doctype/loan/loan.py
@@ -248,8 +248,7 @@
 	for loan_security in loan_security_pledge_details:
 		unpledge_request.append('securities', {
 			"loan_security": loan_security.loan_security,
-			"qty": loan_security.qty,
-			"against_pledge": loan_security.parent
+			"qty": loan_security.qty
 		})
 
 	if as_dict:
diff --git a/erpnext/loan_management/doctype/loan/test_loan.py b/erpnext/loan_management/doctype/loan/test_loan.py
index 77a1fcc..364e2ff 100644
--- a/erpnext/loan_management/doctype/loan/test_loan.py
+++ b/erpnext/loan_management/doctype/loan/test_loan.py
@@ -15,6 +15,7 @@
 from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import days_in_year
 from erpnext.loan_management.doctype.process_loan_security_shortfall.process_loan_security_shortfall import create_process_loan_security_shortfall
 from erpnext.loan_management.doctype.loan.loan import create_loan_security_unpledge
+from erpnext.loan_management.doctype.loan_security_unpledge.loan_security_unpledge import get_pledged_security_qty
 
 class TestLoan(unittest.TestCase):
 	def setUp(self):
@@ -152,7 +153,7 @@
 		repayment_entry.save()
 		repayment_entry.submit()
 
-		penalty_amount = (accrued_interest_amount * 5 * 25) / (100 * days_in_year(get_datetime(first_date).year))
+		penalty_amount = (accrued_interest_amount * 4 * 25) / (100 * days_in_year(get_datetime(first_date).year))
 		self.assertEquals(flt(repayment_entry.penalty_amount, 2), flt(penalty_amount, 2))
 
 		amounts = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['paid_interest_amount',
@@ -305,7 +306,7 @@
 		make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date)
 		process_loan_interest_accrual_for_demand_loans(posting_date = last_date)
 
-		repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 5),
+		repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 6),
 			"Loan Closure", flt(loan.loan_amount + accrued_interest_amount))
 		repayment_entry.submit()
 
@@ -319,13 +320,12 @@
 		unpledge_request.submit()
 		unpledge_request.status = 'Approved'
 		unpledge_request.save()
-
-		loan_security_pledge.load_from_db()
 		loan.load_from_db()
 
+		pledged_qty = get_pledged_security_qty(loan.name)
+
 		self.assertEqual(loan.status, 'Closed')
-		for security in loan_security_pledge.securities:
-			self.assertEquals(security.qty, 0)
+		self.assertEquals(sum(pledged_qty.values()), 0)
 
 
 def create_loan_accounts():
diff --git a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
index 452c836..2ab668a 100644
--- a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
+++ b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
@@ -264,6 +264,7 @@
 	penalty_amount = 0
 	payable_principal_amount = 0
 	final_due_date = ''
+	due_date = ''
 
 	for entry in accrued_interest_entries:
 		# Loan repayment due date is one day after the loan interest is accrued
@@ -272,7 +273,7 @@
 
 		due_date = add_days(entry.posting_date, 1)
 		no_of_late_days = date_diff(posting_date,
-					add_days(due_date, loan_type_details.grace_period_in_days)) + 1
+					add_days(due_date, loan_type_details.grace_period_in_days))
 
 		if no_of_late_days > 0 and (not against_loan_doc.repay_from_salary):
 			penalty_amount += (entry.interest_amount * (loan_type_details.penalty_interest_rate / 100) * no_of_late_days)/365
@@ -290,9 +291,9 @@
 
 	pending_principal_amount = against_loan_doc.total_payment - against_loan_doc.total_principal_paid - against_loan_doc.total_interest_payable
 
-	if payment_type == "Loan Closure" and not payable_principal_amount:
-		if final_due_date:
-			pending_days = date_diff(posting_date, final_due_date)
+	if payment_type == "Loan Closure":
+		if due_date:
+			pending_days = date_diff(posting_date, due_date) + 1
 		else:
 			pending_days = date_diff(posting_date, against_loan_doc.disbursement_date) + 1
 
diff --git a/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.py b/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.py
index f97e596..961c05c 100644
--- a/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.py
+++ b/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.py
@@ -38,7 +38,7 @@
 		for pledge in self.securities:
 
 			if not pledge.qty and not pledge.amount:
-				frappe.throw(_("Qty or Amount is mandatroy for loan security"))
+				frappe.throw(_("Qty or Amount is mandatory for loan security!"))
 
 			if not (self.loan_application and pledge.loan_security_price):
 				pledge.loan_security_price = get_loan_security_price(pledge.loan_security)
diff --git a/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py b/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py
index 8ca6e3e..308c438 100644
--- a/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py
+++ b/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py
@@ -69,7 +69,7 @@
 		loan_security_map[loan.name]['security_value'] += current_loan_security_amount - (current_loan_security_amount * loan.haircut/100)
 
 	for loan, value in iteritems(loan_security_map):
-		if (value["security_value"]/value["loan_amount"]) < ltv_ratio:
+		if (value["loan_amount"]/value['security_value'] * 100) > ltv_ratio:
 			create_loan_security_shortfall(loan, value, process_loan_security_shortfall)
 
 def create_loan_security_shortfall(loan, value, process_loan_security_shortfall):
diff --git a/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.js b/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.js
index 72c5f38..8223206 100644
--- a/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.js
+++ b/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.js
@@ -4,10 +4,8 @@
 frappe.ui.form.on('Loan Security Unpledge', {
 	refresh: function(frm) {
 
-		frm.set_query("against_pledge", "securities", () => {
-			return {
-				filters : [["status", "in", ["Pledged", "Partially Pledged"]]]
-			};
-		});
+		if (frm.doc.docstatus == 1 && frm.doc.status == 'Approved') {
+			frm.set_df_property('status', 'read_only', 1);
+		}
 	}
 });
diff --git a/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.py b/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.py
index b2bb22a..5e9d82a 100644
--- a/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.py
+++ b/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.py
@@ -8,12 +8,13 @@
 from frappe.model.document import Document
 from frappe.utils import get_datetime, flt
 import json
+from six import iteritems
 from erpnext.loan_management.doctype.loan_security_price.loan_security_price import get_loan_security_price
 
 class LoanSecurityUnpledge(Document):
 	def validate(self):
-		self.validate_pledges()
 		self.validate_duplicate_securities()
+		self.validate_unpledge_qty()
 
 	def on_cancel(self):
 		self.update_loan_security_pledge(cancel=1)
@@ -23,80 +24,52 @@
 	def validate_duplicate_securities(self):
 		security_list = []
 		for d in self.securities:
-			security = [d.loan_security, d.against_pledge]
-			if security not in security_list:
-				security_list.append(security)
+			if d.loan_security not in security_list:
+				security_list.append(d.loan_security)
 			else:
-				frappe.throw(_("Row {0}: Loan Security {1} against Loan Security Pledge {2} added multiple times").format(
-					d.idx, frappe.bold(d.loan_security), frappe.bold(d.against_pledge)))
+				frappe.throw(_("Row {0}: Loan Security {1} added multiple times").format(
+					d.idx, frappe.bold(d.loan_security)))
 
-	def validate_pledges(self):
-		pledge_qty_map = self.get_pledge_details()
-		loan = frappe.get_doc("Loan", self.loan)
+	def validate_unpledge_qty(self):
+		pledge_qty_map = get_pledged_security_qty(self.loan)
 
-		remaining_qty = 0
-		unpledge_value = 0
+		ltv_ratio_map = frappe._dict(frappe.get_all("Loan Security Type",
+			fields=["name", "loan_to_value_ratio"], as_list=1))
+
+		loan_security_price_map = frappe._dict(frappe.get_all("Loan Security Price",
+			fields=["loan_security", "loan_security_price"],
+			filters = {
+				"valid_from": ("<=", get_datetime()),
+				"valid_upto": (">=", get_datetime())
+			}, as_list=1))
+
+		loan_amount, principal_paid = frappe.get_value("Loan", self.loan, ['loan_amount', 'total_principal_paid'])
+		pending_principal_amount = loan_amount - principal_paid
+		security_value = 0
 
 		for security in self.securities:
-			pledged_qty = pledge_qty_map.get((security.against_pledge, security.loan_security), 0)
-			if not pledged_qty:
-				frappe.throw(_("Zero qty of {0} pledged against loan {1}").format(frappe.bold(security.loan_security),
-					frappe.bold(self.loan)))
+			pledged_qty = pledge_qty_map.get(security.loan_security)
 
-			unpledge_qty = pledged_qty - security.qty
-			security_price = security.qty * get_loan_security_price(security.loan_security)
+			if security.qty > pledged_qty:
+				frappe.throw(_("""Row {0}: {1} {2} of {3} is pledged against Loan {4}.
+					You are trying to unpledge more""").format(security.idx, pledged_qty, security.uom,
+					frappe.bold(security.loan_security), frappe.bold(self.loan)))
 
-			if unpledge_qty < 0:
-				frappe.throw(_("""Row {0}: Cannot unpledge more than {1} qty of {2} against
-					Loan Security Pledge {3}""").format(security.idx, frappe.bold(pledged_qty),
-					frappe.bold(security.loan_security), frappe.bold(security.against_pledge)))
+			qty_after_unpledge = pledged_qty - security.qty
+			ltv_ratio = ltv_ratio_map.get(security.loan_security_type)
 
-			remaining_qty += unpledge_qty
-			unpledge_value += security_price - flt(security_price * security.haircut/100)
+			security_value += qty_after_unpledge * loan_security_price_map.get(security.loan_security)
 
-		if unpledge_value > loan.total_principal_paid:
-			frappe.throw(_("Cannot Unpledge, loan security value is greater than the repaid amount"))
+		if not security_value and pending_principal_amount > 0:
+			frappe.throw("Cannot Unpledge, loan to value ratio is breaching")
 
-	def get_pledge_details(self):
-		pledge_qty_map = {}
-
-		pledge_details = frappe.db.sql("""
-			SELECT p.parent, p.loan_security, p.qty FROM
-				`tabLoan Security Pledge` lsp,
-				`tabPledge` p
-			WHERE
-				p.parent = lsp.name
-				AND lsp.loan = %s
-				AND lsp.docstatus = 1
-				AND lsp.status in ('Pledged', 'Partially Pledged')
-		""", (self.loan), as_dict=1)
-
-		for pledge in pledge_details:
-			pledge_qty_map.setdefault((pledge.parent, pledge.loan_security), pledge.qty)
-
-		return pledge_qty_map
+		if security_value and (pending_principal_amount/security_value) * 100 > ltv_ratio:
+			frappe.throw("Cannot Unpledge, loan to value ratio is breaching")
 
 	def on_update_after_submit(self):
 		if self.status == "Approved":
-			self.update_loan_security_pledge()
 			self.update_loan_status()
-
-	def update_loan_security_pledge(self, cancel=0):
-		if cancel:
-			new_qty = 'p.qty + u.qty'
-		else:
-			new_qty = 'p.qty - u.qty'
-
-		frappe.db.sql("""
-			UPDATE
-				`tabPledge` p, `tabUnpledge` u, `tabLoan Security Pledge` lsp, `tabLoan Security Unpledge` lsu
-					SET p.qty = {new_qty}
-			WHERE
-				lsp.loan = %s
-				AND p.parent = u.against_pledge
-				AND p.parent = lsp.name
-				AND lsp.docstatus = 1
-				AND p.loan_security = u.loan_security""".format(new_qty=new_qty),(self.loan))
+			self.db_set('unpledge_time', get_datetime())
 
 	def update_loan_status(self, cancel=0):
 		if cancel:
@@ -104,10 +77,45 @@
 			if loan_status == 'Closed':
 				frappe.db.set_value('Loan', self.loan, 'status', 'Loan Closure Requested')
 		else:
-			pledge_qty = frappe.db.sql("""SELECT SUM(c.qty)
-				FROM `tabLoan Security Pledge` p, `tabPledge` c
-				WHERE p.loan = %s AND c.parent = p.name""", (self.loan))[0][0]
+			pledged_qty = 0
+			current_pledges = get_pledged_security_qty(self.loan)
 
-			if not pledge_qty:
+			for security, qty in iteritems(current_pledges):
+				pledged_qty += qty
+
+			if not pledged_qty:
 				frappe.db.set_value('Loan', self.loan, 'status', 'Closed')
 
+@frappe.whitelist()
+def get_pledged_security_qty(loan):
+
+	current_pledges = {}
+
+	unpledges = frappe._dict(frappe.db.sql("""
+		SELECT u.loan_security, sum(u.qty) as qty
+		FROM `tabLoan Security Unpledge` up, `tabUnpledge` u
+		WHERE up.loan = %s
+		AND u.parent = up.name
+		AND up.status = 'Approved'
+		GROUP BY u.loan_security
+	""", (loan)))
+
+	pledges = frappe._dict(frappe.db.sql("""
+		SELECT p.loan_security, sum(p.qty) as qty
+		FROM `tabLoan Security Pledge` lp, `tabPledge`p
+		WHERE lp.loan = %s
+		AND p.parent = lp.name
+		AND lp.status = 'Pledged'
+		GROUP BY p.loan_security
+	""", (loan)))
+
+	for security, qty in iteritems(pledges):
+		current_pledges.setdefault(security, qty)
+		current_pledges[security] -= unpledges.get(security, 0.0)
+
+	return current_pledges
+
+
+
+
+
diff --git a/erpnext/loan_management/doctype/unpledge/unpledge.json b/erpnext/loan_management/doctype/unpledge/unpledge.json
index 9e6277d..ee192d7 100644
--- a/erpnext/loan_management/doctype/unpledge/unpledge.json
+++ b/erpnext/loan_management/doctype/unpledge/unpledge.json
@@ -1,11 +1,11 @@
 {
+ "actions": [],
  "creation": "2019-09-21 13:22:19.793797",
  "doctype": "DocType",
  "editable_grid": 1,
  "engine": "InnoDB",
  "field_order": [
   "loan_security",
-  "against_pledge",
   "loan_security_type",
   "loan_security_code",
   "haircut",
@@ -55,14 +55,6 @@
    "reqd": 1
   },
   {
-   "fieldname": "against_pledge",
-   "fieldtype": "Link",
-   "in_list_view": 1,
-   "label": "Against Pledge",
-   "options": "Loan Security Pledge",
-   "reqd": 1
-  },
-  {
    "fetch_from": "loan_security.haircut",
    "fieldname": "haircut",
    "fieldtype": "Percent",
@@ -71,7 +63,8 @@
   }
  ],
  "istable": 1,
- "modified": "2019-10-02 12:48:18.588236",
+ "links": [],
+ "modified": "2020-05-06 10:50:18.448552",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Unpledge",
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py
index e9627a5..e43b98a 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.py
+++ b/erpnext/manufacturing/doctype/job_card/job_card.py
@@ -206,30 +206,31 @@
 		for_quantity, time_in_mins = 0, 0
 		from_time_list, to_time_list = [], []
 
-
+		field = "operation_id" if self.operation_id else "operation"
 		data = frappe.get_all('Job Card',
 			fields = ["sum(total_time_in_mins) as time_in_mins", "sum(total_completed_qty) as completed_qty"],
 			filters = {"docstatus": 1, "work_order": self.work_order,
-				"workstation": self.workstation, "operation": self.operation})
+				"workstation": self.workstation, field: self.get(field)})
 
 		if data and len(data) > 0:
 			for_quantity = data[0].completed_qty
 			time_in_mins = data[0].time_in_mins
 
-		if for_quantity:
+		if self.get(field):
 			time_data = frappe.db.sql("""
 				SELECT
 					min(from_time) as start_time, max(to_time) as end_time
 				FROM `tabJob Card` jc, `tabJob Card Time Log` jctl
 				WHERE
 					jctl.parent = jc.name and jc.work_order = %s
-					and jc.workstation = %s and jc.operation = %s and jc.docstatus = 1
-			""", (self.work_order, self.workstation, self.operation), as_dict=1)
+					and jc.workstation = %s and jc.{0} = %s and jc.docstatus = 1
+			""".format(field), (self.work_order, self.workstation, self.get(field)), as_dict=1)
 
 			wo = frappe.get_doc('Work Order', self.work_order)
 
+			work_order_field = "name" if field == "operation_id" else field
 			for data in wo.operations:
-				if data.workstation == self.workstation and data.operation == self.operation:
+				if data.get(work_order_field) == self.get(field) and data.workstation == self.workstation:
 					data.completed_qty = for_quantity
 					data.actual_operation_time = time_in_mins
 					data.actual_start_time = time_data[0].start_time if time_data else None
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.py b/erpnext/manufacturing/doctype/work_order/work_order.py
index 84bfab2..8301f30 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/work_order.py
@@ -421,6 +421,9 @@
 		return holidays[holiday_list]
 
 	def update_operation_status(self):
+		allowance_percentage = flt(frappe.db.get_single_value("Manufacturing Settings", "overproduction_percentage_for_work_order"))
+		max_allowed_qty_for_wo = flt(self.qty) + (allowance_percentage/100 * flt(self.qty))
+
 		for d in self.get("operations"):
 			if not d.completed_qty:
 				d.status = "Pending"
@@ -428,6 +431,8 @@
 				d.status = "Work in Progress"
 			elif flt(d.completed_qty) == flt(self.qty):
 				d.status = "Completed"
+			elif flt(d.completed_qty) <= max_allowed_qty_for_wo:
+				d.status = "Completed"
 			else:
 				frappe.throw(_("Completed Qty can not be greater than 'Qty to Manufacture'"))
 
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index ba17b67..ebbcccc 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -495,6 +495,7 @@
 execute:frappe.delete_doc('DocType', 'Production Planning Tool', ignore_missing=True)
 erpnext.patches.v10_0.migrate_daily_work_summary_settings_to_daily_work_summary_group # 24-12-2018
 erpnext.patches.v10_0.add_default_cash_flow_mappers
+erpnext.patches.v11_0.rename_duplicate_item_code_values
 erpnext.patches.v11_0.make_quality_inspection_template
 erpnext.patches.v10_0.update_status_for_multiple_source_in_po
 erpnext.patches.v10_0.set_auto_created_serial_no_in_stock_entry
@@ -622,7 +623,7 @@
 erpnext.patches.v12_0.update_due_date_in_gle
 erpnext.patches.v12_0.add_default_buying_selling_terms_in_company
 erpnext.patches.v12_0.update_ewaybill_field_position
-erpnext.patches.v12_0.create_accounting_dimensions_in_missing_doctypes
+erpnext.patches.v12_0.create_accounting_dimensions_in_missing_doctypes #2020-05-11
 erpnext.patches.v11_1.set_status_for_material_request_type_manufacture
 erpnext.patches.v12_0.move_plaid_settings_to_doctype
 execute:frappe.reload_doc('desk', 'doctype', 'dashboard_chart_link')
@@ -630,7 +631,6 @@
 execute:frappe.reload_doc('desk', 'doctype', 'dashboard_chart_source')
 execute:frappe.reload_doc('desk', 'doctype', 'dashboard_chart')
 execute:frappe.reload_doc('desk', 'doctype', 'dashboard_chart_field')
-erpnext.patches.v12_0.add_default_dashboards # 2020-04-05
 erpnext.patches.v12_0.remove_bank_remittance_custom_fields
 erpnext.patches.v12_0.generate_leave_ledger_entries
 execute:frappe.delete_doc_if_exists("Report", "Loan Repayment")
@@ -678,4 +678,9 @@
 erpnext.patches.v12_0.fix_quotation_expired_status
 erpnext.patches.v12_0.update_appointment_reminder_scheduler_entry
 erpnext.patches.v12_0.retain_permission_rules_for_video_doctype
+erpnext.patches.v12_0.remove_duplicate_leave_ledger_entries
 erpnext.patches.v13_0.patch_to_fix_reverse_linking_in_additional_salary_encashment_and_incentive
+execute:frappe.delete_doc_if_exists("Page", "appointment-analytic")
+execute:frappe.rename_doc("Desk Page", "Getting Started", "Home", force=True)
+erpnext.patches.v12_0.unset_customer_supplier_based_on_type_of_item_price
+erpnext.patches.v12_0.set_valid_till_date_in_supplier_quotation
diff --git a/erpnext/patches/v11_0/rename_duplicate_item_code_values.py b/erpnext/patches/v11_0/rename_duplicate_item_code_values.py
new file mode 100644
index 0000000..00ab562
--- /dev/null
+++ b/erpnext/patches/v11_0/rename_duplicate_item_code_values.py
@@ -0,0 +1,8 @@
+import frappe
+
+def execute():
+	items = []
+	items = frappe.db.sql("""select item_code from `tabItem` group by item_code having count(*) > 1""", as_dict=True)
+	if items:
+		for item in items:
+			frappe.db.sql("""update `tabItem` set item_code=name where item_code = %s""", (item.item_code))
diff --git a/erpnext/patches/v11_0/set_default_email_template_in_hr.py b/erpnext/patches/v11_0/set_default_email_template_in_hr.py
index 14954fb..4622376 100644
--- a/erpnext/patches/v11_0/set_default_email_template_in_hr.py
+++ b/erpnext/patches/v11_0/set_default_email_template_in_hr.py
@@ -1,8 +1,9 @@
 from __future__ import unicode_literals
+from frappe import _
 import frappe
 
 def execute():
 	hr_settings = frappe.get_single("HR Settings")
-	hr_settings.leave_approval_notification_template = "Leave Approval Notification"
-	hr_settings.leave_status_notification_template = "Leave Status Notification"
-	hr_settings.save()
\ No newline at end of file
+	hr_settings.leave_approval_notification_template = _("Leave Approval Notification")
+	hr_settings.leave_status_notification_template = _("Leave Status Notification")
+	hr_settings.save()
diff --git a/erpnext/patches/v12_0/add_default_dashboards.py b/erpnext/patches/v12_0/add_default_dashboards.py
deleted file mode 100644
index 2a91e1b..0000000
--- a/erpnext/patches/v12_0/add_default_dashboards.py
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright (c) 2019, Frappe and Contributors
-# License: GNU General Public License v3. See license.txt
-
-import frappe
-from erpnext.setup.setup_wizard.operations.install_fixtures import add_dashboards
-
-def execute():
-	frappe.reload_doc("desk", "doctype", "number_card_link")
-	frappe.reload_doc("healthcare", "doctype", "patient_appointment")
-	add_dashboards()
diff --git a/erpnext/patches/v12_0/create_accounting_dimensions_in_missing_doctypes.py b/erpnext/patches/v12_0/create_accounting_dimensions_in_missing_doctypes.py
index b71ea66..657decf 100644
--- a/erpnext/patches/v12_0/create_accounting_dimensions_in_missing_doctypes.py
+++ b/erpnext/patches/v12_0/create_accounting_dimensions_in_missing_doctypes.py
@@ -20,7 +20,8 @@
 		else:
 			insert_after_field = 'accounting_dimensions_section'
 
-		for doctype in ["Subscription Plan", "Subscription", "Opening Invoice Creation Tool", "Opening Invoice Creation Tool Item"]:
+		for doctype in ["Subscription Plan", "Subscription", "Opening Invoice Creation Tool", "Opening Invoice Creation Tool Item",
+			"Expense Claim Detail", "Expense Taxes and Charges"]:
 
 			field = frappe.db.get_value("Custom Field", {"dt": doctype, "fieldname": d.fieldname})
 
diff --git a/erpnext/patches/v12_0/remove_duplicate_leave_ledger_entries.py b/erpnext/patches/v12_0/remove_duplicate_leave_ledger_entries.py
new file mode 100644
index 0000000..98a2fcf
--- /dev/null
+++ b/erpnext/patches/v12_0/remove_duplicate_leave_ledger_entries.py
@@ -0,0 +1,44 @@
+# Copyright (c) 2018, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+	"""Delete duplicate leave ledger entries of type allocation created."""
+	if not frappe.db.a_row_exists("Leave Ledger Entry"):
+		return
+
+	duplicate_records_list = get_duplicate_records()
+	delete_duplicate_ledger_entries(duplicate_records_list)
+
+def get_duplicate_records():
+	"""Fetch all but one duplicate records from the list of expired leave allocation."""
+	return frappe.db.sql_list("""
+		WITH duplicate_records AS
+		(SELECT
+			name, transaction_name, is_carry_forward,
+			ROW_NUMBER() over(partition by transaction_name order by creation)as row
+		FROM `tabLeave Ledger Entry` l
+		WHERE (EXISTS
+			(SELECT name
+				FROM `tabLeave Ledger Entry`
+				WHERE
+					transaction_name = l.transaction_name
+					AND transaction_type = 'Leave Allocation'
+					AND name <> l.name
+					AND employee = l.employee
+					AND docstatus = 1
+					AND leave_type = l.leave_type
+					AND is_carry_forward=l.is_carry_forward
+					AND to_date = l.to_date
+					AND from_date = l.from_date
+					AND is_expired = 1
+		)))
+		SELECT name FROM duplicate_records WHERE row > 1
+	""")
+
+def delete_duplicate_ledger_entries(duplicate_records_list):
+	"""Delete duplicate leave ledger entries."""
+	if duplicate_records_list:
+		frappe.db.sql(''' DELETE FROM `tabLeave Ledger Entry` WHERE name in {0}'''.format(tuple(duplicate_records_list))) #nosec
\ No newline at end of file
diff --git a/erpnext/patches/v12_0/set_purchase_receipt_delivery_note_detail.py b/erpnext/patches/v12_0/set_purchase_receipt_delivery_note_detail.py
index f5bd8c3..6f843cd 100644
--- a/erpnext/patches/v12_0/set_purchase_receipt_delivery_note_detail.py
+++ b/erpnext/patches/v12_0/set_purchase_receipt_delivery_note_detail.py
@@ -3,6 +3,10 @@
 from collections import defaultdict
 
 def execute():
+
+	frappe.reload_doc('stock', 'doctype', 'delivery_note_item', force=True)
+	frappe.reload_doc('stock', 'doctype', 'purchase_receipt_item', force=True)
+
 	def map_rows(doc_row, return_doc_row, detail_field, doctype):
 		"""Map rows after identifying similar ones."""
 
diff --git a/erpnext/patches/v12_0/set_valid_till_date_in_supplier_quotation.py b/erpnext/patches/v12_0/set_valid_till_date_in_supplier_quotation.py
new file mode 100644
index 0000000..4a6e228
--- /dev/null
+++ b/erpnext/patches/v12_0/set_valid_till_date_in_supplier_quotation.py
@@ -0,0 +1,8 @@
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+	frappe.reload_doc("buying", "doctype", "supplier_quotation")
+	frappe.db.sql("""UPDATE `tabSupplier Quotation`
+		SET valid_till = DATE_ADD(transaction_date , INTERVAL 1 MONTH)
+		WHERE docstatus < 2""")
diff --git a/erpnext/patches/v12_0/unset_customer_supplier_based_on_type_of_item_price.py b/erpnext/patches/v12_0/unset_customer_supplier_based_on_type_of_item_price.py
new file mode 100644
index 0000000..60aec05
--- /dev/null
+++ b/erpnext/patches/v12_0/unset_customer_supplier_based_on_type_of_item_price.py
@@ -0,0 +1,15 @@
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+    invalid_selling_item_price = frappe.db.sql(
+        """SELECT name FROM `tabItem Price` WHERE selling = 1 and buying = 0 and (supplier IS NOT NULL or supplier = '')"""
+    )
+    invalid_buying_item_price = frappe.db.sql(
+        """SELECT name FROM `tabItem Price` WHERE selling = 0 and buying = 1 and (customer IS NOT NULL or customer = '')"""
+    )
+    docs_to_modify = invalid_buying_item_price + invalid_selling_item_price
+    for d in docs_to_modify:
+        # saving the doc will auto reset invalid customer/supplier field
+        doc = frappe.get_doc("Item Price", d[0])
+        doc.save()
\ No newline at end of file
diff --git a/erpnext/patches/v13_0/move_tax_slabs_from_payroll_period_to_income_tax_slab.py b/erpnext/patches/v13_0/move_tax_slabs_from_payroll_period_to_income_tax_slab.py
index 179be2c..ec94cd0 100644
--- a/erpnext/patches/v13_0/move_tax_slabs_from_payroll_period_to_income_tax_slab.py
+++ b/erpnext/patches/v13_0/move_tax_slabs_from_payroll_period_to_income_tax_slab.py
@@ -7,7 +7,7 @@
 from frappe.model.utils.rename_field import rename_field
 
 def execute():
-	if not frappe.db.table_exists("Payroll Period"):
+	if not (frappe.db.table_exists("Payroll Period") and frappe.db.table_exists("Taxable Salary Slab")):
 		return
 
 	for doctype in ("income_tax_slab", "salary_structure_assignment", "employee_other_income", "income_tax_slab_other_charges"):
@@ -60,6 +60,9 @@
 				""", (income_tax_slab.name, company.name, period.start_date))
 
 	# move other incomes to separate document
+	if not frappe.db.table_exists("Employee Tax Exemption Proof Submission"):
+		return
+
 	migrated = []
 	proofs = frappe.get_all("Employee Tax Exemption Proof Submission",
 		filters = {'docstatus': 1},
@@ -79,6 +82,9 @@
 			except:
 				pass
 
+	if not frappe.db.table_exists("Employee Tax Exemption Declaration"):
+		return
+
 	declerations = frappe.get_all("Employee Tax Exemption Declaration",
 		filters = {'docstatus': 1},
 		fields =['payroll_period', 'employee', 'company', 'income_from_other_sources']
diff --git a/erpnext/regional/address_template/templates/taiwan.html b/erpnext/regional/address_template/templates/taiwan.html
new file mode 100644
index 0000000..1715bea
--- /dev/null
+++ b/erpnext/regional/address_template/templates/taiwan.html
@@ -0,0 +1,4 @@
+{{ country }}<br>{% if pincode %}{{ pincode }}<br>{% endif -%}{{ county }}{{ city }}{{ address_line1 }}{% if address_line2 %}{{ address_line2 }}{% endif -%}
+{% if phone %}<br>Phone: {{ phone }}{% endif -%}
+{% if fax %}<br>Fax: {{ fax }}{% endif -%}
+{% if email_id %}<br>Email: {{ email_id }}{% endif -%}
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index 3309858..732780a 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -251,8 +251,7 @@
 
 
 def calculate_annual_eligible_hra_exemption(doc):
-	basic_component = frappe.get_cached_value('Company',  doc.company,  "basic_component")
-	hra_component = frappe.get_cached_value('Company',  doc.company,  "hra_component")
+	basic_component, hra_component = frappe.db.get_value('Company',  doc.company,  ["basic_component", "hra_component"])
 	if not (basic_component and hra_component):
 		frappe.throw(_("Please mention Basic and HRA component in Company"))
 	annual_exemption, monthly_exemption, hra_amount = 0, 0, 0
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index 50e719f..3d172ac 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -165,6 +165,10 @@
 				contact.mobile_no = lead.mobile_no
 				contact.is_primary_contact = 1
 				contact.append('links', dict(link_doctype='Customer', link_name=self.name))
+				if lead.email_id:
+					contact.append('email_ids', dict(email_id=lead.email_id, is_primary=1))
+				if lead.mobile_no:
+					contact.append('phone_nos', dict(phone=lead.mobile_no, is_primary_mobile_no=1))
 				contact.flags.ignore_permissions = self.flags.ignore_permissions
 				contact.autoname()
 				if not frappe.db.exists("Contact", contact.name):
diff --git a/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.js b/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.js
index a854fa9..d93ffb7 100644
--- a/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.js
+++ b/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.js
@@ -4,6 +4,14 @@
 frappe.query_reports["Customer Acquisition and Loyalty"] = {
 	"filters": [
 		{
+			"fieldname": "view_type",
+			"label": __("View Type"),
+			"fieldtype": "Select",
+			"options": ["Monthly", "Territory Wise"],
+			"default": "Monthly",
+			"reqd": 1
+		},
+		{
 			"fieldname":"company",
 			"label": __("Company"),
 			"fieldtype": "Link",
@@ -24,6 +32,13 @@
 			"fieldtype": "Date",
 			"default": frappe.defaults.get_user_default("year_end_date"),
 			"reqd": 1
-		},
-	]
-}
+		}
+	],
+	'formatter': function(value, row, column, data, default_formatter) {
+		value = default_formatter(value, row, column, data);
+		if (data && data.bold) {
+			value = value.bold();
+		}
+		return value;
+	}
+}
\ No newline at end of file
diff --git a/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.py b/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.py
index aa57665..88bd9c1 100644
--- a/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.py
+++ b/erpnext/selling/report/customer_acquisition_and_loyalty/customer_acquisition_and_loyalty.py
@@ -2,65 +2,186 @@
 # License: GNU General Public License v3. See license.txt
 
 from __future__ import unicode_literals
+import calendar
 import frappe
 from frappe import _
-from frappe.utils import getdate, cint, cstr
-import calendar
+from frappe.utils import cint, cstr
 
 def execute(filters=None):
-	# key yyyy-mm
-	new_customers_in = {}
-	repeat_customers_in = {}
-	customers = []
-	company_condition = ""
+    common_columns = [
+        {
+            'label': _('New Customers'),
+            'fieldname': 'new_customers',
+            'fieldtype': 'Int',
+            'default': 0,
+            'width': 125
+        },
+        {
+            'label': _('Repeat Customers'),
+            'fieldname': 'repeat_customers',
+            'fieldtype': 'Int',
+            'default': 0,
+            'width': 125
+        },
+        {
+            'label': _('Total'),
+            'fieldname': 'total',
+            'fieldtype': 'Int',
+            'default': 0,
+            'width': 100
+        },
+        {
+            'label': _('New Customer Revenue'),
+            'fieldname': 'new_customer_revenue',
+            'fieldtype': 'Currency',
+            'default': 0.0,
+            'width': 175
+        },
+        {
+            'label': _('Repeat Customer Revenue'),
+            'fieldname': 'repeat_customer_revenue',
+            'fieldtype': 'Currency',
+            'default': 0.0,
+            'width': 175
+        },
+        {
+            'label': _('Total Revenue'),
+            'fieldname': 'total_revenue',
+            'fieldtype': 'Currency',
+            'default': 0.0,
+            'width': 175
+        }
+    ]
+    if filters.get('view_type') == 'Monthly':
+        return get_data_by_time(filters, common_columns)
+    else:
+        return get_data_by_territory(filters, common_columns)
 
-	if filters.get("company"):
-		company_condition = ' and company=%(company)s'
+def get_data_by_time(filters, common_columns):
+    # key yyyy-mm
+    columns = [
+        {
+            'label': _('Year'),
+            'fieldname': 'year',
+            'fieldtype': 'Data',
+            'width': 100
+        },
+        {
+            'label': _('Month'),
+            'fieldname': 'month',
+            'fieldtype': 'Data',
+            'width': 100
+        },
+    ]
+    columns += common_columns
 
-	for si in frappe.db.sql("""select posting_date, customer, base_grand_total from `tabSales Invoice`
-		where docstatus=1 and posting_date <= %(to_date)s
-		{company_condition} order by posting_date""".format(company_condition=company_condition),
-		filters, as_dict=1):
+    customers_in = get_customer_stats(filters)
 
-		key = si.posting_date.strftime("%Y-%m")
-		if not si.customer in customers:
-			new_customers_in.setdefault(key, [0, 0.0])
-			new_customers_in[key][0] += 1
-			new_customers_in[key][1] += si.base_grand_total
-			customers.append(si.customer)
-		else:
-			repeat_customers_in.setdefault(key, [0, 0.0])
-			repeat_customers_in[key][0] += 1
-			repeat_customers_in[key][1] += si.base_grand_total
+    # time series
+    from_year, from_month, temp = filters.get('from_date').split('-')
+    to_year, to_month, temp = filters.get('to_date').split('-')
 
-	# time series
-	from_year, from_month, temp = filters.get("from_date").split("-")
-	to_year, to_month, temp = filters.get("to_date").split("-")
+    from_year, from_month, to_year, to_month = \
+        cint(from_year), cint(from_month), cint(to_year), cint(to_month)
 
-	from_year, from_month, to_year, to_month = \
-		cint(from_year), cint(from_month), cint(to_year), cint(to_month)
+    out = []
+    for year in range(from_year, to_year+1):
+        for month in range(from_month if year==from_year else 1, (to_month+1) if year==to_year else 13):
+            key = '{year}-{month:02d}'.format(year=year, month=month)
+            data = customers_in.get(key)
+            new = data['new'] if data else [0, 0.0]
+            repeat = data['repeat'] if data else [0, 0.0]
+            out.append({
+                'year': cstr(year),
+                'month': calendar.month_name[month],
+                'new_customers': new[0],
+                'repeat_customers': repeat[0],
+                'total': new[0] + repeat[0],
+                'new_customer_revenue': new[1],
+                'repeat_customer_revenue': repeat[1],
+                'total_revenue': new[1] + repeat[1]
+            })
+    return columns, out
 
-	out = []
-	for year in range(from_year, to_year+1):
-		for month in range(from_month if year==from_year else 1, (to_month+1) if year==to_year else 13):
-			key = "{year}-{month:02d}".format(year=year, month=month)
+def get_data_by_territory(filters, common_columns):
+    columns = [{
+        'label': 'Territory',
+        'fieldname': 'territory',
+        'fieldtype': 'Link',
+        'options': 'Territory',
+        'width': 150
+    }]
+    columns += common_columns
 
-			new = new_customers_in.get(key, [0,0.0])
-			repeat = repeat_customers_in.get(key, [0,0.0])
+    customers_in = get_customer_stats(filters, tree_view=True)
 
-			out.append([cstr(year), calendar.month_name[month],
-				new[0], repeat[0], new[0] + repeat[0],
-				new[1], repeat[1], new[1] + repeat[1]])
+    territory_dict = {}
+    for t in frappe.db.sql('''SELECT name, lft, parent_territory, is_group FROM `tabTerritory` ORDER BY lft''', as_dict=1):
+        territory_dict.update({
+            t.name: {
+                'parent': t.parent_territory,
+                'is_group': t.is_group
+            }
+        })
 
-	return [
-		_("Year") + "::100",
-		_("Month") + "::100",
-		_("New Customers") + ":Int:100",
-		_("Repeat Customers") + ":Int:100",
-		_("Total") + ":Int:100",
-		_("New Customer Revenue") + ":Currency:150",
-		_("Repeat Customer Revenue") + ":Currency:150",
-		_("Total Revenue") + ":Currency:150"
-	], out
+    depth_map = frappe._dict()
+    for name, info in territory_dict.items():
+        default = depth_map.get(info['parent']) + 1 if info['parent'] else 0
+        depth_map.setdefault(name, default)
 
+    data = []
+    for name, indent in depth_map.items():
+        condition = customers_in.get(name)
+        new = customers_in[name]['new'] if condition else [0, 0.0]
+        repeat = customers_in[name]['repeat'] if condition else [0, 0.0]
+        temp = {
+            'territory': name,
+            'parent_territory': territory_dict[name]['parent'],
+            'indent': indent,
+            'new_customers': new[0],
+            'repeat_customers': repeat[0],
+            'total': new[0] + repeat[0],
+            'new_customer_revenue': new[1],
+            'repeat_customer_revenue': repeat[1],
+            'total_revenue': new[1] + repeat[1],
+            'bold': 0 if indent else 1
+        }
+        data.append(temp)
 
+    loop_data = sorted(data, key=lambda k: k['indent'], reverse=True)
+
+    for ld in loop_data:
+        if ld['parent_territory']:
+            parent_data = [x for x in data if x['territory'] == ld['parent_territory']][0]
+            for key in parent_data.keys():
+                if key not in  ['indent', 'territory', 'parent_territory', 'bold']:
+                    parent_data[key] += ld[key]
+
+    return columns, data, None, None, None, 1
+
+def get_customer_stats(filters, tree_view=False):
+    """ Calculates number of new and repeated customers. """
+    company_condition = ''
+    if filters.get('company'):
+        company_condition = ' and company=%(company)s'
+
+    customers = []
+    customers_in = {}
+
+    for si in frappe.db.sql('''select territory, posting_date, customer, base_grand_total from `tabSales Invoice`
+        where docstatus=1 and posting_date <= %(to_date)s and posting_date >= %(from_date)s
+        {company_condition} order by posting_date'''.format(company_condition=company_condition),
+        filters, as_dict=1):
+
+        key = si.territory if tree_view else si.posting_date.strftime('%Y-%m')
+        customers_in.setdefault(key, {'new': [0, 0.0], 'repeat': [0, 0.0]})
+
+        if not si.customer in customers:
+            customers_in[key]['new'][0] += 1
+            customers_in[key]['new'][1] += si.base_grand_total
+            customers.append(si.customer)
+        else:
+            customers_in[key]['repeat'][0] += 1
+            customers_in[key]['repeat'][1] += si.base_grand_total
+
+    return customers_in
diff --git a/erpnext/selling/report/sales_analytics/sales_analytics.json b/erpnext/selling/report/sales_analytics/sales_analytics.json
index 7193261..bf9edd6 100644
--- a/erpnext/selling/report/sales_analytics/sales_analytics.json
+++ b/erpnext/selling/report/sales_analytics/sales_analytics.json
@@ -1,31 +1,31 @@
 {
- "add_total_row": 0, 
- "creation": "2018-09-21 12:46:29.451048", 
- "disable_prepared_report": 0, 
- "disabled": 0, 
- "docstatus": 0, 
- "doctype": "Report", 
- "idx": 0, 
- "is_standard": "Yes", 
- "modified": "2019-05-24 05:37:02.866139", 
- "modified_by": "Administrator", 
- "module": "Selling", 
- "name": "Sales Analytics", 
- "owner": "Administrator", 
- "prepared_report": 0, 
- "ref_doctype": "Sales Order", 
- "report_name": "Sales Analytics", 
- "report_type": "Script Report", 
+ "add_total_row": 0,
+ "creation": "2018-09-21 12:46:29.451048",
+ "disable_prepared_report": 0,
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "idx": 0,
+ "is_standard": "Yes",
+ "modified": "2020-04-30 19:49:02.303320",
+ "modified_by": "Administrator",
+ "module": "Selling",
+ "name": "Sales Analytics",
+ "owner": "Administrator",
+ "prepared_report": 0,
+ "ref_doctype": "Sales Order",
+ "report_name": "Sales Analytics",
+ "report_type": "Script Report",
  "roles": [
   {
    "role": "Stock User"
-  }, 
+  },
   {
    "role": "Maintenance User"
-  }, 
+  },
   {
    "role": "Accounts User"
-  }, 
+  },
   {
    "role": "Sales Manager"
   }
diff --git a/erpnext/selling/report/sales_analytics/sales_analytics.py b/erpnext/selling/report/sales_analytics/sales_analytics.py
index f1726ab..97d9322 100644
--- a/erpnext/selling/report/sales_analytics/sales_analytics.py
+++ b/erpnext/selling/report/sales_analytics/sales_analytics.py
@@ -194,6 +194,9 @@
 	def get_rows(self):
 		self.data = []
 		self.get_periodic_data()
+		total_row = {
+			"entity": "Total",
+		}
 
 		for entity, period_data in iteritems(self.entity_periodic_data):
 			row = {
@@ -207,6 +210,9 @@
 				row[scrub(period)] = amount
 				total += amount
 
+				if not total_row.get(scrub(period)): total_row[scrub(period)] = 0
+				total_row[scrub(period)] += amount
+
 			row["total"] = total
 
 			if self.filters.tree_type == "Item":
@@ -214,6 +220,8 @@
 
 			self.data.append(row)
 
+		self.data.append(total_row)
+
 	def get_rows_by_group(self):
 		self.get_periodic_data()
 		out = []
@@ -232,8 +240,10 @@
 					self.entity_periodic_data.setdefault(d.parent, frappe._dict()).setdefault(period, 0.0)
 					self.entity_periodic_data[d.parent][period] += amount
 				total += amount
+
 			row["total"] = total
 			out = [row] + out
+
 		self.data = out
 
 	def get_periodic_data(self):
diff --git a/erpnext/selling/report/sales_analytics/test_analytics.py b/erpnext/selling/report/sales_analytics/test_analytics.py
index 4d81a1e..7e8501d 100644
--- a/erpnext/selling/report/sales_analytics/test_analytics.py
+++ b/erpnext/selling/report/sales_analytics/test_analytics.py
@@ -34,6 +34,21 @@
 
 		expected_data = [
 			{
+				'entity': 'Total',
+				'apr_2017': 0.0,
+				'may_2017': 0.0,
+				'jun_2017': 2000.0,
+				'jul_2017': 1000.0,
+				'aug_2017': 0.0,
+				'sep_2017': 1500.0,
+				'oct_2017': 1000.0,
+				'nov_2017': 0.0,
+				'dec_2017': 0.0,
+				'jan_2018': 0.0,
+				'feb_2018': 2000.0,
+				'mar_2018': 0.0
+  			},
+			{
 				"entity": "_Test Customer 1",
 				"entity_name": "_Test Customer 1",
 				"apr_2017": 0.0,
@@ -135,6 +150,21 @@
 
 		expected_data = [
 			{
+				'entity': 'Total',
+				'apr_2017': 0.0,
+				'may_2017': 0.0,
+				'jun_2017': 20.0,
+				'jul_2017': 10.0,
+				'aug_2017': 0.0,
+				'sep_2017': 15.0,
+				'oct_2017': 10.0,
+				'nov_2017': 0.0,
+				'dec_2017': 0.0,
+				'jan_2018': 0.0,
+				'feb_2018': 20.0,
+				'mar_2018': 0.0
+  			},
+			{
 				"entity": "_Test Customer 1",
 				"entity_name": "_Test Customer 1",
 				"apr_2017": 0.0,
diff --git a/erpnext/selling/report/territory_wise_sales/territory_wise_sales.py b/erpnext/selling/report/territory_wise_sales/territory_wise_sales.py
index f2db478..e883500 100644
--- a/erpnext/selling/report/territory_wise_sales/territory_wise_sales.py
+++ b/erpnext/selling/report/territory_wise_sales/territory_wise_sales.py
@@ -20,31 +20,36 @@
 			"label": _("Territory"),
 			"fieldname": "territory",
 			"fieldtype": "Link",
-			"options": "Territory"
+			"options": "Territory",
+			"width": 150
 		},
 		{
 			"label": _("Opportunity Amount"),
 			"fieldname": "opportunity_amount",
 			"fieldtype": "Currency",
-			"options": currency
+			"options": currency,
+			"width": 150
 		},
 		{
 			"label": _("Quotation Amount"),
 			"fieldname": "quotation_amount",
 			"fieldtype": "Currency",
-			"options": currency
+			"options": currency,
+			"width": 150
 		},
 		{
 			"label": _("Order Amount"),
 			"fieldname": "order_amount",
 			"fieldtype": "Currency",
-			"options": currency
+			"options": currency,
+			"width": 150
 		},
 		{
 			"label": _("Billing Amount"),
 			"fieldname": "billing_amount",
 			"fieldtype": "Currency",
-			"options": currency
+			"options": currency,
+			"width": 150
 		}
 	]
 
@@ -62,8 +67,7 @@
 			territory_opportunities = list(filter(lambda x: x.territory == territory.name, opportunities))
 		t_opportunity_names = []
 		if territory_opportunities:
-			t_opportunity_names = [t.name for t in territory_opportunities] 
-
+			t_opportunity_names = [t.name for t in territory_opportunities]
 		territory_quotations = []
 		if t_opportunity_names and quotations:
 			territory_quotations = list(filter(lambda x: x.opportunity in t_opportunity_names, quotations))
@@ -76,7 +80,7 @@
 			list(filter(lambda x: x.quotation in t_quotation_names, sales_orders))
 		t_order_names = []
 		if territory_orders:
-			t_order_names = [t.name for t in territory_orders] 
+			t_order_names = [t.name for t in territory_orders]
 
 		territory_invoices = list(filter(lambda x: x.sales_order in t_order_names, sales_invoices)) if t_order_names and sales_invoices else []
 
@@ -96,12 +100,12 @@
 
 	if filters.get('transaction_date'):
 		conditions = " WHERE transaction_date between {0} and {1}".format(
-			frappe.db.escape(filters['transaction_date'][0]), 
+			frappe.db.escape(filters['transaction_date'][0]),
 			frappe.db.escape(filters['transaction_date'][1]))
-	
+
 	if filters.company:
 		if conditions:
-			conditions += " AND" 
+			conditions += " AND"
 		else:
 			conditions += " WHERE"
 		conditions += " company = %(company)s"
@@ -115,7 +119,7 @@
 def get_quotations(opportunities):
 	if not opportunities:
 		return []
-	
+
 	opportunity_names = [o.name for o in opportunities]
 
 	return frappe.db.sql("""
@@ -155,5 +159,5 @@
 	total = 0
 	for doc in doclist:
 		total += doc.get(amount_field, 0)
-	
+
 	return total
diff --git a/erpnext/setup/desk_page/getting_started/getting_started.json b/erpnext/setup/desk_page/home/home.json
similarity index 96%
rename from erpnext/setup/desk_page/getting_started/getting_started.json
rename to erpnext/setup/desk_page/home/home.json
index 63d8984..63cd5c5 100644
--- a/erpnext/setup/desk_page/getting_started/getting_started.json
+++ b/erpnext/setup/desk_page/home/home.json
@@ -47,26 +47,20 @@
   }
  ],
  "category": "Modules",
- "charts": [
-  {
-   "chart_name": "Bank Balance",
-   "label": "Bank Balance"
-  }
- ],
+ "charts": [],
  "creation": "2020-01-23 13:46:38.833076",
  "developer_mode_only": 0,
  "disable_user_customization": 0,
  "docstatus": 0,
  "doctype": "Desk Page",
  "extends_another_page": 0,
- "icon": "",
  "idx": 0,
  "is_standard": 1,
- "label": "Getting Started",
- "modified": "2020-04-01 11:30:19.763099",
+ "label": "Home",
+ "modified": "2020-05-11 10:20:37.358701",
  "modified_by": "Administrator",
  "module": "Setup",
- "name": "Getting Started",
+ "name": "Home",
  "owner": "Administrator",
  "pin_to_bottom": 0,
  "pin_to_top": 1,
diff --git a/erpnext/setup/doctype/company/test_company.py b/erpnext/setup/doctype/company/test_company.py
index b37cc17..29f6c37 100644
--- a/erpnext/setup/doctype/company/test_company.py
+++ b/erpnext/setup/doctype/company/test_company.py
@@ -47,9 +47,7 @@
 		frappe.delete_doc("Company", "COA from Existing Company")
 
 	def test_coa_based_on_country_template(self):
-		countries = ["India", "Brazil", "United Arab Emirates", "Canada", "Germany", "France",
-			"Guatemala", "Indonesia", "Italy", "Mexico", "Nicaragua", "Netherlands", "Singapore",
-			"Brazil", "Argentina", "Hungary", "Taiwan"]
+		countries = ["Canada", "Germany", "France"]
 
 		for country in countries:
 			templates = get_charts_for_country(country)
diff --git a/erpnext/setup/doctype/territory/territory.py b/erpnext/setup/doctype/territory/territory.py
index 095bd1c..808b538 100644
--- a/erpnext/setup/doctype/territory/territory.py
+++ b/erpnext/setup/doctype/territory/territory.py
@@ -3,8 +3,6 @@
 
 from __future__ import unicode_literals
 import frappe
-
-
 from frappe.utils import flt
 from frappe import _
 
@@ -14,6 +12,7 @@
 	nsm_parent_field = 'parent_territory'
 
 	def validate(self):
+
 		for d in self.get('targets') or []:
 			if not flt(d.target_qty) and not flt(d.target_amount):
 				frappe.throw(_("Either target qty or target amount is mandatory"))
diff --git a/erpnext/setup/setup_wizard/data/dashboard_charts.py b/erpnext/setup/setup_wizard/data/dashboard_charts.py
deleted file mode 100644
index b182dfc..0000000
--- a/erpnext/setup/setup_wizard/data/dashboard_charts.py
+++ /dev/null
@@ -1,133 +0,0 @@
-from __future__ import unicode_literals
-from frappe import _
-import frappe
-import json
-
-def get_company_for_dashboards():
-	company = frappe.defaults.get_defaults().company
-	if company:
-		return company
-	else:
-		company_list = frappe.get_list("Company")
-		if company_list:
-			return company_list[0].name
-	return None
-
-def get_default_dashboards():
-	company = frappe.get_doc("Company", get_company_for_dashboards())
-	income_account = company.default_income_account or get_account("Income Account", company.name)
-	expense_account = company.default_expense_account or get_account("Expense Account", company.name)
-	bank_account = company.default_bank_account or get_account("Bank", company.name)
-
-	return {
-		"Dashboards": [
-			{
-				"doctype": "Dashboard",
-				"dashboard_name": "Accounts",
-				"charts": [
-					{ "chart": "Outgoing Bills (Sales Invoice)" },
-					{ "chart": "Incoming Bills (Purchase Invoice)" },
-					{ "chart": "Bank Balance" },
-					{ "chart": "Income" },
-					{ "chart": "Expenses" },
-					{ "chart": "Patient Appointments" }
-				]
-			}
-		],
-		"Charts": [
-			{
-				"doctype": "Dashboard Chart",
-				"time_interval": "Quarterly",
-				"chart_name": "Income",
-				"timespan": "Last Year",
-				"color": None,
-				"filters_json": json.dumps({"company": company.name, "account": income_account}),
-				"source": "Account Balance Timeline",
-				"chart_type": "Custom",
-				"timeseries": 1,
-				"owner": "Administrator",
-				"type": "Line",
-				"width": "Half"
-			},
-			{
-				"doctype": "Dashboard Chart",
-				"time_interval": "Quarterly",
-				"chart_name": "Expenses",
-				"timespan": "Last Year",
-				"color": None,
-				"filters_json": json.dumps({"company": company.name, "account": expense_account}),
-				"source": "Account Balance Timeline",
-				"chart_type": "Custom",
-				"timeseries": 1,
-				"owner": "Administrator",
-				"type": "Line",
-				"width": "Half"
-			},
-			{
-				"doctype": "Dashboard Chart",
-				"time_interval": "Quarterly",
-				"chart_name": "Bank Balance",
-				"timespan": "Last Year",
-				"color": "#ffb868",
-				"filters_json": json.dumps({"company": company.name, "account": bank_account}),
-				"source": "Account Balance Timeline",
-				"chart_type": "Custom",
-				"timeseries": 1,
-				"owner": "Administrator",
-				"type": "Line",
-				"width": "Half"
-			},
-			{
-				"doctype": "Dashboard Chart",
-				"time_interval": "Monthly",
-				"chart_name": "Incoming Bills (Purchase Invoice)",
-				"timespan": "Last Year",
-				"color": "#a83333",
-				"value_based_on": "base_grand_total",
-				"filters_json": json.dumps({}),
-				"chart_type": "Sum",
-				"timeseries": 1,
-				"based_on": "posting_date",
-				"owner": "Administrator",
-				"document_type": "Purchase Invoice",
-				"type": "Bar",
-				"width": "Half"
-			},
-			{
-				"doctype": "Dashboard Chart",
-				"time_interval": "Monthly",
-				"chart_name": "Outgoing Bills (Sales Invoice)",
-				"timespan": "Last Year",
-				"color": "#7b933d",
-				"value_based_on": "base_grand_total",
-				"filters_json": json.dumps({}),
-				"chart_type": "Sum",
-				"timeseries": 1,
-				"based_on": "posting_date",
-				"owner": "Administrator",
-				"document_type": "Sales Invoice",
-				"type": "Bar",
-				"width": "Half"
-			},
-			{
-				"doctype": "Dashboard Chart",
-				"time_interval": "Daily",
-				"chart_name": "Patient Appointments",
-				"timespan": "Last Month",
-				"color": "#77ecca",
-				"filters_json": json.dumps({}),
-				"chart_type": "Count",
-				"timeseries": 1,
-				"based_on": "appointment_datetime",
-				"owner": "Administrator",
-				"document_type": "Patient Appointment",
-				"type": "Line",
-				"width": "Half"
-			}
-		]
-	}
-
-def get_account(account_type, company):
-	accounts = frappe.get_list("Account", filters={"account_type": account_type, "company": company})
-	if accounts:
-		return accounts[0].name
diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py
index 3be6f44..8bb0a05 100644
--- a/erpnext/setup/setup_wizard/operations/install_fixtures.py
+++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py
@@ -485,8 +485,6 @@
 				# bank account same as a CoA entry
 				pass
 
-	add_dashboards()
-
 	# Now, with fixtures out of the way, onto concrete stuff
 	records = [
 
@@ -504,27 +502,6 @@
 
 	make_records(records)
 
-def add_dashboards():
-	from erpnext.setup.setup_wizard.data.dashboard_charts import get_company_for_dashboards
-
-	if not get_company_for_dashboards():
-		return
-
-	from erpnext.setup.setup_wizard.data.dashboard_charts import get_default_dashboards
-	from frappe.modules.import_file import import_file_by_path
-
-	dashboard_data = get_default_dashboards()
-
-	# create account balance timeline before creating dashbaord charts
-	doctype = "dashboard_chart_source"
-	docname = "account_balance_timeline"
-	folder = os.path.dirname(frappe.get_module("erpnext.accounts").__file__)
-	doc_path = os.path.join(folder, doctype, docname, docname) + ".json"
-	import_file_by_path(doc_path, force=0, for_sync=True)
-
-	make_records(dashboard_data["Charts"])
-	make_records(dashboard_data["Dashboards"])
-
 
 def get_fy_details(fy_start_date, fy_end_date):
 	start_year = getdate(fy_start_date).year
diff --git a/erpnext/shopping_cart/cart.py b/erpnext/shopping_cart/cart.py
index e11e1bb..4ac546e 100644
--- a/erpnext/shopping_cart/cart.py
+++ b/erpnext/shopping_cart/cart.py
@@ -541,27 +541,31 @@
 	return doc.tc_name
 
 @frappe.whitelist(allow_guest=True)
-def apply_coupon_code(applied_code,applied_referral_sales_partner):
+def apply_coupon_code(applied_code, applied_referral_sales_partner):
 	quotation = True
-	if applied_code:
-		coupon_list=frappe.get_all('Coupon Code', filters={"docstatus": ("<", "2"), 'coupon_code':applied_code }, fields=['name'])
-		if coupon_list:
-			coupon_name=coupon_list[0].name
-			from erpnext.accounts.doctype.pricing_rule.utils import validate_coupon_code
-			validate_coupon_code(coupon_name)
-			quotation = _get_cart_quotation()
-			quotation.coupon_code=coupon_name
+
+	if not applied_code:
+		frappe.throw(_("Please enter a coupon code"))
+
+	coupon_list = frappe.get_all('Coupon Code', filters={'coupon_code': applied_code})
+	if not coupon_list:
+		frappe.throw(_("Please enter a valid coupon code"))
+
+	coupon_name = coupon_list[0].name
+
+	from erpnext.accounts.doctype.pricing_rule.utils import validate_coupon_code
+	validate_coupon_code(coupon_name)
+	quotation = _get_cart_quotation()
+	quotation.coupon_code = coupon_name
+	quotation.flags.ignore_permissions = True
+	quotation.save()
+
+	if applied_referral_sales_partner:
+		sales_partner_list = frappe.get_all('Sales Partner', filters={'referral_code': applied_referral_sales_partner})
+		if sales_partner_list:
+			sales_partner_name = sales_partner_list[0].name
+			quotation.referral_sales_partner = sales_partner_name
 			quotation.flags.ignore_permissions = True
 			quotation.save()
-			if applied_referral_sales_partner:
-				sales_partner_list=frappe.get_all('Sales Partner', filters={'docstatus': 0, 'referral_code':applied_referral_sales_partner }, fields=['name'])
-				if sales_partner_list:
-					sales_partner_name=sales_partner_list[0].name
-					quotation.referral_sales_partner=sales_partner_name
-					quotation.flags.ignore_permissions = True
-					quotation.save()
-		else:
-			frappe.throw(_("Please enter valid coupon code !!"))
-	else:
-		frappe.throw(_("Please enter coupon code !!"))
+
 	return quotation
diff --git a/erpnext/shopping_cart/product_info.py b/erpnext/shopping_cart/product_info.py
index a7da09c..21ee335 100644
--- a/erpnext/shopping_cart/product_info.py
+++ b/erpnext/shopping_cart/product_info.py
@@ -10,14 +10,16 @@
 from erpnext.utilities.product import get_price, get_qty_in_stock, get_non_stock_item_status
 
 @frappe.whitelist(allow_guest=True)
-def get_product_info_for_website(item_code):
+def get_product_info_for_website(item_code, skip_quotation_creation=False):
 	"""get product price / stock info for website"""
 
 	cart_settings = get_shopping_cart_settings()
 	if not cart_settings.enabled:
 		return frappe._dict()
 
-	cart_quotation = _get_cart_quotation()
+	cart_quotation = frappe._dict()
+	if not skip_quotation_creation:
+		cart_quotation = _get_cart_quotation()
 
 	price = get_price(
 		item_code,
@@ -51,7 +53,7 @@
 
 def set_product_info_for_website(item):
 	"""set product price uom for website"""
-	product_info = get_product_info_for_website(item.item_code)
+	product_info = get_product_info_for_website(item.item_code, skip_quotation_creation=True)
 
 	if product_info:
 		item.update(product_info)
diff --git a/erpnext/stock/doctype/batch/batch.py b/erpnext/stock/doctype/batch/batch.py
index 9b7249e..a091ac7 100644
--- a/erpnext/stock/doctype/batch/batch.py
+++ b/erpnext/stock/doctype/batch/batch.py
@@ -7,7 +7,7 @@
 from frappe import _
 from frappe.model.document import Document
 from frappe.model.naming import make_autoname, revert_series_if_last
-from frappe.utils import flt, cint
+from frappe.utils import flt, cint, get_link_to_form
 from frappe.utils.jinja import render_template
 from frappe.utils.data import add_days
 from six import string_types
@@ -124,7 +124,7 @@
 		if has_expiry_date and not self.expiry_date:
 			frappe.throw(msg=_("Please set {0} for Batched Item {1}, which is used to set {2} on Submit.") \
 				.format(frappe.bold("Shelf Life in Days"),
-					frappe.utils.get_link_to_form("Item", self.item),
+					get_link_to_form("Item", self.item),
 					frappe.bold("Batch Expiry Date")),
 				title=_("Expiry Date Mandatory"))
 
@@ -264,16 +264,20 @@
 def get_batches(item_code, warehouse, qty=1, throw=False, serial_no=None):
 	from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
 	cond = ''
-	if serial_no:
+	if serial_no and frappe.get_cached_value('Item', item_code, 'has_batch_no'):
+		serial_nos = get_serial_nos(serial_no)
 		batch = frappe.get_all("Serial No",
 			fields = ["distinct batch_no"],
 			filters= {
 				"item_code": item_code,
 				"warehouse": warehouse,
-				"name": ("in", get_serial_nos(serial_no))
+				"name": ("in", serial_nos)
 			}
 		)
 
+		if not batch:
+			validate_serial_no_with_batch(serial_nos, item_code)
+
 		if batch and len(batch) > 1:
 			return []
 
@@ -288,4 +292,15 @@
 			and (`tabBatch`.expiry_date >= CURDATE() or `tabBatch`.expiry_date IS NULL) {0}
 		group by batch_id
 		order by `tabBatch`.expiry_date ASC, `tabBatch`.creation ASC
-	""".format(cond), (item_code, warehouse), as_dict=True)
\ No newline at end of file
+	""".format(cond), (item_code, warehouse), as_dict=True)
+
+def validate_serial_no_with_batch(serial_nos, item_code):
+	if frappe.get_cached_value("Serial No", serial_nos[0], "item_code") != item_code:
+		frappe.throw(_("The serial no {0} does not belong to item {1}")
+			.format(get_link_to_form("Serial No", serial_nos[0]), get_link_to_form("Item", item_code)))
+
+	serial_no_link = ','.join([get_link_to_form("Serial No", sn) for sn in serial_nos])
+
+	message = "Serial Nos" if len(serial_nos) > 1 else "Serial No"
+	frappe.throw(_("There is no batch found against the {0}: {1}")
+		.format(message, serial_no_link))
\ No newline at end of file
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index c62b3ab..7a1c127 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -467,7 +467,7 @@
 
 	def set_shopping_cart_data(self, context):
 		from erpnext.shopping_cart.product_info import get_product_info_for_website
-		context.shopping_cart = get_product_info_for_website(self.name)
+		context.shopping_cart = get_product_info_for_website(self.name, skip_quotation_creation=True)
 
 	def add_default_uom_in_conversion_factor_table(self):
 		uom_conv_list = [d.uom for d in self.get("uoms")]
@@ -572,6 +572,13 @@
 							frappe.throw(_("Barcode {0} is not a valid {1} code").format(
 								item_barcode.barcode, item_barcode.barcode_type), InvalidBarcode)
 
+					if item_barcode.barcode != item_barcode.name:
+						# if barcode is getting updated , the row name has to reset.
+						# Delete previous old row doc and re-enter row as if new to reset name in db.
+						item_barcode.set("__islocal", True)
+						item_barcode.name = None
+						frappe.delete_doc("Item Barcode", item_barcode.name)
+
 	def validate_warehouse_for_reorder(self):
 		'''Validate Reorder level table for duplicate and conditional mandatory'''
 		warehouse = []
diff --git a/erpnext/stock/doctype/item_price/item_price.py b/erpnext/stock/doctype/item_price/item_price.py
index 957c415..8e39eb5 100644
--- a/erpnext/stock/doctype/item_price/item_price.py
+++ b/erpnext/stock/doctype/item_price/item_price.py
@@ -69,3 +69,10 @@
 			self.reference = self.customer
 		if self.buying:
 			self.reference = self.supplier
+		
+		if self.selling and not self.buying:
+			# if only selling then remove supplier
+			self.supplier = None
+		if self.buying and not self.selling:
+			# if only buying then remove customer
+			self.customer = None
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index ddf4ec0..62c9eb1 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -181,7 +181,7 @@
 		stock_items = self.get_stock_items()
 		serialized_items = self.get_serialized_items()
 		for item in self.get("items"):
-			if item.qty and item.qty < 0:
+			if flt(item.qty) and flt(item.qty) < 0:
 				frappe.throw(_("Row {0}: The item {1}, quantity must be positive number")
 					.format(item.idx, frappe.bold(item.item_code)))
 
@@ -470,7 +470,7 @@
 			"qty": item.s_warehouse and -1*flt(item.transfer_qty) or flt(item.transfer_qty),
 			"serial_no": item.serial_no,
 			"voucher_type": self.doctype,
-			"voucher_no": item.name,
+			"voucher_no": self.name,
 			"company": self.company,
 			"allow_zero_valuation": item.allow_zero_valuation_rate,
 		})
diff --git a/erpnext/stock/doctype/warehouse/warehouse.py b/erpnext/stock/doctype/warehouse/warehouse.py
index eb4867d..cd86be3 100644
--- a/erpnext/stock/doctype/warehouse/warehouse.py
+++ b/erpnext/stock/doctype/warehouse/warehouse.py
@@ -177,7 +177,7 @@
 	return frappe.get_doc("Warehouse", args.docname).convert_to_group_or_ledger()
 
 def get_child_warehouses(warehouse):
-	lft, rgt = frappe.get_cached_value("Warehouse", warehouse, [lft, rgt])
+	lft, rgt = frappe.get_cached_value("Warehouse", warehouse, ["lft", "rgt"])
 
 	return frappe.db.sql_list("""select name from `tabWarehouse`
 		where lft >= %s and rgt <= %s""", (lft, rgt))
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index d50712a..11b6403 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -630,7 +630,7 @@
 		elif args.get("supplier"):
 			conditions += " and supplier=%(supplier)s"
 		else:
-			conditions += " and (customer is null or customer = '') and (supplier is null or supplier = '')"
+			conditions += "and (customer is null or customer = '') and (supplier is null or supplier = '')"
 
 	if args.get('transaction_date'):
 		conditions += """ and %(transaction_date)s between
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index b4cb8ca..e1b3730 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -548,7 +548,16 @@
 	if not allow_zero_rate and not valuation_rate and raise_error_if_no_rate \
 			and cint(erpnext.is_perpetual_inventory_enabled(company)):
 		frappe.local.message_log = []
-		frappe.throw(_("Valuation rate not found for the Item {0}, which is required to do accounting entries for {1} {2}. If the item is transacting as a zero valuation rate item in the {1}, please mention that in the {1} Item table. Otherwise, please create an incoming stock transaction for the item or mention valuation rate in the Item record, and then try submiting / cancelling this entry.")
-			.format(item_code, voucher_type, voucher_no))
+		form_link = frappe.utils.get_link_to_form("Item", item_code)
+
+		message = _("Valuation Rate for the Item {0}, is required to do accounting entries for {1} {2}.").format(form_link, voucher_type, voucher_no)
+		message += "<br><br>" + _(" Here are the options to proceed:")
+		solutions = "<li>" + _("If the item is transacting as a Zero Valuation Rate item in this entry, please enable 'Allow Zero Valuation Rate' in the {0} Item table.").format(voucher_type) + "</li>"
+		solutions += "<li>" + _("If not, you can Cancel / Submit this entry ") + _("{0}").format(frappe.bold("after")) + _(" performing either one below:") + "</li>"
+		sub_solutions = "<ul><li>" + _("Create an incoming stock transaction for the Item.") + "</li>"
+		sub_solutions += "<li>" + _("Mention Valuation Rate in the Item master.") + "</li></ul>"
+		msg = message + solutions + sub_solutions + "</li>"
+
+		frappe.throw(msg=msg, title=_("Valuation Rate Missing"))
 
 	return valuation_rate