refactor!: Removed healthcare module from ERPNext (#27362)

* chore: Removed healthcare module

* chore: Removed healthcare demo, patch files

* chore: Rename imports from erpnext to healthcare

* chore: Added healthcare deprecation warning patch

* chore: Removed healthcare module code in other modules

* chore: Code clean up

* refactor: Remove sales invoice custom js related to healthcare

* fix: sider

Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
diff --git a/erpnext/accounts/doctype/account/account_tree.js b/erpnext/accounts/doctype/account/account_tree.js
index 7516134..a4b6e0b 100644
--- a/erpnext/accounts/doctype/account/account_tree.js
+++ b/erpnext/accounts/doctype/account/account_tree.js
@@ -45,6 +45,49 @@
 	],
 	root_label: "Accounts",
 	get_tree_nodes: 'erpnext.accounts.utils.get_children',
+	on_get_node: function(nodes, deep=false) {
+		if (frappe.boot.user.can_read.indexOf("GL Entry") == -1) return;
+
+		let accounts = [];
+		if (deep) {
+			// in case of `get_all_nodes`
+			accounts = nodes.reduce((acc, node) => [...acc, ...node.data], []);
+		} else {
+			accounts = nodes;
+		}
+
+		const get_balances = frappe.call({
+			method: 'erpnext.accounts.utils.get_account_balances',
+			args: {
+				accounts: accounts,
+				company: cur_tree.args.company
+			},
+		});
+
+		get_balances.then(r => {
+			if (!r.message || r.message.length == 0) return;
+
+			for (let account of r.message) {
+
+				const node = cur_tree.nodes && cur_tree.nodes[account.value];
+				if (!node || node.is_root) continue;
+
+				// show Dr if positive since balance is calculated as debit - credit else show Cr
+				const balance = account.balance_in_account_currency || account.balance;
+				const dr_or_cr = balance > 0 ? "Dr": "Cr";
+				const format = (value, currency) => format_currency(Math.abs(value), currency);
+
+				if (account.balance!==undefined) {
+					$('<span class="balance-area pull-right">'
+						+ (account.balance_in_account_currency ?
+							(format(account.balance_in_account_currency, account.account_currency) + " / ") : "")
+						+ format(account.balance, account.company_currency)
+						+ " " + dr_or_cr
+						+ '</span>').insertBefore(node.$ul);
+				}
+			}
+		});
+	},
 	add_tree_node: 'erpnext.accounts.utils.add_ac',
 	menu_items:[
 		{
@@ -122,24 +165,6 @@
 			}
 		}, "add");
 	},
-	onrender: function(node) {
-		if (frappe.boot.user.can_read.indexOf("GL Entry") !== -1) {
-
-			// show Dr if positive since balance is calculated as debit - credit else show Cr
-			let balance = node.data.balance_in_account_currency || node.data.balance;
-			let dr_or_cr = balance > 0 ? "Dr": "Cr";
-
-			if (node.data && node.data.balance!==undefined) {
-				$('<span class="balance-area pull-right">'
-					+ (node.data.balance_in_account_currency ?
-						(format_currency(Math.abs(node.data.balance_in_account_currency),
-							node.data.account_currency) + " / ") : "")
-					+ format_currency(Math.abs(node.data.balance), node.data.company_currency)
-					+ " " + dr_or_cr
-					+ '</span>').insertBefore(node.$ul);
-			}
-		}
-	},
 	toolbar: [
 		{
 			label:__("Add Child"),
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index a530321..8037ca1 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -390,6 +390,9 @@
 						invoice_paid_amount_map[invoice_key]['discounted_amt'] = ref.total_amount * (term.discount / 100)
 
 		for key, allocated_amount in iteritems(invoice_payment_amount_map):
+			if not invoice_paid_amount_map.get(key):
+				frappe.throw(_('Payment term {0} not used in {1}').format(key[0], key[1]))
+
 			outstanding = flt(invoice_paid_amount_map.get(key, {}).get('outstanding'))
 			discounted_amt = flt(invoice_paid_amount_map.get(key, {}).get('discounted_amt'))
 
diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py
index fbad171..fdd8d09 100644
--- a/erpnext/accounts/utils.py
+++ b/erpnext/accounts/utils.py
@@ -4,11 +4,14 @@
 
 from __future__ import unicode_literals
 
+from json import loads
+
 import frappe
 import frappe.defaults
 from frappe import _, throw
 from frappe.model.meta import get_field_precision
 from frappe.utils import cint, cstr, flt, formatdate, get_number_format_info, getdate, now, nowdate
+from six import string_types
 
 import erpnext
 
@@ -787,16 +790,28 @@
 
 	if doctype == 'Account':
 		sort_accounts(acc, is_root, key="value")
-		company_currency = frappe.get_cached_value('Company',  company,  "default_currency")
-		for each in acc:
-			each["company_currency"] = company_currency
-			each["balance"] = flt(get_balance_on(each.get("value"), in_account_currency=False, company=company))
-
-			if each.account_currency != company_currency:
-				each["balance_in_account_currency"] = flt(get_balance_on(each.get("value"), company=company))
 
 	return acc
 
+@frappe.whitelist()
+def get_account_balances(accounts, company):
+
+	if isinstance(accounts, string_types):
+		accounts = loads(accounts)
+
+	if not accounts:
+		return []
+
+	company_currency = frappe.get_cached_value("Company",  company,  "default_currency")
+
+	for account in accounts:
+		account["company_currency"] = company_currency
+		account["balance"] = flt(get_balance_on(account["value"], in_account_currency=False, company=company))
+		if account["account_currency"] and account["account_currency"] != company_currency:
+			account["balance_in_account_currency"] = flt(get_balance_on(account["value"], company=company))
+
+	return accounts
+
 def create_payment_gateway_account(gateway, payment_channel="Email"):
 	from erpnext.setup.setup_wizard.operations.install_fixtures import create_bank_account
 
diff --git a/erpnext/regional/india/utils.py b/erpnext/regional/india/utils.py
index 0faf80b..9493614 100644
--- a/erpnext/regional/india/utils.py
+++ b/erpnext/regional/india/utils.py
@@ -249,6 +249,9 @@
 	elif doctype in ("Purchase Invoice", "Purchase Order", "Purchase Receipt"):
 		destination_gstin = party_details.supplier_gstin
 
+	if not destination_gstin or party_details.gstin:
+		return False
+
 	if party_details.gstin == destination_gstin:
 		return True
 	else:
diff --git a/erpnext/selling/doctype/customer/customer.js b/erpnext/selling/doctype/customer/customer.js
index cb00019..4b0bbd5 100644
--- a/erpnext/selling/doctype/customer/customer.js
+++ b/erpnext/selling/doctype/customer/customer.js
@@ -116,14 +116,15 @@
 			frappe.contacts.render_address_and_contact(frm);
 
 			// custom buttons
-			frm.add_custom_button(__('Accounting Ledger'), function() {
-				frappe.set_route('query-report', 'General Ledger',
-					{party_type:'Customer', party:frm.doc.name});
-			});
 
-			frm.add_custom_button(__('Accounts Receivable'), function() {
+			frm.add_custom_button(__('Accounts Receivable'), function () {
 				frappe.set_route('query-report', 'Accounts Receivable', {customer:frm.doc.name});
-			});
+			}, __('View'));
+
+			frm.add_custom_button(__('Accounting Ledger'), function () {
+				frappe.set_route('query-report', 'General Ledger',
+					{party_type: 'Customer', party: frm.doc.name});
+			}, __('View'));
 
 			frm.add_custom_button(__('Pricing Rule'), function () {
 				erpnext.utils.make_pricing_rule(frm.doc.doctype, frm.doc.name);
diff --git a/erpnext/support/doctype/service_level_agreement/service_level_agreement.json b/erpnext/support/doctype/service_level_agreement/service_level_agreement.json
index b649b87..5f470aa 100644
--- a/erpnext/support/doctype/service_level_agreement/service_level_agreement.json
+++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement.json
@@ -203,10 +203,11 @@
   }
  ],
  "links": [],
- "modified": "2021-07-27 11:16:45.596579",
+ "modified": "2021-10-02 11:32:55.556024",
  "modified_by": "Administrator",
  "module": "Support",
  "name": "Service Level Agreement",
+ "naming_rule": "Expression",
  "owner": "Administrator",
  "permissions": [
   {
@@ -237,4 +238,4 @@
  "sort_field": "modified",
  "sort_order": "DESC",
  "track_changes": 1
-}
+}
\ No newline at end of file
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 bd47811..6bdd8f2 100644
--- a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
+++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py
@@ -339,7 +339,7 @@
 
 def apply(doc, method=None):
 	# Applies SLA to document on validate
-	if frappe.flags.in_patch or frappe.flags.in_install or frappe.flags.in_setup_wizard or \
+	if frappe.flags.in_patch or frappe.flags.in_migrate or frappe.flags.in_install or frappe.flags.in_setup_wizard or \
 		doc.doctype not in get_documents_with_active_service_level_agreement():
 		return