feat: Make Depreciation Entry posting more flexible (#28421)

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):