Merge branch 'develop' into exit-interview
diff --git a/erpnext/accounts/deferred_revenue.py b/erpnext/accounts/deferred_revenue.py
index 5df8269..22c81dd 100644
--- a/erpnext/accounts/deferred_revenue.py
+++ b/erpnext/accounts/deferred_revenue.py
@@ -374,12 +374,13 @@
 			frappe.db.commit()
 		except Exception as e:
 			if frappe.flags.in_test:
+				traceback = frappe.get_traceback()
+				frappe.log_error(title=_('Error while processing deferred accounting for Invoice {0}').format(doc.name), message=traceback)
 				raise e
 			else:
 				frappe.db.rollback()
 				traceback = frappe.get_traceback()
-				frappe.log_error(message=traceback)
-
+				frappe.log_error(title=_('Error while processing deferred accounting for Invoice {0}').format(doc.name), message=traceback)
 				frappe.flags.deferred_accounting_error = True
 
 def send_mail(deferred_process):
@@ -446,10 +447,12 @@
 
 		if submit:
 			journal_entry.submit()
+
+		frappe.db.commit()
 	except Exception:
 		frappe.db.rollback()
 		traceback = frappe.get_traceback()
-		frappe.log_error(message=traceback)
+		frappe.log_error(title=_('Error while processing deferred accounting for Invoice {0}').format(doc.name), message=traceback)
 
 		frappe.flags.deferred_accounting_error = True
 
diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py
index ca10b1d..874fb63 100644
--- a/erpnext/assets/doctype/asset/depreciation.py
+++ b/erpnext/assets/doctype/asset/depreciation.py
@@ -57,8 +57,10 @@
 			je.finance_book = d.finance_book
 			je.remark = "Depreciation Entry against {0} worth {1}".format(asset_name, d.depreciation_amount)
 
+			credit_account, debit_account = get_credit_and_debit_accounts(accumulated_depreciation_account, depreciation_expense_account)
+
 			credit_entry = {
-				"account": accumulated_depreciation_account,
+				"account": credit_account,
 				"credit_in_account_currency": d.depreciation_amount,
 				"reference_type": "Asset",
 				"reference_name": asset.name,
@@ -66,7 +68,7 @@
 			}
 
 			debit_entry = {
-				"account": depreciation_expense_account,
+				"account": debit_account,
 				"debit_in_account_currency": d.depreciation_amount,
 				"reference_type": "Asset",
 				"reference_name": asset.name,
@@ -132,6 +134,20 @@
 
 	return fixed_asset_account, accumulated_depreciation_account, depreciation_expense_account
 
+def get_credit_and_debit_accounts(accumulated_depreciation_account, depreciation_expense_account):
+	root_type = frappe.get_value("Account", depreciation_expense_account, "root_type")
+
+	if root_type == "Expense":
+		credit_account = accumulated_depreciation_account
+		debit_account = depreciation_expense_account
+	elif root_type == "Income":
+		credit_account = depreciation_expense_account
+		debit_account = accumulated_depreciation_account
+	else:
+		frappe.throw(_("Depreciation Expense Account should be an Income or Expense Account."))
+
+	return credit_account, debit_account
+
 @frappe.whitelist()
 def scrap_asset(asset_name):
 	asset = frappe.get_doc("Asset", asset_name)
diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py
index 0e8ceb5..ce2cb01 100644
--- a/erpnext/assets/doctype/asset/test_asset.py
+++ b/erpnext/assets/doctype/asset/test_asset.py
@@ -868,6 +868,72 @@
 		self.assertFalse(asset.schedules[1].journal_entry)
 		self.assertFalse(asset.schedules[2].journal_entry)
 
+	def test_depr_entry_posting_when_depr_expense_account_is_an_expense_account(self):
+		"""Tests if the Depreciation Expense Account gets debited and the Accumulated Depreciation Account gets credited when the former's an Expense Account."""
+
+		asset = create_asset(
+			item_code = "Macbook Pro",
+			calculate_depreciation = 1,
+			available_for_use_date = "2019-12-31",
+			depreciation_start_date = "2020-12-31",
+			frequency_of_depreciation = 12,
+			total_number_of_depreciations = 3,
+			expected_value_after_useful_life = 10000,
+			submit = 1
+		)
+
+		post_depreciation_entries(date="2021-06-01")
+		asset.load_from_db()
+
+		je = frappe.get_doc("Journal Entry", asset.schedules[0].journal_entry)
+		accounting_entries = [{"account": entry.account, "debit": entry.debit, "credit": entry.credit} for entry in je.accounts]
+
+		for entry in accounting_entries:
+			if entry["account"] == "_Test Depreciations - _TC":
+				self.assertTrue(entry["debit"])
+				self.assertFalse(entry["credit"])
+			else:
+				self.assertTrue(entry["credit"])
+				self.assertFalse(entry["debit"])
+
+	def test_depr_entry_posting_when_depr_expense_account_is_an_income_account(self):
+		"""Tests if the Depreciation Expense Account gets credited and the Accumulated Depreciation Account gets debited when the former's an Income Account."""
+
+		depr_expense_account = frappe.get_doc("Account", "_Test Depreciations - _TC")
+		depr_expense_account.root_type = "Income"
+		depr_expense_account.parent_account = "Income - _TC"
+		depr_expense_account.save()
+
+		asset = create_asset(
+			item_code = "Macbook Pro",
+			calculate_depreciation = 1,
+			available_for_use_date = "2019-12-31",
+			depreciation_start_date = "2020-12-31",
+			frequency_of_depreciation = 12,
+			total_number_of_depreciations = 3,
+			expected_value_after_useful_life = 10000,
+			submit = 1
+		)
+
+		post_depreciation_entries(date="2021-06-01")
+		asset.load_from_db()
+
+		je = frappe.get_doc("Journal Entry", asset.schedules[0].journal_entry)
+		accounting_entries = [{"account": entry.account, "debit": entry.debit, "credit": entry.credit} for entry in je.accounts]
+
+		for entry in accounting_entries:
+			if entry["account"] == "_Test Depreciations - _TC":
+				self.assertTrue(entry["credit"])
+				self.assertFalse(entry["debit"])
+			else:
+				self.assertTrue(entry["debit"])
+				self.assertFalse(entry["credit"])
+
+		# resetting
+		depr_expense_account.root_type = "Expense"
+		depr_expense_account.parent_account = "Expenses - _TC"
+		depr_expense_account.save()
+
 	def test_clear_depreciation_schedule(self):
 		"""Tests if clear_depreciation_schedule() works as expected."""
 
diff --git a/erpnext/assets/doctype/asset_category/asset_category.js b/erpnext/assets/doctype/asset_category/asset_category.js
index 51ce157..c702687 100644
--- a/erpnext/assets/doctype/asset_category/asset_category.js
+++ b/erpnext/assets/doctype/asset_category/asset_category.js
@@ -33,7 +33,7 @@
 			var d  = locals[cdt][cdn];
 			return {
 				"filters": {
-					"root_type": "Expense",
+					"root_type": ["in", ["Expense", "Income"]],
 					"is_group": 0,
 					"company": d.company_name
 				}
diff --git a/erpnext/assets/doctype/asset_category/asset_category.py b/erpnext/assets/doctype/asset_category/asset_category.py
index e2f3ca3..bd573bf 100644
--- a/erpnext/assets/doctype/asset_category/asset_category.py
+++ b/erpnext/assets/doctype/asset_category/asset_category.py
@@ -42,10 +42,10 @@
 
 	def validate_account_types(self):
 		account_type_map = {
-			'fixed_asset_account': { 'account_type': 'Fixed Asset' },
-			'accumulated_depreciation_account': { 'account_type': 'Accumulated Depreciation' },
-			'depreciation_expense_account': { 'root_type': 'Expense' },
-			'capital_work_in_progress_account': { 'account_type': 'Capital Work in Progress' }
+			'fixed_asset_account': {'account_type': ['Fixed Asset']},
+			'accumulated_depreciation_account': {'account_type': ['Accumulated Depreciation']},
+			'depreciation_expense_account': {'root_type': ['Expense', 'Income']},
+			'capital_work_in_progress_account': {'account_type': ['Capital Work in Progress']}
 		}
 		for d in self.accounts:
 			for fieldname in account_type_map.keys():
@@ -53,11 +53,11 @@
 					selected_account = d.get(fieldname)
 					key_to_match = next(iter(account_type_map.get(fieldname))) # acount_type or root_type
 					selected_key_type = frappe.db.get_value('Account', selected_account, key_to_match)
-					expected_key_type = account_type_map[fieldname][key_to_match]
+					expected_key_types = account_type_map[fieldname][key_to_match]
 
-					if selected_key_type != expected_key_type:
+					if selected_key_type not in expected_key_types:
 						frappe.throw(_("Row #{}: {} of {} should be {}. Please modify the account or select a different account.")
-							.format(d.idx, frappe.unscrub(key_to_match), frappe.bold(selected_account), frappe.bold(expected_key_type)),
+							.format(d.idx, frappe.unscrub(key_to_match), frappe.bold(selected_account), frappe.bold(expected_key_types)),
 							title=_("Invalid Account"))
 
 	def valide_cwip_account(self):
diff --git a/erpnext/crm/doctype/crm_settings/__init__.py b/erpnext/crm/doctype/crm_settings/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/crm/doctype/crm_settings/__init__.py
diff --git a/erpnext/crm/doctype/crm_settings/crm_settings.js b/erpnext/crm/doctype/crm_settings/crm_settings.js
new file mode 100644
index 0000000..c6569d8
--- /dev/null
+++ b/erpnext/crm/doctype/crm_settings/crm_settings.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('CRM Settings', {
+	// refresh: function(frm) {
+
+	// }
+});
diff --git a/erpnext/crm/doctype/crm_settings/crm_settings.json b/erpnext/crm/doctype/crm_settings/crm_settings.json
new file mode 100644
index 0000000..95b19fa
--- /dev/null
+++ b/erpnext/crm/doctype/crm_settings/crm_settings.json
@@ -0,0 +1,114 @@
+{
+ "actions": [],
+ "creation": "2021-09-09 17:03:22.754446",
+ "description": "Settings for Selling Module",
+ "doctype": "DocType",
+ "document_type": "Other",
+ "engine": "InnoDB",
+ "field_order": [
+  "section_break_5",
+  "campaign_naming_by",
+  "allow_lead_duplication_based_on_emails",
+  "column_break_4",
+  "create_event_on_next_contact_date",
+  "auto_creation_of_contact",
+  "opportunity_section",
+  "close_opportunity_after_days",
+  "column_break_9",
+  "create_event_on_next_contact_date_opportunity",
+  "quotation_section",
+  "default_valid_till"
+ ],
+ "fields": [
+  {
+   "fieldname": "campaign_naming_by",
+   "fieldtype": "Select",
+   "in_list_view": 1,
+   "label": "Campaign Naming By",
+   "options": "Campaign Name\nNaming Series"
+  },
+  {
+   "fieldname": "column_break_9",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "default_valid_till",
+   "fieldtype": "Data",
+   "label": "Default Quotation Validity Days"
+  },
+  {
+   "fieldname": "section_break_5",
+   "fieldtype": "Section Break",
+   "label": "Lead"
+  },
+  {
+   "default": "0",
+   "fieldname": "allow_lead_duplication_based_on_emails",
+   "fieldtype": "Check",
+   "label": "Allow Lead Duplication based on Emails"
+  },
+  {
+   "default": "1",
+   "fieldname": "auto_creation_of_contact",
+   "fieldtype": "Check",
+   "label": "Auto Creation of Contact"
+  },
+  {
+   "default": "1",
+   "fieldname": "create_event_on_next_contact_date",
+   "fieldtype": "Check",
+   "label": "Create Event on Next Contact Date"
+  },
+  {
+   "fieldname": "opportunity_section",
+   "fieldtype": "Section Break",
+   "label": "Opportunity"
+  },
+  {
+   "default": "15",
+   "description": "Auto close Opportunity Replied after the no. of days mentioned above",
+   "fieldname": "close_opportunity_after_days",
+   "fieldtype": "Int",
+   "label": "Close Replied Opportunity After Days"
+  },
+  {
+   "default": "1",
+   "fieldname": "create_event_on_next_contact_date_opportunity",
+   "fieldtype": "Check",
+   "label": "Create Event on Next Contact Date"
+  },
+  {
+   "fieldname": "column_break_4",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "quotation_section",
+   "fieldtype": "Section Break",
+   "label": "Quotation"
+  }
+ ],
+ "icon": "fa fa-cog",
+ "index_web_pages_for_search": 1,
+ "issingle": 1,
+ "links": [],
+ "migration_hash": "3ae78b12dd1c64d551736c6e82092f90",
+ "modified": "2021-11-03 09:00:36.883496",
+ "modified_by": "Administrator",
+ "module": "CRM",
+ "name": "CRM Settings",
+ "owner": "Administrator",
+ "permissions": [
+  {
+   "create": 1,
+   "email": 1,
+   "print": 1,
+   "read": 1,
+   "role": "System Manager",
+   "share": 1,
+   "write": 1
+  }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/crm/doctype/crm_settings/crm_settings.py b/erpnext/crm/doctype/crm_settings/crm_settings.py
new file mode 100644
index 0000000..bde5254
--- /dev/null
+++ b/erpnext/crm/doctype/crm_settings/crm_settings.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+# import frappe
+from frappe.model.document import Document
+
+
+class CRMSettings(Document):
+	pass
diff --git a/erpnext/crm/doctype/crm_settings/test_crm_settings.py b/erpnext/crm/doctype/crm_settings/test_crm_settings.py
new file mode 100644
index 0000000..3372c5d
--- /dev/null
+++ b/erpnext/crm/doctype/crm_settings/test_crm_settings.py
@@ -0,0 +1,9 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+
+# import frappe
+import unittest
+
+
+class TestCRMSettings(unittest.TestCase):
+	pass
diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py
index c590523..9adbe8b 100644
--- a/erpnext/crm/doctype/lead/lead.py
+++ b/erpnext/crm/doctype/lead/lead.py
@@ -11,6 +11,7 @@
 	cint,
 	comma_and,
 	cstr,
+	get_link_to_form,
 	getdate,
 	has_gravatar,
 	nowdate,
@@ -91,13 +92,14 @@
 			self.contact_doc.save()
 
 	def add_calendar_event(self, opts=None, force=False):
-		super(Lead, self).add_calendar_event({
-			"owner": self.lead_owner,
-			"starts_on": self.contact_date,
-			"ends_on": self.ends_on or "",
-			"subject": ('Contact ' + cstr(self.lead_name)),
-			"description": ('Contact ' + cstr(self.lead_name)) + (self.contact_by and ('. By : ' + cstr(self.contact_by)) or '')
-		}, force)
+		if frappe.db.get_single_value('CRM Settings', 'create_event_on_next_contact_date'):
+			super(Lead, self).add_calendar_event({
+				"owner": self.lead_owner,
+				"starts_on": self.contact_date,
+				"ends_on": self.ends_on or "",
+				"subject": ('Contact ' + cstr(self.lead_name)),
+				"description": ('Contact ' + cstr(self.lead_name)) + (self.contact_by and ('. By : ' + cstr(self.contact_by)) or '')
+			}, force)
 
 	def update_prospects(self):
 		prospects = frappe.get_all('Prospect Lead', filters={'lead': self.name}, fields=['parent'])
@@ -108,12 +110,13 @@
 	def check_email_id_is_unique(self):
 		if self.email_id:
 			# validate email is unique
-			duplicate_leads = frappe.get_all("Lead", filters={"email_id": self.email_id, "name": ["!=", self.name]})
-			duplicate_leads = [lead.name for lead in duplicate_leads]
+			if not frappe.db.get_single_value('CRM Settings', 'allow_lead_duplication_based_on_emails'):
+				duplicate_leads = frappe.get_all("Lead", filters={"email_id": self.email_id, "name": ["!=", self.name]})
+				duplicate_leads = [frappe.bold(get_link_to_form('Lead', lead.name)) for lead in duplicate_leads]
 
-			if duplicate_leads:
-				frappe.throw(_("Email Address must be unique, already exists for {0}")
-					.format(comma_and(duplicate_leads)), frappe.DuplicateEntryError)
+				if duplicate_leads:
+					frappe.throw(_("Email Address must be unique, already exists for {0}")
+						.format(comma_and(duplicate_leads)), frappe.DuplicateEntryError)
 
 	def on_trash(self):
 		frappe.db.sql("""update `tabIssue` set lead='' where lead=%s""", self.name)
@@ -172,41 +175,42 @@
 		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()
+		if frappe.db.get_single_value('CRM Settings', 'auto_creation_of_contact'):
+			if not self.lead_name:
+				self.set_full_name()
+				self.set_lead_name()
 
-		contact = frappe.new_doc("Contact")
-		contact.update({
-			"first_name": self.first_name or self.lead_name,
-			"last_name": self.last_name,
-			"salutation": self.salutation,
-			"gender": self.gender,
-			"designation": self.designation,
-			"company_name": self.company_name,
-		})
-
-		if self.email_id:
-			contact.append("email_ids", {
-				"email_id": self.email_id,
-				"is_primary": 1
+			contact = frappe.new_doc("Contact")
+			contact.update({
+				"first_name": self.first_name or self.lead_name,
+				"last_name": self.last_name,
+				"salutation": self.salutation,
+				"gender": self.gender,
+				"designation": self.designation,
+				"company_name": self.company_name,
 			})
 
-		if self.phone:
-			contact.append("phone_nos", {
-				"phone": self.phone,
-				"is_primary_phone": 1
-			})
+			if self.email_id:
+				contact.append("email_ids", {
+					"email_id": self.email_id,
+					"is_primary": 1
+				})
 
-		if self.mobile_no:
-			contact.append("phone_nos", {
-				"phone": self.mobile_no,
-				"is_primary_mobile_no":1
-			})
+			if self.phone:
+				contact.append("phone_nos", {
+					"phone": self.phone,
+					"is_primary_phone": 1
+				})
 
-		contact.insert(ignore_permissions=True)
+			if self.mobile_no:
+				contact.append("phone_nos", {
+					"phone": self.mobile_no,
+					"is_primary_mobile_no":1
+				})
 
-		return contact
+			contact.insert(ignore_permissions=True)
+
+			return contact
 
 @frappe.whitelist()
 def make_customer(source_name, target_doc=None):
diff --git a/erpnext/crm/doctype/opportunity/opportunity.py b/erpnext/crm/doctype/opportunity/opportunity.py
index 0bef80a..fcbd4de 100644
--- a/erpnext/crm/doctype/opportunity/opportunity.py
+++ b/erpnext/crm/doctype/opportunity/opportunity.py
@@ -8,6 +8,7 @@
 from frappe import _
 from frappe.email.inbox import link_communication_to_document
 from frappe.model.mapper import get_mapped_doc
+from frappe.query_builder import DocType
 from frappe.utils import cint, cstr, flt, get_fullname
 
 from erpnext.setup.utils import get_exchange_rate
@@ -28,7 +29,6 @@
 		})
 
 		self.make_new_lead_if_required()
-
 		self.validate_item_details()
 		self.validate_uom_is_integer("uom", "qty")
 		self.validate_cust_name()
@@ -70,21 +70,21 @@
 		"""Set lead against new opportunity"""
 		if (not self.get("party_name")) and self.contact_email:
 			# check if customer is already created agains the self.contact_email
-			customer = frappe.db.sql("""select
-				distinct `tabDynamic Link`.link_name as customer
-				from
-					`tabContact`,
-					`tabDynamic Link`
-				where `tabContact`.email_id='{0}'
-				and
-					`tabContact`.name=`tabDynamic Link`.parent
-				and
-					ifnull(`tabDynamic Link`.link_name, '')<>''
-				and
-					`tabDynamic Link`.link_doctype='Customer'
-			""".format(self.contact_email), as_dict=True)
-			if customer and customer[0].customer:
-				self.party_name = customer[0].customer
+			dynamic_link, contact = DocType("Dynamic Link"), DocType("Contact")
+			customer = frappe.qb.from_(
+				dynamic_link
+			).join(
+				contact
+			).on(
+				(contact.name == dynamic_link.parent)
+				& (dynamic_link.link_doctype == "Customer")
+				& (contact.email_id == self.contact_email)
+			).select(
+				dynamic_link.link_name
+			).distinct().run(as_dict=True)
+
+			if customer and customer[0].link_name:
+				self.party_name = customer[0].link_name
 				self.opportunity_from = "Customer"
 				return
 
@@ -191,30 +191,31 @@
 		self.add_calendar_event()
 
 	def add_calendar_event(self, opts=None, force=False):
-		if not opts:
-			opts = frappe._dict()
+		if frappe.db.get_single_value('CRM Settings', 'create_event_on_next_contact_date_opportunity'):
+			if not opts:
+				opts = frappe._dict()
 
-		opts.description = ""
-		opts.contact_date = self.contact_date
+			opts.description = ""
+			opts.contact_date = self.contact_date
 
-		if self.party_name and self.opportunity_from == 'Customer':
-			if self.contact_person:
-				opts.description = 'Contact '+cstr(self.contact_person)
-			else:
-				opts.description = 'Contact customer '+cstr(self.party_name)
-		elif self.party_name and self.opportunity_from == 'Lead':
-			if self.contact_display:
-				opts.description = 'Contact '+cstr(self.contact_display)
-			else:
-				opts.description = 'Contact lead '+cstr(self.party_name)
+			if self.party_name and self.opportunity_from == 'Customer':
+				if self.contact_person:
+					opts.description = 'Contact '+cstr(self.contact_person)
+				else:
+					opts.description = 'Contact customer '+cstr(self.party_name)
+			elif self.party_name and self.opportunity_from == 'Lead':
+				if self.contact_display:
+					opts.description = 'Contact '+cstr(self.contact_display)
+				else:
+					opts.description = 'Contact lead '+cstr(self.party_name)
 
-		opts.subject = opts.description
-		opts.description += '. By : ' + cstr(self.contact_by)
+			opts.subject = opts.description
+			opts.description += '. By : ' + cstr(self.contact_by)
 
-		if self.to_discuss:
-			opts.description += ' To Discuss : ' + cstr(self.to_discuss)
+			if self.to_discuss:
+				opts.description += ' To Discuss : ' + cstr(self.to_discuss)
 
-		super(Opportunity, self).add_calendar_event(opts, force)
+			super(Opportunity, self).add_calendar_event(opts, force)
 
 	def validate_item_details(self):
 		if not self.get('items'):
@@ -363,7 +364,7 @@
 
 def auto_close_opportunity():
 	""" auto close the `Replied` Opportunities after 7 days """
-	auto_close_after_days = frappe.db.get_single_value("Selling Settings", "close_opportunity_after_days") or 15
+	auto_close_after_days = frappe.db.get_single_value("CRM Settings", "close_opportunity_after_days") or 15
 
 	opportunities = frappe.db.sql(""" select name from tabOpportunity where status='Replied' and
 		modified<DATE_SUB(CURDATE(), INTERVAL %s DAY) """, (auto_close_after_days), as_dict=True)
diff --git a/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.json b/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.json
index 23ccb7e..ae1f36e 100644
--- a/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.json
+++ b/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.json
@@ -20,7 +20,6 @@
   "configuration_cb",
   "shipping_account_head",
   "section_break_12",
-  "nexus_address",
   "nexus"
  ],
  "fields": [
@@ -87,16 +86,12 @@
    "fieldtype": "Column Break"
   },
   {
+   "depends_on": "nexus",
    "fieldname": "section_break_12",
    "fieldtype": "Section Break",
    "label": "Nexus List"
   },
   {
-   "fieldname": "nexus_address",
-   "fieldtype": "HTML",
-   "label": "Nexus Address"
-  },
-  {
    "fieldname": "nexus",
    "fieldtype": "Table",
    "label": "Nexus",
@@ -108,19 +103,20 @@
    "fieldtype": "Column Break"
   },
   {
-   "fieldname": "column_break_10",
-   "fieldtype": "Column Break"
-  },
-  {
    "fieldname": "company",
    "fieldtype": "Link",
    "label": "Company",
    "options": "Company"
+  },
+  {
+   "fieldname": "column_break_10",
+   "fieldtype": "Column Break"
   }
  ],
  "issingle": 1,
  "links": [],
- "modified": "2021-11-08 18:02:29.232090",
+ "migration_hash": "8ca1ea3309ed28547b19da8e6e27e96f",
+ "modified": "2021-11-30 11:17:24.647979",
  "modified_by": "Administrator",
  "module": "ERPNext Integrations",
  "name": "TaxJar Settings",
diff --git a/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.py b/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.py
index b9f24b6..d4bbe88 100644
--- a/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.py
+++ b/erpnext/erpnext_integrations/doctype/taxjar_settings/taxjar_settings.py
@@ -16,9 +16,9 @@
 class TaxJarSettings(Document):
 
 	def on_update(self):
-		TAXJAR_CREATE_TRANSACTIONS = frappe.db.get_single_value("TaxJar Settings", "taxjar_create_transactions")
-		TAXJAR_CALCULATE_TAX = frappe.db.get_single_value("TaxJar Settings", "taxjar_calculate_tax")
-		TAXJAR_SANDBOX_MODE = frappe.db.get_single_value("TaxJar Settings", "is_sandbox")
+		TAXJAR_CREATE_TRANSACTIONS = self.taxjar_create_transactions
+		TAXJAR_CALCULATE_TAX = self.taxjar_calculate_tax
+		TAXJAR_SANDBOX_MODE = self.is_sandbox
 
 		fields_already_exist = frappe.db.exists('Custom Field', {'dt': ('in', ['Item','Sales Invoice Item']), 'fieldname':'product_tax_category'})
 		fields_hidden = frappe.get_value('Custom Field', {'dt': ('in', ['Sales Invoice Item'])}, 'hidden')
diff --git a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py
index db126cd..2ffae1a 100644
--- a/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py
+++ b/erpnext/maintenance/doctype/maintenance_schedule/maintenance_schedule.py
@@ -323,10 +323,14 @@
 		target.maintenance_schedule = source.name
 		target.maintenance_schedule_detail = s_id
 
-	def update_sales(source, target, parent):
+	def update_sales_and_serial(source, target, parent):
 		sales_person = frappe.db.get_value('Maintenance Schedule Detail', s_id, 'sales_person')
 		target.service_person = sales_person
-		target.serial_no = ''
+		serial_nos = get_serial_nos(target.serial_no)
+		if len(serial_nos) == 1:
+			target.serial_no = serial_nos[0]
+		else:
+			target.serial_no = ''
 
 	doclist = get_mapped_doc("Maintenance Schedule", source_name, {
 		"Maintenance Schedule": {
@@ -342,7 +346,7 @@
 		"Maintenance Schedule Item": {
 			"doctype": "Maintenance Visit Purpose",
 			"condition": lambda doc: doc.item_name == item_name,
-			"postprocess": update_sales
+			"postprocess": update_sales_and_serial
 		}
 	}, target_doc)
 
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 717965a..b280247 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -278,6 +278,7 @@
 erpnext.patches.v13_0.add_custom_field_for_south_africa #2
 erpnext.patches.v13_0.update_recipient_email_digest
 erpnext.patches.v13_0.shopify_deprecation_warning
+erpnext.patches.v13_0.remove_bad_selling_defaults
 erpnext.patches.v13_0.migrate_stripe_api
 erpnext.patches.v13_0.reset_clearance_date_for_intracompany_payment_entries
 erpnext.patches.v13_0.einvoicing_deprecation_warning
@@ -312,4 +313,5 @@
 erpnext.patches.v13_0.create_pan_field_for_india #2
 erpnext.patches.v14_0.delete_hub_doctypes
 erpnext.patches.v13_0.create_ksa_vat_custom_fields
-erpnext.patches.v14_0.add_default_exit_questionnaire_notification_template
\ No newline at end of file
+erpnext.patches.v14_0.migrate_crm_settings
+erpnext.patches.v14_0.add_default_exit_questionnaire_notification_template
diff --git a/erpnext/patches/v13_0/remove_bad_selling_defaults.py b/erpnext/patches/v13_0/remove_bad_selling_defaults.py
new file mode 100644
index 0000000..5487a6c
--- /dev/null
+++ b/erpnext/patches/v13_0/remove_bad_selling_defaults.py
@@ -0,0 +1,15 @@
+import frappe
+from frappe import _
+
+
+def execute():
+	selling_settings = frappe.get_single("Selling Settings")
+
+	if selling_settings.customer_group in (_("All Customer Groups"), "All Customer Groups"):
+		selling_settings.customer_group = None
+
+	if selling_settings.territory in (_("All Territories"), "All Territories"):
+		selling_settings.territory = None
+
+	selling_settings.flags.ignore_mandatory=True
+	selling_settings.save(ignore_permissions=True)
diff --git a/erpnext/patches/v14_0/migrate_crm_settings.py b/erpnext/patches/v14_0/migrate_crm_settings.py
new file mode 100644
index 0000000..30d3ea0
--- /dev/null
+++ b/erpnext/patches/v14_0/migrate_crm_settings.py
@@ -0,0 +1,16 @@
+import frappe
+
+
+def execute():
+	settings = frappe.db.get_value('Selling Settings', 'Selling Settings', [
+		'campaign_naming_by',
+		'close_opportunity_after_days',
+		'default_valid_till'
+	], as_dict=True)
+
+	frappe.reload_doc('crm', 'doctype', 'crm_settings')
+	frappe.db.set_value('CRM Settings', 'CRM Settings', {
+		'campaign_naming_by': settings.campaign_naming_by,
+		'close_opportunity_after_days': settings.close_opportunity_after_days,
+		'default_valid_till': settings.default_valid_till
+	})
diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.json b/erpnext/selling/doctype/selling_settings/selling_settings.json
index c27f1ea..27bc541 100644
--- a/erpnext/selling/doctype/selling_settings/selling_settings.json
+++ b/erpnext/selling/doctype/selling_settings/selling_settings.json
@@ -11,11 +11,6 @@
   "customer_group",
   "column_break_4",
   "territory",
-  "crm_settings_section",
-  "campaign_naming_by",
-  "default_valid_till",
-  "column_break_9",
-  "close_opportunity_after_days",
   "item_price_settings_section",
   "selling_price_list",
   "maintain_same_rate_action",
@@ -44,13 +39,6 @@
    "options": "Customer Name\nNaming Series\nAuto Name"
   },
   {
-   "fieldname": "campaign_naming_by",
-   "fieldtype": "Select",
-   "in_list_view": 1,
-   "label": "Campaign Naming By",
-   "options": "Campaign Name\nNaming Series\nAuto Name"
-  },
-  {
    "fieldname": "customer_group",
    "fieldtype": "Link",
    "in_list_view": 1,
@@ -72,18 +60,6 @@
    "options": "Price List"
   },
   {
-   "default": "15",
-   "description": "Auto close Opportunity after the no. of days mentioned above",
-   "fieldname": "close_opportunity_after_days",
-   "fieldtype": "Int",
-   "label": "Close Opportunity After Days"
-  },
-  {
-   "fieldname": "default_valid_till",
-   "fieldtype": "Data",
-   "label": "Default Quotation Validity Days"
-  },
-  {
    "fieldname": "column_break_5",
    "fieldtype": "Column Break"
   },
@@ -170,15 +146,6 @@
    "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"
@@ -204,7 +171,7 @@
  "index_web_pages_for_search": 1,
  "issingle": 1,
  "links": [],
- "modified": "2021-09-08 19:38:10.175989",
+ "modified": "2021-09-13 12:32:17.004404",
  "modified_by": "Administrator",
  "module": "Selling",
  "name": "Selling Settings",
diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.py b/erpnext/selling/doctype/selling_settings/selling_settings.py
index e7c5e76..fb86e61 100644
--- a/erpnext/selling/doctype/selling_settings/selling_settings.py
+++ b/erpnext/selling/doctype/selling_settings/selling_settings.py
@@ -8,7 +8,6 @@
 from frappe.custom.doctype.property_setter.property_setter import make_property_setter
 from frappe.model.document import Document
 from frappe.utils import cint
-from frappe.utils.nestedset import get_root_of
 
 
 class SellingSettings(Document):
@@ -37,9 +36,3 @@
 		editable_bundle_item_rates = cint(self.editable_bundle_item_rates)
 
 		make_property_setter("Packed Item", "rate", "read_only", not(editable_bundle_item_rates), "Check", validate_fields_for_doctype=False)
-
-	def set_default_customer_group_and_territory(self):
-		if not self.customer_group:
-			self.customer_group = get_root_of('Customer Group')
-		if not self.territory:
-			self.territory = get_root_of('Territory')
diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py
index 323a794..97d850b 100644
--- a/erpnext/setup/setup_wizard/operations/install_fixtures.py
+++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py
@@ -308,7 +308,6 @@
 
 def update_selling_defaults():
 	selling_settings = frappe.get_doc("Selling Settings")
-	selling_settings.set_default_customer_group_and_territory()
 	selling_settings.cust_master_name = "Customer Name"
 	selling_settings.so_required = "No"
 	selling_settings.dn_required = "No"
diff --git a/erpnext/setup/utils.py b/erpnext/setup/utils.py
index 1478007..cad4c54 100644
--- a/erpnext/setup/utils.py
+++ b/erpnext/setup/utils.py
@@ -53,6 +53,7 @@
 
 	frappe.db.set_value("Stock Settings", None, "auto_insert_price_list_rate_if_missing", 0)
 	enable_all_roles_and_domains()
+	set_defaults_for_tests()
 
 	frappe.db.commit()
 
@@ -127,6 +128,14 @@
 		[d.name for d in domains])
 	add_all_roles_to('Administrator')
 
+def set_defaults_for_tests():
+	from frappe.utils.nestedset import get_root_of
+
+	selling_settings = frappe.get_single("Selling Settings")
+	selling_settings.customer_group = get_root_of("Customer Group")
+	selling_settings.territory = get_root_of("Territory")
+	selling_settings.save()
+
 
 def insert_record(records):
 	for r in records:
diff --git a/erpnext/setup/workspace/erpnext_settings/erpnext_settings.json b/erpnext/setup/workspace/erpnext_settings/erpnext_settings.json
index 1412acf..e47837f 100644
--- a/erpnext/setup/workspace/erpnext_settings/erpnext_settings.json
+++ b/erpnext/setup/workspace/erpnext_settings/erpnext_settings.json
@@ -10,7 +10,7 @@
  "idx": 0,
  "label": "ERPNext Settings",
  "links": [],
- "modified": "2021-10-26 21:32:55.323591",
+ "modified": "2021-11-05 21:32:55.323591",
  "modified_by": "Administrator",
  "module": "Setup",
  "name": "ERPNext Settings",
@@ -123,6 +123,13 @@
    "label": "Products Settings",
    "link_to": "Products Settings",
    "type": "DocType"
+  },
+  {
+   "doc_view": "",
+   "icon": "crm",
+   "label": "CRM Settings",
+   "link_to": "CRM Settings",
+   "type": "DocType"
   }
  ],
  "title": "ERPNext Settings"
diff --git a/erpnext/startup/boot.py b/erpnext/startup/boot.py
index ed8c878..0da45a5 100644
--- a/erpnext/startup/boot.py
+++ b/erpnext/startup/boot.py
@@ -22,7 +22,7 @@
 			'customer_group')
 		bootinfo.sysdefaults.allow_stale = cint(frappe.db.get_single_value('Accounts Settings',
 			'allow_stale'))
-		bootinfo.sysdefaults.quotation_valid_till = cint(frappe.db.get_single_value('Selling Settings',
+		bootinfo.sysdefaults.quotation_valid_till = cint(frappe.db.get_single_value('CRM Settings',
 			'default_valid_till'))
 
 		# if no company, show a dialog box to create a new company
diff --git a/erpnext/stock/doctype/item/test_item.py b/erpnext/stock/doctype/item/test_item.py
index 8b1224b..4028d93 100644
--- a/erpnext/stock/doctype/item/test_item.py
+++ b/erpnext/stock/doctype/item/test_item.py
@@ -534,8 +534,6 @@
 
 	def test_index_creation(self):
 		"check if index is getting created in db"
-		from erpnext.stock.doctype.item.item import on_doctype_update
-		on_doctype_update()
 
 		indices = frappe.db.sql("show index from tabItem", as_dict=1)
 		expected_columns = {"item_code", "item_name", "item_group", "route"}