Merge branch 'develop' into payment_entry_validations_and_trigger_develop
diff --git a/erpnext/accounts/doctype/account/account.py b/erpnext/accounts/doctype/account/account.py
index 1be2fbf..f763df0 100644
--- a/erpnext/accounts/doctype/account/account.py
+++ b/erpnext/accounts/doctype/account/account.py
@@ -230,7 +230,7 @@
 		if self.check_gle_exists():
 			throw(_("Account with existing transaction can not be converted to group."))
 		elif self.account_type and not self.flags.exclude_account_type_check:
-			throw(_("Cannot covert to Group because Account Type is selected."))
+			throw(_("Cannot convert to Group because Account Type is selected."))
 		else:
 			self.is_group = 1
 			self.save()
diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
index 703e93c..7bcc6ee 100644
--- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
+++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json
@@ -10,6 +10,7 @@
   "accounts_transactions_settings_section",
   "over_billing_allowance",
   "role_allowed_to_over_bill",
+  "credit_controller",
   "make_payment_via_journal_entry",
   "column_break_11",
   "check_supplier_invoice_uniqueness",
@@ -27,7 +28,6 @@
   "acc_frozen_upto",
   "frozen_accounts_modifier",
   "column_break_4",
-  "credit_controller",
   "deferred_accounting_settings_section",
   "book_deferred_entries_based_on",
   "column_break_18",
@@ -73,11 +73,10 @@
    "fieldtype": "Column Break"
   },
   {
-   "description": "This role is allowed to submit transactions that exceed credit limits",
    "fieldname": "credit_controller",
    "fieldtype": "Link",
    "in_list_view": 1,
-   "label": "Credit Controller",
+   "label": "Role allowed to bypass Credit Limit",
    "options": "Role"
   },
   {
@@ -268,7 +267,7 @@
  "index_web_pages_for_search": 1,
  "issingle": 1,
  "links": [],
- "modified": "2021-06-17 20:26:03.721202",
+ "modified": "2021-08-09 13:08:01.335416",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Accounts Settings",
diff --git a/erpnext/accounts/doctype/budget/test_budget.py b/erpnext/accounts/doctype/budget/test_budget.py
index 603e21e..6c25f00 100644
--- a/erpnext/accounts/doctype/budget/test_budget.py
+++ b/erpnext/accounts/doctype/budget/test_budget.py
@@ -249,7 +249,7 @@
 
 def set_total_expense_zero(posting_date, budget_against_field=None, budget_against_CC=None):
 	if budget_against_field == "project":
-		budget_against = "_Test Project"
+		budget_against = frappe.db.get_value("Project", {"project_name": "_Test Project"})
 	else:
 		budget_against = budget_against_CC or "_Test Cost Center - _TC"
 
@@ -275,7 +275,7 @@
 			"_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", posting_date=nowdate(), submit=True)
 		elif budget_against_field == "project":
 			make_journal_entry("_Test Account Cost for Goods Sold - _TC",
-			"_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", submit=True, project="_Test Project", posting_date=nowdate())
+			"_Test Bank - _TC", -existing_expense, "_Test Cost Center - _TC", submit=True, project=budget_against, posting_date=nowdate())
 
 def make_budget(**args):
 	args = frappe._dict(args)
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py
index 11465b7..0844995 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py
@@ -58,8 +58,8 @@
 			if not self.get(k):
 				frappe.throw(_("{0} is required").format(_(self.meta.get_label(k))))
 
-		account_type = frappe.get_cached_value("Account", self.account, "account_type")
 		if not (self.party_type and self.party):
+			account_type = frappe.get_cached_value("Account", self.account, "account_type")
 			if account_type == "Receivable":
 				frappe.throw(_("{0} {1}: Customer is required against Receivable account {2}")
 					.format(self.voucher_type, self.voucher_no, self.account))
@@ -73,15 +73,19 @@
 				.format(self.voucher_type, self.voucher_no, self.account))
 
 	def pl_must_have_cost_center(self):
-		if frappe.get_cached_value("Account", self.account, "report_type") == "Profit and Loss":
-			if not self.cost_center and self.voucher_type != 'Period Closing Voucher':
-				msg = _("{0} {1}: Cost Center is required for 'Profit and Loss' account {2}.").format(
-					self.voucher_type, self.voucher_no, self.account)
-				msg += " "
-				msg += _("Please set the cost center field in {0} or setup a default Cost Center for the Company.").format(
-					self.voucher_type)
+		"""Validate that profit and loss type account GL entries have a cost center."""
 
-				frappe.throw(msg, title=_("Missing Cost Center"))
+		if self.cost_center or self.voucher_type == 'Period Closing Voucher':
+			return
+
+		if frappe.get_cached_value("Account", self.account, "report_type") == "Profit and Loss":
+			msg = _("{0} {1}: Cost Center is required for 'Profit and Loss' account {2}.").format(
+				self.voucher_type, self.voucher_no, self.account)
+			msg += " "
+			msg += _("Please set the cost center field in {0} or setup a default Cost Center for the Company.").format(
+				self.voucher_type)
+
+			frappe.throw(msg, title=_("Missing Cost Center"))
 
 	def validate_dimensions_for_pl_and_bs(self):
 		account_type = frappe.db.get_value("Account", self.account, "report_type")
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
index 428989a..0be41b4 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json
@@ -558,7 +558,8 @@
    "description": "Simple Python Expression, Example: territory != 'All Territories'",
    "fieldname": "condition",
    "fieldtype": "Code",
-   "label": "Condition"
+   "label": "Condition",
+   "options": "PythonExpression"
   },
   {
    "fieldname": "column_break_42",
@@ -575,7 +576,7 @@
  "icon": "fa fa-gift",
  "idx": 1,
  "links": [],
- "modified": "2021-03-06 22:01:24.840422",
+ "modified": "2021-08-06 15:10:04.219321",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Pricing Rule",
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index 7562418..bda9f41 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -134,7 +134,7 @@
 					},
 					get_query_filters: {
 						docstatus: 1,
-						status: ["not in", ["Closed", "Completed"]],
+						status: ["not in", ["Closed", "Completed", "Return Issued"]],
 						company: me.frm.doc.company,
 						is_return: 0
 					}
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
index 863c104..25f42bc 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -22,7 +22,7 @@
 from frappe.model.mapper import get_mapped_doc
 from six import iteritems
 from erpnext.accounts.doctype.sales_invoice.sales_invoice import validate_inter_company_party, update_linked_doc,\
-	unlink_inter_company_doc
+	unlink_inter_company_doc, check_if_return_invoice_linked_with_payment_entry
 from erpnext.accounts.doctype.tax_withholding_category.tax_withholding_category import get_party_tax_withholding_details
 from erpnext.accounts.deferred_revenue import validate_service_stop_date
 from erpnext.stock.doctype.purchase_receipt.purchase_receipt import get_item_account_wise_additional_cost
@@ -1014,6 +1014,8 @@
 				}, item=self))
 
 	def on_cancel(self):
+		check_if_return_invoice_linked_with_payment_entry(self)
+
 		super(PurchaseInvoice, self).on_cancel()
 
 		self.check_on_hold_or_closed_status()
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 8889913..cecc1a1 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -290,6 +290,8 @@
 		self.update_time_sheet(None)
 
 	def on_cancel(self):
+		check_if_return_invoice_linked_with_payment_entry(self)
+
 		super(SalesInvoice, self).on_cancel()
 
 		self.check_sales_order_on_hold_or_close("sales_order")
@@ -480,7 +482,7 @@
 		if not self.pos_profile:
 			pos_profile = get_pos_profile(self.company) or {}
 			if not pos_profile:
-				frappe.throw(_("No POS Profile found. Please create a New POS Profile first"))
+				return
 			self.pos_profile = pos_profile.get('name')
 
 		pos = {}
@@ -922,7 +924,7 @@
 						asset = frappe.get_doc("Asset", item.asset)
 					else:
 						frappe.throw(_(
-							"Row #{0}: You must select an Asset for Item {1}.").format(item.idx, item.item_name), 
+							"Row #{0}: You must select an Asset for Item {1}.").format(item.idx, item.item_name),
 							title=_("Missing Asset")
 						)
 					if (len(asset.finance_books) > 1 and not item.finance_book
@@ -944,7 +946,7 @@
 						gl_entries.append(self.get_gl_dict(gle, item=item))
 
 					self.set_asset_status(asset)
-				
+
 				else:
 					# Do not book income for transfer within same company
 					if not self.is_internal_transfer():
@@ -973,7 +975,7 @@
 	def set_asset_status(self, asset):
 		if self.is_return:
 			asset.set_status()
-		else: 	
+		else:
 			asset.set_status("Sold" if self.docstatus==1 else None)
 
 	def make_loyalty_point_redemption_gle(self, gl_entries):
@@ -1941,3 +1943,41 @@
 		}
 	}, target_doc, set_missing_values)
 	return doclist
+
+def check_if_return_invoice_linked_with_payment_entry(self):
+	# If a Return invoice is linked with payment entry along with other invoices,
+	# the cancellation of the Return causes allocated amount to be greater than paid
+
+	if not frappe.db.get_single_value('Accounts Settings', 'unlink_payment_on_cancellation_of_invoice'):
+		return
+
+	payment_entries = []
+	if self.is_return and self.return_against:
+		invoice = self.return_against
+	else:
+		invoice = self.name
+
+	payment_entries = frappe.db.sql_list("""
+		SELECT
+			t1.name
+		FROM
+			`tabPayment Entry` t1, `tabPayment Entry Reference` t2
+		WHERE
+			t1.name = t2.parent
+			and t1.docstatus = 1
+			and t2.reference_name = %s
+			and t2.allocated_amount < 0
+		""", invoice)
+
+	links_to_pe = []
+	if payment_entries:
+		for payment in payment_entries:
+			payment_entry = frappe.get_doc("Payment Entry", payment)
+			if len(payment_entry.references) > 1:
+				links_to_pe.append(payment_entry.name)
+		if links_to_pe:
+			payment_entries_link = [get_link_to_form('Payment Entry', name, label=name) for name in links_to_pe]
+			message = _("Please cancel and amend the Payment Entry")
+			message += " " + ", ".join(payment_entries_link) + " "
+			message += _("to unallocate the amount of this Return Invoice before cancelling it.")
+			frappe.throw(message)
diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.py b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.py
index 52d19d5..8f9eb65 100644
--- a/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.py
+++ b/erpnext/accounts/doctype/sales_taxes_and_charges_template/sales_taxes_and_charges_template.py
@@ -6,7 +6,7 @@
 from frappe import _
 from frappe.utils import flt
 from frappe.model.document import Document
-from erpnext.controllers.accounts_controller import validate_taxes_and_charges, validate_inclusive_tax
+from erpnext.controllers.accounts_controller import validate_taxes_and_charges, validate_inclusive_tax, validate_cost_center, validate_account_head
 
 class SalesTaxesandChargesTemplate(Document):
 	def validate(self):
@@ -39,6 +39,8 @@
 
 	for tax in doc.get("taxes"):
 		validate_taxes_and_charges(tax)
+		validate_account_head(tax, doc)
+		validate_cost_center(tax, doc)
 		validate_inclusive_tax(tax, doc)
 
 def validate_disabled(doc):
diff --git a/erpnext/accounts/doctype/sales_taxes_and_charges_template/test_records.json b/erpnext/accounts/doctype/sales_taxes_and_charges_template/test_records.json
index 2b737b9..74db08d 100644
--- a/erpnext/accounts/doctype/sales_taxes_and_charges_template/test_records.json
+++ b/erpnext/accounts/doctype/sales_taxes_and_charges_template/test_records.json
@@ -8,6 +8,7 @@
     "charge_type": "On Net Total",
     "description": "VAT",
     "doctype": "Sales Taxes and Charges",
+    "cost_center": "Main - _TC",
     "parentfield": "taxes",
     "rate": 6
    },
@@ -16,6 +17,7 @@
     "charge_type": "On Net Total",
     "description": "Service Tax",
     "doctype": "Sales Taxes and Charges",
+    "cost_center": "Main - _TC",
     "parentfield": "taxes",
     "rate": 6.36
    }
@@ -114,6 +116,7 @@
     "charge_type": "On Net Total",
     "description": "VAT",
     "doctype": "Sales Taxes and Charges",
+    "cost_center": "Main - _TC",
     "parentfield": "taxes",
     "rate": 12
    },
@@ -122,6 +125,7 @@
     "charge_type": "On Net Total",
     "description": "Service Tax",
     "doctype": "Sales Taxes and Charges",
+    "cost_center": "Main - _TC",
     "parentfield": "taxes",
     "rate": 4
    }
@@ -137,6 +141,7 @@
     "charge_type": "On Net Total",
     "description": "VAT",
     "doctype": "Sales Taxes and Charges",
+    "cost_center": "Main - _TC",
     "parentfield": "taxes",
     "rate": 12
    },
@@ -145,6 +150,7 @@
     "charge_type": "On Net Total",
     "description": "Service Tax",
     "doctype": "Sales Taxes and Charges",
+    "cost_center": "Main - _TC",
     "parentfield": "taxes",
     "rate": 4
    }
@@ -160,6 +166,7 @@
     "charge_type": "On Net Total",
     "description": "VAT",
     "doctype": "Sales Taxes and Charges",
+    "cost_center": "Main - _TC",
     "parentfield": "taxes",
     "rate": 12
    },
@@ -168,6 +175,7 @@
     "charge_type": "On Net Total",
     "description": "Service Tax",
     "doctype": "Sales Taxes and Charges",
+    "cost_center": "Main - _TC",
     "parentfield": "taxes",
     "rate": 4
    }
diff --git a/erpnext/accounts/doctype/subscription_plan/subscription_plan.json b/erpnext/accounts/doctype/subscription_plan/subscription_plan.json
index 46ce093..771611a 100644
--- a/erpnext/accounts/doctype/subscription_plan/subscription_plan.json
+++ b/erpnext/accounts/doctype/subscription_plan/subscription_plan.json
@@ -78,7 +78,7 @@
    "label": "Cost"
   },
   {
-   "depends_on": "eval:doc.price_determination==\"Based on price list\"",
+   "depends_on": "eval:doc.price_determination==\"Based On Price List\"",
    "fieldname": "price_list",
    "fieldtype": "Link",
    "label": "Price List",
@@ -147,7 +147,7 @@
   }
  ],
  "links": [],
- "modified": "2020-06-25 10:53:44.205774",
+ "modified": "2021-08-09 10:53:44.205774",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Subscription Plan",
diff --git a/erpnext/accounts/general_ledger.py b/erpnext/accounts/general_ledger.py
index 25d2cf1..4c7c567 100644
--- a/erpnext/accounts/general_ledger.py
+++ b/erpnext/accounts/general_ledger.py
@@ -100,8 +100,8 @@
 	return merged_gl_map
 
 def check_if_in_list(gle, gl_map, dimensions=None):
-	account_head_fieldnames = ['party_type', 'party', 'against_voucher', 'against_voucher_type',
-		'cost_center', 'project', 'voucher_detail_no']
+	account_head_fieldnames = ['voucher_detail_no', 'party', 'against_voucher',
+			'cost_center', 'against_voucher_type', 'party_type', 'project']
 
 	if dimensions:
 		account_head_fieldnames = account_head_fieldnames + dimensions
@@ -110,10 +110,12 @@
 		same_head = True
 		if e.account != gle.account:
 			same_head = False
+			continue
 
 		for fieldname in account_head_fieldnames:
 			if cstr(e.get(fieldname)) != cstr(gle.get(fieldname)):
 				same_head = False
+				break
 
 		if same_head:
 			return e
@@ -143,16 +145,19 @@
 		validate_expense_against_budget(args)
 
 def validate_cwip_accounts(gl_map):
-	cwip_enabled = any(cint(ac.enable_cwip_accounting) for ac in frappe.db.get_all("Asset Category","enable_cwip_accounting"))
+	"""Validate that CWIP account are not used in Journal Entry"""
+	if gl_map and gl_map[0].voucher_type != "Journal Entry":
+		return
 
-	if cwip_enabled and gl_map[0].voucher_type == "Journal Entry":
-			cwip_accounts = [d[0] for d in frappe.db.sql("""select name from tabAccount
-				where account_type = 'Capital Work in Progress' and is_group=0""")]
+	cwip_enabled = any(cint(ac.enable_cwip_accounting) for ac in frappe.db.get_all("Asset Category", "enable_cwip_accounting"))
+	if cwip_enabled:
+		cwip_accounts = [d[0] for d in frappe.db.sql("""select name from tabAccount
+			where account_type = 'Capital Work in Progress' and is_group=0""")]
 
-			for entry in gl_map:
-				if entry.account in cwip_accounts:
-					frappe.throw(
-						_("Account: <b>{0}</b> is capital Work in progress and can not be updated by Journal Entry").format(entry.account))
+		for entry in gl_map:
+			if entry.account in cwip_accounts:
+				frappe.throw(
+					_("Account: <b>{0}</b> is capital Work in progress and can not be updated by Journal Entry").format(entry.account))
 
 def round_off_debit_credit(gl_map):
 	precision = get_field_precision(frappe.get_meta("GL Entry").get_field("debit"),
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index 73e2c2e..8da2d75 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -927,7 +927,6 @@
 			_delete_gl_entries(voucher_type, voucher_no)
 
 def get_future_stock_vouchers(posting_date, posting_time, for_warehouses=None, for_items=None, company=None):
-	future_stock_vouchers = []
 
 	values = []
 	condition = ""
@@ -943,30 +942,46 @@
 		condition += " and company = %s"
 		values.append(company)
 
-	for d in frappe.db.sql("""select distinct sle.voucher_type, sle.voucher_no
+	future_stock_vouchers = frappe.db.sql("""select distinct sle.voucher_type, sle.voucher_no
 		from `tabStock Ledger Entry` sle
 		where
 			timestamp(sle.posting_date, sle.posting_time) >= timestamp(%s, %s)
 			and is_cancelled = 0
 			{condition}
 		order by timestamp(sle.posting_date, sle.posting_time) asc, creation asc for update""".format(condition=condition),
-		tuple([posting_date, posting_time] + values), as_dict=True):
-			future_stock_vouchers.append([d.voucher_type, d.voucher_no])
+		tuple([posting_date, posting_time] + values), as_dict=True)
 
-	return future_stock_vouchers
+	return [(d.voucher_type, d.voucher_no) for d in future_stock_vouchers]
 
 def get_voucherwise_gl_entries(future_stock_vouchers, posting_date):
+	""" Get voucherwise list of GL entries.
+
+	Only fetches GLE fields required for comparing with new GLE.
+	Check compare_existing_and_expected_gle function below.
+	"""
 	gl_entries = {}
-	if future_stock_vouchers:
-		for d in frappe.db.sql("""select * from `tabGL Entry`
-			where posting_date >= %s and voucher_no in (%s)""" %
-			('%s', ', '.join(['%s']*len(future_stock_vouchers))),
-			tuple([posting_date] + [d[1] for d in future_stock_vouchers]), as_dict=1):
-				gl_entries.setdefault((d.voucher_type, d.voucher_no), []).append(d)
+	if not future_stock_vouchers:
+		return gl_entries
+
+	voucher_nos = [d[1] for d in future_stock_vouchers]
+
+	gles = frappe.db.sql("""
+		select name, account, credit, debit, cost_center, project
+			from `tabGL Entry`
+		where
+			posting_date >= %s and voucher_no in (%s)""" %
+		('%s', ', '.join(['%s'] * len(voucher_nos))),
+		tuple([posting_date] + voucher_nos), as_dict=1)
+
+	for d in gles:
+		gl_entries.setdefault((d.voucher_type, d.voucher_no), []).append(d)
 
 	return gl_entries
 
 def compare_existing_and_expected_gle(existing_gle, expected_gle, precision):
+	if len(existing_gle) != len(expected_gle):
+		return False
+
 	matched = True
 	for entry in expected_gle:
 		account_existed = False
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index 59fbe3b..e23a715 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -639,7 +639,7 @@
 		asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
 		asset = frappe.get_doc('Asset', asset_name)
 		asset.calculate_depreciation = 1
-		asset.available_for_use_date = '2030-06-12'
+		asset.available_for_use_date = '2030-07-12'
 		asset.purchase_date = '2030-01-01'
 		asset.append("finance_books", {
 			"expected_value_after_useful_life": 1000,
@@ -653,10 +653,10 @@
 		self.assertEqual(asset.finance_books[0].rate_of_depreciation, 50.0)
 
 		expected_schedules = [
-			["2030-12-31", 1106.85, 1106.85],
-			["2031-12-31", 3446.58, 4553.43],
-			["2032-12-31", 1723.29, 6276.72],
-			["2033-06-12", 723.28, 7000.00]
+			["2030-12-31", 942.47, 942.47],
+			["2031-12-31", 3528.77, 4471.24],
+			["2032-12-31", 1764.38, 6235.62],
+			["2033-07-12", 764.38, 7000.00]
 		]
 
 		schedules = [[cstr(d.schedule_date), flt(d.depreciation_amount, 2), flt(d.accumulated_depreciation_amount, 2)]
diff --git a/erpnext/assets/doctype/asset_movement/test_asset_movement.py b/erpnext/assets/doctype/asset_movement/test_asset_movement.py
index cddee5f..2b2d2b4 100644
--- a/erpnext/assets/doctype/asset_movement/test_asset_movement.py
+++ b/erpnext/assets/doctype/asset_movement/test_asset_movement.py
@@ -15,6 +15,7 @@
 
 class TestAssetMovement(unittest.TestCase):
 	def setUp(self):
+		frappe.db.set_value("Company", "_Test Company", "capital_work_in_progress_account", "CWIP Account - _TC")
 		create_asset_data()
 		make_location()
 
@@ -45,12 +46,12 @@
 				'location_name': 'Test Location 2'
 			}).insert()
 
-		movement1 = create_asset_movement(purpose = 'Transfer', company = asset.company, 
+		movement1 = create_asset_movement(purpose = 'Transfer', company = asset.company,
 			assets = [{ 'asset': asset.name , 'source_location': 'Test Location', 'target_location': 'Test Location 2'}],
 			reference_doctype = 'Purchase Receipt', reference_name = pr.name)
 		self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location 2")
 
-		movement2 = create_asset_movement(purpose = 'Transfer', company = asset.company, 
+		create_asset_movement(purpose = 'Transfer', company = asset.company,
 			assets = [{ 'asset': asset.name , 'source_location': 'Test Location 2', 'target_location': 'Test Location'}],
 			reference_doctype = 'Purchase Receipt', reference_name = pr.name)
 		self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location")
@@ -59,18 +60,18 @@
 		self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location")
 
 		employee = make_employee("testassetmovemp@example.com", company="_Test Company")
-		movement3 = create_asset_movement(purpose = 'Issue', company = asset.company, 
+		create_asset_movement(purpose = 'Issue', company = asset.company,
 			assets = [{ 'asset': asset.name , 'source_location': 'Test Location', 'to_employee': employee}],
 			reference_doctype = 'Purchase Receipt', reference_name = pr.name)
-		
+
 		# after issuing asset should belong to an employee not at a location
 		self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), None)
 		self.assertEqual(frappe.db.get_value("Asset", asset.name, "custodian"), employee)
-	
+
 	def test_last_movement_cancellation(self):
 		pr = make_purchase_receipt(item_code="Macbook Pro",
 			qty=1, rate=100000.0, location="Test Location")
-		
+
 		asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, 'name')
 		asset = frappe.get_doc('Asset', asset_name)
 		asset.calculate_depreciation = 1
@@ -85,17 +86,17 @@
 		})
 		if asset.docstatus == 0:
 			asset.submit()
-		
+
 		if not frappe.db.exists("Location", "Test Location 2"):
 			frappe.get_doc({
 				'doctype': 'Location',
 				'location_name': 'Test Location 2'
 			}).insert()
-		
+
 		movement = frappe.get_doc({'doctype': 'Asset Movement', 'reference_name': pr.name })
 		self.assertRaises(frappe.ValidationError, movement.cancel)
 
-		movement1 = create_asset_movement(purpose = 'Transfer', company = asset.company, 
+		movement1 = create_asset_movement(purpose = 'Transfer', company = asset.company,
 			assets = [{ 'asset': asset.name , 'source_location': 'Test Location', 'target_location': 'Test Location 2'}],
 			reference_doctype = 'Purchase Receipt', reference_name = pr.name)
 		self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location 2")
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index bf4ab1a..bc8e4ce 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -1288,6 +1288,27 @@
 		tax.rate = None
 
 
+def validate_account_head(tax, doc):
+	company = frappe.get_cached_value('Account',
+		tax.account_head, 'company')
+
+	if company != doc.company:
+		frappe.throw(_('Row {0}: Account {1} does not belong to Company {2}')
+			.format(tax.idx, frappe.bold(tax.account_head), frappe.bold(doc.company)), title=_('Invalid Account'))
+
+
+def validate_cost_center(tax, doc):
+	if not tax.cost_center:
+		return
+
+	company = frappe.get_cached_value('Cost Center',
+		tax.cost_center, 'company')
+
+	if company != doc.company:
+		frappe.throw(_('Row {0}: Cost Center {1} does not belong to Company {2}')
+			.format(tax.idx, frappe.bold(tax.cost_center), frappe.bold(doc.company)), title=_('Invalid Cost Center'))
+
+
 def validate_inclusive_tax(tax, doc):
 	def _on_previous_row_error(row_range):
 		throw(_("To include tax in row {0} in Item rate, taxes in rows {1} must also be included").format(tax.idx, row_range))
@@ -1507,7 +1528,7 @@
 	if child_item.get("item_tax_template"):
 		child_item.item_tax_rate = get_item_tax_map(parent_doc.get('company'), child_item.item_tax_template, as_json=True)
 
-def add_taxes_from_tax_template(child_item, parent_doc):
+def add_taxes_from_tax_template(child_item, parent_doc, db_insert=True):
 	add_taxes_from_item_tax_template = frappe.db.get_single_value("Accounts Settings", "add_taxes_from_item_tax_template")
 
 	if child_item.get("item_tax_rate") and add_taxes_from_item_tax_template:
@@ -1530,7 +1551,8 @@
 						"category" : "Total",
 						"add_deduct_tax" : "Add"
 					})
-				tax_row.db_insert()
+				if db_insert:
+					tax_row.db_insert()
 
 def set_order_defaults(parent_doctype, parent_doctype_name, child_doctype, child_docname, trans_item):
 	"""
diff --git a/erpnext/controllers/stock_controller.py b/erpnext/controllers/stock_controller.py
index 17bd735..17707ec 100644
--- a/erpnext/controllers/stock_controller.py
+++ b/erpnext/controllers/stock_controller.py
@@ -27,6 +27,7 @@
 		if not self.get('is_return'):
 			self.validate_inspection()
 		self.validate_serialized_batch()
+		self.clean_serial_nos()
 		self.validate_customer_provided_item()
 		self.set_rate_of_stock_uom()
 		self.validate_internal_transfer()
@@ -72,6 +73,12 @@
 					frappe.throw(_("Row #{0}: The batch {1} has already expired.")
 						.format(d.idx, get_link_to_form("Batch", d.get("batch_no"))))
 
+	def clean_serial_nos(self):
+		for row in self.get("items"):
+			if hasattr(row, "serial_no") and row.serial_no:
+				# replace commas by linefeed and remove all spaces in string
+				row.serial_no = row.serial_no.replace(",", "\n").replace(" ", "")
+
 	def get_gl_entries(self, warehouse_account=None, default_expense_account=None,
 			default_cost_center=None):
 
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index 099c7d4..05edb25 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -679,17 +679,13 @@
 		default_mode_of_payment = frappe.db.get_value('POS Payment Method',
 			{'parent': self.doc.pos_profile, 'default': 1}, ['mode_of_payment'], as_dict=1)
 
-		self.doc.payments = []
-
 		if default_mode_of_payment:
+			self.doc.payments = []
 			self.doc.append('payments', {
 				'mode_of_payment': default_mode_of_payment.mode_of_payment,
 				'amount': total_amount_to_pay,
 				'default': 1
 			})
-		else:
-			self.doc.is_pos = 0
-			self.doc.pos_profile = ''
 
 		self.calculate_paid_amount()
 
diff --git a/erpnext/crm/doctype/appointment/test_appointment.py b/erpnext/crm/doctype/appointment/test_appointment.py
index 50c98c5..c7563e9 100644
--- a/erpnext/crm/doctype/appointment/test_appointment.py
+++ b/erpnext/crm/doctype/appointment/test_appointment.py
@@ -9,7 +9,7 @@
 
 
 def create_test_lead():
-    test_lead = frappe.db.exists({'doctype': 'Lead', 'lead_name': 'Test Lead'})
+    test_lead = frappe.db.exists({'doctype': 'Lead', 'email_id':'test@example.com'})
     if test_lead:
         return frappe.get_doc('Lead', test_lead[0][0])
     test_lead = frappe.get_doc({
diff --git a/erpnext/crm/doctype/lead/lead.js b/erpnext/crm/doctype/lead/lead.js
index ebe8524..75af937 100644
--- a/erpnext/crm/doctype/lead/lead.js
+++ b/erpnext/crm/doctype/lead/lead.js
@@ -12,7 +12,8 @@
 			'Opportunity': this.make_opportunity
 		};
 
-		this.frm.toggle_reqd("lead_name", !this.frm.doc.organization_lead);
+		// For avoiding integration issues.
+		this.frm.set_df_property('first_name', 'reqd', true);
 	}
 
 	onload () {
@@ -42,6 +43,7 @@
 
 		if (!this.frm.is_new()) {
 			frappe.contacts.render_address_and_contact(this.frm);
+			cur_frm.trigger('render_contact_day_html');
 		} else {
 			frappe.contacts.clear_address_and_contact(this.frm);
 		}
@@ -68,13 +70,8 @@
 		})
 	}
 
-	organization_lead () {
-		this.frm.toggle_reqd("lead_name", !this.frm.doc.organization_lead);
-		this.frm.toggle_reqd("company_name", this.frm.doc.organization_lead);
-	}
-
 	company_name () {
-		if (this.frm.doc.organization_lead && !this.frm.doc.lead_name) {
+		if (!this.frm.doc.lead_name) {
 			this.frm.set_value("lead_name", this.frm.doc.company_name);
 		}
 	}
@@ -86,6 +83,19 @@
 			this.frm.set_value("ends_on", d.format(frappe.defaultDatetimeFormat));
 		}
 	}
+
+	render_contact_day_html() {
+		if (cur_frm.doc.contact_date) {
+			let contact_date = frappe.datetime.obj_to_str(cur_frm.doc.contact_date);
+			let diff_days = frappe.datetime.get_day_diff(contact_date, frappe.datetime.get_today());
+			let color = diff_days > 0 ? "orange" : "green";
+			let message = diff_days > 0 ? __("Next Contact Date") : __("Last Contact Date");
+			let html = `<div class="col-xs-12">
+						<span class="indicator whitespace-nowrap ${color}"><span> ${message} : ${frappe.datetime.global_date_format(contact_date)}</span></span>
+					</div>` ;
+			cur_frm.dashboard.set_headline_alert(html);
+		}
+	}
 };
 
 extend_cscript(cur_frm.cscript, new erpnext.LeadController({ frm: cur_frm }));
diff --git a/erpnext/crm/doctype/lead/lead.json b/erpnext/crm/doctype/lead/lead.json
index 1b33fd7..542977e 100644
--- a/erpnext/crm/doctype/lead/lead.json
+++ b/erpnext/crm/doctype/lead/lead.json
@@ -9,71 +9,70 @@
  "email_append_to": 1,
  "engine": "InnoDB",
  "field_order": [
-  "organization_lead",
   "lead_details",
   "naming_series",
-  "lead_name",
-  "company_name",
-  "email_id",
-  "col_break123",
-  "lead_owner",
-  "status",
   "salutation",
+  "first_name",
+  "middle_name",
+  "last_name",
+  "lead_name",
+  "col_break123",
+  "status",
+  "company_name",
   "designation",
   "gender",
-  "source",
-  "customer",
-  "campaign_name",
-  "image",
-  "section_break_12",
-  "contact_by",
-  "column_break_14",
-  "contact_date",
-  "ends_on",
-  "notes_section",
-  "notes",
-  "address_info",
+  "contact_details_section",
+  "email_id",
+  "mobile_no",
+  "whatsapp_no",
+  "column_break_16",
+  "phone",
+  "phone_ext",
+  "additional_information_section",
+  "no_of_employees",
+  "industry",
+  "market_segment",
+  "column_break_22",
+  "fax",
+  "website",
+  "type",
+  "request_type",
+  "address_section",
   "address_html",
-  "address_type",
-  "address_title",
-  "address_line1",
-  "address_line2",
   "city",
+  "pincode",
   "county",
   "column_break2",
   "contact_html",
   "state",
   "country",
-  "pincode",
-  "contact_section",
-  "phone",
-  "mobile_no",
-  "fax",
-  "website",
-  "more_info",
-  "type",
-  "market_segment",
-  "industry",
-  "request_type",
-  "column_break3",
+  "section_break_12",
+  "lead_owner",
+  "ends_on",
+  "column_break_14",
+  "contact_by",
+  "contact_date",
+  "lead_source_details_section",
   "company",
   "territory",
   "language",
+  "column_break_50",
+  "source",
+  "campaign_name",
   "unsubscribed",
   "blog_subscriber",
+  "notes_section",
+  "notes",
+  "other_information_section",
+  "customer",
+  "image",
   "title"
  ],
  "fields": [
   {
-   "default": "0",
-   "fieldname": "organization_lead",
-   "fieldtype": "Check",
-   "label": "Lead is an Organization",
-   "set_only_once": 1
-  },
-  {
    "fieldname": "lead_details",
    "fieldtype": "Section Break",
+   "label": "Lead Details",
    "options": "fa fa-user"
   },
   {
@@ -90,16 +89,19 @@
    "fieldname": "lead_name",
    "fieldtype": "Data",
    "in_global_search": 1,
-   "label": "Person Name",
+   "label": "Full Name",
    "oldfieldname": "lead_name",
    "oldfieldtype": "Data",
+   "read_only": 1,
    "search_index": 1
   },
   {
    "fieldname": "company_name",
    "fieldtype": "Data",
    "in_list_view": 1,
+   "in_standard_filter": 1,
    "label": "Organization Name",
+   "mandatory_depends_on": "eval: !(doc.first_name)",
    "oldfieldname": "company_name",
    "oldfieldtype": "Data"
   },
@@ -121,7 +123,6 @@
    "default": "__user",
    "fieldname": "lead_owner",
    "fieldtype": "Link",
-   "in_list_view": 1,
    "label": "Lead Owner",
    "oldfieldname": "lead_owner",
    "oldfieldtype": "Link",
@@ -143,7 +144,6 @@
    "search_index": 1
   },
   {
-   "depends_on": "eval: doc.__islocal",
    "fieldname": "salutation",
    "fieldtype": "Link",
    "label": "Salutation",
@@ -241,46 +241,22 @@
    "read_only": 1
   },
   {
-   "depends_on": "eval: doc.__islocal",
-   "description": "Home, Work, etc.",
-   "fieldname": "address_title",
-   "fieldtype": "Data",
-   "label": "Address Title"
-  },
-  {
-   "depends_on": "eval: doc.__islocal",
-   "fieldname": "address_line1",
-   "fieldtype": "Data",
-   "label": "Address Line 1",
-   "mandatory_depends_on": "eval: doc.address_title && doc.address_type"
-  },
-  {
-   "depends_on": "eval: doc.__islocal",
-   "fieldname": "address_line2",
-   "fieldtype": "Data",
-   "label": "Address Line 2"
-  },
-  {
-   "depends_on": "eval: doc.__islocal",
    "fieldname": "city",
    "fieldtype": "Data",
    "label": "City/Town",
    "mandatory_depends_on": "eval: doc.address_title && doc.address_type"
   },
   {
-   "depends_on": "eval: doc.__islocal",
    "fieldname": "county",
    "fieldtype": "Data",
    "label": "County"
   },
   {
-   "depends_on": "eval: doc.__islocal",
    "fieldname": "state",
    "fieldtype": "Data",
    "label": "State"
   },
   {
-   "depends_on": "eval: doc.__islocal",
    "fieldname": "country",
    "fieldtype": "Link",
    "label": "Country",
@@ -288,7 +264,6 @@
    "options": "Country"
   },
   {
-   "depends_on": "eval: doc.__islocal",
    "fieldname": "pincode",
    "fieldtype": "Data",
    "label": "Postal Code"
@@ -304,7 +279,6 @@
    "read_only": 1
   },
   {
-   "depends_on": "eval: doc.__islocal",
    "fieldname": "phone",
    "fieldtype": "Data",
    "label": "Phone",
@@ -313,7 +287,6 @@
    "options": "Phone"
   },
   {
-   "depends_on": "eval: doc.__islocal",
    "fieldname": "mobile_no",
    "fieldtype": "Data",
    "label": "Mobile No.",
@@ -322,7 +295,6 @@
    "options": "Phone"
   },
   {
-   "depends_on": "eval: doc.__islocal",
    "fieldname": "fax",
    "fieldtype": "Data",
    "label": "Fax",
@@ -330,14 +302,6 @@
    "oldfieldtype": "Data"
   },
   {
-   "collapsible": 1,
-   "fieldname": "more_info",
-   "fieldtype": "Section Break",
-   "label": "More Information",
-   "oldfieldtype": "Section Break",
-   "options": "fa fa-file-text"
-  },
-  {
    "fieldname": "type",
    "fieldtype": "Select",
    "label": "Lead Type",
@@ -370,12 +334,6 @@
    "options": "\nProduct Enquiry\nRequest for Information\nSuggestions\nOther"
   },
   {
-   "fieldname": "column_break3",
-   "fieldtype": "Column Break",
-   "oldfieldtype": "Column Break",
-   "width": "50%"
-  },
-  {
    "fieldname": "company",
    "fieldtype": "Link",
    "label": "Company",
@@ -389,11 +347,14 @@
    "fieldtype": "Data",
    "label": "Website",
    "oldfieldname": "website",
-   "oldfieldtype": "Data"
+   "oldfieldtype": "Data",
+   "options": "URL"
   },
   {
    "fieldname": "territory",
    "fieldtype": "Link",
+   "in_list_view": 1,
+   "in_standard_filter": 1,
    "label": "Territory",
    "oldfieldname": "territory",
    "oldfieldtype": "Link",
@@ -422,45 +383,95 @@
   {
    "fieldname": "designation",
    "fieldtype": "Link",
+   "in_list_view": 1,
+   "in_standard_filter": 1,
    "label": "Designation",
    "options": "Designation"
   },
   {
-   "collapsible": 1,
-   "collapsible_depends_on": "eval: doc.__islocal",
-   "fieldname": "address_info",
-   "fieldtype": "Section Break",
-   "label": "Address & Contact",
-   "oldfieldtype": "Column Break",
-   "options": "fa fa-map-marker"
-  },
-  {
-   "collapsible": 1,
-   "collapsible_depends_on": "eval: doc.__islocal",
-   "fieldname": "contact_section",
-   "fieldtype": "Section Break",
-   "label": "Contact"
-  },
-  {
-   "default": "Billing",
-   "depends_on": "eval: doc.__islocal",
-   "fieldname": "address_type",
-   "fieldtype": "Select",
-   "label": "Address Type",
-   "options": "Billing\nShipping\nOffice\nPersonal\nPlant\nPostal\nShop\nSubsidiary\nWarehouse\nCurrent\nPermanent\nOther"
-  },
-  {
    "fieldname": "language",
    "fieldtype": "Link",
    "label": "Print Language",
    "options": "Language"
+  },
+  {
+   "fieldname": "first_name",
+   "fieldtype": "Data",
+   "label": "First Name",
+   "mandatory_depends_on": "eval: !(doc.company_name)"
+  },
+  {
+   "fieldname": "middle_name",
+   "fieldtype": "Data",
+   "label": "Middle Name"
+  },
+  {
+   "fieldname": "last_name",
+   "fieldtype": "Data",
+   "label": "Last Name"
+  },
+  {
+   "collapsible": 1,
+   "fieldname": "additional_information_section",
+   "fieldtype": "Section Break",
+   "label": "Additional Information"
+  },
+  {
+   "fieldname": "no_of_employees",
+   "fieldtype": "Int",
+   "label": "No. of Employees"
+  },
+  {
+   "fieldname": "column_break_22",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "whatsapp_no",
+   "fieldtype": "Data",
+   "label": "WhatsApp No.",
+   "options": "Phone"
+  },
+  {
+   "collapsible": 1,
+   "depends_on": "eval: !doc.__islocal",
+   "fieldname": "address_section",
+   "fieldtype": "Section Break",
+   "label": "Address"
+  },
+  {
+   "fieldname": "lead_source_details_section",
+   "fieldtype": "Section Break",
+   "label": "Lead Source Details"
+  },
+  {
+   "fieldname": "column_break_50",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "other_information_section",
+   "fieldtype": "Section Break",
+   "label": "Other Information"
+  },
+  {
+   "fieldname": "contact_details_section",
+   "fieldtype": "Section Break",
+   "label": "Contact Details"
+  },
+  {
+   "fieldname": "column_break_16",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "phone_ext",
+   "fieldtype": "Data",
+   "label": "Phone Ext."
   }
  ],
  "icon": "fa fa-user",
  "idx": 5,
  "image_field": "image",
  "links": [],
- "modified": "2021-01-06 19:39:58.748978",
+ "modified": "2021-08-04 00:24:57.208590",
  "modified_by": "Administrator",
  "module": "CRM",
  "name": "Lead",
diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py
index ce3de40..7f028cb 100644
--- a/erpnext/crm/doctype/lead/lead.py
+++ b/erpnext/crm/doctype/lead/lead.py
@@ -21,26 +21,24 @@
 		self.get("__onload").is_customer = customer
 		load_address_and_contact(self)
 
-	def before_insert(self):
-		if self.address_title and self.address_type:
-			self.address_doc = self.create_address()
-		self.contact_doc = self.create_contact()
-
-	def after_insert(self):
-		self.update_links()
-
 	def validate(self):
+		self.set_full_name()
 		self.set_lead_name()
 		self.set_title()
+		self.set_status()
+		self.check_email_id_is_unique()
+		self.validate_email_id()
+		self.validate_contact_date()
 		self._prev = frappe._dict({
 			"contact_date": frappe.db.get_value("Lead", self.name, "contact_date") if (not cint(self.is_new())) else None,
 			"ends_on": frappe.db.get_value("Lead", self.name, "ends_on") if (not cint(self.is_new())) else None,
 			"contact_by": frappe.db.get_value("Lead", self.name, "contact_by") if (not cint(self.is_new())) else None,
 		})
+		
+	def set_full_name(self):
+		self.lead_name = " ".join(filter(None, [self.first_name, self.middle_name, self.last_name]))
 
-		self.set_status()
-		self.check_email_id_is_unique()
-
+	def validate_email_id(self):
 		if self.email_id:
 			if not self.flags.ignore_email_validation:
 				validate_email_address(self.email_id, throw=True)
@@ -54,6 +52,7 @@
 			if self.is_new() or not self.image:
 				self.image = has_gravatar(self.email_id)
 
+	def validate_contact_date(self):
 		if self.contact_date and getdate(self.contact_date) < getdate(nowdate()):
 			frappe.throw(_("Next Contact Date cannot be in the past"))
 
@@ -64,6 +63,22 @@
 	def on_update(self):
 		self.add_calendar_event()
 
+	def before_insert(self):
+		self.contact_doc = self.create_contact()
+
+	def after_insert(self):
+		self.update_links()
+
+	def update_links(self):
+		# update contact links
+		if self.contact_doc:
+			self.contact_doc.append("links", {
+				"link_doctype": "Lead",
+				"link_name": self.name,
+				"link_title": self.lead_name
+			})
+			self.contact_doc.save()
+
 	def add_calendar_event(self, opts=None, force=False):
 		super(Lead, self).add_calendar_event({
 			"owner": self.lead_owner,
@@ -86,8 +101,26 @@
 	def on_trash(self):
 		frappe.db.sql("""update `tabIssue` set lead='' where lead=%s""", self.name)
 
+		self.unlink_dynamic_links()
 		self.delete_events()
 
+	def unlink_dynamic_links(self):
+		links = frappe.get_all('Dynamic Link', filters={'link_doctype': self.doctype, 'link_name': self.name}, fields=['parent', 'parenttype'])
+
+		for link in links:
+			linked_doc = frappe.get_doc(link['parenttype'], link['parent'])
+
+			if len(linked_doc.get('links')) == 1:
+				linked_doc.delete(ignore_permissions=True)
+			else:
+				to_remove = None
+				for d in linked_doc.get('links'):
+					if d.link_doctype == self.doctype and d.link_name == self.name:
+						to_remove = d
+				if to_remove:
+					linked_doc.remove(to_remove)
+					linked_doc.save(ignore_permissions=True)
+
 	def has_customer(self):
 		return frappe.db.get_value("Customer", {"lead_name": self.name})
 
@@ -99,7 +132,6 @@
 			"party_name": self.name,
 			"docstatus": 1,
 			"status": ["!=", "Lost"]
-
 		})
 
 	def has_lost_quotation(self):
@@ -120,40 +152,17 @@
 				self.lead_name = self.email_id.split("@")[0]
 
 	def set_title(self):
-		if self.organization_lead:
-			self.title = self.company_name
-		else:
-			self.title = self.lead_name
-
-	def create_address(self):
-		address_fields = ["address_type", "address_title", "address_line1", "address_line2",
-			"city", "county", "state", "country", "pincode"]
-		info_fields = ["email_id", "phone", "fax"]
-
-		# do not create an address if no fields are available,
-		# skipping country since the system auto-sets it from system defaults
-		address = frappe.new_doc("Address")
-
-		address.update({addr_field: self.get(addr_field) for addr_field in address_fields})
-		address.update({info_field: self.get(info_field) for info_field in info_fields})
-		address.insert()
-
-		return address
+		self.title = self.company_name or self.lead_name
 
 	def create_contact(self):
 		if not self.lead_name:
+			self.set_full_name()
 			self.set_lead_name()
 
-		names = self.lead_name.strip().split(" ")
-		if len(names) > 1:
-			first_name, last_name = names[0], " ".join(names[1:])
-		else:
-			first_name, last_name = self.lead_name, None
-
 		contact = frappe.new_doc("Contact")
 		contact.update({
-			"first_name": first_name,
-			"last_name": last_name,
+			"first_name": self.first_name or self.lead_name,
+			"last_name": self.last_name,
 			"salutation": self.salutation,
 			"gender": self.gender,
 			"designation": self.designation,
@@ -181,25 +190,6 @@
 
 		return contact
 
-	def update_links(self):
-		# update address links
-		if hasattr(self, 'address_doc'):
-			self.address_doc.append("links", {
-				"link_doctype": "Lead",
-				"link_name": self.name,
-				"link_title": self.lead_name
-			})
-			self.address_doc.save()
-
-		# update contact links
-		if self.contact_doc:
-			self.contact_doc.append("links", {
-				"link_doctype": "Lead",
-				"link_name": self.name,
-				"link_title": self.lead_name
-			})
-			self.contact_doc.save()
-
 @frappe.whitelist()
 def make_customer(source_name, target_doc=None):
 	return _make_customer(source_name, target_doc)
diff --git a/erpnext/crm/doctype/lead/test_lead.py b/erpnext/crm/doctype/lead/test_lead.py
index d428a45..d4886d3 100644
--- a/erpnext/crm/doctype/lead/test_lead.py
+++ b/erpnext/crm/doctype/lead/test_lead.py
@@ -4,6 +4,7 @@
 from __future__ import unicode_literals
 
 import frappe
+from frappe.utils import random_string
 import unittest
 
 test_records = frappe.get_test_records('Lead')
@@ -32,3 +33,53 @@
 		customer.company = "_Test Company"
 		customer.customer_group = "_Test Customer Group"
 		customer.insert()
+
+	def test_create_lead_and_unlinking_dynamic_links(self):
+		lead_doc = make_lead(first_name = "Lorem", last_name="Ipsum", email_id="lorem_ipsum@example.com")
+		lead_doc_1 = make_lead()
+		frappe.get_doc({
+			"doctype": "Address",
+			"address_type": "Billing",
+			"city": "Mumbai",
+			"address_line1": "Vidya Vihar West",
+			"country": "India",
+			"links": [{
+				"link_doctype": "Lead",
+				"link_name": lead_doc.name
+			}]
+		}).insert()
+
+		address_1 = frappe.get_doc({
+			"doctype": "Address",
+			"address_type": "Billing",
+			"address_line1": "Baner",
+			"city": "Pune",
+			"country": "India",
+			"links": [
+				{
+					"link_doctype": "Lead",
+					"link_name": lead_doc.name
+				},
+				{
+					"link_doctype": "Lead",
+					"link_name": lead_doc_1.name
+				}
+			]
+		}).insert()
+
+		lead_doc.delete()
+		address_1.reload()
+		self.assertEqual(frappe.db.exists("Lead",lead_doc.name), None)
+		self.assertEqual(len(address_1.get('links')), 1)
+
+def make_lead(**args):
+	args = frappe._dict(args)
+
+	lead_doc = frappe.get_doc({
+		"doctype": "Lead",
+		"first_name": args.first_name or "_Test",
+		"last_name": args.last_name or "Lead",
+		"email_id": args.email_id or "new_lead_{}@example.com".format(random_string(5)),
+	}).insert()
+
+	return lead_doc
\ No newline at end of file
diff --git a/erpnext/crm/doctype/lead/test_records.json b/erpnext/crm/doctype/lead/test_records.json
index 39864e2..3158add 100644
--- a/erpnext/crm/doctype/lead/test_records.json
+++ b/erpnext/crm/doctype/lead/test_records.json
@@ -27,7 +27,6 @@
 {
  "doctype": "Lead",
  "email_id": "test_lead4@example.com",
- "organization_lead": 1,
  "lead_name": "_Test Lead 4",
  "company_name": "_Test Lead 4",
  "status": "Open"
diff --git a/erpnext/crm/doctype/lead/tests/test_lead_organization.js b/erpnext/crm/doctype/lead/tests/test_lead_organization.js
index 4395935..7fb9573 100644
--- a/erpnext/crm/doctype/lead/tests/test_lead_organization.js
+++ b/erpnext/crm/doctype/lead/tests/test_lead_organization.js
@@ -9,7 +9,6 @@
 		() => frappe.set_route("List", "Lead"),
 		() => frappe.new_doc("Lead"),
 		() => frappe.timeout(1),
-		() => cur_frm.set_value("organization_lead", "1"),
 		() => cur_frm.set_value("company_name", lead_name),
 		() => cur_frm.save(),
 		() => frappe.timeout(1),
diff --git a/erpnext/crm/doctype/opportunity/opportunity.js b/erpnext/crm/doctype/opportunity/opportunity.js
index 43e1b99..e9a7a95 100644
--- a/erpnext/crm/doctype/opportunity/opportunity.js
+++ b/erpnext/crm/doctype/opportunity/opportunity.js
@@ -53,6 +53,13 @@
 		frm.get_field("items").grid.set_multiple_add("item_code", "qty");
 	},
 
+	status:function(frm){
+		if (frm.doc.status == "Lost"){
+			frm.trigger('set_as_lost_dialog');
+		}
+	
+	},
+
 	customer_address: function(frm, cdt, cdn) {
 		erpnext.utils.get_address_display(frm, 'customer_address', 'address_display', false);
 	},
@@ -91,11 +98,6 @@
 			frm.add_custom_button(__('Quotation'),
 				cur_frm.cscript.create_quotation, __('Create'));
 
-			if(doc.status!=="Quotation") {
-				frm.add_custom_button(__('Lost'), () => {
-					frm.trigger('set_as_lost_dialog');
-				});
-			}
 		}
 
 		if(!frm.doc.__islocal && frm.perm[0].write && frm.doc.docstatus==0) {
diff --git a/erpnext/hr/doctype/attendance_request/test_attendance_request.py b/erpnext/hr/doctype/attendance_request/test_attendance_request.py
index 3c42bd9..9e668aa 100644
--- a/erpnext/hr/doctype/attendance_request/test_attendance_request.py
+++ b/erpnext/hr/doctype/attendance_request/test_attendance_request.py
@@ -15,7 +15,11 @@
 		for doctype in ["Attendance Request", "Attendance"]:
 			frappe.db.sql("delete from `tab{doctype}`".format(doctype=doctype))
 
+	def tearDown(self):
+		frappe.db.rollback()
+
 	def test_on_duty_attendance_request(self):
+		"Test creation/updation of Attendace from Attendance Request, on duty."
 		today = nowdate()
 		employee = get_employee()
 		attendance_request = frappe.new_doc("Attendance Request")
@@ -26,17 +30,36 @@
 		attendance_request.company = "_Test Company"
 		attendance_request.insert()
 		attendance_request.submit()
-		attendance = frappe.get_doc('Attendance', {
-			'employee': employee.name,
-			'attendance_date': date(date.today().year, 1, 1),
-			'docstatus': 1
-		})
-		self.assertEqual(attendance.status, 'Present')
+
+		attendance = frappe.db.get_value(
+			"Attendance",
+			filters={
+				"attendance_request": attendance_request.name,
+				"attendance_date": date(date.today().year, 1, 1)
+			},
+			fieldname=["status", "docstatus"],
+			as_dict=True
+		)
+		self.assertEqual(attendance.status, "Present")
+		self.assertEqual(attendance.docstatus, 1)
+
+		# cancelling attendance request cancels linked attendances
 		attendance_request.cancel()
-		attendance.reload()
-		self.assertEqual(attendance.docstatus, 2)
+
+		# cancellation alters docname
+		# fetch attendance value again to avoid stale docname
+		attendance_docstatus = frappe.db.get_value(
+			"Attendance",
+			filters={
+				"attendance_request": attendance_request.name,
+				"attendance_date": date(date.today().year, 1, 1)
+			},
+			fieldname="docstatus"
+		)
+		self.assertEqual(attendance_docstatus, 2)
 
 	def test_work_from_home_attendance_request(self):
+		"Test creation/updation of Attendace from Attendance Request, work from home."
 		today = nowdate()
 		employee = get_employee()
 		attendance_request = frappe.new_doc("Attendance Request")
@@ -47,15 +70,30 @@
 		attendance_request.company = "_Test Company"
 		attendance_request.insert()
 		attendance_request.submit()
-		attendance = frappe.get_doc('Attendance', {
-			'employee': employee.name,
-			'attendance_date': date(date.today().year, 1, 1),
-			'docstatus': 1
-		})
-		self.assertEqual(attendance.status, 'Work From Home')
+
+		attendance_status = frappe.db.get_value(
+			"Attendance",
+			filters={
+				"attendance_request": attendance_request.name,
+				"attendance_date": date(date.today().year, 1, 1)
+			},
+			fieldname="status"
+		)
+		self.assertEqual(attendance_status, 'Work From Home')
+
 		attendance_request.cancel()
-		attendance.reload()
-		self.assertEqual(attendance.docstatus, 2)
+
+		# cancellation alters docname
+		# fetch attendance value again to avoid stale docname
+		attendance_docstatus = frappe.db.get_value(
+			"Attendance",
+			filters={
+				"attendance_request": attendance_request.name,
+				"attendance_date": date(date.today().year, 1, 1)
+			},
+			fieldname="docstatus"
+		)
+		self.assertEqual(attendance_docstatus, 2)
 
 def get_employee():
 	return frappe.get_doc("Employee", "_T-Employee-00001")
diff --git a/erpnext/hr/doctype/shift_request/test_shift_request.py b/erpnext/hr/doctype/shift_request/test_shift_request.py
index 9c0d8e3..3525540 100644
--- a/erpnext/hr/doctype/shift_request/test_shift_request.py
+++ b/erpnext/hr/doctype/shift_request/test_shift_request.py
@@ -15,24 +15,35 @@
 		for doctype in ["Shift Request", "Shift Assignment"]:
 			frappe.db.sql("delete from `tab{doctype}`".format(doctype=doctype))
 
+	def tearDown(self):
+		frappe.db.rollback()
+
 	def test_make_shift_request(self):
+		"Test creation/updation of Shift Assignment from Shift Request."
 		department = frappe.get_value("Employee", "_T-Employee-00001", 'department')
 		set_shift_approver(department)
 		approver = frappe.db.sql("""select approver from `tabDepartment Approver` where parent= %s and parentfield = 'shift_request_approver'""", (department))[0][0]
 
 		shift_request = make_shift_request(approver)
 
-		shift_assignments = frappe.db.sql('''
-				SELECT shift_request, employee
-				FROM `tabShift Assignment`
-				WHERE shift_request = '{0}'
-			'''.format(shift_request.name), as_dict=1)
-		for d in shift_assignments:
-			employee = d.get('employee')
-			self.assertEqual(shift_request.employee, employee)
-			shift_request.cancel()
-			shift_assignment_doc = frappe.get_doc("Shift Assignment", {"shift_request": d.get('shift_request')})
-			self.assertEqual(shift_assignment_doc.docstatus, 2)
+		# Only one shift assignment is created against a shift request
+		shift_assignment = frappe.db.get_value(
+			"Shift Assignment",
+			filters={"shift_request": shift_request.name},
+			fieldname=["employee", "docstatus"],
+			as_dict=True
+		)
+		self.assertEqual(shift_request.employee, shift_assignment.employee)
+		self.assertEqual(shift_assignment.docstatus, 1)
+
+		shift_request.cancel()
+
+		shift_assignment_docstatus = frappe.db.get_value(
+			"Shift Assignment",
+			filters={"shift_request": shift_request.name},
+			fieldname="docstatus"
+		)
+		self.assertEqual(shift_assignment_docstatus, 2)
 
 	def test_shift_request_approver_perms(self):
 		employee = frappe.get_doc("Employee", "_T-Employee-00001")
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index 4e93fc6..0ba8507 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -717,9 +717,8 @@
 			"ignore_conversion_rate": True
 		})
 		item_doc = frappe.get_cached_doc("Item", args.get("item_code"))
-		out = frappe._dict()
-		get_price_list_rate(bom_args, item_doc, out)
-		rate = out.price_list_rate
+		price_list_data = get_price_list_rate(bom_args, item_doc)
+		rate = price_list_data.price_list_rate
 
 	return rate
 
diff --git a/erpnext/manufacturing/doctype/job_card/job_card.py b/erpnext/manufacturing/doctype/job_card/job_card.py
index 69c7f5c..66e2394 100644
--- a/erpnext/manufacturing/doctype/job_card/job_card.py
+++ b/erpnext/manufacturing/doctype/job_card/job_card.py
@@ -608,6 +608,11 @@
 		target.set_missing_values()
 		target.set_stock_entry_type()
 
+		wo_allows_alternate_item = frappe.db.get_value("Work Order", target.work_order, "allow_alternative_item")
+		for item in target.items:
+			item.allow_alternative_item = int(wo_allows_alternate_item and
+					frappe.get_cached_value("Item", item.item_code, "allow_alternative_item"))
+
 	doclist = get_mapped_doc("Job Card", source_name, {
 		"Job Card": {
 			"doctype": "Stock Entry",
@@ -698,4 +703,4 @@
 		}
 	}, target_doc, set_missing_values)
 
-	return doclist
\ No newline at end of file
+	return doclist
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 04f05ed..86356e3 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -294,7 +294,9 @@
 erpnext.patches.v13_0.add_missing_fg_item_for_stock_entry
 erpnext.patches.v13_0.update_subscription_status_in_memberships
 erpnext.patches.v13_0.update_amt_in_work_order_required_items
+erpnext.patches.v12_0.show_einvoice_irn_cancelled_field
+erpnext.patches.v13_0.delete_orphaned_tables
 erpnext.patches.v13_0.update_export_type_for_gst
 erpnext.patches.v13_0.update_tds_check_field #3
-erpnext.patches.v13_0.add_custom_field_for_south_africa
+erpnext.patches.v13_0.add_custom_field_for_south_africa #2
 erpnext.patches.v13_0.shopify_deprecation_warning
diff --git a/erpnext/patches/v12_0/show_einvoice_irn_cancelled_field.py b/erpnext/patches/v12_0/show_einvoice_irn_cancelled_field.py
new file mode 100644
index 0000000..2319c17
--- /dev/null
+++ b/erpnext/patches/v12_0/show_einvoice_irn_cancelled_field.py
@@ -0,0 +1,12 @@
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+	company = frappe.get_all('Company', filters = {'country': 'India'})
+	if not company:
+		return
+
+	irn_cancelled_field = frappe.db.exists('Custom Field', {'dt': 'Sales Invoice', 'fieldname': 'irn_cancelled'})
+	if irn_cancelled_field:
+		frappe.db.set_value('Custom Field', irn_cancelled_field, 'depends_on', 'eval: doc.irn')
+		frappe.db.set_value('Custom Field', irn_cancelled_field, 'read_only', 0)
diff --git a/erpnext/patches/v13_0/add_custom_field_for_south_africa.py b/erpnext/patches/v13_0/add_custom_field_for_south_africa.py
index f882fde..73ff1ca 100644
--- a/erpnext/patches/v13_0/add_custom_field_for_south_africa.py
+++ b/erpnext/patches/v13_0/add_custom_field_for_south_africa.py
@@ -3,7 +3,7 @@
 
 from __future__ import unicode_literals
 import frappe
-from erpnext.regional.south_africa.setup import make_custom_fields
+from erpnext.regional.south_africa.setup import make_custom_fields, add_permissions
 
 def execute():
 	company = frappe.get_all('Company', filters = {'country': 'South Africa'})
@@ -11,3 +11,4 @@
 		return
 
 	make_custom_fields()
+	add_permissions()
diff --git a/erpnext/patches/v13_0/delete_orphaned_tables.py b/erpnext/patches/v13_0/delete_orphaned_tables.py
new file mode 100644
index 0000000..1d6eebe
--- /dev/null
+++ b/erpnext/patches/v13_0/delete_orphaned_tables.py
@@ -0,0 +1,69 @@
+# Copyright (c) 2019, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+
+import frappe
+from frappe.utils import getdate
+
+def execute():
+    frappe.reload_doc('setup', 'doctype', 'transaction_deletion_record')
+
+    if has_deleted_company_transactions():
+        child_doctypes = get_child_doctypes_whose_parent_doctypes_were_affected()
+
+        for doctype in child_doctypes:
+            docs = frappe.get_all(doctype, fields=['name', 'parent', 'parenttype', 'creation'])
+
+            for doc in docs:
+                if not frappe.db.exists(doc['parenttype'], doc['parent']):
+                    frappe.db.delete(doctype, {'name': doc['name']})
+
+                elif check_for_new_doc_with_same_name_as_deleted_parent(doc):
+                    frappe.db.delete(doctype, {'name': doc['name']})
+
+def has_deleted_company_transactions():
+    return frappe.get_all('Transaction Deletion Record')
+
+def get_child_doctypes_whose_parent_doctypes_were_affected():
+    parent_doctypes = get_affected_doctypes()
+    child_doctypes = frappe.get_all(
+        'DocField', 
+        filters={
+            'fieldtype': 'Table', 
+            'parent':['in', parent_doctypes]
+        }, pluck='options')
+
+    return child_doctypes
+
+def get_affected_doctypes():
+    affected_doctypes = []
+    tdr_docs = frappe.get_all('Transaction Deletion Record', pluck="name")
+    
+    for tdr in tdr_docs:
+        tdr_doc = frappe.get_doc("Transaction Deletion Record", tdr)
+
+        for doctype in tdr_doc.doctypes:
+            if is_not_child_table(doctype.doctype_name):
+                affected_doctypes.append(doctype.doctype_name)
+
+    affected_doctypes = remove_duplicate_items(affected_doctypes)
+    return affected_doctypes
+
+def is_not_child_table(doctype):
+    return not bool(frappe.get_value('DocType', doctype, 'istable'))
+
+def remove_duplicate_items(affected_doctypes):
+    return list(set(affected_doctypes))
+
+def check_for_new_doc_with_same_name_as_deleted_parent(doc):
+    """
+        Compares creation times of parent and child docs.
+        Since Transaction Deletion Record resets the naming series after deletion,
+        it allows the creation of new docs with the same names as the deleted ones.
+    """
+
+    parent_creation_time = frappe.db.get_value(doc['parenttype'], doc['parent'], 'creation')
+    child_creation_time = doc['creation']
+
+    return getdate(parent_creation_time) > getdate(child_creation_time)
\ No newline at end of file
diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py
index b39cef8..f0ca64f 100644
--- a/erpnext/payroll/doctype/salary_slip/salary_slip.py
+++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py
@@ -647,10 +647,13 @@
 				continue
 
 			if (
-				(not d.additional_salary
-				and (not additional_salary or additional_salary.overwrite))
-				or (additional_salary
-				and additional_salary.name == d.additional_salary)
+				(
+					not d.additional_salary
+					and (not additional_salary or additional_salary.overwrite)
+				) or (
+					additional_salary
+					and additional_salary.name == d.additional_salary
+				)
 			):
 				component_row = d
 				break
@@ -679,8 +682,12 @@
 
 		if additional_salary:
 			component_row.is_recurring_additional_salary = is_recurring
-			component_row.default_amount = 0
-			component_row.additional_amount = amount
+			if additional_salary.overwrite:
+				component_row.additional_amount = flt(flt(amount) - flt(component_row.get("default_amount", 0)),
+					component_row.precision("additional_amount"))
+			else:
+				component_row.default_amount = 0
+				component_row.additional_amount = amount
 			component_row.additional_salary = additional_salary.name
 			component_row.deduct_full_tax_on_selected_payroll_date = \
 				additional_salary.deduct_full_tax_on_selected_payroll_date
diff --git a/erpnext/public/js/controllers/accounts.js b/erpnext/public/js/controllers/accounts.js
index 7b997a1..84c7176 100644
--- a/erpnext/public/js/controllers/accounts.js
+++ b/erpnext/public/js/controllers/accounts.js
@@ -31,6 +31,14 @@
 					}
 				}
 			});
+			frm.set_query("cost_center", "taxes", function(doc) {
+				return {
+					filters: {
+						"company": doc.company,
+						"is_group": 0
+					}
+				};
+			});
 		}
 	},
 	validate: function(frm) {
diff --git a/erpnext/public/js/controllers/taxes_and_totals.js b/erpnext/public/js/controllers/taxes_and_totals.js
index a495a9b..84697e0 100644
--- a/erpnext/public/js/controllers/taxes_and_totals.js
+++ b/erpnext/public/js/controllers/taxes_and_totals.js
@@ -751,8 +751,6 @@
 		this.frm.doc.payments.find(pay => {
 			if (pay.default) {
 				pay.amount = total_amount_to_pay;
-			} else {
-				pay.amount = 0.0
 			}
 		});
 		this.frm.refresh_fields();
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 33366db..3c6c347 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -752,7 +752,7 @@
 				this.frm.trigger("item_code", cdt, cdn);
 			}
 			else {
-				// Replacing all occurences of comma with carriage return
+				// Replace all occurences of comma with line feed
 				item.serial_no = item.serial_no.replace(/,/g, '\n');
 				item.conversion_factor = item.conversion_factor || 1;
 				refresh_field("serial_no", item.name, item.parentfield);
diff --git a/erpnext/regional/address_template/templates/france.html b/erpnext/regional/address_template/templates/france.html
new file mode 100644
index 0000000..752331e
--- /dev/null
+++ b/erpnext/regional/address_template/templates/france.html
@@ -0,0 +1,5 @@
+{% if address_line1 %}{{ address_line1 }}{% endif -%}
+{% if address_line2 %}<br>{{ address_line2 }}{% endif -%}
+{% if pincode %}<br>{{ pincode }}{% endif -%}
+{% if city %} {{ city }}{% endif -%}
+{% if country %}<br>{{ country }}{% endif -%}
diff --git a/erpnext/regional/india/e_invoice/utils.py b/erpnext/regional/india/e_invoice/utils.py
index f8a230d..4276946 100644
--- a/erpnext/regional/india/e_invoice/utils.py
+++ b/erpnext/regional/india/e_invoice/utils.py
@@ -316,10 +316,6 @@
 	))
 
 def get_return_doc_reference(invoice):
-	if not invoice.return_against:
-		frappe.throw(_('For generating IRN, reference to the original invoice is mandatory for a credit note. Please set {} field to generate e-invoice.')
-			.format(frappe.bold('Return Against')), title=_('Missing Field'))
-
 	invoice_date = frappe.db.get_value('Sales Invoice', invoice.return_against, 'posting_date')
 	return frappe._dict(dict(
 		invoice_name=invoice.return_against, invoice_date=format_date(invoice_date, 'dd/mm/yyyy')
@@ -438,7 +434,7 @@
 	if invoice.is_pos and invoice.base_paid_amount:
 		payment_details = get_payment_details(invoice)
 
-	if invoice.is_return:
+	if invoice.is_return and invoice.return_against:
 		prev_doc_details = get_return_doc_reference(invoice)
 
 	if invoice.transporter and not invoice.is_return:
@@ -932,7 +928,7 @@
 
 	def set_einvoice_data(self, res):
 		enc_signed_invoice = res.get('SignedInvoice')
-		dec_signed_invoice = jwt.decode(enc_signed_invoice, verify=False)['data']
+		dec_signed_invoice = jwt.decode(enc_signed_invoice, options={"verify_signature": False})['data']
 
 		self.invoice.irn = res.get('Irn')
 		self.invoice.ewaybill = res.get('EwbNo')
@@ -1130,4 +1126,4 @@
 def job_already_enqueued(job_name):
 	enqueued_jobs = [d.get("job_name") for d in get_info()]
 	if job_name in enqueued_jobs:
-		return True
\ No newline at end of file
+		return True
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index e9372f9..b4f146c 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -457,7 +457,7 @@
 			depends_on='eval:in_list(["Registered Regular", "SEZ", "Overseas", "Deemed Export"], doc.gst_category) && doc.irn_cancelled === 0'),
 
 		dict(fieldname='irn_cancelled', label='IRN Cancelled', fieldtype='Check', no_copy=1, print_hide=1,
-			depends_on='eval:(doc.irn_cancelled === 1)', read_only=1, allow_on_submit=1, insert_after='customer'),
+			depends_on='eval: doc.irn', allow_on_submit=1, insert_after='customer'),
 
 		dict(fieldname='eway_bill_validity', label='E-Way Bill Validity', fieldtype='Data', no_copy=1, print_hide=1,
 			depends_on='ewaybill', read_only=1, allow_on_submit=1, insert_after='ewaybill'),
@@ -985,4 +985,4 @@
 
 def update_accounts_settings_for_taxes():
 	if frappe.db.count('Company') == 1:
-		frappe.db.set_value('Accounts Settings', None, "add_taxes_from_item_tax_template", 0)
\ No newline at end of file
+		frappe.db.set_value('Accounts Settings', None, "add_taxes_from_item_tax_template", 0)
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index 88c350a..a152797 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -851,7 +851,7 @@
 		# if its the first depreciation
 		if depreciable_value == asset.gross_purchase_amount:
 			# as per IT act, if the asset is purchased in the 2nd half of fiscal year, then rate is divided by 2
-			diff = date_diff(asset.available_for_use_date, row.depreciation_start_date)
+			diff = date_diff(row.depreciation_start_date, asset.available_for_use_date)
 			if diff <= 180:
 				rate_of_depreciation = rate_of_depreciation / 2
 				frappe.msgprint(
diff --git a/erpnext/regional/report/vat_audit_report/vat_audit_report.json b/erpnext/regional/report/vat_audit_report/vat_audit_report.json
index 8917e8f..a8be7bf 100644
--- a/erpnext/regional/report/vat_audit_report/vat_audit_report.json
+++ b/erpnext/regional/report/vat_audit_report/vat_audit_report.json
@@ -18,15 +18,5 @@
  "ref_doctype": "GL Entry",
  "report_name": "VAT Audit Report",
  "report_type": "Script Report",
- "roles": [
-  {
-   "role": "Accounts User"
-  },
-  {
-   "role": "Accounts Manager"
-  },
-  {
-   "role": "Auditor"
-  }
- ]
+ "roles": []
 }
\ No newline at end of file
diff --git a/erpnext/regional/report/vat_audit_report/vat_audit_report.py b/erpnext/regional/report/vat_audit_report/vat_audit_report.py
index f45ba01..292605e 100644
--- a/erpnext/regional/report/vat_audit_report/vat_audit_report.py
+++ b/erpnext/regional/report/vat_audit_report/vat_audit_report.py
@@ -189,6 +189,8 @@
 						row["posting_date"] = formatdate(inv_data.get("posting_date"), "dd-mm-yyyy")
 						row["voucher_type"] = doctype
 						row["voucher_no"] = inv
+						row["party_type"] = "Customer" if doctype == "Sales Invoice" else "Supplier" 
+						row["party"] = inv_data.get("party")
 						row["remarks"] = inv_data.get("remarks")
 						row["gross_amount"]= item_details[0].get("gross_amount")
 						row["tax_amount"]= item_details[0].get("tax_amount")
@@ -227,6 +229,20 @@
 				"width": 150
 			},
 			{
+				"fieldname": "party_type",
+				"label": "Party Type",
+				"fieldtype": "Data",
+				"width": 140,
+				"hidden": 1
+			},
+			{
+				"fieldname": "party",
+				"label": "Party",
+				"fieldtype": "Dynamic Link",
+				"options": "party_type",
+				"width": 150
+			},
+			{
 				"fieldname": "remarks",
 				"label": "Details",
 				"fieldtype": "Data",
@@ -236,18 +252,18 @@
 				"fieldname": "net_amount",
 				"label": "Net Amount",
 				"fieldtype": "Currency",
-				"width": 150
+				"width": 130
 			},
 			{
 				"fieldname": "tax_amount",
 				"label": "Tax Amount",
 				"fieldtype": "Currency",
-				"width": 150
+				"width": 130
 			},
 			{
 				"fieldname": "gross_amount",
 				"label": "Gross Amount",
 				"fieldtype": "Currency",
-				"width": 150
+				"width": 130
 			},
 		]
diff --git a/erpnext/regional/south_africa/setup.py b/erpnext/regional/south_africa/setup.py
index ac783b8..4657ff8 100644
--- a/erpnext/regional/south_africa/setup.py
+++ b/erpnext/regional/south_africa/setup.py
@@ -3,11 +3,12 @@
 
 from __future__ import unicode_literals
 
-# import frappe, os, json
+import frappe
 from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
 from frappe.permissions import add_permission, update_permission_property
 
 def setup(company=None, patch=True):
+	make_custom_fields()
 	add_permissions()
 
 def make_custom_fields(update=True):
@@ -27,10 +28,23 @@
 	create_custom_fields(custom_fields, update=update)
 
 def add_permissions():
-	"""Add Permissions for South Africa VAT Settings and South Africa VAT Account"""
+	"""Add Permissions for South Africa VAT Settings and South Africa VAT Account
+		and VAT Audit Report"""
 	for doctype in ('South Africa VAT Settings', 'South Africa VAT Account'):
 		add_permission(doctype, 'All', 0)
 		for role in ('Accounts Manager', 'Accounts User', 'System Manager'):
 			add_permission(doctype, role, 0)
 			update_permission_property(doctype, role, 0, 'write', 1)
-			update_permission_property(doctype, role, 0, 'create', 1)
\ No newline at end of file
+			update_permission_property(doctype, role, 0, 'create', 1)
+	
+
+	if not frappe.db.get_value('Custom Role', dict(report="VAT Audit Report")):
+		frappe.get_doc(dict(
+			doctype='Custom Role',
+			report="VAT Audit Report",
+			roles= [
+				dict(role='Accounts User'),
+				dict(role='Accounts Manager'),
+				dict(role='Auditor')
+			]
+		)).insert()
\ No newline at end of file
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index 3b62081..abf146c 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -157,9 +157,7 @@
 		'''If Customer created from Lead, update lead status to "Converted"
 		update Customer link in Quotation, Opportunity'''
 		if self.lead_name:
-			lead = frappe.get_doc('Lead', self.lead_name)
-			lead.status = 'Converted'
-			lead.save()
+			frappe.db.set_value("Lead", self.lead_name, "status", "Converted")
 
 	def create_lead_address_contact(self):
 		if self.lead_name:
@@ -176,12 +174,12 @@
 					address.append('links', dict(link_doctype='Customer', link_name=self.name))
 					address.save(ignore_permissions=self.flags.ignore_permissions)
 
-			lead = frappe.db.get_value("Lead", self.lead_name, ["organization_lead", "lead_name", "email_id", "phone", "mobile_no", "gender", "salutation"], as_dict=True)
+			lead = frappe.db.get_value("Lead", self.lead_name, ["company_name", "lead_name", "email_id", "phone", "mobile_no", "gender", "salutation"], as_dict=True)
 
 			if not lead.lead_name:
 				frappe.throw(_("Please mention the Lead Name in Lead {0}").format(self.lead_name))
 
-			if lead.organization_lead:
+			if lead.company_name:
 				contact_names = frappe.get_all('Dynamic Link', filters={
 									"parenttype":"Contact",
 									"link_doctype":"Lead",
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index 974648d..1de1e00 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -673,6 +673,8 @@
 
 		so.cancel()
 
+		dn.load_from_db()
+
 		self.assertRaises(frappe.CancelledLinkError, dn.submit)
 
 	def test_service_type_product_bundle(self):
diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.json b/erpnext/selling/doctype/selling_settings/selling_settings.json
index f01934b..717fd9b 100644
--- a/erpnext/selling/doctype/selling_settings/selling_settings.json
+++ b/erpnext/selling/doctype/selling_settings/selling_settings.json
@@ -6,24 +6,31 @@
  "document_type": "Other",
  "engine": "InnoDB",
  "field_order": [
+  "customer_defaults_section",
   "cust_master_name",
-  "campaign_naming_by",
   "customer_group",
+  "column_break_4",
   "territory",
-  "selling_price_list",
-  "close_opportunity_after_days",
+  "crm_settings_section",
+  "campaign_naming_by",
   "default_valid_till",
-  "column_break_5",
+  "column_break_9",
+  "close_opportunity_after_days",
+  "item_price_settings_section",
+  "selling_price_list",
+  "column_break_15",
+  "maintain_same_sales_rate",
+  "maintain_same_rate_action",
+  "editable_price_list_rate",
+  "validate_selling_price",
+  "sales_transactions_settings_section",
   "so_required",
   "dn_required",
   "sales_update_frequency",
-  "maintain_same_sales_rate",
-  "maintain_same_rate_action",
+  "column_break_5",
   "role_to_override_stop_action",
-  "editable_price_list_rate",
   "allow_multiple_items",
   "allow_against_multiple_purchase_orders",
-  "validate_selling_price",
   "hide_tax_id"
  ],
  "fields": [
@@ -116,7 +123,7 @@
    "default": "0",
    "fieldname": "allow_multiple_items",
    "fieldtype": "Check",
-   "label": "Allow Item to Be Added Multiple Times in a Transaction"
+   "label": "Allow Item to be Added Multiple Times in a Transaction"
   },
   {
    "default": "0",
@@ -142,7 +149,7 @@
    "description": "Configure the action to stop the transaction or just warn if the same rate is not maintained.",
    "fieldname": "maintain_same_rate_action",
    "fieldtype": "Select",
-   "label": "Action If Same Rate is Not Maintained",
+   "label": "Action if Same Rate is Not Maintained",
    "mandatory_depends_on": "maintain_same_sales_rate",
    "options": "Stop\nWarn"
   },
@@ -152,6 +159,38 @@
    "fieldtype": "Link",
    "label": "Role Allowed to Override Stop Action",
    "options": "Role"
+  },
+  {
+   "fieldname": "customer_defaults_section",
+   "fieldtype": "Section Break",
+   "label": "Customer Defaults"
+  },
+  {
+   "fieldname": "column_break_4",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "crm_settings_section",
+   "fieldtype": "Section Break",
+   "label": "CRM Settings"
+  },
+  {
+   "fieldname": "column_break_9",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "item_price_settings_section",
+   "fieldtype": "Section Break",
+   "label": "Item Price Settings"
+  },
+  {
+   "fieldname": "column_break_15",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "sales_transactions_settings_section",
+   "fieldtype": "Section Break",
+   "label": "Transaction Settings"
   }
  ],
  "icon": "fa fa-cog",
@@ -159,7 +198,7 @@
  "index_web_pages_for_search": 1,
  "issingle": 1,
  "links": [],
- "modified": "2021-04-04 20:18:12.814624",
+ "modified": "2021-08-06 22:25:50.119458",
  "modified_by": "Administrator",
  "module": "Selling",
  "name": "Selling Settings",
diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py
index 8755125..95cbf51 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -108,6 +108,9 @@
 				frappe.flags.country_change = True
 				self.create_default_accounts()
 				self.create_default_warehouses()
+		
+		if not frappe.db.get_value("Cost Center", {"is_group": 0, "company": self.name}):
+			self.create_default_cost_center()
 
 		if frappe.flags.country_change:
 			install_country_fixtures(self.name, self.country)
@@ -117,9 +120,6 @@
 			from erpnext.setup.setup_wizard.operations.install_fixtures import install_post_company_fixtures
 			install_post_company_fixtures(frappe._dict({'company_name': self.name}))
 
-		if not frappe.db.get_value("Cost Center", {"is_group": 0, "company": self.name}):
-			self.create_default_cost_center()
-
 		if not frappe.local.flags.ignore_chart_of_accounts:
 			self.set_default_accounts()
 			if self.default_cash_account:
diff --git a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.json b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.json
index 9313f95..23e5947 100644
--- a/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.json
+++ b/erpnext/setup/doctype/transaction_deletion_record/transaction_deletion_record.json
@@ -54,7 +54,7 @@
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2021-05-08 23:13:48.049879",
+ "modified": "2021-08-04 20:15:59.071493",
  "modified_by": "Administrator",
  "module": "Setup",
  "name": "Transaction Deletion Record",
@@ -70,6 +70,7 @@
    "report": 1,
    "role": "System Manager",
    "share": 1,
+   "submit": 1,
    "write": 1
   }
  ],
diff --git a/erpnext/setup/setup_wizard/operations/taxes_setup.py b/erpnext/setup/setup_wizard/operations/taxes_setup.py
index cbb3dc8..bacada9 100644
--- a/erpnext/setup/setup_wizard/operations/taxes_setup.py
+++ b/erpnext/setup/setup_wizard/operations/taxes_setup.py
@@ -124,7 +124,8 @@
 		account_data = tax_row.get('account_head')
 		tax_row_defaults = {
 			'category': 'Total',
-			'charge_type': 'On Net Total'
+			'charge_type': 'On Net Total',
+			'cost_center': frappe.db.get_value('Company', company_name, 'cost_center')
 		}
 
 		if doctype == 'Purchase Taxes and Charges Template':
diff --git a/erpnext/stock/doctype/batch/test_batch.py b/erpnext/stock/doctype/batch/test_batch.py
index cbd272d..a85a022 100644
--- a/erpnext/stock/doctype/batch/test_batch.py
+++ b/erpnext/stock/doctype/batch/test_batch.py
@@ -269,11 +269,14 @@
 		batch2 = create_batch('_Test Batch Price Item', 300, 1)
 		batch3 = create_batch('_Test Batch Price Item', 400, 0)
 
+		company = "_Test Company with perpetual inventory"
+		currency = frappe.get_cached_value("Company",  company,  "default_currency")
+
 		args = frappe._dict({
 			"item_code": "_Test Batch Price Item",
-			"company": "_Test Company with perpetual inventory",
+			"company": company,
 			"price_list": "_Test Price List",
-			"currency": "_Test Currency",
+			"currency": currency,
 			"doctype": "Sales Invoice",
 			"conversion_rate": 1,
 			"price_list_currency": "_Test Currency",
@@ -333,4 +336,4 @@
 	except frappe.DuplicateEntryError:
 		batch = frappe.get_doc("Batch", args.batch_id)
 
-	return batch
\ No newline at end of file
+	return batch
diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py
index 922049f..7a9985d 100644
--- a/erpnext/stock/doctype/item/test_item.py
+++ b/erpnext/stock/doctype/item/test_item.py
@@ -83,14 +83,17 @@
 
 		make_test_objects("Item Price")
 
+		company = "_Test Company"
+		currency = frappe.get_cached_value("Company",  company,  "default_currency")
+
 		details = get_item_details({
 			"item_code": "_Test Item",
-			"company": "_Test Company",
+			"company": company,
 			"price_list": "_Test Price List",
-			"currency": "_Test Currency",
+			"currency": currency,
 			"doctype": "Sales Order",
 			"conversion_rate": 1,
-			"price_list_currency": "_Test Currency",
+			"price_list_currency": currency,
 			"plc_conversion_rate": 1,
 			"order_type": "Sales",
 			"customer": "_Test Customer",
diff --git a/erpnext/stock/doctype/item_quality_inspection_parameter/item_quality_inspection_parameter.json b/erpnext/stock/doctype/item_quality_inspection_parameter/item_quality_inspection_parameter.json
index 9b1a47e..5de45cb 100644
--- a/erpnext/stock/doctype/item_quality_inspection_parameter/item_quality_inspection_parameter.json
+++ b/erpnext/stock/doctype/item_quality_inspection_parameter/item_quality_inspection_parameter.json
@@ -47,7 +47,8 @@
    "description": "Simple Python formula applied on Reading fields.<br> Numeric eg. 1: <b>reading_1 &gt; 0.2 and reading_1 &lt; 0.5</b><br>\nNumeric eg. 2: <b>mean &gt; 3.5</b> (mean of populated fields)<br>\nValue based eg.:  <b>reading_value in (\"A\", \"B\", \"C\")</b>",
    "fieldname": "acceptance_formula",
    "fieldtype": "Code",
-   "label": "Acceptance Criteria Formula"
+   "label": "Acceptance Criteria Formula",
+   "options": "PythonExpression"
   },
   {
    "default": "0",
@@ -89,7 +90,7 @@
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2021-02-04 18:50:02.056173",
+ "modified": "2021-08-06 15:08:20.911338",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Item Quality Inspection Parameter",
diff --git a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
index 32b08f6..cb09d93 100644
--- a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
+++ b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py
@@ -11,6 +11,7 @@
 from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
 from erpnext.accounts.doctype.account.test_account import get_inventory_account
 from erpnext.accounts.doctype.account.test_account import create_account
+from erpnext.assets.doctype.asset.test_asset import create_asset_category, create_fixed_asset_item
 
 class TestLandedCostVoucher(unittest.TestCase):
 	def test_landed_cost_voucher(self):
@@ -250,6 +251,39 @@
 			self.assertEqual(entry.credit, amounts[0])
 			self.assertEqual(entry.credit_in_account_currency, amounts[1])
 
+	def test_asset_lcv(self):
+		"Check if LCV for an Asset updates the Assets Gross Purchase Amount correctly."
+		frappe.db.set_value("Company", "_Test Company", "capital_work_in_progress_account", "CWIP Account - _TC")
+
+		if not frappe.db.exists("Asset Category", "Computers"):
+			create_asset_category()
+
+		if not frappe.db.exists("Item", "Macbook Pro"):
+			create_fixed_asset_item()
+
+		pr = make_purchase_receipt(item_code="Macbook Pro", qty=1, rate=50000)
+
+		# check if draft asset was created
+		assets = frappe.db.get_all('Asset', filters={'purchase_receipt': pr.name})
+		self.assertEqual(len(assets), 1)
+
+		lcv = make_landed_cost_voucher(
+			company = pr.company,
+			receipt_document_type = "Purchase Receipt",
+			receipt_document=pr.name,
+			charges=80,
+			expense_account="Expenses Included In Valuation - _TC")
+
+		lcv.save()
+		lcv.submit()
+
+		# lcv updates amount in draft asset
+		self.assertEqual(frappe.db.get_value("Asset", assets[0].name, "gross_purchase_amount"), 50080)
+
+		# tear down
+		lcv.cancel()
+		pr.cancel()
+
 def make_landed_cost_voucher(** args):
 	args = frappe._dict(args)
 	ref_doc = frappe.get_doc(args.receipt_document_type, args.receipt_document)
@@ -268,7 +302,7 @@
 
 	lcv.set("taxes", [{
 		"description": "Shipping Charges",
-		"expense_account": "Expenses Included In Valuation - TCP1",
+		"expense_account": args.expense_account or "Expenses Included In Valuation - TCP1",
 		"amount": args.charges
 	}])
 
diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
index 899d7e8..bcf6052 100644
--- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py
@@ -290,8 +290,16 @@
 						and warehouse_account_name == supplier_warehouse_account:
 							continue
 
-					self.add_gl_entry(gl_entries, warehouse_account_name, d.cost_center, stock_value_diff, 0.0, remarks,
-						stock_rbnb, account_currency=warehouse_account_currency, item=d)
+					self.add_gl_entry(
+						gl_entries=gl_entries,
+						account=warehouse_account_name,
+						cost_center=d.cost_center,
+						debit=stock_value_diff,
+						credit=0.0,
+						remarks=remarks,
+						against_account=stock_rbnb,
+						account_currency=warehouse_account_currency,
+						item=d)
 
 					# GL Entry for from warehouse or Stock Received but not billed
 					# Intentionally passed negative debit amount to avoid incorrect GL Entry validation
@@ -304,9 +312,17 @@
 						account = warehouse_account[d.from_warehouse]['account'] \
 								if d.from_warehouse else stock_rbnb
 
-						self.add_gl_entry(gl_entries, account, d.cost_center,
-							-1 * flt(d.base_net_amount, d.precision("base_net_amount")), 0.0, remarks, warehouse_account_name,
-							debit_in_account_currency=-1 * credit_amount, account_currency=credit_currency, item=d)
+						self.add_gl_entry(
+							gl_entries=gl_entries,
+							account=account,
+							cost_center=d.cost_center,
+							debit=-1 * flt(d.base_net_amount, d.precision("base_net_amount")),
+							credit=0.0,
+							remarks=remarks,
+							against_account=warehouse_account_name,
+							debit_in_account_currency=-1 * credit_amount,
+							account_currency=credit_currency,
+							item=d)
 
 						# check if the exchange rate has changed
 						if d.get('purchase_invoice'):
@@ -317,13 +333,29 @@
 								discrepancy_caused_by_exchange_rate_difference = (d.qty * d.net_rate) * \
 									(exchange_rate_map[d.purchase_invoice] - self.conversion_rate)
 
-								self.add_gl_entry(gl_entries, account, d.cost_center, 0.0, discrepancy_caused_by_exchange_rate_difference,
-									remarks, self.supplier, debit_in_account_currency=-1 * discrepancy_caused_by_exchange_rate_difference,
-									account_currency=credit_currency, item=d)
+								self.add_gl_entry(
+									gl_entries=gl_entries,
+									account=account,
+									cost_center=d.cost_center,
+									debit=0.0,
+									credit=discrepancy_caused_by_exchange_rate_difference,
+									remarks=remarks,
+									against_account=self.supplier,
+									debit_in_account_currency=-1 * discrepancy_caused_by_exchange_rate_difference,
+									account_currency=credit_currency,
+									item=d)
 
-								self.add_gl_entry(gl_entries, self.get_company_default("exchange_gain_loss_account"), d.cost_center, discrepancy_caused_by_exchange_rate_difference, 0.0,
-									remarks, self.supplier, debit_in_account_currency=-1 * discrepancy_caused_by_exchange_rate_difference,
-									account_currency=credit_currency, item=d)
+								self.add_gl_entry(
+									gl_entries=gl_entries,
+									account=self.get_company_default("exchange_gain_loss_account"),
+									cost_center=d.cost_center,
+									debit=discrepancy_caused_by_exchange_rate_difference,
+									credit=0.0,
+									remarks=remarks,
+									against_account=self.supplier,
+									debit_in_account_currency=-1 * discrepancy_caused_by_exchange_rate_difference,
+									account_currency=credit_currency,
+									item=d)
 
 					# Amount added through landed-cos-voucher
 					if d.landed_cost_voucher_amount and landed_cost_entries:
@@ -332,14 +364,31 @@
 							credit_amount = (flt(amount["base_amount"]) if (amount["base_amount"] or
 								account_currency!=self.company_currency) else flt(amount["amount"]))
 
-							self.add_gl_entry(gl_entries, account, d.cost_center, 0.0, credit_amount, remarks,
-								warehouse_account_name, credit_in_account_currency=flt(amount["amount"]),
-								account_currency=account_currency, project=d.project, item=d)
+							self.add_gl_entry(
+								gl_entries=gl_entries,
+								account=account,
+								cost_center=d.cost_center,
+								debit=0.0,
+								credit=credit_amount,
+								remarks=remarks,
+								against_account=warehouse_account_name,
+								credit_in_account_currency=flt(amount["amount"]),
+								account_currency=account_currency,
+								project=d.project,
+								item=d)
 
 					# sub-contracting warehouse
 					if flt(d.rm_supp_cost) and warehouse_account.get(self.supplier_warehouse):
-						self.add_gl_entry(gl_entries, supplier_warehouse_account, d.cost_center, 0.0, flt(d.rm_supp_cost),
-							remarks, warehouse_account_name, account_currency=supplier_warehouse_account_currency, item=d)
+						self.add_gl_entry(
+							gl_entries=gl_entries,
+							account=supplier_warehouse_account,
+							cost_center=d.cost_center,
+							debit=0.0,
+							credit=flt(d.rm_supp_cost),
+							remarks=remarks,
+							against_account=warehouse_account_name,
+							account_currency=supplier_warehouse_account_currency,
+							item=d)
 
 					# divisional loss adjustment
 					valuation_amount_as_per_doc = flt(d.base_net_amount, d.precision("base_net_amount")) + \
@@ -356,8 +405,17 @@
 
 						cost_center = d.cost_center or frappe.get_cached_value("Company", self.company, "cost_center")
 
-						self.add_gl_entry(gl_entries, loss_account, cost_center, divisional_loss, 0.0, remarks,
-							warehouse_account_name, account_currency=credit_currency, project=d.project, item=d)
+						self.add_gl_entry(
+							gl_entries=gl_entries,
+							account=loss_account,
+							cost_center=cost_center,
+							debit=divisional_loss,
+							credit=0.0,
+							remarks=remarks,
+							against_account=warehouse_account_name,
+							account_currency=credit_currency,
+							project=d.project,
+							item=d)
 
 				elif d.warehouse not in warehouse_with_no_account or \
 					d.rejected_warehouse not in warehouse_with_no_account:
@@ -368,12 +426,30 @@
 				debit_currency = get_account_currency(d.expense_account)
 				remarks = self.get("remarks") or _("Accounting Entry for Service")
 
-				self.add_gl_entry(gl_entries, service_received_but_not_billed_account, d.cost_center, 0.0, d.amount,
-					remarks, d.expense_account, account_currency=credit_currency, project=d.project,
+				self.add_gl_entry(
+					gl_entries=gl_entries,
+					account=service_received_but_not_billed_account,
+					cost_center=d.cost_center,
+					debit=0.0,
+					credit=d.amount,
+					remarks=remarks,
+					against_account=d.expense_account,
+					account_currency=credit_currency,
+					project=d.project,
 					voucher_detail_no=d.name, item=d)
 
-				self.add_gl_entry(gl_entries, d.expense_account, d.cost_center, d.amount, 0.0, remarks, service_received_but_not_billed_account,
-					account_currency = debit_currency, project=d.project, voucher_detail_no=d.name, item=d)
+				self.add_gl_entry(
+					gl_entries=gl_entries,
+					account=d.expense_account,
+					cost_center=d.cost_center,
+					debit=d.amount,
+					credit=0.0,
+					remarks=remarks,
+					against_account=service_received_but_not_billed_account,
+					account_currency = debit_currency,
+					project=d.project,
+					voucher_detail_no=d.name,
+					item=d)
 
 		if warehouse_with_no_account:
 			frappe.msgprint(_("No accounting entries for the following warehouses") + ": \n" +
@@ -423,8 +499,15 @@
 						applicable_amount = negative_expense_to_be_booked * (valuation_tax[tax.name] / total_valuation_amount)
 						amount_including_divisional_loss -= applicable_amount
 
-					self.add_gl_entry(gl_entries, account, tax.cost_center, 0.0, applicable_amount, self.remarks or _("Accounting Entry for Stock"),
-						against_account, item=tax)
+					self.add_gl_entry(
+						gl_entries=gl_entries,
+						account=account,
+						cost_center=tax.cost_center,
+						debit=0.0,
+						credit=applicable_amount,
+						remarks=self.remarks or _("Accounting Entry for Stock"),
+						against_account=against_account,
+						item=tax)
 
 					i += 1
 
@@ -477,15 +560,31 @@
 		# debit cwip account
 		debit_in_account_currency = (base_asset_amount
 			if cwip_account_currency == self.company_currency else asset_amount)
-		self.add_gl_entry(gl_entries, cwip_account, item.cost_center, base_asset_amount, 0.0, remarks,
-			arbnb_account, debit_in_account_currency=debit_in_account_currency, item=item)
+		self.add_gl_entry(
+			gl_entries=gl_entries,
+			account=cwip_account,
+			cost_center=item.cost_center,
+			debit=base_asset_amount,
+			credit=0.0,
+			remarks=remarks,
+			against_account=arbnb_account,
+			debit_in_account_currency=debit_in_account_currency,
+			item=item)
 
 		asset_rbnb_currency = get_account_currency(arbnb_account)
 		# credit arbnb account
 		credit_in_account_currency = (base_asset_amount
 			if asset_rbnb_currency == self.company_currency else asset_amount)
-		self.add_gl_entry(gl_entries, arbnb_account, item.cost_center, 0.0, base_asset_amount, remarks,
-			cwip_account, credit_in_account_currency=credit_in_account_currency, item=item)
+		self.add_gl_entry(
+			gl_entries=gl_entries,
+			account=arbnb_account,
+			cost_center=item.cost_center,
+			debit=0.0,
+			credit=base_asset_amount,
+			remarks=remarks,
+			against_account=cwip_account,
+			credit_in_account_currency=credit_in_account_currency,
+			item=item)
 
 	def add_lcv_gl_entries(self, item, gl_entries):
 		expenses_included_in_asset_valuation = self.get_company_default("expenses_included_in_asset_valuation")
@@ -498,11 +597,27 @@
 
 		remarks = self.get("remarks") or _("Accounting Entry for Stock")
 
-		self.add_gl_entry(gl_entries, expenses_included_in_asset_valuation, item.cost_center, 0.0, flt(item.landed_cost_voucher_amount),
-			remarks, asset_account, project=item.project, item=item)
+		self.add_gl_entry(
+			gl_entries=gl_entries,
+			account=expenses_included_in_asset_valuation,
+			cost_center=item.cost_center,
+			debit=0.0,
+			credit=flt(item.landed_cost_voucher_amount),
+			remarks=remarks,
+			against_account=asset_account,
+			project=item.project,
+			item=item)
 
-		self.add_gl_entry(gl_entries, asset_account, item.cost_center, 0.0, flt(item.landed_cost_voucher_amount),
-			remarks, expenses_included_in_asset_valuation, project=item.project, item=item)
+		self.add_gl_entry(
+			gl_entries=gl_entries,
+			account=asset_account,
+			cost_center=item.cost_center,
+			debit=flt(item.landed_cost_voucher_amount),
+			credit=0.0,
+			remarks=remarks,
+			against_account=expenses_included_in_asset_valuation,
+			project=item.project,
+			item=item)
 
 	def update_assets(self, item, valuation_rate):
 		assets = frappe.db.get_all('Asset',
diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
index 82461cb..d40d781 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -23,9 +23,7 @@
 
 	def test_reverse_purchase_receipt_sle(self):
 
-		frappe.db.set_value('UOM', '_Test UOM', 'must_be_whole_number', 0)
-
-		pr = make_purchase_receipt(qty=0.5)
+		pr = make_purchase_receipt(qty=0.5, item_code="_Test Item Home Desktop 200")
 
 		sl_entry = frappe.db.get_all("Stock Ledger Entry", {"voucher_type": "Purchase Receipt",
 			"voucher_no": pr.name}, ['actual_qty'])
@@ -41,8 +39,6 @@
 		self.assertEqual(len(sl_entry_cancelled), 2)
 		self.assertEqual(sl_entry_cancelled[1].actual_qty, -0.5)
 
-		frappe.db.set_value('UOM', '_Test UOM', 'must_be_whole_number', 1)
-
 	def test_make_purchase_invoice(self):
 		if not frappe.db.exists('Payment Terms Template', '_Test Payment Terms Template For Purchase Invoice'):
 			frappe.get_doc({
@@ -328,21 +324,8 @@
 
 		pr1.submit()
 		self.assertRaises(frappe.ValidationError, pr2.submit)
+		frappe.db.rollback()
 
-		pr1.cancel()
-		se.cancel()
-		se1.cancel()
-		se2.cancel()
-		se3.cancel()
-		po.reload()
-		pr2.load_from_db()
-
-		if pr2.docstatus == 1 and frappe.db.get_value('Stock Ledger Entry',
-			{'voucher_no': pr2.name, 'is_cancelled': 0}, 'name'):
-			pr2.cancel()
-
-			po.load_from_db()
-			po.cancel()
 
 	def test_serial_no_supplier(self):
 		pr = make_purchase_receipt(item_code="_Test Serialized Item With Series", qty=1)
diff --git a/erpnext/stock/doctype/serial_no/serial_no.py b/erpnext/stock/doctype/serial_no/serial_no.py
index bad7b60..70312bc 100644
--- a/erpnext/stock/doctype/serial_no/serial_no.py
+++ b/erpnext/stock/doctype/serial_no/serial_no.py
@@ -165,8 +165,14 @@
 				)
 			ORDER BY
 				posting_date desc, posting_time desc, creation desc""",
-			(self.item_code, self.company,
-				serial_no, serial_no+'\n%', '%\n'+serial_no, '%\n'+serial_no+'\n%'), as_dict=1):
+			(
+				self.item_code, self.company,
+				serial_no,
+				serial_no+'\n%',
+				'%\n'+serial_no,
+				'%\n'+serial_no+'\n%'
+			),
+			as_dict=1):
 				if serial_no.upper() in get_serial_nos(sle.serial_no):
 					if cint(sle.actual_qty) > 0:
 						sle_dict.setdefault("incoming", []).append(sle)
diff --git a/erpnext/stock/doctype/serial_no/test_serial_no.py b/erpnext/stock/doctype/serial_no/test_serial_no.py
index cde7fe0..b9a58cf 100644
--- a/erpnext/stock/doctype/serial_no/test_serial_no.py
+++ b/erpnext/stock/doctype/serial_no/test_serial_no.py
@@ -174,5 +174,23 @@
 		self.assertEqual(sn_doc.warehouse, "_Test Warehouse - _TC")
 		self.assertEqual(sn_doc.purchase_document_no, se.name)
 
+	def test_serial_no_sanitation(self):
+		"Test if Serial No input is sanitised before entering the DB."
+		item_code = "_Test Serialized Item"
+		test_records = frappe.get_test_records('Stock Entry')
+
+		se = frappe.copy_doc(test_records[0])
+		se.get("items")[0].item_code = item_code
+		se.get("items")[0].qty = 3
+		se.get("items")[0].serial_no = " _TS1, _TS2 , _TS3  "
+		se.get("items")[0].transfer_qty = 3
+		se.set_stock_entry_type()
+		se.insert()
+		se.submit()
+
+		self.assertEqual(se.get("items")[0].serial_no, "_TS1\n_TS2\n_TS3")
+
+		frappe.db.rollback()
+
 	def tearDown(self):
 		frappe.db.rollback()
\ No newline at end of file
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 95c7311..8293319 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -76,6 +76,7 @@
 		self.validate_difference_account()
 		self.set_job_card_data()
 		self.set_purpose_for_stock_entry()
+		self.clean_serial_nos()
 		self.validate_duplicate_serial_no()
 
 		if not self.from_bom:
diff --git a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
index b4f4583..be1f00e 100644
--- a/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
+++ b/erpnext/stock/doctype/stock_ledger_entry/stock_ledger_entry.py
@@ -55,8 +55,8 @@
 				"sum(actual_qty)") or 0
 			frappe.db.set_value("Batch", self.batch_no, "batch_qty", batch_qty)
 
-	#check for item quantity available in stock
 	def actual_amt_check(self):
+		"""Validate that qty at warehouse for selected batch is >=0"""
 		if self.batch_no and not self.get("allow_negative_stock"):
 			batch_bal_after_transaction = flt(frappe.db.sql("""select sum(actual_qty)
 				from `tabStock Ledger Entry`
@@ -107,7 +107,7 @@
 		self.stock_uom = item_det.stock_uom
 
 	def check_stock_frozen_date(self):
-		stock_settings = frappe.get_doc('Stock Settings', 'Stock Settings')
+		stock_settings = frappe.get_cached_doc('Stock Settings')
 
 		if stock_settings.stock_frozen_upto:
 			if (getdate(self.posting_date) <= getdate(stock_settings.stock_frozen_upto)
diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
index 0bae7cf..cda7c1d 100644
--- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
+++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py
@@ -31,6 +31,7 @@
 		self.validate_expense_account()
 		self.validate_customer_provided_item()
 		self.set_zero_value_for_customer_provided_items()
+		self.clean_serial_nos()
 		self.set_total_qty_and_amount()
 		self.validate_putaway_capacity()
 
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index 2ed7a04..be8508a 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -74,8 +74,7 @@
 
 	update_party_blanket_order(args, out)
 
-	
-	get_price_list_rate(args, item, out)
+	out.update(get_price_list_rate(args, item))
 
 	if args.customer and cint(args.is_pos):
 		out.update(get_pos_profile_item_details(args.company, args, update_data=True))
@@ -638,7 +637,10 @@
 		or item_group.get("default_supplier")
 		or brand.get("default_supplier"))
 
-def get_price_list_rate(args, item_doc, out):
+def get_price_list_rate(args, item_doc, out=None):
+	if out is None:
+		out = frappe._dict()
+
 	meta = frappe.get_meta(args.parenttype or args.doctype)
 
 	if meta.get_field("currency") or args.get('currency'):
@@ -651,17 +653,17 @@
 		if meta.get_field("currency"):
 			validate_conversion_rate(args, meta)
 
-		price_list_rate = get_price_list_rate_for(args, item_doc.name) or 0
+		price_list_rate = get_price_list_rate_for(args, item_doc.name)
 
 		# variant
-		if not price_list_rate and item_doc.variant_of:
+		if price_list_rate is None and item_doc.variant_of:
 			price_list_rate = get_price_list_rate_for(args, item_doc.variant_of)
 
 		# insert in database
-		if not price_list_rate:
+		if price_list_rate is None:
 			if args.price_list and args.rate:
 				insert_item_price(args)
-			return {}
+			return out
 
 		out.price_list_rate = flt(price_list_rate) * flt(args.plc_conversion_rate) \
 			/ flt(args.conversion_rate)
@@ -671,6 +673,8 @@
 			out.update(get_last_purchase_details(item_doc.name,
 				args.name, args.conversion_rate))
 
+	return out
+
 def insert_item_price(args):
 	"""Insert Item Price if Price List and Price List Rate are specified and currency is the same"""
 	if frappe.db.get_value("Price List", args.price_list, "currency", cache=True) == args.currency \
@@ -1073,9 +1077,8 @@
 		}
 
 def apply_price_list_on_item(args):
-	item_details = frappe._dict()
 	item_doc = frappe.get_doc("Item", args.item_code)
-	get_price_list_rate(args, item_doc, item_details)
+	item_details = get_price_list_rate(args, item_doc)
 
 	item_details.update(get_pricing_rule_for_item(args, item_details.price_list_rate))
 
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index f990ce0..eddd048 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -279,15 +279,13 @@
 			}
 
 		"""
-		self.data.setdefault(args.warehouse, frappe._dict())
-		warehouse_dict = self.data[args.warehouse]
 		previous_sle = get_previous_sle_of_current_voucher(args)
-		warehouse_dict.previous_sle = previous_sle
 
-		for key in ("qty_after_transaction", "valuation_rate", "stock_value"):
-			setattr(warehouse_dict, key, flt(previous_sle.get(key)))
-
-		warehouse_dict.update({
+		self.data[args.warehouse] = frappe._dict({
+			"previous_sle": previous_sle,
+			"qty_after_transaction": flt(previous_sle.qty_after_transaction),
+			"valuation_rate": flt(previous_sle.valuation_rate),
+			"stock_value": flt(previous_sle.stock_value),
 			"prev_stock_value": previous_sle.stock_value or 0.0,
 			"stock_queue": json.loads(previous_sle.stock_queue or "[]"),
 			"stock_value_difference": 0.0
diff --git a/erpnext/stock/utils.py b/erpnext/stock/utils.py
index b57b2aa..9f6d0a8 100644
--- a/erpnext/stock/utils.py
+++ b/erpnext/stock/utils.py
@@ -224,7 +224,7 @@
 
 def get_valuation_method(item_code):
 	"""get valuation method from item or default"""
-	val_method = frappe.db.get_value('Item', item_code, 'valuation_method')
+	val_method = frappe.db.get_value('Item', item_code, 'valuation_method', cache=True)
 	if not val_method:
 		val_method = frappe.db.get_value("Stock Settings", None, "valuation_method") or "FIFO"
 	return val_method
@@ -275,17 +275,17 @@
 	return valid_serial_nos
 
 def validate_warehouse_company(warehouse, company):
-	warehouse_company = frappe.db.get_value("Warehouse", warehouse, "company")
+	warehouse_company = frappe.db.get_value("Warehouse", warehouse, "company", cache=True)
 	if warehouse_company and warehouse_company != company:
 		frappe.throw(_("Warehouse {0} does not belong to company {1}").format(warehouse, company),
 			InvalidWarehouseCompany)
 
 def is_group_warehouse(warehouse):
-	if frappe.db.get_value("Warehouse", warehouse, "is_group"):
+	if frappe.db.get_value("Warehouse", warehouse, "is_group", cache=True):
 		frappe.throw(_("Group node warehouse is not allowed to select for transactions"))
 
 def validate_disabled_warehouse(warehouse):
-	if frappe.db.get_value("Warehouse", warehouse, "disabled"):
+	if frappe.db.get_value("Warehouse", warehouse, "disabled", cache=True):
 		frappe.throw(_("Disabled Warehouse {0} cannot be used for this transaction.").format(get_link_to_form('Warehouse', warehouse)))
 
 def update_included_uom_in_report(columns, result, include_uom, conversion_factors):
diff --git a/erpnext/support/doctype/issue/issue.py b/erpnext/support/doctype/issue/issue.py
index b9a65b6..24dadd5 100644
--- a/erpnext/support/doctype/issue/issue.py
+++ b/erpnext/support/doctype/issue/issue.py
@@ -116,6 +116,10 @@
 		}).insert(ignore_permissions=True)
 
 		return replicated_issue.name
+	
+	def reset_issue_metrics(self):
+		self.db_set("resolution_time", None)
+		self.db_set("user_resolution_time", None)
 
 def get_list_context(context=None):
 	return {
diff --git a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
index 8739cb2..cfa264f 100644
--- a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
+++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
@@ -281,15 +281,18 @@
 
 
 def get_documents_with_active_service_level_agreement():
-	if not frappe.cache().hget("service_level_agreement", "active"):
-		set_documents_with_active_service_level_agreement()
+	sla_doctypes = frappe.cache().hget("service_level_agreement", "active")
 
-	return frappe.cache().hget("service_level_agreement", "active")
+	if sla_doctypes is None:
+		return set_documents_with_active_service_level_agreement()
+
+	return sla_doctypes
 
 
 def set_documents_with_active_service_level_agreement():
 	active = [sla.document_type for sla in frappe.get_all("Service Level Agreement", fields=["document_type"])]
 	frappe.cache().hset("service_level_agreement", "active", active)
+	return active
 
 
 def apply(doc, method=None):