Merge pull request #21756 from deepeshgarg007/loan_patch_and_fixes

fix: Description for fields and patch for old loans
diff --git a/erpnext/loan_management/desk_page/loan/loan.json b/erpnext/loan_management/desk_page/loan/loan.json
index 48193b0..3bdd1ce 100644
--- a/erpnext/loan_management/desk_page/loan/loan.json
+++ b/erpnext/loan_management/desk_page/loan/loan.json
@@ -3,7 +3,7 @@
   {
    "hidden": 0,
    "label": "Loan",
-   "links": "[\n    {\n        \"description\": \"Loan Type for interest and penalty rates\",\n        \"label\": \"Loan Type\",\n        \"name\": \"Loan Type\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"description\": \"Loan Applications from customers and employees.\",\n        \"label\": \"Loan Application\",\n        \"name\": \"Loan Application\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"description\": \"Loans provided to customers and employees.\",\n        \"label\": \"Loan\",\n        \"name\": \"Loan\",\n        \"type\": \"doctype\"\n    }\n]"
+   "links": "[\n    {\n        \"description\": \"Loan Type for interest and penalty rates\",\n        \"label\": \"Loan Type\",\n        \"name\": \"Loan Type\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"description\": \"Loan Applications from customers and employees.\",\n        \"label\": \"Loan Application\",\n        \"name\": \"Loan Application\",\n        \"type\": \"doctype\"\n    },\n    {   \"dependencies\": [\n            \"Loan Type\"\n        ],\n        \"description\": \"Loans provided to customers and employees.\",\n        \"label\": \"Loan\",\n        \"name\": \"Loan\",\n        \"type\": \"doctype\"\n    }\n]"
   },
   {
    "hidden": 0,
diff --git a/erpnext/loan_management/doctype/loan_application/loan_application.js b/erpnext/loan_management/doctype/loan_application/loan_application.js
index 6cf47bf..b56fce1 100644
--- a/erpnext/loan_management/doctype/loan_application/loan_application.js
+++ b/erpnext/loan_management/doctype/loan_application/loan_application.js
@@ -112,16 +112,19 @@
 frappe.ui.form.on("Proposed Pledge", {
 	loan_security: function(frm, cdt, cdn) {
 		let row = locals[cdt][cdn];
-		frappe.call({
-			method: "erpnext.loan_management.doctype.loan_security_price.loan_security_price.get_loan_security_price",
-			args: {
-				loan_security: row.loan_security
-			},
-			callback: function(r) {
-				frappe.model.set_value(cdt, cdn, 'loan_security_price', r.message);
-				frm.events.calculate_amounts(frm, cdt, cdn);
-			}
-		})
+
+		if (row.loan_security) {
+			frappe.call({
+				method: "erpnext.loan_management.doctype.loan_security_price.loan_security_price.get_loan_security_price",
+				args: {
+					loan_security: row.loan_security
+				},
+				callback: function(r) {
+					frappe.model.set_value(cdt, cdn, 'loan_security_price', r.message);
+					frm.events.calculate_amounts(frm, cdt, cdn);
+				}
+			})
+		}
 	},
 
 	amount: function(frm, cdt, cdn) {
diff --git a/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py b/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py
index e6ceb55..b56fa80 100644
--- a/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py
+++ b/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.py
@@ -19,8 +19,8 @@
 		if not self.posting_date:
 			self.posting_date = nowdate()
 
-		if not self.interest_amount:
-			frappe.throw(_("Interest Amount is mandatory"))
+		if not self.interest_amount and not self.payable_principal_amount:
+			frappe.throw(_("Interest Amount or Principal Amount is mandatory"))
 
 
 	def on_submit(self):
@@ -39,37 +39,38 @@
 	def make_gl_entries(self, cancel=0, adv_adj=0):
 		gle_map = []
 
-		gle_map.append(
-			self.get_gl_dict({
-				"account": self.loan_account,
-				"party_type": self.applicant_type,
-				"party": self.applicant,
-				"against": self.interest_income_account,
-				"debit": self.interest_amount,
-				"debit_in_account_currency": self.interest_amount,
-				"against_voucher_type": "Loan",
-				"against_voucher": self.loan,
-				"remarks": _("Against Loan:") + self.loan,
-				"cost_center": erpnext.get_default_cost_center(self.company),
-				"posting_date": self.posting_date
-			})
-		)
+		if self.interest_amount:
+			gle_map.append(
+				self.get_gl_dict({
+					"account": self.loan_account,
+					"party_type": self.applicant_type,
+					"party": self.applicant,
+					"against": self.interest_income_account,
+					"debit": self.interest_amount,
+					"debit_in_account_currency": self.interest_amount,
+					"against_voucher_type": "Loan",
+					"against_voucher": self.loan,
+					"remarks": _("Against Loan:") + self.loan,
+					"cost_center": erpnext.get_default_cost_center(self.company),
+					"posting_date": self.posting_date
+				})
+			)
 
-		gle_map.append(
-			self.get_gl_dict({
-				"account": self.interest_income_account,
-				"party_type": self.applicant_type,
-				"party": self.applicant,
-				"against": self.loan_account,
-				"credit": self.interest_amount,
-				"credit_in_account_currency":  self.interest_amount,
-				"against_voucher_type": "Loan",
-				"against_voucher": self.loan,
-				"remarks": _("Against Loan:") + self.loan,
-				"cost_center": erpnext.get_default_cost_center(self.company),
-				"posting_date": self.posting_date
-			})
-		)
+			gle_map.append(
+				self.get_gl_dict({
+					"account": self.interest_income_account,
+					"party_type": self.applicant_type,
+					"party": self.applicant,
+					"against": self.loan_account,
+					"credit": self.interest_amount,
+					"credit_in_account_currency":  self.interest_amount,
+					"against_voucher_type": "Loan",
+					"against_voucher": self.loan,
+					"remarks": _("Against Loan:") + self.loan,
+					"cost_center": erpnext.get_default_cost_center(self.company),
+					"posting_date": self.posting_date
+				})
+			)
 
 		if gle_map:
 			make_gl_entries(gle_map, cancel=cancel, adv_adj=adv_adj)
diff --git a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json
index 789c129..5942455 100644
--- a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json
+++ b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json
@@ -173,7 +173,7 @@
   {
    "fieldname": "references_section",
    "fieldtype": "Section Break",
-   "label": "References"
+   "label": "Payment References"
   },
   {
    "fieldname": "reference_number",
@@ -221,7 +221,7 @@
  ],
  "is_submittable": 1,
  "links": [],
- "modified": "2020-04-16 18:14:45.166754",
+ "modified": "2020-05-16 09:40:15.581165",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Loan Repayment",
diff --git a/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.js b/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.js
index 82837b3..11c932f 100644
--- a/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.js
+++ b/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.js
@@ -22,16 +22,19 @@
 frappe.ui.form.on("Pledge", {
 	loan_security: function(frm, cdt, cdn) {
 		let row = locals[cdt][cdn];
-		frappe.call({
-			method: "erpnext.loan_management.doctype.loan_security_price.loan_security_price.get_loan_security_price",
-			args: {
-				loan_security: row.loan_security
-			},
-			callback: function(r) {
-				frappe.model.set_value(cdt, cdn, 'loan_security_price', r.message);
-				frm.events.calculate_amounts(frm, cdt, cdn);
-			}
-		});
+
+		if (row.loan_security) {
+			frappe.call({
+				method: "erpnext.loan_management.doctype.loan_security_price.loan_security_price.get_loan_security_price",
+				args: {
+					loan_security: row.loan_security
+				},
+				callback: function(r) {
+					frappe.model.set_value(cdt, cdn, 'loan_security_price', r.message);
+					frm.events.calculate_amounts(frm, cdt, cdn);
+				}
+			});
+		}
 	},
 
 	qty: function(frm, cdt, cdn) {
diff --git a/erpnext/loan_management/doctype/loan_security_type/loan_security_type.json b/erpnext/loan_management/doctype/loan_security_type/loan_security_type.json
index f46b88c..871e825 100644
--- a/erpnext/loan_management/doctype/loan_security_type/loan_security_type.json
+++ b/erpnext/loan_management/doctype/loan_security_type/loan_security_type.json
@@ -29,6 +29,7 @@
    "unique": 1
   },
   {
+   "description": "Haircut percentage is the percentage difference between market value of the Loan Security and the value ascribed to that Loan Security when used as collateral for that loan.",
    "fieldname": "haircut",
    "fieldtype": "Percent",
    "label": "Haircut %"
@@ -46,13 +47,14 @@
    "fieldtype": "Column Break"
   },
   {
+   "description": "Loan To Value Ratio expresses the ratio of the loan amount to the value of the security pledged. A loan security shortfall will be triggered if this falls below the specified value for any loan ",
    "fieldname": "loan_to_value_ratio",
    "fieldtype": "Percent",
    "label": "Loan To Value Ratio"
   }
  ],
  "links": [],
- "modified": "2020-04-28 14:06:49.046177",
+ "modified": "2020-05-16 09:38:45.988080",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Loan Security Type",
diff --git a/erpnext/loan_management/doctype/loan_type/loan_type.json b/erpnext/loan_management/doctype/loan_type/loan_type.json
index 1dd3710..669490a 100644
--- a/erpnext/loan_management/doctype/loan_type/loan_type.json
+++ b/erpnext/loan_management/doctype/loan_type/loan_type.json
@@ -76,6 +76,7 @@
    "reqd": 1
   },
   {
+   "description": "This account is used for booking loan repayments from the borrower and also disbursing loans to the borrower",
    "fieldname": "payment_account",
    "fieldtype": "Link",
    "label": "Payment Account",
@@ -83,6 +84,7 @@
    "reqd": 1
   },
   {
+   "description": "This account is capital account which is used to allocate capital for loan disbursal account ",
    "fieldname": "loan_account",
    "fieldtype": "Link",
    "label": "Loan Account",
@@ -94,6 +96,7 @@
    "fieldtype": "Column Break"
   },
   {
+   "description": "This account will be used for booking loan interest accruals",
    "fieldname": "interest_income_account",
    "fieldtype": "Link",
    "label": "Interest Income Account",
@@ -101,6 +104,7 @@
    "reqd": 1
   },
   {
+   "description": "This account will be used for booking penalties levied due to delayed repayments",
    "fieldname": "penalty_income_account",
    "fieldtype": "Link",
    "label": "Penalty Income Account",
@@ -109,6 +113,7 @@
   },
   {
    "default": "0",
+   "description": "If this is not checked the loan by default will be considered as a Demand Loan",
    "fieldname": "is_term_loan",
    "fieldtype": "Check",
    "label": "Is Term Loan"
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index ae20d9e..49af0ba 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -687,6 +687,7 @@
 execute:frappe.rename_doc("Desk Page", "Getting Started", "Home", force=True)
 erpnext.patches.v12_0.unset_customer_supplier_based_on_type_of_item_price
 erpnext.patches.v12_0.set_valid_till_date_in_supplier_quotation
+erpnext.patches.v13_0.update_old_loans
 erpnext.patches.v12_0.set_serial_no_status #2020-05-21
 erpnext.patches.v12_0.update_price_list_currency_in_bom
 execute:frappe.delete_doc_if_exists('Dashboard', 'Accounts')
diff --git a/erpnext/patches/v13_0/update_old_loans.py b/erpnext/patches/v13_0/update_old_loans.py
new file mode 100644
index 0000000..7723942
--- /dev/null
+++ b/erpnext/patches/v13_0/update_old_loans.py
@@ -0,0 +1,88 @@
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+from frappe.utils import nowdate
+from erpnext.accounts.doctype.account.test_account import create_account
+from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_term_loans
+from erpnext.loan_management.doctype.loan.loan import make_repayment_entry
+
+def execute():
+
+	# Create a penalty account for loan types
+
+	frappe.reload_doc('loan_management', 'doctype', 'loan_type')
+	frappe.reload_doc('loan_management', 'doctype', 'loan')
+	frappe.reload_doc('loan_management', 'doctype', 'repayment_schedule')
+	frappe.reload_doc('loan_management', 'doctype', 'process_loan_interest_accrual')
+	frappe.reload_doc('loan_management', 'doctype', 'loan_repayment')
+	frappe.reload_doc('loan_management', 'doctype', 'loan_repayment_detail')
+	frappe.reload_doc('loan_management', 'doctype', 'loan_interest_accrual')
+	frappe.reload_doc('accounts', 'doctype', 'gl_entry')
+
+	updated_loan_types = []
+
+	loans = frappe.get_all('Loan', fields=['name', 'loan_type', 'company', 'status', 'mode_of_payment',
+		'applicant_type', 'applicant', 'loan_account', 'payment_account', 'interest_income_account'])
+
+	for loan in loans:
+		# Update details in Loan Types and Loan
+		loan_type_company = frappe.db.get_value('Loan Type', loan.loan_type, 'company')
+
+		group_income_account = frappe.get_value('Account', {'company': loan.company,
+			'is_group': 1, 'root_type': 'Income', 'account_name': _('Indirect Income')})
+
+		if not group_income_account:
+			group_income_account = frappe.get_value('Account', {'company': loan.company,
+				'is_group': 1, 'root_type': 'Income'})
+
+		penalty_account = create_account(company=loan.company, account_type='Income Account',
+			account_name='Penalty Account', parent_account=group_income_account)
+
+		if not loan_type_company:
+			loan_type_doc = frappe.get_doc('Loan Type', loan.loan_type)
+			loan_type_doc.is_term_loan = 1
+			loan_type_doc.company = loan.company
+			loan_type_doc.mode_of_payment = loan.mode_of_payment
+			loan_type_doc.payment_account = loan.payment_account
+			loan_type_doc.loan_account = loan.loan_account
+			loan_type_doc.interest_income_account = loan.interest_income_account
+			loan_type_doc.penalty_income_account = penalty_account
+			loan_type_doc.submit()
+			updated_loan_types.append(loan.loan_type)
+
+		if loan.loan_type in updated_loan_types:
+			if loan.status == 'Fully Disbursed':
+				status = 'Disbursed'
+			elif loan.status == 'Repaid/Closed':
+				status = 'Closed'
+			else:
+				status = loan.status
+
+			frappe.db.set_value('Loan', loan.name, {
+				'is_term_loan': 1,
+				'penalty_income_account': penalty_account,
+				'status': status
+			})
+
+			process_loan_interest_accrual_for_term_loans(posting_date=nowdate(), loan_type=loan.loan_type,
+				loan=loan.name)
+
+			payments = frappe.db.sql(''' SELECT j.name, a.debit, a.debit_in_account_currency, j.posting_date
+				FROM `tabJournal Entry` j, `tabJournal Entry Account` a
+				WHERE a.parent = j.name and a.reference_type='Loan' and a.reference_name = %s
+				and account = %s
+			''', (loan.name, loan.loan_account), as_dict=1)
+
+			for payment in payments:
+				repayment_entry = make_repayment_entry(loan.name, loan.loan_applicant_type, loan.applicant,
+					loan.loan_type, loan.company)
+
+				repayment_entry.amount_paid = payment.debit_in_account_currency
+				repayment_entry.posting_date = payment.posting_date
+				repayment_entry.save()
+				repayment_entry.submit()
+
+				jv = frappe.get_doc('Journal Entry', payment.name)
+				jv.flags.ignore_links = True
+				jv.cancel()
+