fix: Write Off amount handling in Loan accrual and closure
diff --git a/erpnext/loan_management/desk_page/loan/loan.json b/erpnext/loan_management/desk_page/loan/loan.json
index 3bdd1ce..fc59c19 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    {   \"dependencies\": [\n            \"Loan Type\"\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    {\n        \"description\": \"Loans provided to customers and employees.\",\n        \"label\": \"Loan\",\n        \"name\": \"Loan\",\n        \"type\": \"doctype\"\n    }\n]"
   },
   {
    "hidden": 0,
@@ -13,7 +13,7 @@
   {
    "hidden": 0,
    "label": "Disbursement and Repayment",
-   "links": "[\n    {\n        \"label\": \"Loan Disbursement\",\n        \"name\": \"Loan Disbursement\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"label\": \"Loan Repayment\",\n        \"name\": \"Loan Repayment\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"label\": \"Loan Interest Accrual\",\n        \"name\": \"Loan Interest Accrual\",\n        \"type\": \"doctype\"\n    }\n]"
+   "links": "[\n    {\n        \"label\": \"Loan Disbursement\",\n        \"name\": \"Loan Disbursement\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"label\": \"Loan Repayment\",\n        \"name\": \"Loan Repayment\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"label\": \"Loan Write Off\",\n        \"name\": \"Loan Write Off\",\n        \"type\": \"doctype\"\n    },\n    {\n        \"label\": \"Loan Interest Accrual\",\n        \"name\": \"Loan Interest Accrual\",\n        \"type\": \"doctype\"\n    }\n]"
   },
   {
    "hidden": 0,
@@ -34,10 +34,11 @@
  "docstatus": 0,
  "doctype": "Desk Page",
  "extends_another_page": 0,
+ "hide_custom": 0,
  "idx": 0,
  "is_standard": 1,
  "label": "Loan",
- "modified": "2020-06-07 19:42:14.947902",
+ "modified": "2020-10-17 12:59:50.336085",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Loan",
diff --git a/erpnext/loan_management/doctype/loan/loan.js b/erpnext/loan_management/doctype/loan/loan.js
index 0dc3bf8..8d101b8 100644
--- a/erpnext/loan_management/doctype/loan/loan.js
+++ b/erpnext/loan_management/doctype/loan/loan.js
@@ -64,12 +64,13 @@
 				frm.add_custom_button(__('Request Loan Closure'), function() {
 					frm.trigger("request_loan_closure");
 				},__('Status'));
+
 				frm.add_custom_button(__('Loan Repayment'), function() {
 					frm.trigger("make_repayment_entry");
 				},__('Create'));
 			}
 
-			if (frm.doc.status == "Sanctioned" || frm.doc.status == 'Partially Disbursed') {
+			if (["Sanctioned", "Partially Disbursed"].includes(frm.doc.status)) {
 				frm.add_custom_button(__('Loan Disbursement'), function() {
 					frm.trigger("make_loan_disbursement");
 				},__('Create'));
@@ -80,6 +81,12 @@
 					frm.trigger("create_loan_security_unpledge");
 				},__('Create'));
 			}
+
+			if (["Loan Closure Requested", "Disbursed", "Partially Disbursed"].includes(frm.doc.status)) {
+				frm.add_custom_button(__('Loan Write Off'), function() {
+					frm.trigger("make_loan_write_off_entry");
+				},__('Create'));
+			}
 		}
 		frm.trigger("toggle_fields");
 	},
@@ -130,6 +137,22 @@
 		})
 	},
 
+	make_loan_write_off_entry: function(frm) {
+		frappe.call({
+			args: {
+				"loan": frm.doc.name,
+				"company": frm.doc.company,
+				"as_dict": 1
+			},
+			method: "erpnext.loan_management.doctype.loan.loan.make_loan_write_off",
+			callback: function (r) {
+				if (r.message)
+					var doc = frappe.model.sync(r.message)[0];
+				frappe.set_route("Form", doc.doctype, doc.name);
+			}
+		})
+	},
+
 	request_loan_closure: function(frm) {
 		frappe.confirm(__("Do you really want to close this loan"),
 			function() {
diff --git a/erpnext/loan_management/doctype/loan/loan.json b/erpnext/loan_management/doctype/loan/loan.json
index aa5e21b..312e9af 100644
--- a/erpnext/loan_management/doctype/loan/loan.json
+++ b/erpnext/loan_management/doctype/loan/loan.json
@@ -43,6 +43,7 @@
   "section_break_17",
   "total_payment",
   "total_principal_paid",
+  "written_off_amount",
   "column_break_19",
   "total_interest_payable",
   "total_amount_paid",
@@ -330,11 +331,18 @@
    "label": "Maximum Loan Amount",
    "options": "Company:company:default_currency",
    "read_only": 1
+  },
+  {
+   "fieldname": "written_off_amount",
+   "fieldtype": "Currency",
+   "label": "Written Off Amount",
+   "options": "Company:company:default_currency"
   }
  ],
+ "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2020-08-01 12:36:11.255233",
+ "modified": "2020-10-17 10:35:44.361836",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Loan",
diff --git a/erpnext/loan_management/doctype/loan/loan.py b/erpnext/loan_management/doctype/loan/loan.py
index 2d705fc..8405d6e 100644
--- a/erpnext/loan_management/doctype/loan/loan.py
+++ b/erpnext/loan_management/doctype/loan/loan.py
@@ -143,7 +143,7 @@
 		if pledge_list:
 			frappe.db.sql("""UPDATE `tabLoan Security Pledge` SET
 				loan = '', status = 'Unpledged'
-				where name in (%s) """ % (', '.join(['%s']*len(pledge_list))), tuple(pledge_list))
+				where name in (%s) """ % (', '.join(['%s']*len(pledge_list))), tuple(pledge_list)) #nosec
 
 def update_total_amount_paid(doc):
 	total_amount_paid = 0
@@ -187,17 +187,22 @@
 	return monthly_repayment_amount
 
 @frappe.whitelist()
-def request_loan_closure(loan):
-	amounts = calculate_amounts(loan, getdate())
+def request_loan_closure(loan, posting_date=None):
+	if not posting_date:
+		posting_date = getdate()
 
+	amounts = calculate_amounts(loan, posting_date)
 	pending_amount = amounts['payable_amount'] + amounts['unaccrued_interest']
 
+	loan_type = frappe.get_value('Loan', loan, 'loan_type')
+	write_off_limit = frappe.get_value('Loan Type', loan_type, 'write_off_amount')
+
 	# checking greater than 0 as there may be some minor precision error
-	if pending_amount > 0:
-		frappe.throw(_("Cannot close loan as there is an outstanding of {0}").format(pending_amount))
-	else:
+	if pending_amount < write_off_limit:
 		# update status as loan closure requested
 		frappe.db.set_value('Loan', loan, 'status', 'Loan Closure Requested')
+	else:
+		frappe.throw(_("Cannot close loan as there is an outstanding of {0}").format(pending_amount))
 
 @frappe.whitelist()
 def get_loan_application(loan_application):
@@ -217,6 +222,7 @@
 	disbursement_entry.applicant = applicant
 	disbursement_entry.company = company
 	disbursement_entry.disbursement_date = nowdate()
+	disbursement_entry.posting_date = nowdate()
 
 	disbursement_entry.disbursed_amount = pending_amount
 	if as_dict:
@@ -240,6 +246,38 @@
 		return repayment_entry
 
 @frappe.whitelist()
+def make_loan_write_off(loan, company=None, posting_date=None, amount=0, as_dict=0):
+	if not company:
+		company = frappe.get_value('Loan', loan, 'company')
+
+	if not posting_date:
+		posting_date = getdate()
+
+	amounts = calculate_amounts(loan, posting_date)
+	pending_amount = amounts['pending_principal_amount']
+
+	if amount and (amount > pending_amount):
+		frappe.throw('Write Off amount cannot be greater than pending loan amount')
+
+	if not amount:
+		amount = pending_amount
+
+	# get default write off account from company master
+	write_off_account = frappe.get_value('Company', company, 'write_off_account')
+
+	write_off = frappe.new_doc('Loan Write Off')
+	write_off.loan = loan
+	write_off.posting_date = posting_date
+	write_off.write_off_account = write_off_account
+	write_off.write_off_amount = amount
+	write_off.save()
+
+	if as_dict:
+		return write_off.as_dict()
+	else:
+		return write_off
+
+@frappe.whitelist()
 def unpledge_security(loan=None, loan_security_pledge=None, as_dict=0, save=0, submit=0, approve=0):
 	# if loan is passed it will be considered as full unpledge
 	if loan:
diff --git a/erpnext/loan_management/doctype/loan/loan_dashboard.py b/erpnext/loan_management/doctype/loan/loan_dashboard.py
index 90d5ae2..7a8190f 100644
--- a/erpnext/loan_management/doctype/loan/loan_dashboard.py
+++ b/erpnext/loan_management/doctype/loan/loan_dashboard.py
@@ -13,7 +13,7 @@
 				'items': ['Loan Security Pledge', 'Loan Security Shortfall', 'Loan Disbursement']
 			},
 			{
-				'items': ['Loan Repayment', 'Loan Interest Accrual', 'Loan Security Unpledge']
+				'items': ['Loan Repayment', 'Loan Interest Accrual', 'Loan Write Off', 'Loan Security Unpledge']
 			}
 		]
 	}
\ No newline at end of file
diff --git a/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.json b/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.json
index c437a98..89f671b 100644
--- a/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.json
+++ b/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.json
@@ -26,19 +26,23 @@
   {
    "fieldname": "against_loan",
    "fieldtype": "Link",
+   "in_list_view": 1,
    "label": "Against Loan ",
-   "options": "Loan"
+   "options": "Loan",
+   "reqd": 1
   },
   {
    "fieldname": "disbursement_date",
    "fieldtype": "Date",
-   "label": "Disbursement Date"
+   "label": "Disbursement Date",
+   "reqd": 1
   },
   {
    "fieldname": "disbursed_amount",
    "fieldtype": "Currency",
    "label": "Disbursed Amount",
-   "options": "Company:company:default_currency"
+   "options": "Company:company:default_currency",
+   "reqd": 1
   },
   {
    "fieldname": "amended_from",
@@ -53,17 +57,21 @@
    "fetch_from": "against_loan.company",
    "fieldname": "company",
    "fieldtype": "Link",
+   "in_list_view": 1,
    "label": "Company",
    "options": "Company",
-   "read_only": 1
+   "read_only": 1,
+   "reqd": 1
   },
   {
    "fetch_from": "against_loan.applicant",
    "fieldname": "applicant",
    "fieldtype": "Dynamic Link",
+   "in_list_view": 1,
    "label": "Applicant",
    "options": "applicant_type",
-   "read_only": 1
+   "read_only": 1,
+   "reqd": 1
   },
   {
    "collapsible": 1,
@@ -102,9 +110,11 @@
    "fetch_from": "against_loan.applicant_type",
    "fieldname": "applicant_type",
    "fieldtype": "Select",
+   "in_list_view": 1,
    "label": "Applicant Type",
    "options": "Employee\nMember\nCustomer",
-   "read_only": 1
+   "read_only": 1,
+   "reqd": 1
   },
   {
    "fieldname": "bank_account",
@@ -117,9 +127,10 @@
    "fieldtype": "Column Break"
   }
  ],
+ "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2020-04-29 05:20:41.629911",
+ "modified": "2020-10-16 10:04:26.229216",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Loan Disbursement",
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 4517de0..e31b844 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
@@ -89,9 +89,10 @@
 
 	if loan.status == 'Disbursed':
 		pending_principal_amount = flt(loan.total_payment) - flt(loan.total_interest_payable) \
-			- flt(loan.total_principal_paid)
+			- flt(loan.total_principal_paid) - flt(loan.written_off_amount)
 	else:
-		pending_principal_amount = loan.disbursed_amount
+		pending_principal_amount = flt(loan.disbursed_amount) - flt(loan.total_interest_payable) \
+			- flt(loan.total_principal_paid) - flt(loan.written_off_amount)
 
 	interest_per_day = get_per_day_interest(pending_principal_amount, loan.rate_of_interest, posting_date)
 	payable_interest = interest_per_day * no_of_days
@@ -128,7 +129,7 @@
 		open_loans = frappe.get_all("Loan",
 			fields=["name", "total_payment", "total_amount_paid", "loan_account", "interest_income_account",
 				"is_term_loan", "status", "disbursement_date", "disbursed_amount", "applicant_type", "applicant",
-				"rate_of_interest", "total_interest_payable", "total_principal_paid", "repayment_start_date"],
+				"rate_of_interest", "total_interest_payable", "written_off_amount", "total_principal_paid", "repayment_start_date"],
 			filters=query_filters)
 
 	for loan in open_loans:
@@ -239,5 +240,5 @@
 
 	precision = cint(frappe.db.get_default("currency_precision")) or 2
 
-	return flt((principal_amount * rate_of_interest) / (days_in_year(get_datetime(posting_date).year) * 100), 2)
+	return flt((principal_amount * rate_of_interest) / (days_in_year(get_datetime(posting_date).year) * 100), precision)
 
diff --git a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
index 940f82e..de5ba8f 100644
--- a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
+++ b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
@@ -31,8 +31,8 @@
 
 	def on_cancel(self):
 		self.mark_as_unpaid()
-		self.make_gl_entries(cancel=1)
 		self.ignore_linked_doctypes = ['GL Entry']
+		self.make_gl_entries(cancel=1)
 
 	def set_missing_values(self, amounts):
 		precision = cint(frappe.db.get_default("currency_precision")) or 2
@@ -235,7 +235,7 @@
 				"against": loan_details.loan_account + ", " + loan_details.interest_income_account
 						+ ", " + loan_details.penalty_income_account,
 				"debit": self.amount_paid,
-				"debit_in_account_currency": self.amount_paid ,
+				"debit_in_account_currency": self.amount_paid,
 				"against_voucher_type": "Loan",
 				"against_voucher": self.against_loan,
 				"remarks": _("Against Loan:") + self.against_loan,
@@ -344,9 +344,11 @@
 			final_due_date = add_days(due_date, loan_type_details.grace_period_in_days)
 
 	if against_loan_doc.status in ('Disbursed', 'Loan Closure Requested', 'Closed'):
-		pending_principal_amount = against_loan_doc.total_payment - against_loan_doc.total_principal_paid - against_loan_doc.total_interest_payable
+		pending_principal_amount = against_loan_doc.total_payment - against_loan_doc.total_principal_paid \
+			- against_loan_doc.total_interest_payable - against_loan_doc.written_off_amount
 	else:
-		pending_principal_amount = against_loan_doc.disbursed_amount
+		pending_principal_amount = against_loan_doc.disbursed_amount - against_loan_doc.total_principal_paid \
+			- against_loan_doc.total_interest_payable - against_loan_doc.written_off_amount
 
 	unaccrued_interest = 0
 	if due_date:
diff --git a/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.py b/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.py
index b3eb600..d0d25e8 100644
--- a/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.py
+++ b/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.py
@@ -42,10 +42,10 @@
 				"valid_upto": (">=", get_datetime())
 			}, as_list=1))
 
-		total_payment, principal_paid, interest_payable = frappe.get_value("Loan", self.loan, ['total_payment', 'total_principal_paid',
-			'total_interest_payable'])
+		total_payment, principal_paid, interest_payable, written_off_amount = frappe.get_value("Loan", self.loan, ['total_payment', 'total_principal_paid',
+			'total_interest_payable', 'written_off_amount'])
 
-		pending_principal_amount = flt(total_payment) - flt(interest_payable) - flt(principal_paid)
+		pending_principal_amount = flt(total_payment) - flt(interest_payable) - flt(principal_paid) - flt(written_off_amount)
 		security_value = 0
 
 		for security in self.securities:
diff --git a/erpnext/loan_management/doctype/loan_type/loan_type.json b/erpnext/loan_management/doctype/loan_type/loan_type.json
index 669490a..5d9232d 100644
--- a/erpnext/loan_management/doctype/loan_type/loan_type.json
+++ b/erpnext/loan_management/doctype/loan_type/loan_type.json
@@ -11,6 +11,7 @@
   "rate_of_interest",
   "penalty_interest_rate",
   "grace_period_in_days",
+  "write_off_amount",
   "column_break_2",
   "company",
   "is_term_loan",
@@ -76,7 +77,6 @@
    "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",
@@ -84,7 +84,6 @@
    "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",
@@ -96,7 +95,6 @@
    "fieldtype": "Column Break"
   },
   {
-   "description": "This account will be used for booking loan interest accruals",
    "fieldname": "interest_income_account",
    "fieldtype": "Link",
    "label": "Interest Income Account",
@@ -104,7 +102,6 @@
    "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",
@@ -113,7 +110,6 @@
   },
   {
    "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"
@@ -145,11 +141,20 @@
    "label": "Company",
    "options": "Company",
    "reqd": 1
+  },
+  {
+   "allow_on_submit": 1,
+   "description": "Pending amount that will be automatically ignored on loan closure request ",
+   "fieldname": "write_off_amount",
+   "fieldtype": "Currency",
+   "label": "Write Off Amount ",
+   "options": "Company:company:default_currency"
   }
  ],
+ "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2020-06-07 18:55:59.346292",
+ "modified": "2020-10-17 11:41:17.907683",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Loan Type",
diff --git a/erpnext/loan_management/loan_common.js b/erpnext/loan_management/loan_common.js
index 33a5de0..50b68da 100644
--- a/erpnext/loan_management/loan_common.js
+++ b/erpnext/loan_management/loan_common.js
@@ -8,7 +8,7 @@
 			frm.refresh_field('applicant_type');
 		}
 
-		if (['Loan Disbursement', 'Loan Repayment', 'Loan Interest Accrual'].includes(frm.doc.doctype)
+		if (['Loan Disbursement', 'Loan Repayment', 'Loan Interest Accrual', 'Loan Write Off'].includes(frm.doc.doctype)
 			&& frm.doc.docstatus > 0) {
 
 			frm.add_custom_button(__("Accounting Ledger"), function() {