Merge pull request #29208 from deepeshgarg007/nil_exempt_non_gst_gstr_1

fix(India): NIL Rated, Exempted and non gst invoices in GSTR-1 report
diff --git a/erpnext/accounts/doctype/tax_withholding_rate/tax_withholding_rate.json b/erpnext/accounts/doctype/tax_withholding_rate/tax_withholding_rate.json
index d2c505c..e032bb3 100644
--- a/erpnext/accounts/doctype/tax_withholding_rate/tax_withholding_rate.json
+++ b/erpnext/accounts/doctype/tax_withholding_rate/tax_withholding_rate.json
@@ -28,14 +28,14 @@
   {
    "columns": 2,
    "fieldname": "single_threshold",
-   "fieldtype": "Currency",
+   "fieldtype": "Float",
    "in_list_view": 1,
    "label": "Single Transaction Threshold"
   },
   {
    "columns": 3,
    "fieldname": "cumulative_threshold",
-   "fieldtype": "Currency",
+   "fieldtype": "Float",
    "in_list_view": 1,
    "label": "Cumulative Transaction Threshold"
   },
@@ -59,7 +59,7 @@
  "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2021-08-31 11:42:12.213977",
+ "modified": "2022-01-13 12:04:42.904263",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Tax Withholding Rate",
@@ -68,5 +68,6 @@
  "quick_entry": 1,
  "sort_field": "modified",
  "sort_order": "DESC",
+ "states": [],
  "track_changes": 1
 }
\ No newline at end of file
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 5190f9f..fe62050 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -325,3 +325,4 @@
 erpnext.patches.v13_0.agriculture_deprecation_warning
 erpnext.patches.v14_0.delete_agriculture_doctypes
 erpnext.patches.v13_0.update_exchange_rate_settings
+erpnext.patches.v14_0.rearrange_company_fields
diff --git a/erpnext/patches/v14_0/delete_healthcare_doctypes.py b/erpnext/patches/v14_0/delete_healthcare_doctypes.py
index 28fc01b..3a4f8f5 100644
--- a/erpnext/patches/v14_0/delete_healthcare_doctypes.py
+++ b/erpnext/patches/v14_0/delete_healthcare_doctypes.py
@@ -47,3 +47,18 @@
 		frappe.delete_doc("DocType", doctype, ignore_missing=True)
 
 	frappe.delete_doc("Module Def", "Healthcare", ignore_missing=True, force=True)
+
+	custom_fields = {
+		'Sales Invoice': ['patient', 'patient_name', 'ref_practitioner'],
+		'Sales Invoice Item': ['reference_dt', 'reference_dn'],
+		'Stock Entry': ['inpatient_medication_entry'],
+		'Stock Entry Detail': ['patient', 'inpatient_medication_entry_child'],
+	}
+	for doc, fields in custom_fields.items():
+		filters = {
+			'dt': doc,
+			'fieldname': ['in', fields]
+		}
+		records = frappe.get_all('Custom Field', filters=filters, pluck='name')
+		for record in records:
+			frappe.delete_doc('Custom Field', record, ignore_missing=True, force=True)
diff --git a/erpnext/patches/v14_0/rearrange_company_fields.py b/erpnext/patches/v14_0/rearrange_company_fields.py
new file mode 100644
index 0000000..dd953ff
--- /dev/null
+++ b/erpnext/patches/v14_0/rearrange_company_fields.py
@@ -0,0 +1,31 @@
+import frappe
+from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
+
+
+def execute():
+	frappe.reload_doc('setup', 'doctype', 'company')
+
+	custom_fields = {
+		'Company': [
+			dict(fieldname='hra_section', label='HRA Settings',
+				fieldtype='Section Break', insert_after='asset_received_but_not_billed', collapsible=1),
+			dict(fieldname='basic_component', label='Basic Component',
+				fieldtype='Link', options='Salary Component', insert_after='hra_section'),
+			dict(fieldname='hra_component', label='HRA Component',
+				fieldtype='Link', options='Salary Component', insert_after='basic_component'),
+			dict(fieldname='hra_column_break', fieldtype='Column Break', insert_after='hra_component'),
+			dict(fieldname='arrear_component', label='Arrear Component',
+				fieldtype='Link', options='Salary Component', insert_after='hra_column_break'),
+			dict(fieldname='non_profit_section', label='Non Profit Settings',
+				fieldtype='Section Break', insert_after='arrear_component', collapsible=1),
+			dict(fieldname='company_80g_number', label='80G Number',
+				fieldtype='Data', insert_after='non_profit_section'),
+			dict(fieldname='with_effect_from', label='80G With Effect From',
+				fieldtype='Date', insert_after='company_80g_number'),
+			dict(fieldname='non_profit_column_break', fieldtype='Column Break', insert_after='with_effect_from'),
+			dict(fieldname='pan_details', label='PAN Number',
+				fieldtype='Data', insert_after='non_profit_column_break')
+		]
+	}
+
+	create_custom_fields(custom_fields, update=True)
\ No newline at end of file
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index c0dcb70..4b99421 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -567,16 +567,16 @@
 				fieldtype='Link', options='Salary Component', insert_after='basic_component'),
 			dict(fieldname='hra_column_break', fieldtype='Column Break', insert_after='hra_component'),
 			dict(fieldname='arrear_component', label='Arrear Component',
-				fieldtype='Link', options='Salary Component', insert_after='hra_component'),
+				fieldtype='Link', options='Salary Component', insert_after='hra_column_break'),
 			dict(fieldname='non_profit_section', label='Non Profit Settings',
-				fieldtype='Section Break', insert_after='asset_received_but_not_billed', collapsible=1),
+				fieldtype='Section Break', insert_after='arrear_component', collapsible=1),
 			dict(fieldname='company_80g_number', label='80G Number',
 				fieldtype='Data', insert_after='non_profit_section'),
 			dict(fieldname='with_effect_from', label='80G With Effect From',
 				fieldtype='Date', insert_after='company_80g_number'),
 			dict(fieldname='non_profit_column_break', fieldtype='Column Break', insert_after='with_effect_from'),
 			dict(fieldname='pan_details', label='PAN Number',
-				fieldtype='Data', insert_after='with_effect_from')
+				fieldtype='Data', insert_after='non_profit_column_break')
 		],
 		'Employee Tax Exemption Declaration':[
 			dict(fieldname='hra_section', label='HRA Exemption',
diff --git a/erpnext/support/doctype/service_level_agreement/service_level_agreement.js b/erpnext/support/doctype/service_level_agreement/service_level_agreement.js
index bfbffe2..4dbb0e7 100644
--- a/erpnext/support/doctype/service_level_agreement/service_level_agreement.js
+++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement.js
@@ -111,6 +111,7 @@
 				filters: [
 					['DocType', 'issingle', '=', 0],
 					['DocType', 'istable', '=', 0],
+					['DocType', 'is_submittable', '=', 0],
 					['DocType', 'name', 'not in', invalid_doctypes],
 					['DocType', 'module', 'not in', ["Email", "Core", "Custom", "Event Streaming", "Social", "Data Migration", "Geo", "Desk"]]
 				]
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 ea617fd..de8f506 100644
--- a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
+++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
@@ -29,6 +29,7 @@
 
 class ServiceLevelAgreement(Document):
 	def validate(self):
+		self.validate_selected_doctype()
 		self.validate_doc()
 		self.validate_status_field()
 		self.check_priorities()
@@ -106,6 +107,23 @@
 			frappe.throw(_("Service Level Agreement for {0} {1} already exists.").format(
 				frappe.bold(self.entity_type), frappe.bold(self.entity)))
 
+	def validate_selected_doctype(self):
+		invalid_doctypes = list(frappe.model.core_doctypes_list)
+		invalid_doctypes.extend(['Cost Center', 'Company'])
+		valid_document_types = frappe.get_all('DocType', {
+			'issingle': 0,
+			'istable': 0,
+			'is_submittable': 0,
+			'name': ['not in', invalid_doctypes],
+			'module': ['not in', ["Email", "Core", "Custom", "Event Streaming", "Social", "Data Migration", "Geo", "Desk"]]
+		}, pluck="name")
+
+		if self.document_type not in valid_document_types:
+			frappe.throw(
+				msg=_("Please select valid document type."),
+				title=_("Invalid Document Type")
+			)
+
 	def validate_status_field(self):
 		meta = frappe.get_meta(self.document_type)
 		if not meta.get_field("status"):
@@ -247,9 +265,15 @@
 		]
 
 	customer = doc.get('customer')
-	or_filters.append(
-		["Service Level Agreement", "entity", "in", [customer] + get_customer_group(customer) + get_customer_territory(customer)]
-	)
+	if customer:
+		or_filters.extend([
+			["Service Level Agreement", "entity", "in", [customer] + get_customer_group(customer) + get_customer_territory(customer)],
+			["Service Level Agreement", "entity_type", "is", "not set"]
+		])
+	else:
+		or_filters.append(
+			["Service Level Agreement", "entity_type", "is", "not set"]
+		)
 
 	default_sla_filter = filters + [["Service Level Agreement", "default_service_level_agreement", "=", 1]]
 	default_sla = frappe.get_all("Service Level Agreement", filters=default_sla_filter,
@@ -361,11 +385,18 @@
 	sla = get_active_service_level_agreement_for(doc)
 
 	if not sla:
+		remove_sla_if_applied(doc)
 		return
 
 	process_sla(doc, sla)
 
 
+def remove_sla_if_applied(doc):
+	doc.service_level_agreement = None
+	doc.response_by = None
+	doc.resolution_by = None
+
+
 def process_sla(doc, sla):
 
 	if not doc.creation:
diff --git a/erpnext/support/doctype/service_level_agreement/service_level_agreement_dashboard.py b/erpnext/support/doctype/service_level_agreement/service_level_agreement_dashboard.py
deleted file mode 100644
index 22e2c37..0000000
--- a/erpnext/support/doctype/service_level_agreement/service_level_agreement_dashboard.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from frappe import _
-
-
-def get_data():
-	return {
-		'fieldname': 'service_level_agreement',
-		'transactions': [
-			{
-				'label': _('Issue'),
-				'items': ['Issue']
-			}
-		]
-	}
diff --git a/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py b/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py
index b07c862..a34124f 100644
--- a/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py
+++ b/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py
@@ -244,6 +244,13 @@
 		applied_sla = frappe.db.get_value('Lead', lead.name, 'service_level_agreement')
 		self.assertEqual(applied_sla, lead_sla.name)
 
+		# check if SLA is removed if condition fails
+		lead.reload()
+		lead.source = None
+		lead.save()
+		applied_sla = frappe.db.get_value('Lead', lead.name, 'service_level_agreement')
+		self.assertFalse(applied_sla)
+
 	def tearDown(self):
 		for d in frappe.get_all("Service Level Agreement"):
 			frappe.delete_doc("Service Level Agreement", d.name, force=1)