Merge branch 'develop' into serial-no-space
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/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/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/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index bf4ab1a..9e2e596 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -1507,7 +1507,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 +1530,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/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/patches.txt b/erpnext/patches.txt
index 04f05ed..35b248c 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -294,7 +294,8 @@
 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.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/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/regional/india/e_invoice/utils.py b/erpnext/regional/india/e_invoice/utils.py
index f497613..4276946 100644
--- a/erpnext/regional/india/e_invoice/utils.py
+++ b/erpnext/regional/india/e_invoice/utils.py
@@ -928,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')
@@ -1126,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/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/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/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..128a2ab 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,38 @@
 			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."
+		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)
+
+		frappe.db.set_value("Company", pr.company, "capital_work_in_progress_account", "CWIP Account - _TC")
+		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 +301,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 bb4a710..d40d781 100644
--- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
+++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py
@@ -324,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/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):