Merge pull request #23447 from hasnain2808/UAE-VAT-Format

feat: UAE VAT 201 Report
diff --git a/erpnext/accounts/desk_page/accounting/accounting.json b/erpnext/accounts/desk_page/accounting/accounting.json
index 536f403..b2a3f83 100644
--- a/erpnext/accounts/desk_page/accounting/accounting.json
+++ b/erpnext/accounts/desk_page/accounting/accounting.json
@@ -23,7 +23,7 @@
   {
    "hidden": 0,
    "label": "Reports",
-   "links": "[\n    {\n        \"dependencies\": [\n            \"GL Entry\"\n        ],\n        \"doctype\": \"GL Entry\",\n        \"is_query_report\": true,\n        \"label\": \"Trial Balance for Party\",\n        \"name\": \"Trial Balance for Party\",\n        \"type\": \"report\"\n    },\n    {\n        \"dependencies\": [\n            \"Journal Entry\"\n        ],\n        \"doctype\": \"Journal Entry\",\n        \"is_query_report\": true,\n        \"label\": \"Payment Period Based On Invoice Date\",\n        \"name\": \"Payment Period Based On Invoice Date\",\n        \"type\": \"report\"\n    },\n    {\n        \"dependencies\": [\n            \"Sales Invoice\"\n        ],\n        \"doctype\": \"Sales Invoice\",\n        \"is_query_report\": true,\n        \"label\": \"Sales Partners Commission\",\n        \"name\": \"Sales Partners Commission\",\n        \"type\": \"report\"\n    },\n    {\n        \"dependencies\": [\n            \"Customer\"\n        ],\n        \"doctype\": \"Customer\",\n        \"is_query_report\": true,\n        \"label\": \"Customer Credit Balance\",\n        \"name\": \"Customer Credit Balance\",\n        \"type\": \"report\"\n    },\n    {\n        \"dependencies\": [\n            \"Sales Invoice\"\n        ],\n        \"doctype\": \"Sales Invoice\",\n        \"is_query_report\": true,\n        \"label\": \"Sales Payment Summary\",\n        \"name\": \"Sales Payment Summary\",\n        \"type\": \"report\"\n    },\n    {\n        \"dependencies\": [\n            \"Address\"\n        ],\n        \"doctype\": \"Address\",\n        \"is_query_report\": true,\n        \"label\": \"Address And Contacts\",\n        \"name\": \"Address And Contacts\",\n        \"type\": \"report\"\n    }\n]"
+   "links": "[\n    {\n        \"dependencies\": [\n            \"GL Entry\"\n        ],\n        \"doctype\": \"GL Entry\",\n        \"is_query_report\": true,\n        \"label\": \"Trial Balance for Party\",\n        \"name\": \"Trial Balance for Party\",\n        \"type\": \"report\"\n    },\n    {\n        \"dependencies\": [\n            \"Journal Entry\"\n        ],\n        \"doctype\": \"Journal Entry\",\n        \"is_query_report\": true,\n        \"label\": \"Payment Period Based On Invoice Date\",\n        \"name\": \"Payment Period Based On Invoice Date\",\n        \"type\": \"report\"\n    },\n    {\n        \"dependencies\": [\n            \"Sales Invoice\"\n        ],\n        \"doctype\": \"Sales Invoice\",\n        \"is_query_report\": true,\n        \"label\": \"Sales Partners Commission\",\n        \"name\": \"Sales Partners Commission\",\n        \"type\": \"report\"\n    },\n    {\n        \"dependencies\": [\n            \"Customer\"\n        ],\n        \"doctype\": \"Customer\",\n        \"is_query_report\": true,\n        \"label\": \"Customer Credit Balance\",\n        \"name\": \"Customer Credit Balance\",\n        \"type\": \"report\"\n    },\n    {\n        \"dependencies\": [\n            \"Sales Invoice\"\n        ],\n        \"doctype\": \"Sales Invoice\",\n        \"is_query_report\": true,\n        \"label\": \"Sales Payment Summary\",\n        \"name\": \"Sales Payment Summary\",\n        \"type\": \"report\"\n    },\n    {\n        \"dependencies\": [\n            \"Address\"\n        ],\n        \"doctype\": \"Address\",\n        \"is_query_report\": true,\n        \"label\": \"Address And Contacts\",\n        \"name\": \"Address And Contacts\",\n        \"type\": \"report\"\n    },\n    {\n        \"dependencies\": [\n            \"GL Entry\"\n        ],\n        \"doctype\": \"GL Entry\",\n        \"is_query_report\": true,\n        \"label\": \"DATEV Export\",\n        \"name\": \"DATEV\",\n        \"type\": \"report\"\n    }\n]"
   },
   {
    "hidden": 0,
@@ -103,7 +103,7 @@
  "idx": 0,
  "is_standard": 1,
  "label": "Accounting",
- "modified": "2020-11-06 13:05:58.650150",
+ "modified": "2020-11-11 18:35:11.542909",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Accounting",
diff --git a/erpnext/accounts/doctype/fiscal_year/fiscal_year.js b/erpnext/accounts/doctype/fiscal_year/fiscal_year.js
index 152e17d..bc77dac 100644
--- a/erpnext/accounts/doctype/fiscal_year/fiscal_year.js
+++ b/erpnext/accounts/doctype/fiscal_year/fiscal_year.js
@@ -9,11 +9,7 @@
 		}
 	},
 	refresh: function (frm) {
-		let doc = frm.doc;
-		frm.toggle_enable('year_start_date', doc.__islocal);
-		frm.toggle_enable('year_end_date', doc.__islocal);
-
-		if (!doc.__islocal && (doc.name != frappe.sys_defaults.fiscal_year)) {
+		if (!frm.doc.__islocal && (frm.doc.name != frappe.sys_defaults.fiscal_year)) {
 			frm.add_custom_button(__("Set as Default"), () => frm.events.set_as_default(frm));
 			frm.set_intro(__("To set this Fiscal Year as Default, click on 'Set as Default'"));
 		} else {
@@ -24,8 +20,10 @@
 		return frm.call('set_as_default');
 	},
 	year_start_date: function(frm) {
-		let year_end_date =
-			frappe.datetime.add_days(frappe.datetime.add_months(frm.doc.year_start_date, 12), -1);
-		frm.set_value("year_end_date", year_end_date);
+		if (!frm.doc.is_short_year) {
+			let year_end_date =
+				frappe.datetime.add_days(frappe.datetime.add_months(frm.doc.year_start_date, 12), -1);
+			frm.set_value("year_end_date", year_end_date);
+		}
 	},
 });
diff --git a/erpnext/accounts/doctype/fiscal_year/fiscal_year.json b/erpnext/accounts/doctype/fiscal_year/fiscal_year.json
index 4ca9f6b..5ab91f2 100644
--- a/erpnext/accounts/doctype/fiscal_year/fiscal_year.json
+++ b/erpnext/accounts/doctype/fiscal_year/fiscal_year.json
@@ -1,347 +1,126 @@
 {
- "allow_copy": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 1, 
- "allow_rename": 0, 
- "autoname": "field:year", 
- "beta": 0, 
- "creation": "2013-01-22 16:50:25", 
- "custom": 0, 
- "description": "**Fiscal Year** represents a Financial Year. All accounting entries and other major transactions are tracked against **Fiscal Year**.", 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "Setup", 
- "editable_grid": 0, 
+ "actions": [],
+ "allow_import": 1,
+ "autoname": "field:year",
+ "creation": "2013-01-22 16:50:25",
+ "description": "**Fiscal Year** represents a Financial Year. All accounting entries and other major transactions are tracked against **Fiscal Year**.",
+ "doctype": "DocType",
+ "document_type": "Setup",
+ "engine": "InnoDB",
+ "field_order": [
+  "year",
+  "disabled",
+  "is_short_year",
+  "year_start_date",
+  "year_end_date",
+  "companies",
+  "auto_created"
+ ],
  "fields": [
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "description": "For e.g. 2012, 2012-13", 
-   "fieldname": "year", 
-   "fieldtype": "Data", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Year Name", 
-   "length": 0, 
-   "no_copy": 0, 
-   "oldfieldname": "year", 
-   "oldfieldtype": "Data", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "description": "For e.g. 2012, 2012-13",
+   "fieldname": "year",
+   "fieldtype": "Data",
+   "in_list_view": 1,
+   "label": "Year Name",
+   "oldfieldname": "year",
+   "oldfieldtype": "Data",
+   "reqd": 1,
+   "unique": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "disabled", 
-   "fieldtype": "Check", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Disabled", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "default": "0",
+   "fieldname": "disabled",
+   "fieldtype": "Check",
+   "label": "Disabled"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "year_start_date", 
-   "fieldtype": "Date", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Year Start Date", 
-   "length": 0, 
-   "no_copy": 1, 
-   "oldfieldname": "year_start_date", 
-   "oldfieldtype": "Date", 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "year_start_date",
+   "fieldtype": "Date",
+   "in_list_view": 1,
+   "label": "Year Start Date",
+   "no_copy": 1,
+   "oldfieldname": "year_start_date",
+   "oldfieldtype": "Date",
+   "reqd": 1,
+   "set_only_once": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "year_end_date", 
-   "fieldtype": "Date", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Year End Date", 
-   "length": 0, 
-   "no_copy": 1, 
-   "permlevel": 0, 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "year_end_date",
+   "fieldtype": "Date",
+   "in_list_view": 1,
+   "label": "Year End Date",
+   "no_copy": 1,
+   "reqd": 1,
+   "set_only_once": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "companies", 
-   "fieldtype": "Table", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Companies", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Fiscal Year Company", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "companies",
+   "fieldtype": "Table",
+   "label": "Companies",
+   "options": "Fiscal Year Company"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "default": "0", 
-   "fieldname": "auto_created", 
-   "fieldtype": "Check", 
-   "hidden": 1, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Auto Created", 
-   "length": 0, 
-   "no_copy": 1, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 1, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
+   "default": "0",
+   "fieldname": "auto_created",
+   "fieldtype": "Check",
+   "hidden": 1,
+   "label": "Auto Created",
+   "no_copy": 1,
+   "print_hide": 1,
+   "read_only": 1
+  },
+  {
+   "default": "0",
+   "description": "Less than 12 months.",
+   "fieldname": "is_short_year",
+   "fieldtype": "Check",
+   "label": "Is Short Year",
+   "set_only_once": 1
   }
- ], 
- "has_web_view": 0, 
- "hide_heading": 0, 
- "hide_toolbar": 0, 
- "icon": "fa fa-calendar", 
- "idx": 1, 
- "image_view": 0, 
- "in_create": 0, 
- "is_submittable": 0, 
- "issingle": 0, 
- "istable": 0, 
- "max_attachments": 0, 
- "modified": "2018-04-25 14:21:41.273354", 
- "modified_by": "Administrator", 
- "module": "Accounts", 
- "name": "Fiscal Year", 
- "owner": "Administrator", 
+ ],
+ "icon": "fa fa-calendar",
+ "idx": 1,
+ "links": [],
+ "modified": "2020-11-05 12:16:53.081573",
+ "modified_by": "Administrator",
+ "module": "Accounts",
+ "name": "Fiscal Year",
+ "owner": "Administrator",
  "permissions": [
   {
-   "amend": 0, 
-   "cancel": 0, 
-   "create": 1, 
-   "delete": 1, 
-   "email": 1, 
-   "export": 0, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "System Manager", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 0, 
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "System Manager",
+   "share": 1,
    "write": 1
-  }, 
+  },
   {
-   "amend": 0, 
-   "cancel": 0, 
-   "create": 0, 
-   "delete": 0, 
-   "email": 0, 
-   "export": 0, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 0, 
-   "read": 1, 
-   "report": 0, 
-   "role": "Sales User", 
-   "set_user_permissions": 0, 
-   "share": 0, 
-   "submit": 0, 
-   "write": 0
-  }, 
+   "read": 1,
+   "role": "Sales User"
+  },
   {
-   "amend": 0, 
-   "cancel": 0, 
-   "create": 0, 
-   "delete": 0, 
-   "email": 0, 
-   "export": 0, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 0, 
-   "read": 1, 
-   "report": 0, 
-   "role": "Purchase User", 
-   "set_user_permissions": 0, 
-   "share": 0, 
-   "submit": 0, 
-   "write": 0
-  }, 
+   "read": 1,
+   "role": "Purchase User"
+  },
   {
-   "amend": 0, 
-   "cancel": 0, 
-   "create": 0, 
-   "delete": 0, 
-   "email": 0, 
-   "export": 0, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 0, 
-   "read": 1, 
-   "report": 0, 
-   "role": "Accounts User", 
-   "set_user_permissions": 0, 
-   "share": 0, 
-   "submit": 0, 
-   "write": 0
-  }, 
+   "read": 1,
+   "role": "Accounts User"
+  },
   {
-   "amend": 0, 
-   "cancel": 0, 
-   "create": 0, 
-   "delete": 0, 
-   "email": 0, 
-   "export": 0, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 0, 
-   "read": 1, 
-   "report": 0, 
-   "role": "Stock User", 
-   "set_user_permissions": 0, 
-   "share": 0, 
-   "submit": 0, 
-   "write": 0
-  }, 
+   "read": 1,
+   "role": "Stock User"
+  },
   {
-   "amend": 0, 
-   "cancel": 0, 
-   "create": 0, 
-   "delete": 0, 
-   "email": 0, 
-   "export": 0, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 0, 
-   "read": 1, 
-   "report": 0, 
-   "role": "Employee", 
-   "set_user_permissions": 0, 
-   "share": 0, 
-   "submit": 0, 
-   "write": 0
+   "read": 1,
+   "role": "Employee"
   }
- ], 
- "quick_entry": 0, 
- "read_only": 0, 
- "read_only_onload": 0, 
- "show_name_in_global_search": 1, 
- "sort_field": "name", 
- "sort_order": "DESC", 
- "track_changes": 0, 
- "track_seen": 0
+ ],
+ "show_name_in_global_search": 1,
+ "sort_field": "name",
+ "sort_order": "DESC"
 }
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/fiscal_year/fiscal_year.py b/erpnext/accounts/doctype/fiscal_year/fiscal_year.py
index d80bc7f..da6a3fd 100644
--- a/erpnext/accounts/doctype/fiscal_year/fiscal_year.py
+++ b/erpnext/accounts/doctype/fiscal_year/fiscal_year.py
@@ -36,6 +36,11 @@
 					frappe.throw(_("Cannot change Fiscal Year Start Date and Fiscal Year End Date once the Fiscal Year is saved."))
 
 	def validate_dates(self):
+		if self.is_short_year:
+			# Fiscal Year can be shorter than one year, in some jurisdictions
+			# under certain circumstances. For example, in the USA and Germany.
+			return
+
 		if getdate(self.year_start_date) > getdate(self.year_end_date):
 			frappe.throw(_("Fiscal Year Start Date should be one year earlier than Fiscal Year End Date"),
 				FiscalYearIncorrectDate)
@@ -116,12 +121,8 @@
 			pass
 
 def get_from_and_to_date(fiscal_year):
-	from_and_to_date_tuple = frappe.db.sql("""select year_start_date, year_end_date
-		from `tabFiscal Year` where name=%s""", (fiscal_year))[0]
-
-	from_and_to_date = {
-		"from_date": from_and_to_date_tuple[0],
-		"to_date": from_and_to_date_tuple[1]
-	}
-
-	return from_and_to_date
+	fields = [
+		"year_start_date as from_date",
+		"year_end_date as to_date"
+	]
+	return frappe.db.get_value("Fiscal Year", fiscal_year, fields, as_dict=1)
diff --git a/erpnext/accounts/doctype/fiscal_year/test_fiscal_year.py b/erpnext/accounts/doctype/fiscal_year/test_fiscal_year.py
index f7b7782..cec4f44 100644
--- a/erpnext/accounts/doctype/fiscal_year/test_fiscal_year.py
+++ b/erpnext/accounts/doctype/fiscal_year/test_fiscal_year.py
@@ -11,6 +11,7 @@
 test_ignore = ["Company"]
 
 class TestFiscalYear(unittest.TestCase):
+
 	def test_extra_year(self):
 		if frappe.db.exists("Fiscal Year", "_Test Fiscal Year 2000"):
 			frappe.delete_doc("Fiscal Year", "_Test Fiscal Year 2000")
diff --git a/erpnext/accounts/doctype/fiscal_year/test_records.json b/erpnext/accounts/doctype/fiscal_year/test_records.json
index d5723ca..4405253 100644
--- a/erpnext/accounts/doctype/fiscal_year/test_records.json
+++ b/erpnext/accounts/doctype/fiscal_year/test_records.json
@@ -1,6 +1,13 @@
 [
  {
   "doctype": "Fiscal Year",
+  "year": "_Test Short Fiscal Year 2011",
+  "is_short_year": 1,
+  "year_end_date": "2011-04-01",
+  "year_start_date": "2011-12-31"
+ },
+ {
+  "doctype": "Fiscal Year",
   "year": "_Test Fiscal Year 2012",
   "year_end_date": "2012-12-31",
   "year_start_date": "2012-01-01"
diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
index a7e20a0..d486ff6 100644
--- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
+++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py
@@ -39,6 +39,7 @@
 		self.validate_serialised_or_batched_item()
 		self.validate_stock_availablility()
 		self.validate_return_items_qty()
+		self.validate_non_stock_items()
 		self.set_status()
 		self.set_account_for_mode_of_payment()
 		self.validate_pos()
@@ -174,6 +175,14 @@
 							_("Row #{}: Serial No {} cannot be returned since it was not transacted in original invoice {}")
 							.format(d.idx, bold_serial_no, bold_return_against)
 						)
+	
+	def validate_non_stock_items(self):
+		for d in self.get("items"):
+			is_stock_item = frappe.get_cached_value("Item", d.get("item_code"), "is_stock_item")
+			if not is_stock_item:
+				frappe.throw(_("Row #{}: Item {} is a non stock item. You can only include stock items in a POS Invoice. ").format(
+					d.idx, frappe.bold(d.item_code)
+				), title=_("Invalid Item"))
 
 	def validate_mode_of_payment(self):
 		if len(self.payments) == 0:
diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
index 149c476..55a5b0e 100644
--- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py
@@ -352,8 +352,14 @@
 		pricing_rule_rate = 0.0
 		if pricing_rule.currency == args.currency:
 			pricing_rule_rate = pricing_rule.rate
+
+		if pricing_rule_rate:
+			# Override already set price list rate (from item price)
+			# if pricing_rule_rate > 0
+			item_details.update({
+				"price_list_rate": pricing_rule_rate * args.get("conversion_factor", 1),
+			})
 		item_details.update({
-			"price_list_rate": pricing_rule_rate * args.get("conversion_factor", 1),
 			"discount_percentage": 0.0
 		})
 
diff --git a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
index 22a031c..ec0a485 100644
--- a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
+++ b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py
@@ -484,6 +484,43 @@
 		frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 1")
 		frappe.delete_doc_if_exists("Pricing Rule", "_Test Pricing Rule 2")
 
+	def test_item_price_with_pricing_rule(self):
+		item = make_item("Water Flask")
+		make_item_price("Water Flask", "_Test Price List", 100)
+
+		pricing_rule_record = {
+			"doctype": "Pricing Rule",
+			"title": "_Test Water Flask Rule",
+			"apply_on": "Item Code",
+			"items": [{
+				"item_code": "Water Flask",
+			}],
+			"selling": 1,
+			"currency": "INR",
+			"rate_or_discount": "Rate",
+			"rate": 0,
+			"margin_type": "Percentage",
+			"margin_rate_or_amount": 2,
+			"company": "_Test Company"
+		}
+		rule = frappe.get_doc(pricing_rule_record)
+		rule.insert()
+
+		si = create_sales_invoice(do_not_save=True, item_code="Water Flask")
+		si.selling_price_list = "_Test Price List"
+		si.save()
+
+		# If rate in Rule is 0, give preference to Item Price if it exists
+		self.assertEqual(si.items[0].price_list_rate, 100)
+		self.assertEqual(si.items[0].margin_rate_or_amount, 2)
+		self.assertEqual(si.items[0].rate_with_margin, 102)
+		self.assertEqual(si.items[0].rate, 102)
+
+		si.delete()
+		rule.delete()
+		frappe.get_doc("Item Price", {"item_code": "Water Flask"}).delete()
+		item.delete()
+
 def make_pricing_rule(**args):
 	args = frappe._dict(args)
 
diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
index 4b59887..af6c696 100644
--- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py
@@ -1401,6 +1401,7 @@
 	def set_missing_values(source, target):
 		target.ignore_pricing_rule = 1
 		target.run_method("set_missing_values")
+		target.run_method("set_po_nos")
 		target.run_method("calculate_taxes_and_totals")
 
 	def update_item(source_doc, target_doc, source_parent):
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js
index 2f52a9e..47483c9 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.js
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.js
@@ -90,6 +90,11 @@
 		this.frm.set_df_property("drop_ship", "hidden", !is_drop_ship);
 
 		if(doc.docstatus == 1) {
+			this.frm.fields_dict.items_section.wrapper.addClass("hide-border");
+			if(!this.frm.doc.set_warehouse) {
+				this.frm.fields_dict.items_section.wrapper.removeClass("hide-border");
+			}
+
 			if(!in_list(["Closed", "Delivered"], doc.status)) {
 				if(this.frm.doc.status !== 'Closed' && flt(this.frm.doc.per_received) < 100 && flt(this.frm.doc.per_billed) < 100) {
 					this.frm.add_custom_button(__('Update Items'), () => {
@@ -126,16 +131,25 @@
 			if(doc.status != "Closed") {
 				if (doc.status != "On Hold") {
 					if(flt(doc.per_received) < 100 && allow_receipt) {
-						cur_frm.add_custom_button(__('Receipt'), this.make_purchase_receipt, __('Create'));
+						cur_frm.add_custom_button(__('Purchase Receipt'), this.make_purchase_receipt, __('Create'));
 						if(doc.is_subcontracted==="Yes" && me.has_unsupplied_items()) {
 							cur_frm.add_custom_button(__('Material to Supplier'),
 								function() { me.make_stock_entry(); }, __("Transfer"));
 						}
 					}
 					if(flt(doc.per_billed) < 100)
-						cur_frm.add_custom_button(__('Invoice'),
+						cur_frm.add_custom_button(__('Purchase Invoice'),
 							this.make_purchase_invoice, __('Create'));
 
+					if(flt(doc.per_billed)==0 && doc.status != "Delivered") {
+						cur_frm.add_custom_button(__('Payment'), cur_frm.cscript.make_payment_entry, __('Create'));
+					}
+
+					if(flt(doc.per_billed)==0) {
+						this.frm.add_custom_button(__('Payment Request'),
+							function() { me.make_payment_request() }, __('Create'));
+					}
+
 					if(!doc.auto_repeat) {
 						cur_frm.add_custom_button(__('Subscription'), function() {
 							erpnext.utils.make_subscription(doc.doctype, doc.name)
@@ -156,13 +170,7 @@
 						});
 					}
 				}
-				if(flt(doc.per_billed)==0) {
-					this.frm.add_custom_button(__('Payment Request'),
-						function() { me.make_payment_request() }, __('Create'));
-				}
-				if(flt(doc.per_billed)==0 && doc.status != "Delivered") {
-					cur_frm.add_custom_button(__('Payment'), cur_frm.cscript.make_payment_entry, __('Create'));
-				}
+
 				cur_frm.page.set_inner_btn_group_as_primary(__('Create'));
 			}
 		} else if(doc.docstatus===0) {
@@ -358,12 +366,16 @@
 					method: "erpnext.stock.doctype.material_request.material_request.make_purchase_order",
 					source_doctype: "Material Request",
 					target: me.frm,
-					setters: {},
+					setters: {
+						schedule_date: undefined,
+						status: undefined
+					},
 					get_query_filters: {
 						material_request_type: "Purchase",
 						docstatus: 1,
 						status: ["!=", "Stopped"],
 						per_ordered: ["<", 99.99],
+						company: me.frm.doc.company
 					}
 				})
 			}, __("Get Items From"));
@@ -375,16 +387,17 @@
 					source_doctype: "Supplier Quotation",
 					target: me.frm,
 					setters: {
-						supplier: me.frm.doc.supplier
+						supplier: me.frm.doc.supplier,
+						valid_till: undefined
 					},
 					get_query_filters: {
 						docstatus: 1,
-						status: ["!=", "Stopped"],
+						status: ["not in", ["Stopped", "Expired"]],
 					}
 				})
 			}, __("Get Items From"));
 
-		this.frm.add_custom_button(__('Update rate as per last purchase'),
+		this.frm.add_custom_button(__('Update Rate as per Last Purchase'),
 			function() {
 				frappe.call({
 					"method": "get_last_purchase_rate",
diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.json b/erpnext/buying/doctype/purchase_order/purchase_order.json
index 2747c7c..4b865a9 100644
--- a/erpnext/buying/doctype/purchase_order/purchase_order.json
+++ b/erpnext/buying/doctype/purchase_order/purchase_order.json
@@ -30,8 +30,8 @@
   "customer_contact_email",
   "section_addresses",
   "supplier_address",
-  "contact_person",
   "address_display",
+  "contact_person",
   "contact_display",
   "contact_mobile",
   "contact_email",
@@ -49,12 +49,14 @@
   "plc_conversion_rate",
   "ignore_pricing_rule",
   "sec_warehouse",
-  "set_warehouse",
-  "col_break_warehouse",
   "is_subcontracted",
+  "col_break_warehouse",
   "supplier_warehouse",
-  "items_section",
+  "before_items_section",
   "scan_barcode",
+  "items_col_break",
+  "set_warehouse",
+  "items_section",
   "items",
   "sb_last_purchase",
   "total_qty",
@@ -108,18 +110,13 @@
   "payment_terms_template",
   "payment_schedule",
   "tracking_section",
-  "per_billed",
+  "status",
   "column_break_75",
+  "per_billed",
   "per_received",
   "terms_section_break",
   "tc_name",
   "terms",
-  "more_info",
-  "status",
-  "ref_sq",
-  "column_break_74",
-  "party_account_currency",
-  "inter_company_order_reference",
   "column_break5",
   "letter_head",
   "select_print_heading",
@@ -131,7 +128,12 @@
   "to_date",
   "column_break_97",
   "auto_repeat",
-  "update_auto_repeat_reference"
+  "update_auto_repeat_reference",
+  "more_info",
+  "ref_sq",
+  "column_break_74",
+  "party_account_currency",
+  "inter_company_order_reference"
  ],
  "fields": [
   {
@@ -313,34 +315,34 @@
   {
    "fieldname": "supplier_address",
    "fieldtype": "Link",
-   "label": "Select Supplier Address",
+   "label": "Supplier Address",
    "options": "Address",
    "print_hide": 1
   },
   {
    "fieldname": "contact_person",
    "fieldtype": "Link",
-   "label": "Contact Person",
+   "label": "Supplier Contact",
    "options": "Contact",
    "print_hide": 1
   },
   {
    "fieldname": "address_display",
    "fieldtype": "Small Text",
-   "label": "Address",
+   "label": "Supplier Address Details",
    "read_only": 1
   },
   {
    "fieldname": "contact_display",
    "fieldtype": "Small Text",
    "in_global_search": 1,
-   "label": "Contact",
+   "label": "Contact Name",
    "read_only": 1
   },
   {
    "fieldname": "contact_mobile",
    "fieldtype": "Small Text",
-   "label": "Mobile No",
+   "label": "Contact Mobile No",
    "read_only": 1
   },
   {
@@ -358,14 +360,14 @@
   {
    "fieldname": "shipping_address",
    "fieldtype": "Link",
-   "label": "Select Shipping Address",
+   "label": "Company Shipping Address",
    "options": "Address",
    "print_hide": 1
   },
   {
    "fieldname": "shipping_address_display",
    "fieldtype": "Small Text",
-   "label": "Shipping Address",
+   "label": "Shipping Address Details",
    "print_hide": 1,
    "read_only": 1
   },
@@ -433,7 +435,8 @@
   },
   {
    "fieldname": "sec_warehouse",
-   "fieldtype": "Section Break"
+   "fieldtype": "Section Break",
+   "label": "Subcontracting"
   },
   {
    "description": "Sets 'Warehouse' in each row of the Items table.",
@@ -466,6 +469,7 @@
   {
    "fieldname": "items_section",
    "fieldtype": "Section Break",
+   "hide_border": 1,
    "oldfieldtype": "Section Break",
    "options": "fa fa-shopping-cart"
   },
@@ -598,7 +602,8 @@
   },
   {
    "fieldname": "section_break_52",
-   "fieldtype": "Section Break"
+   "fieldtype": "Section Break",
+   "hide_border": 1
   },
   {
    "fieldname": "taxes",
@@ -626,10 +631,12 @@
   {
    "fieldname": "totals",
    "fieldtype": "Section Break",
+   "label": "Taxes and Charges",
    "oldfieldtype": "Section Break",
    "options": "fa fa-money"
   },
   {
+   "depends_on": "base_taxes_and_charges_added",
    "fieldname": "base_taxes_and_charges_added",
    "fieldtype": "Currency",
    "label": "Taxes and Charges Added (Company Currency)",
@@ -640,6 +647,7 @@
    "read_only": 1
   },
   {
+   "depends_on": "base_taxes_and_charges_deducted",
    "fieldname": "base_taxes_and_charges_deducted",
    "fieldtype": "Currency",
    "label": "Taxes and Charges Deducted (Company Currency)",
@@ -650,6 +658,7 @@
    "read_only": 1
   },
   {
+   "depends_on": "base_total_taxes_and_charges",
    "fieldname": "base_total_taxes_and_charges",
    "fieldtype": "Currency",
    "label": "Total Taxes and Charges (Company Currency)",
@@ -665,6 +674,7 @@
    "fieldtype": "Column Break"
   },
   {
+   "depends_on": "taxes_and_charges_added",
    "fieldname": "taxes_and_charges_added",
    "fieldtype": "Currency",
    "label": "Taxes and Charges Added",
@@ -675,6 +685,7 @@
    "read_only": 1
   },
   {
+   "depends_on": "taxes_and_charges_deducted",
    "fieldname": "taxes_and_charges_deducted",
    "fieldtype": "Currency",
    "label": "Taxes and Charges Deducted",
@@ -685,6 +696,7 @@
    "read_only": 1
   },
   {
+   "depends_on": "total_taxes_and_charges",
    "fieldname": "total_taxes_and_charges",
    "fieldtype": "Currency",
    "label": "Total Taxes and Charges",
@@ -694,7 +706,7 @@
   },
   {
    "collapsible": 1,
-   "collapsible_depends_on": "discount_amount",
+   "collapsible_depends_on": "apply_discount_on",
    "fieldname": "discount_section",
    "fieldtype": "Section Break",
    "label": "Additional Discount"
@@ -734,7 +746,8 @@
   },
   {
    "fieldname": "totals_section",
-   "fieldtype": "Section Break"
+   "fieldtype": "Section Break",
+   "label": "Totals"
   },
   {
    "fieldname": "base_grand_total",
@@ -902,12 +915,12 @@
   },
   {
    "fieldname": "ref_sq",
-   "fieldtype": "Data",
-   "hidden": 1,
-   "label": "Ref SQ",
+   "fieldtype": "Link",
+   "label": "Supplier Quotation",
    "no_copy": 1,
    "oldfieldname": "ref_sq",
    "oldfieldtype": "Data",
+   "options": "Supplier Quotation",
    "print_hide": 1,
    "read_only": 1
   },
@@ -1061,7 +1074,7 @@
    "collapsible": 1,
    "fieldname": "tracking_section",
    "fieldtype": "Section Break",
-   "label": "Tracking"
+   "label": "Order Status"
   },
   {
    "fieldname": "column_break_75",
@@ -1070,21 +1083,29 @@
   {
    "fieldname": "billing_address",
    "fieldtype": "Link",
-   "label": "Select Billing Address",
+   "label": "Company Billing Address",
    "options": "Address"
   },
   {
    "fieldname": "billing_address_display",
    "fieldtype": "Small Text",
-   "label": "Billing Address",
+   "label": "Billing Address Details",
    "read_only": 1
+  },
+  {
+   "fieldname": "before_items_section",
+   "fieldtype": "Section Break"
+  },
+  {
+   "fieldname": "items_col_break",
+   "fieldtype": "Column Break"
   }
  ],
  "icon": "fa fa-file-text",
  "idx": 105,
  "is_submittable": 1,
  "links": [],
- "modified": "2020-10-07 14:31:57.661221",
+ "modified": "2020-10-30 11:39:37.388249",
  "modified_by": "Administrator",
  "module": "Buying",
  "name": "Purchase Order",
diff --git a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
index 7a52c28..10db240 100644
--- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
+++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json
@@ -24,6 +24,7 @@
   "col_break2",
   "uom",
   "conversion_factor",
+  "stock_qty",
   "sec_break1",
   "price_list_rate",
   "discount_percentage",
@@ -46,11 +47,8 @@
   "column_break_32",
   "base_net_rate",
   "base_net_amount",
-  "billed_amt",
   "warehouse_and_reference",
   "warehouse",
-  "delivered_by_supplier",
-  "project",
   "material_request",
   "material_request_item",
   "sales_order",
@@ -58,36 +56,37 @@
   "supplier_quotation",
   "supplier_quotation_item",
   "col_break5",
+  "delivered_by_supplier",
   "against_blanket_order",
   "blanket_order",
   "blanket_order_rate",
   "item_group",
   "brand",
-  "bom",
-  "include_exploded_items",
   "section_break_56",
-  "stock_qty",
-  "column_break_60",
   "received_qty",
   "returned_qty",
-  "manufacture_details",
-  "manufacturer",
-  "column_break_14",
-  "manufacturer_part_no",
-  "more_info_section_break",
-  "is_fixed_asset",
-  "item_tax_rate",
+  "column_break_60",
+  "billed_amt",
   "accounting_details",
   "expense_account",
-  "column_break_68",
+  "manufacture_details",
+  "manufacturer",
+  "manufacturer_part_no",
+  "column_break_14",
+  "bom",
+  "include_exploded_items",
   "item_weight_details",
   "weight_per_unit",
   "total_weight",
   "column_break_40",
   "weight_uom",
   "accounting_dimensions_section",
-  "cost_center",
+  "project",
   "dimension_col_break",
+  "cost_center",
+  "more_info_section_break",
+  "is_fixed_asset",
+  "item_tax_rate",
   "section_break_72",
   "page_break"
  ],
@@ -346,6 +345,7 @@
   },
   {
    "default": "0",
+   "depends_on": "is_free_item",
    "fieldname": "is_free_item",
    "fieldtype": "Check",
    "label": "Is Free Item",
@@ -508,9 +508,10 @@
   },
   {
    "default": "0",
+   "depends_on": "delivered_by_supplier",
    "fieldname": "delivered_by_supplier",
    "fieldtype": "Check",
-   "label": "To be delivered to customer",
+   "label": "To be Delivered to Customer",
    "print_hide": 1,
    "read_only": 1
   },
@@ -558,6 +559,7 @@
    "read_only": 1
   },
   {
+   "depends_on": "eval:parent.is_subcontracted == 'Yes'",
    "fieldname": "bom",
    "fieldtype": "Link",
    "label": "BOM",
@@ -574,21 +576,21 @@
   },
   {
    "fieldname": "section_break_56",
-   "fieldtype": "Section Break"
+   "fieldtype": "Section Break",
+   "label": "Billed, Received & Returned"
   },
   {
    "fieldname": "stock_qty",
    "fieldtype": "Float",
-   "label": "Qty as per Stock UOM",
+   "label": "Qty in Stock UOM",
    "no_copy": 1,
-   "oldfieldname": "stock_qty",
-   "oldfieldtype": "Currency",
    "print_hide": 1,
    "print_width": "100px",
    "read_only": 1,
    "width": "100px"
   },
   {
+   "depends_on": "received_qty",
    "fieldname": "received_qty",
    "fieldtype": "Float",
    "label": "Received Qty",
@@ -612,9 +614,10 @@
    "fieldtype": "Column Break"
   },
   {
+   "depends_on": "billed_amt",
    "fieldname": "billed_amt",
    "fieldtype": "Currency",
-   "label": "Billed Amt",
+   "label": "Billed Amount",
    "no_copy": 1,
    "options": "currency",
    "print_hide": 1,
@@ -633,6 +636,7 @@
    "report_hide": 1
   },
   {
+   "collapsible": 1,
    "fieldname": "accounting_details",
    "fieldtype": "Section Break",
    "label": "Accounting Details"
@@ -645,10 +649,6 @@
    "print_hide": 1
   },
   {
-   "fieldname": "column_break_68",
-   "fieldtype": "Column Break"
-  },
-  {
    "fieldname": "cost_center",
    "fieldtype": "Link",
    "label": "Cost Center",
@@ -715,6 +715,7 @@
   },
   {
    "default": "0",
+   "depends_on": "is_fixed_asset",
    "fetch_from": "item_code.is_fixed_asset",
    "fieldname": "is_fixed_asset",
    "fieldtype": "Check",
@@ -728,9 +729,10 @@
   }
  ],
  "idx": 1,
+ "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2020-04-21 11:55:58.643393",
+ "modified": "2020-10-30 11:59:47.670951",
  "modified_by": "Administrator",
  "module": "Buying",
  "name": "Purchase Order Item",
diff --git a/erpnext/communication/doctype/communication_medium/communication_medium.json b/erpnext/communication/doctype/communication_medium/communication_medium.json
index f009b38..1e1fe3b 100644
--- a/erpnext/communication/doctype/communication_medium/communication_medium.json
+++ b/erpnext/communication/doctype/communication_medium/communication_medium.json
@@ -1,12 +1,14 @@
 {
+ "actions": [],
  "autoname": "Prompt",
  "creation": "2019-06-05 11:48:30.572795",
  "doctype": "DocType",
  "engine": "InnoDB",
  "field_order": [
+  "communication_channel",
   "communication_medium_type",
-  "catch_all",
   "column_break_3",
+  "catch_all",
   "provider",
   "disabled",
   "timeslots_section",
@@ -54,9 +56,16 @@
    "fieldtype": "Table",
    "label": "Timeslots",
    "options": "Communication Medium Timeslot"
+  },
+  {
+   "fieldname": "communication_channel",
+   "fieldtype": "Select",
+   "label": "Communication Channel",
+   "options": "\nExotel"
   }
  ],
- "modified": "2019-06-05 11:49:30.769006",
+ "links": [],
+ "modified": "2020-10-27 16:22:08.068542",
  "modified_by": "Administrator",
  "module": "Communication",
  "name": "Communication Medium",
diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py
index 5886171..7504746 100644
--- a/erpnext/controllers/selling_controller.py
+++ b/erpnext/controllers/selling_controller.py
@@ -371,13 +371,27 @@
 		self.make_sl_entries(sl_entries)
 
 	def set_po_nos(self):
-		if self.doctype in ("Delivery Note", "Sales Invoice") and hasattr(self, "items"):
-			ref_fieldname = "against_sales_order" if self.doctype == "Delivery Note" else "sales_order"
-			sales_orders = list(set([d.get(ref_fieldname) for d in self.items if d.get(ref_fieldname)]))
-			if sales_orders:
-				po_nos = frappe.get_all('Sales Order', 'po_no', filters = {'name': ('in', sales_orders)})
-				if po_nos and po_nos[0].get('po_no'):
-					self.po_no = ', '.join(list(set([d.po_no for d in po_nos if d.po_no])))
+		if self.doctype == 'Sales Invoice' and hasattr(self, "items"):
+			self.set_pos_for_sales_invoice()
+		if self.doctype == 'Delivery Note' and hasattr(self, "items"):
+			self.set_pos_for_delivery_note()
+
+	def set_pos_for_sales_invoice(self):
+		po_nos = []
+		self.get_po_nos('Sales Order', 'sales_order', po_nos)
+		self.get_po_nos('Delivery Note', 'delivery_note', po_nos)
+		self.po_no = ', '.join(list(set(x.strip() for x in ','.join(po_nos).split(','))))
+
+	def set_pos_for_delivery_note(self):
+		po_nos = []
+		self.get_po_nos('Sales Order', 'against_sales_order', po_nos)
+		self.get_po_nos('Sales Invoice', 'against_sales_invoice', po_nos)
+		self.po_no = ', '.join(list(set(x.strip() for x in ','.join(po_nos).split(','))))
+
+	def get_po_nos(self, ref_doctype, ref_fieldname, po_nos):
+		doc_list = list(set([d.get(ref_fieldname) for d in self.items if d.get(ref_fieldname)]))
+		if doc_list:
+			po_nos += [d.po_no for d in frappe.get_all(ref_doctype, 'po_no', filters = {'name': ('in', doc_list)}) if d.get('po_no')]
 
 	def set_gross_profit(self):
 		if self.doctype in ["Sales Order", "Quotation"]:
diff --git a/erpnext/crm/doctype/contract_template/contract_template.json b/erpnext/crm/doctype/contract_template/contract_template.json
index ef9974f..5e4582f 100644
--- a/erpnext/crm/doctype/contract_template/contract_template.json
+++ b/erpnext/crm/doctype/contract_template/contract_template.json
@@ -23,8 +23,7 @@
   {
    "fieldname": "contract_terms",
    "fieldtype": "Text Editor",
-   "label": "Contract Terms and Conditions",
-   "read_only": 1
+   "label": "Contract Terms and Conditions"
   },
   {
    "fieldname": "sb_fulfilment",
@@ -45,7 +44,7 @@
   }
  ],
  "links": [],
- "modified": "2020-06-03 00:24:58.179816",
+ "modified": "2020-11-11 17:49:44.879363",
  "modified_by": "Administrator",
  "module": "CRM",
  "name": "Contract Template",
diff --git a/erpnext/erpnext_integrations/connectors/shopify_connection.py b/erpnext/erpnext_integrations/connectors/shopify_connection.py
index d59f909..8aa7453 100644
--- a/erpnext/erpnext_integrations/connectors/shopify_connection.py
+++ b/erpnext/erpnext_integrations/connectors/shopify_connection.py
@@ -2,12 +2,13 @@
 import frappe
 from frappe import _
 import json
-from frappe.utils import cstr, cint, nowdate, flt
+from frappe.utils import cstr, cint, nowdate, getdate, flt, get_request_session, get_datetime
 from erpnext.erpnext_integrations.utils import validate_webhooks_request
 from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note, make_sales_invoice
 from erpnext.erpnext_integrations.doctype.shopify_settings.sync_product import sync_item_from_shopify
 from erpnext.erpnext_integrations.doctype.shopify_settings.sync_customer import create_customer
 from erpnext.erpnext_integrations.doctype.shopify_log.shopify_log import make_shopify_log, dump_request_data
+from erpnext.erpnext_integrations.doctype.shopify_settings.shopify_settings import get_shopify_url, get_header
 
 @frappe.whitelist(allow_guest=True)
 @validate_webhooks_request("Shopify Settings", 'X-Shopify-Hmac-Sha256', secret_key='shared_secret')
@@ -18,7 +19,7 @@
 
 	dump_request_data(order, event)
 
-def sync_sales_order(order, request_id=None):
+def sync_sales_order(order, request_id=None, old_order_sync=False):
 	frappe.set_user('Administrator')
 	shopify_settings = frappe.get_doc("Shopify Settings")
 	frappe.flags.request_id = request_id
@@ -27,7 +28,7 @@
 		try:
 			validate_customer(order, shopify_settings)
 			validate_item(order, shopify_settings)
-			create_order(order, shopify_settings)
+			create_order(order, shopify_settings, old_order_sync=old_order_sync)
 		except Exception as e:
 			make_shopify_log(status="Error", exception=e)
 
@@ -77,13 +78,13 @@
 		if item.get("product_id") and not frappe.db.get_value("Item", {"shopify_product_id": item.get("product_id")}, "name"):
 			sync_item_from_shopify(shopify_settings, item)
 
-def create_order(order, shopify_settings, company=None):
+def create_order(order, shopify_settings, old_order_sync=False, company=None):
 	so = create_sales_order(order, shopify_settings, company)
 	if so:
 		if order.get("financial_status") == "paid":
-			create_sales_invoice(order, shopify_settings, so)
+			create_sales_invoice(order, shopify_settings, so, old_order_sync=old_order_sync)
 
-		if order.get("fulfillments"):
+		if order.get("fulfillments") and not old_order_sync:
 			create_delivery_note(order, shopify_settings, so)
 
 def create_sales_order(shopify_order, shopify_settings, company=None):
@@ -92,7 +93,7 @@
 	so = frappe.db.get_value("Sales Order", {"shopify_order_id": shopify_order.get("id")}, "name")
 
 	if not so:
-		items = get_order_items(shopify_order.get("line_items"), shopify_settings)
+		items = get_order_items(shopify_order.get("line_items"), shopify_settings, getdate(shopify_order.get('created_at')))
 
 		if not items:
 			message = 'Following items exists in the shopify order but relevant records were not found in the shopify Product master'
@@ -106,8 +107,10 @@
 			"doctype": "Sales Order",
 			"naming_series": shopify_settings.sales_order_series or "SO-Shopify-",
 			"shopify_order_id": shopify_order.get("id"),
+			"shopify_order_number": shopify_order.get("name"),
 			"customer": customer or shopify_settings.default_customer,
-			"delivery_date": nowdate(),
+			"transaction_date": getdate(shopify_order.get("created_at")) or nowdate(),
+			"delivery_date": getdate(shopify_order.get("created_at")) or nowdate(),
 			"company": shopify_settings.company,
 			"selling_price_list": shopify_settings.price_list,
 			"ignore_pricing_rule": 1,
@@ -132,12 +135,20 @@
 	frappe.db.commit()
 	return so
 
-def create_sales_invoice(shopify_order, shopify_settings, so):
+def create_sales_invoice(shopify_order, shopify_settings, so, old_order_sync=False):
 	if not frappe.db.get_value("Sales Invoice", {"shopify_order_id": shopify_order.get("id")}, "name")\
 		and so.docstatus==1 and not so.per_billed and cint(shopify_settings.sync_sales_invoice):
 
+		if old_order_sync:
+			posting_date = getdate(shopify_order.get('created_at'))
+		else:
+			posting_date = nowdate()
+
 		si = make_sales_invoice(so.name, ignore_permissions=True)
 		si.shopify_order_id = shopify_order.get("id")
+		si.shopify_order_number = shopify_order.get("name")
+		si.set_posting_time = 1
+		si.posting_date = posting_date
 		si.naming_series = shopify_settings.sales_invoice_series or "SI-Shopify-"
 		si.flags.ignore_mandatory = True
 		set_cost_center(si.items, shopify_settings.cost_center)
@@ -169,6 +180,9 @@
 
 			dn = make_delivery_note(so.name)
 			dn.shopify_order_id = fulfillment.get("order_id")
+			dn.shopify_order_number = shopify_order.get("name")
+			dn.set_posting_time = 1
+			dn.posting_date = getdate(fulfillment.get("created_at"))
 			dn.shopify_fulfillment_id = fulfillment.get("id")
 			dn.naming_series = shopify_settings.delivery_note_series or "DN-Shopify-"
 			dn.items = get_fulfillment_items(dn.items, fulfillment.get("line_items"), shopify_settings)
@@ -187,7 +201,7 @@
 		discounted_amount += flt(discount.get("amount"))
 	return discounted_amount
 
-def get_order_items(order_items, shopify_settings):
+def get_order_items(order_items, shopify_settings, delivery_date):
 	items = []
 	all_product_exists = True
 	product_not_exists = []
@@ -205,7 +219,7 @@
 				"item_code": item_code,
 				"item_name": shopify_item.get("name"),
 				"rate": shopify_item.get("price"),
-				"delivery_date": nowdate(),
+				"delivery_date": delivery_date,
 				"qty": shopify_item.get("quantity"),
 				"stock_uom": shopify_item.get("uom") or _("Nos"),
 				"warehouse": shopify_settings.warehouse
@@ -265,3 +279,64 @@
 		frappe.throw(_("Tax Account not specified for Shopify Tax {0}").format(tax.get("title")))
 
 	return tax_account
+
+@frappe.whitelist(allow_guest=True)
+def sync_old_orders():
+	frappe.set_user('Administrator')
+	shopify_settings = frappe.get_doc('Shopify Settings')
+
+	if not shopify_settings.sync_missing_orders:
+		return
+
+	url = get_url(shopify_settings)
+	session = get_request_session()
+
+	try:
+		res = session.get(url, headers=get_header(shopify_settings))
+		res.raise_for_status()
+		orders = res.json()["orders"]
+
+		for order in orders:
+			if is_sync_complete(shopify_settings, order):
+				stop_sync(shopify_settings)
+				return
+
+			sync_sales_order(order=order, old_order_sync=True)
+			last_order_id = order.get('id')
+
+		if last_order_id:
+			shopify_settings.load_from_db()
+			shopify_settings.last_order_id = last_order_id
+			shopify_settings.save()
+			frappe.db.commit()
+
+	except Exception as e:
+		raise e
+
+def stop_sync(shopify_settings):
+	shopify_settings.sync_missing_orders = 0
+	shopify_settings.last_order_id = ''
+	shopify_settings.save()
+	frappe.db.commit()
+
+def get_url(shopify_settings):
+	last_order_id = shopify_settings.last_order_id
+
+	if not last_order_id:
+		if shopify_settings.sync_based_on == 'Date':
+			url = get_shopify_url("admin/api/2020-10/orders.json?limit=250&created_at_min={0}&since_id=0".format(
+				get_datetime(shopify_settings.from_date)), shopify_settings)
+		else:
+			url = get_shopify_url("admin/api/2020-10/orders.json?limit=250&since_id={0}".format(
+				shopify_settings.from_order_id), shopify_settings)
+	else:
+		url = get_shopify_url("admin/api/2020-10/orders.json?limit=250&since_id={0}".format(last_order_id), shopify_settings)
+
+	return url
+
+def is_sync_complete(shopify_settings, order):
+	if shopify_settings.sync_based_on == 'Date':
+		return getdate(shopify_settings.to_date) < getdate(order.get('created_at'))
+	else:
+		return cstr(order.get('id')) == cstr(shopify_settings.to_order_id)
+
diff --git a/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.json b/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.json
index 2e10751..20ec063 100644
--- a/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.json
+++ b/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.json
@@ -1,7 +1,9 @@
 {
+ "actions": [],
  "creation": "2015-05-18 05:21:07.270859",
  "doctype": "DocType",
  "document_type": "System",
+ "engine": "InnoDB",
  "field_order": [
   "status_html",
   "enable_shopify",
@@ -40,7 +42,16 @@
   "sales_invoice_series",
   "section_break_22",
   "html_16",
-  "taxes"
+  "taxes",
+  "syncing_details_section",
+  "sync_missing_orders",
+  "sync_based_on",
+  "column_break_41",
+  "from_date",
+  "to_date",
+  "from_order_id",
+  "to_order_id",
+  "last_order_id"
  ],
  "fields": [
   {
@@ -255,10 +266,71 @@
    "fieldtype": "Table",
    "label": "Shopify Tax Account",
    "options": "Shopify Tax Account"
+  },
+  {
+   "collapsible": 1,
+   "fieldname": "syncing_details_section",
+   "fieldtype": "Section Break",
+   "label": "Syncing Missing Orders"
+  },
+  {
+   "depends_on": "eval:doc.sync_missing_orders",
+   "fieldname": "last_order_id",
+   "fieldtype": "Data",
+   "label": "Last Order Id",
+   "read_only": 1
+  },
+  {
+   "fieldname": "column_break_41",
+   "fieldtype": "Column Break"
+  },
+  {
+   "default": "0",
+   "description": "On checking this Order from the ",
+   "fieldname": "sync_missing_orders",
+   "fieldtype": "Check",
+   "label": "Sync Missing Old Shopify Orders"
+  },
+  {
+   "depends_on": "eval:doc.sync_missing_orders",
+   "fieldname": "sync_based_on",
+   "fieldtype": "Select",
+   "label": "Sync Based On",
+   "mandatory_depends_on": "eval:doc.sync_missing_orders",
+   "options": "\nDate\nShopify Order Id"
+  },
+  {
+   "depends_on": "eval:doc.sync_based_on == 'Date' && doc.sync_missing_orders",
+   "fieldname": "from_date",
+   "fieldtype": "Date",
+   "label": "From Date",
+   "mandatory_depends_on": "eval:doc.sync_based_on == 'Date' && doc.sync_missing_orders"
+  },
+  {
+   "depends_on": "eval:doc.sync_based_on == 'Date' && doc.sync_missing_orders",
+   "fieldname": "to_date",
+   "fieldtype": "Date",
+   "label": "To Date",
+   "mandatory_depends_on": "eval:doc.sync_based_on == 'Date' && doc.sync_missing_orders"
+  },
+  {
+   "depends_on": "eval:doc.sync_based_on == 'Shopify Order Id' && doc.sync_missing_orders",
+   "fieldname": "from_order_id",
+   "fieldtype": "Data",
+   "label": "From Order Id",
+   "mandatory_depends_on": "eval:doc.sync_based_on == 'Shopify Order Id' && doc.sync_missing_orders"
+  },
+  {
+   "depends_on": "eval:doc.sync_based_on == 'Shopify Order Id' && doc.sync_missing_orders",
+   "fieldname": "to_order_id",
+   "fieldtype": "Data",
+   "label": "To Order Id",
+   "mandatory_depends_on": "eval:doc.sync_based_on == 'Shopify Order Id' && doc.sync_missing_orders"
   }
  ],
  "issingle": 1,
- "modified": "2020-09-18 17:26:09.703215",
+ "links": [],
+ "modified": "2020-11-05 20:44:03.664891",
  "modified_by": "Administrator",
  "module": "ERPNext Integrations",
  "name": "Shopify Settings",
@@ -277,4 +349,4 @@
  ],
  "sort_field": "modified",
  "sort_order": "DESC"
-}
+}
\ No newline at end of file
diff --git a/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py b/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py
index 25ffd28..cbdf906 100644
--- a/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py
+++ b/erpnext/erpnext_integrations/doctype/shopify_settings/shopify_settings.py
@@ -87,7 +87,7 @@
 def get_header(settings):
 	header = {'Content-Type': 'application/json'}
 
-	return header;
+	return header
 
 @frappe.whitelist()
 def get_series():
@@ -121,17 +121,23 @@
 		],
 		"Sales Order": [
 			dict(fieldname='shopify_order_id', label='Shopify Order Id',
-				fieldtype='Data', insert_after='title', read_only=1, print_hide=1)
+				fieldtype='Data', insert_after='title', read_only=1, print_hide=1),
+			dict(fieldname='shopify_order_number', label='Shopify Order Number',
+				fieldtype='Data', insert_after='shopify_order_id', read_only=1, print_hide=1)
 		],
 		"Delivery Note":[
 			dict(fieldname='shopify_order_id', label='Shopify Order Id',
 				fieldtype='Data', insert_after='title', read_only=1, print_hide=1),
+			dict(fieldname='shopify_order_number', label='Shopify Order Number',
+				fieldtype='Data', insert_after='shopify_order_id', read_only=1, print_hide=1),
 			dict(fieldname='shopify_fulfillment_id', label='Shopify Fulfillment Id',
 				fieldtype='Data', insert_after='title', read_only=1, print_hide=1)
 		],
 		"Sales Invoice": [
 			dict(fieldname='shopify_order_id', label='Shopify Order Id',
-				fieldtype='Data', insert_after='title', read_only=1, print_hide=1)
+				fieldtype='Data', insert_after='title', read_only=1, print_hide=1),
+			dict(fieldname='shopify_order_number', label='Shopify Order Number',
+				fieldtype='Data', insert_after='shopify_order_id', read_only=1, print_hide=1)
 		]
 	}
 
diff --git a/erpnext/erpnext_integrations/doctype/shopify_settings/test_shopify_settings.py b/erpnext/erpnext_integrations/doctype/shopify_settings/test_shopify_settings.py
index 64ef3dc..30fa23c 100644
--- a/erpnext/erpnext_integrations/doctype/shopify_settings/test_shopify_settings.py
+++ b/erpnext/erpnext_integrations/doctype/shopify_settings/test_shopify_settings.py
@@ -58,7 +58,7 @@
 		}).save(ignore_permissions=True)
 
 		self.shopify_settings = shopify_settings
-	
+
 	def test_order(self):
 		### Create Customer ###
 		with open (os.path.join(os.path.dirname(__file__), "test_data", "shopify_customer.json")) as shopify_customer:
@@ -75,7 +75,7 @@
 		with open (os.path.join(os.path.dirname(__file__), "test_data", "shopify_order.json")) as shopify_order:
 			shopify_order = json.load(shopify_order)
 
-		create_order(shopify_order.get("order"), self.shopify_settings, "_Test Company")
+		create_order(shopify_order.get("order"), self.shopify_settings, False, company="_Test Company")
 
 		sales_order = frappe.get_doc("Sales Order", {"shopify_order_id": cstr(shopify_order.get("order").get("id"))})
 
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index e7e0c81..b4c57d7 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -15,10 +15,10 @@
 
 develop_version = '13.x.x-develop'
 
-app_include_js = "assets/js/erpnext.min.js"
-app_include_css = "assets/css/erpnext.css"
-web_include_js = "assets/js/erpnext-web.min.js"
-web_include_css = "assets/css/erpnext-web.css"
+app_include_js = "/assets/js/erpnext.min.js"
+app_include_css = "/assets/css/erpnext.css"
+web_include_js = "/assets/js/erpnext-web.min.js"
+web_include_css = "/assets/css/erpnext-web.css"
 
 doctype_js = {
 	"Address": "public/js/address.js",
@@ -311,6 +311,7 @@
 		"erpnext.projects.doctype.project.project.collect_project_status",
 		"erpnext.hr.doctype.shift_type.shift_type.process_auto_attendance_for_all_shifts",
 		"erpnext.support.doctype.issue.issue.set_service_level_agreement_variance",
+		"erpnext.erpnext_integrations.connectors.shopify_connection.sync_old_orders",
 	],
 	"daily": [
 		"erpnext.stock.reorder_item.reorder_item",
diff --git a/erpnext/hr/doctype/leave_encashment/leave_encashment.py b/erpnext/hr/doctype/leave_encashment/leave_encashment.py
index 8913c64..c1dcc97 100644
--- a/erpnext/hr/doctype/leave_encashment/leave_encashment.py
+++ b/erpnext/hr/doctype/leave_encashment/leave_encashment.py
@@ -32,7 +32,7 @@
 		additional_salary.employee = self.employee
 		earning_component = frappe.get_value("Leave Type", self.leave_type, "earning_component")
 		if not earning_component:
-			frappe.throw(_("Please set Earning Component for Leave type: {0}.".format(self.leave_type)))
+			frappe.throw(_("Please set Earning Component for Leave type: {0}.").format(self.leave_type))
 		additional_salary.salary_component = earning_component
 		additional_salary.payroll_date = self.encashment_date
 		additional_salary.amount = self.encashment_amount
@@ -98,7 +98,11 @@
 		create_leave_ledger_entry(self, args, submit)
 
 		# create reverse entry for expired leaves
-		to_date = self.get_leave_allocation().get('to_date')
+		leave_allocation = self.get_leave_allocation()
+		if not leave_allocation:
+			return
+
+		to_date = leave_allocation.get('to_date')
 		if to_date < getdate(nowdate()):
 			args = frappe._dict(
 				leaves=self.encashable_days,
diff --git a/erpnext/hr/doctype/upload_attendance/upload_attendance.js b/erpnext/hr/doctype/upload_attendance/upload_attendance.js
index 9df2948..29aa854 100644
--- a/erpnext/hr/doctype/upload_attendance/upload_attendance.js
+++ b/erpnext/hr/doctype/upload_attendance/upload_attendance.js
@@ -24,10 +24,10 @@
 		}
 		window.location.href = repl(frappe.request.url +
 			'?cmd=%(cmd)s&from_date=%(from_date)s&to_date=%(to_date)s', {
-				cmd: "erpnext.hr.doctype.upload_attendance.upload_attendance.get_template",
-				from_date: this.frm.doc.att_fr_date,
-				to_date: this.frm.doc.att_to_date,
-			});
+			cmd: "erpnext.hr.doctype.upload_attendance.upload_attendance.get_template",
+			from_date: this.frm.doc.att_fr_date,
+			to_date: this.frm.doc.att_to_date,
+		});
 	},
 
 	show_upload() {
diff --git a/erpnext/hr/doctype/upload_attendance/upload_attendance.py b/erpnext/hr/doctype/upload_attendance/upload_attendance.py
index edf05e8..674c8e3 100644
--- a/erpnext/hr/doctype/upload_attendance/upload_attendance.py
+++ b/erpnext/hr/doctype/upload_attendance/upload_attendance.py
@@ -28,7 +28,12 @@
 	w = UnicodeWriter()
 	w = add_header(w)
 
-	w = add_data(w, args)
+	try:
+		w = add_data(w, args)
+	except Exception as e:
+		frappe.clear_messages()
+		frappe.respond_as_web_page("Holiday List Missing", html=e)
+		return
 
 	# write out response as a type csv
 	frappe.response['result'] = cstr(w.getvalue())
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 9b4c217..28af3a9 100644
--- a/erpnext/loan_management/doctype/loan/loan.js
+++ b/erpnext/loan_management/doctype/loan/loan.js
@@ -7,10 +7,14 @@
 	setup: function(frm) {
 		frm.make_methods = {
 			'Loan Disbursement': function() { frm.trigger('make_loan_disbursement') },
-			'Loan Security Unpledge': function() { frm.trigger('create_loan_security_unpledge') }
+			'Loan Security Unpledge': function() { frm.trigger('create_loan_security_unpledge') },
+			'Loan Write Off': function() { frm.trigger('make_loan_write_off_entry') }
 		}
 	},
 	onload: function (frm) {
+		// Ignore loan security pledge on cancel of loan
+		frm.ignore_doctypes_on_cancel_all = ["Loan Security Pledge"];
+
 		frm.set_query("loan_application", function () {
 			return {
 				"filters": {
@@ -21,6 +25,14 @@
 			};
 		});
 
+		frm.set_query("loan_type", function () {
+			return {
+				"filters": {
+					"docstatus": 1
+				}
+			};
+		});
+
 		$.each(["penalty_income_account", "interest_income_account"], function(i, field) {
 			frm.set_query(field, function () {
 				return {
@@ -49,24 +61,33 @@
 
 	refresh: function (frm) {
 		if (frm.doc.docstatus == 1) {
-			if (frm.doc.status == "Sanctioned" || frm.doc.status == 'Partially Disbursed') {
+			if (["Disbursed", "Partially Disbursed"].includes(frm.doc.status) && (!frm.doc.repay_from_salary)) {
+				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 (["Sanctioned", "Partially Disbursed"].includes(frm.doc.status)) {
 				frm.add_custom_button(__('Loan Disbursement'), function() {
 					frm.trigger("make_loan_disbursement");
 				},__('Create'));
 			}
 
-			if (["Disbursed", "Partially Disbursed"].includes(frm.doc.status) && (!frm.doc.repay_from_salary)) {
-				frm.add_custom_button(__('Loan Repayment'), function() {
-					frm.trigger("make_repayment_entry");
-				},__('Create'));
-
-			}
-
 			if (frm.doc.status == "Loan Closure Requested") {
 				frm.add_custom_button(__('Loan Security Unpledge'), function() {
 					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");
 	},
@@ -117,6 +138,38 @@
 		})
 	},
 
+	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() {
+				frappe.call({
+					args: {
+						'loan': frm.doc.name
+					},
+					method: "erpnext.loan_management.doctype.loan.loan.request_loan_closure",
+					callback: function() {
+						frm.reload_doc();
+					}
+				});
+			}
+		);
+	},
+
 	create_loan_security_unpledge: function(frm) {
 		frappe.call({
 			method: "erpnext.loan_management.doctype.loan.loan.unpledge_security",
diff --git a/erpnext/loan_management/doctype/loan/loan.json b/erpnext/loan_management/doctype/loan/loan.json
index aa5e21b..e8ecf01 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",
@@ -75,6 +76,7 @@
    "fieldname": "loan_application",
    "fieldtype": "Link",
    "label": "Loan Application",
+   "no_copy": 1,
    "options": "Loan Application"
   },
   {
@@ -134,6 +136,7 @@
    "fieldname": "loan_amount",
    "fieldtype": "Currency",
    "label": "Loan Amount",
+   "non_negative": 1,
    "options": "Company:company:default_currency"
   },
   {
@@ -148,7 +151,8 @@
    "depends_on": "eval:doc.status==\"Disbursed\"",
    "fieldname": "disbursement_date",
    "fieldtype": "Date",
-   "label": "Disbursement Date"
+   "label": "Disbursement Date",
+   "no_copy": 1
   },
   {
    "depends_on": "is_term_loan",
@@ -252,6 +256,7 @@
    "fieldname": "total_payment",
    "fieldtype": "Currency",
    "label": "Total Payable Amount",
+   "no_copy": 1,
    "options": "Company:company:default_currency",
    "read_only": 1
   },
@@ -265,6 +270,7 @@
    "fieldname": "total_interest_payable",
    "fieldtype": "Currency",
    "label": "Total Interest Payable",
+   "no_copy": 1,
    "options": "Company:company:default_currency",
    "read_only": 1
   },
@@ -273,6 +279,7 @@
    "fieldname": "total_amount_paid",
    "fieldtype": "Currency",
    "label": "Total Amount Paid",
+   "no_copy": 1,
    "options": "Company:company:default_currency",
    "read_only": 1
   },
@@ -289,8 +296,7 @@
    "default": "0",
    "fieldname": "is_secured_loan",
    "fieldtype": "Check",
-   "label": "Is Secured Loan",
-   "read_only": 1
+   "label": "Is Secured Loan"
   },
   {
    "default": "0",
@@ -313,6 +319,7 @@
    "fieldname": "total_principal_paid",
    "fieldtype": "Currency",
    "label": "Total Principal Paid",
+   "no_copy": 1,
    "options": "Company:company:default_currency",
    "read_only": 1
   },
@@ -320,6 +327,7 @@
    "fieldname": "disbursed_amount",
    "fieldtype": "Currency",
    "label": "Disbursed Amount",
+   "no_copy": 1,
    "options": "Company:company:default_currency",
    "read_only": 1
   },
@@ -328,13 +336,23 @@
    "fieldname": "maximum_loan_amount",
    "fieldtype": "Currency",
    "label": "Maximum Loan Amount",
+   "no_copy": 1,
+   "options": "Company:company:default_currency",
+   "read_only": 1
+  },
+  {
+   "fieldname": "written_off_amount",
+   "fieldtype": "Currency",
+   "label": "Written Off Amount",
+   "no_copy": 1,
    "options": "Company:company:default_currency",
    "read_only": 1
   }
  ],
+ "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2020-08-01 12:36:11.255233",
+ "modified": "2020-11-05 10:04:00.762975",
  "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 d1b7589..8405d6e 100644
--- a/erpnext/loan_management/doctype/loan/loan.py
+++ b/erpnext/loan_management/doctype/loan/loan.py
@@ -9,6 +9,7 @@
 from frappe.utils import flt, rounded, add_months, nowdate, getdate, now_datetime
 from erpnext.loan_management.doctype.loan_security_unpledge.loan_security_unpledge import get_pledged_security_qty
 from erpnext.controllers.accounts_controller import AccountsController
+from erpnext.loan_management.doctype.loan_repayment.loan_repayment import calculate_amounts
 
 class Loan(AccountsController):
 	def validate(self):
@@ -137,9 +138,12 @@
 				})
 
 	def unlink_loan_security_pledge(self):
-		frappe.db.sql("""UPDATE `tabLoan Security Pledge` SET
-			loan = '', status = 'Unpledged'
-			where name = %s """, (self.loan_security_pledge))
+		pledges = frappe.get_all('Loan Security Pledge', fields=['name'], filters={'loan': self.name})
+		pledge_list = [d.name for d in pledges]
+		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)) #nosec
 
 def update_total_amount_paid(doc):
 	total_amount_paid = 0
@@ -183,6 +187,24 @@
 	return monthly_repayment_amount
 
 @frappe.whitelist()
+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 < 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):
 	loan = frappe.get_doc("Loan Application", loan_application)
 	if loan:
@@ -200,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:
@@ -223,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/loan_list.js b/erpnext/loan_management/doctype/loan/loan_list.js
new file mode 100644
index 0000000..6591b72
--- /dev/null
+++ b/erpnext/loan_management/doctype/loan/loan_list.js
@@ -0,0 +1,16 @@
+// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+// License: GNU General Public License v3. See license.txt
+
+frappe.listview_settings['Loan'] = {
+	get_indicator: function(doc) {
+		var status_color = {
+			"Draft": "red",
+			"Sanctioned": "blue",
+			"Disbursed": "orange",
+			"Partially Disbursed": "yellow",
+			"Loan Closure Requested": "green",
+			"Closed": "green"
+		};
+		return [__(doc.status), status_color[doc.status], "status,=,"+doc.status];
+	},
+};
diff --git a/erpnext/loan_management/doctype/loan/test_loan.py b/erpnext/loan_management/doctype/loan/test_loan.py
index 5a4a19a..10a7b11 100644
--- a/erpnext/loan_management/doctype/loan/test_loan.py
+++ b/erpnext/loan_management/doctype/loan/test_loan.py
@@ -14,7 +14,7 @@
 	process_loan_interest_accrual_for_term_loans)
 from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import days_in_year
 from erpnext.loan_management.doctype.process_loan_security_shortfall.process_loan_security_shortfall import create_process_loan_security_shortfall
-from erpnext.loan_management.doctype.loan.loan import unpledge_security
+from erpnext.loan_management.doctype.loan.loan import unpledge_security, request_loan_closure, make_loan_write_off
 from erpnext.loan_management.doctype.loan_security_unpledge.loan_security_unpledge import get_pledged_security_qty
 from erpnext.loan_management.doctype.loan_application.loan_application import create_pledge
 from erpnext.loan_management.doctype.loan_disbursement.loan_disbursement import get_disbursal_amount
@@ -132,7 +132,7 @@
 		loan_application = create_loan_application('_Test Company', self.applicant2, 'Demand Loan', pledge)
 		create_pledge(loan_application)
 
-		loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date=get_first_day(nowdate()))
+		loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
 		loan.submit()
 
 		self.assertEquals(loan.loan_amount, 1000000)
@@ -142,30 +142,30 @@
 
 		no_of_days = date_diff(last_date, first_date) + 1
 
-		accrued_interest_amount = (loan.loan_amount * loan.rate_of_interest * no_of_days) \
-			/ (days_in_year(get_datetime(first_date).year) * 100)
+		accrued_interest_amount = flt((loan.loan_amount * loan.rate_of_interest * no_of_days)
+			/ (days_in_year(get_datetime(first_date).year) * 100), 2)
 
 		make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date)
 
 		process_loan_interest_accrual_for_demand_loans(posting_date = last_date)
 
-		repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 10), "Regular Payment", 111118.68)
+		repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 10), 111119)
 		repayment_entry.save()
 		repayment_entry.submit()
 
-		penalty_amount = (accrued_interest_amount * 4 * 25) / (100 * days_in_year(get_datetime(first_date).year))
-		self.assertEquals(flt(repayment_entry.penalty_amount, 2), flt(penalty_amount, 2))
+		penalty_amount = (accrued_interest_amount * 5 * 25) / 100
+		self.assertEquals(flt(repayment_entry.penalty_amount,0), flt(penalty_amount, 0))
 
-		amounts = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['paid_interest_amount',
-			'paid_principal_amount'])
+		amounts = frappe.db.get_all('Loan Interest Accrual', {'loan': loan.name}, ['paid_interest_amount'])
 
 		loan.load_from_db()
 
-		self.assertEquals(amounts[0], repayment_entry.interest_payable)
-		self.assertEquals(flt(loan.total_principal_paid, 2), flt(repayment_entry.amount_paid -
-			 penalty_amount - amounts[0], 2))
+		total_interest_paid = amounts[0]['paid_interest_amount'] + amounts[1]['paid_interest_amount']
+		self.assertEquals(amounts[1]['paid_interest_amount'], repayment_entry.interest_payable)
+		self.assertEquals(flt(loan.total_principal_paid, 0), flt(repayment_entry.amount_paid -
+			 penalty_amount - total_interest_paid, 0))
 
-	def test_loan_closure_repayment(self):
+	def test_loan_closure(self):
 		pledge = [{
 			"loan_security": "Test Security 1",
 			"qty": 4000.00
@@ -174,7 +174,7 @@
 		loan_application = create_loan_application('_Test Company', self.applicant2, 'Demand Loan', pledge)
 		create_pledge(loan_application)
 
-		loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date=get_first_day(nowdate()))
+		loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
 		loan.submit()
 
 		self.assertEquals(loan.loan_amount, 1000000)
@@ -184,10 +184,10 @@
 
 		no_of_days = date_diff(last_date, first_date) + 1
 
-		# Adding 6 since repayment is made 5 days late after due date
+		# Adding 5 since repayment is made 5 days late after due date
 		# and since payment type is loan closure so interest should be considered for those
-		# 6 days as well though in grace period
-		no_of_days += 6
+		# 5 days as well though in grace period
+		no_of_days += 5
 
 		accrued_interest_amount = (loan.loan_amount * loan.rate_of_interest * no_of_days) \
 			/ (days_in_year(get_datetime(first_date).year) * 100)
@@ -195,15 +195,17 @@
 		make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date)
 		process_loan_interest_accrual_for_demand_loans(posting_date = last_date)
 
-		repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 6),
-			"Loan Closure", flt(loan.loan_amount + accrued_interest_amount))
+		repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 5),
+			flt(loan.loan_amount + accrued_interest_amount))
+
 		repayment_entry.submit()
 
 		amount = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['sum(paid_interest_amount)'])
 
-		self.assertEquals(flt(amount, 2),flt(accrued_interest_amount, 2))
+		self.assertEquals(flt(amount, 0),flt(accrued_interest_amount, 0))
 		self.assertEquals(flt(repayment_entry.penalty_amount, 5), 0)
 
+		request_loan_closure(loan.name)
 		loan.load_from_db()
 		self.assertEquals(loan.status, "Loan Closure Requested")
 
@@ -230,8 +232,7 @@
 
 		process_loan_interest_accrual_for_term_loans(posting_date=nowdate())
 
-		repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(nowdate(), 5),
-			"Regular Payment", 89768.75)
+		repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(nowdate(), 5), 89768.75)
 
 		repayment_entry.submit()
 
@@ -281,7 +282,7 @@
 		loan_application = create_loan_application('_Test Company', self.applicant2, 'Demand Loan', pledge)
 		create_pledge(loan_application)
 
-		loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date=get_first_day(nowdate()))
+		loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
 		loan.submit()
 
 		self.assertEquals(loan.loan_amount, 1000000)
@@ -291,7 +292,7 @@
 
 		no_of_days = date_diff(last_date, first_date) + 1
 
-		no_of_days += 6
+		no_of_days += 5
 
 		accrued_interest_amount = (loan.loan_amount * loan.rate_of_interest * no_of_days) \
 			/ (days_in_year(get_datetime(first_date).year) * 100)
@@ -299,10 +300,10 @@
 		make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date)
 		process_loan_interest_accrual_for_demand_loans(posting_date = last_date)
 
-		repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 6),
-			"Loan Closure", flt(loan.loan_amount + accrued_interest_amount))
+		repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 5), flt(loan.loan_amount + accrued_interest_amount))
 		repayment_entry.submit()
 
+		request_loan_closure(loan.name)
 		loan.load_from_db()
 		self.assertEquals(loan.status, "Loan Closure Requested")
 
@@ -317,9 +318,9 @@
 		self.assertEqual(loan.status, 'Closed')
 		self.assertEquals(sum(pledged_qty.values()), 0)
 
-		amounts = amounts = calculate_amounts(loan.name, add_days(last_date, 6), "Regular Repayment")
-		self.assertEqual(amounts['pending_principal_amount'], 0)
-		self.assertEqual(amounts['payable_principal_amount'], 0)
+		amounts = amounts = calculate_amounts(loan.name, add_days(last_date, 5))
+		self.assertTrue(amounts['pending_principal_amount'] < 0)
+		self.assertEquals(amounts['payable_principal_amount'], 0.0)
 		self.assertEqual(amounts['interest_amount'], 0)
 
 	def test_disbursal_check_with_shortfall(self):
@@ -381,7 +382,7 @@
 		loan_application = create_loan_application('_Test Company', self.applicant2, 'Demand Loan', pledge)
 		create_pledge(loan_application)
 
-		loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date=get_first_day(nowdate()))
+		loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
 		loan.submit()
 
 		self.assertEquals(loan.loan_amount, 1000000)
@@ -391,7 +392,7 @@
 
 		no_of_days = date_diff(last_date, first_date) + 1
 
-		no_of_days += 6
+		no_of_days += 5
 
 		accrued_interest_amount = (loan.loan_amount * loan.rate_of_interest * no_of_days) \
 			/ (days_in_year(get_datetime(first_date).year) * 100)
@@ -399,20 +400,192 @@
 		make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date)
 		process_loan_interest_accrual_for_demand_loans(posting_date = last_date)
 
-		amounts = calculate_amounts(loan.name, add_days(last_date, 6), "Regular Repayment")
+		amounts = calculate_amounts(loan.name, add_days(last_date, 5))
 
-		repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 6),
-			"Loan Closure", flt(loan.loan_amount + accrued_interest_amount))
+		repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 5), flt(loan.loan_amount + accrued_interest_amount))
 		repayment_entry.submit()
 
 		amounts = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['paid_interest_amount',
 			'paid_principal_amount'])
 
+		request_loan_closure(loan.name)
 		loan.load_from_db()
 		self.assertEquals(loan.status, "Loan Closure Requested")
 
-		amounts = calculate_amounts(loan.name, add_days(last_date, 6), "Regular Repayment")
-		self.assertEquals(amounts['pending_principal_amount'], 0.0)
+		amounts = calculate_amounts(loan.name, add_days(last_date, 5))
+		self.assertTrue(amounts['pending_principal_amount'] < 0.0)
+
+	def test_partial_unaccrued_interest_payment(self):
+		pledge = [{
+			"loan_security": "Test Security 1",
+			"qty": 4000.00
+		}]
+
+		loan_application = create_loan_application('_Test Company', self.applicant2, 'Demand Loan', pledge)
+		create_pledge(loan_application)
+
+		loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
+		loan.submit()
+
+		self.assertEquals(loan.loan_amount, 1000000)
+
+		first_date = '2019-10-01'
+		last_date = '2019-10-30'
+
+		no_of_days = date_diff(last_date, first_date) + 1
+
+		no_of_days += 5.5
+
+		# get partial unaccrued interest amount
+		paid_amount = (loan.loan_amount * loan.rate_of_interest * no_of_days) \
+			/ (days_in_year(get_datetime(first_date).year) * 100)
+
+		make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date)
+		process_loan_interest_accrual_for_demand_loans(posting_date = last_date)
+
+		amounts = calculate_amounts(loan.name, add_days(last_date, 5))
+
+		repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 5),
+			paid_amount)
+
+		repayment_entry.submit()
+		repayment_entry.load_from_db()
+
+		partial_accrued_interest_amount = (loan.loan_amount * loan.rate_of_interest * 5) \
+			/ (days_in_year(get_datetime(first_date).year) * 100)
+
+		interest_amount = flt(amounts['interest_amount'] + partial_accrued_interest_amount, 2)
+		self.assertEqual(flt(repayment_entry.total_interest_paid, 0), flt(interest_amount, 0))
+
+	def test_penalty(self):
+		pledge = [{
+			"loan_security": "Test Security 1",
+			"qty": 4000.00
+		}]
+
+		loan_application = create_loan_application('_Test Company', self.applicant2, 'Demand Loan', pledge)
+		create_pledge(loan_application)
+
+		loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
+		loan.submit()
+
+		self.assertEquals(loan.loan_amount, 1000000)
+
+		first_date = '2019-10-01'
+		last_date = '2019-10-30'
+
+		make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date)
+		process_loan_interest_accrual_for_demand_loans(posting_date = last_date)
+
+		amounts = calculate_amounts(loan.name, add_days(last_date, 1))
+		paid_amount = amounts['interest_amount']/2
+
+		repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 5),
+			paid_amount)
+
+		repayment_entry.submit()
+
+		# 30 days - grace period
+		penalty_days = 30 - 4
+		penalty_applicable_amount = flt(amounts['interest_amount']/2, 2)
+		penalty_amount = flt((((penalty_applicable_amount * 25) / 100) * penalty_days), 2)
+		process = process_loan_interest_accrual_for_demand_loans(posting_date = '2019-11-30')
+
+		calculated_penalty_amount = frappe.db.get_value('Loan Interest Accrual',
+			{'process_loan_interest_accrual': process, 'loan': loan.name}, 'penalty_amount')
+
+		self.assertEquals(calculated_penalty_amount, penalty_amount)
+
+	def test_loan_write_off_limit(self):
+		pledge = [{
+			"loan_security": "Test Security 1",
+			"qty": 4000.00
+		}]
+
+		loan_application = create_loan_application('_Test Company', self.applicant2, 'Demand Loan', pledge)
+		create_pledge(loan_application)
+
+		loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
+		loan.submit()
+
+		self.assertEquals(loan.loan_amount, 1000000)
+
+		first_date = '2019-10-01'
+		last_date = '2019-10-30'
+
+		no_of_days = date_diff(last_date, first_date) + 1
+		no_of_days += 5
+
+		accrued_interest_amount = (loan.loan_amount * loan.rate_of_interest * no_of_days) \
+			/ (days_in_year(get_datetime(first_date).year) * 100)
+
+		make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date)
+		process_loan_interest_accrual_for_demand_loans(posting_date = last_date)
+
+		# repay 50 less so that it can be automatically written off
+		repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 5),
+			flt(loan.loan_amount + accrued_interest_amount - 50))
+
+		repayment_entry.submit()
+
+		amount = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['sum(paid_interest_amount)'])
+
+		self.assertEquals(flt(amount, 0),flt(accrued_interest_amount, 0))
+		self.assertEquals(flt(repayment_entry.penalty_amount, 5), 0)
+
+		amounts = calculate_amounts(loan.name, add_days(last_date, 5))
+		self.assertEquals(flt(amounts['pending_principal_amount'], 0), 50)
+
+		request_loan_closure(loan.name)
+		loan.load_from_db()
+		self.assertEquals(loan.status, "Loan Closure Requested")
+
+	def test_loan_amount_write_off(self):
+		pledge = [{
+			"loan_security": "Test Security 1",
+			"qty": 4000.00
+		}]
+
+		loan_application = create_loan_application('_Test Company', self.applicant2, 'Demand Loan', pledge)
+		create_pledge(loan_application)
+
+		loan = create_demand_loan(self.applicant2, "Demand Loan", loan_application, posting_date='2019-10-01')
+		loan.submit()
+
+		self.assertEquals(loan.loan_amount, 1000000)
+
+		first_date = '2019-10-01'
+		last_date = '2019-10-30'
+
+		no_of_days = date_diff(last_date, first_date) + 1
+		no_of_days += 5
+
+		accrued_interest_amount = (loan.loan_amount * loan.rate_of_interest * no_of_days) \
+			/ (days_in_year(get_datetime(first_date).year) * 100)
+
+		make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date)
+		process_loan_interest_accrual_for_demand_loans(posting_date = last_date)
+
+		# repay 100 less so that it can be automatically written off
+		repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 5),
+			flt(loan.loan_amount + accrued_interest_amount - 100))
+
+		repayment_entry.submit()
+
+		amount = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name}, ['sum(paid_interest_amount)'])
+
+		self.assertEquals(flt(amount, 0),flt(accrued_interest_amount, 0))
+		self.assertEquals(flt(repayment_entry.penalty_amount, 5), 0)
+
+		amounts = calculate_amounts(loan.name, add_days(last_date, 5))
+		self.assertEquals(flt(amounts['pending_principal_amount'], 0), 100)
+
+		we = make_loan_write_off(loan.name, amount=amounts['pending_principal_amount'])
+		we.submit()
+
+		amounts = calculate_amounts(loan.name, add_days(last_date, 5))
+		self.assertEquals(flt(amounts['pending_principal_amount'], 0), 0)
+
 
 def create_loan_accounts():
 	if not frappe.db.exists("Account", "Loans and Advances (Assets) - _TC"):
@@ -496,7 +669,8 @@
 			"interest_income_account": interest_income_account,
 			"penalty_income_account": penalty_income_account,
 			"repayment_method": repayment_method,
-			"repayment_periods": repayment_periods
+			"repayment_periods": repayment_periods,
+			"write_off_amount": 100
 		}).insert()
 
 		loan_type.submit()
@@ -532,7 +706,7 @@
 			"haircut": 50.00,
 		}).insert(ignore_permissions=True)
 
-def create_loan_security_pledge(applicant, pledges, loan_application):
+def create_loan_security_pledge(applicant, pledges, loan_application=None, loan=None):
 
 	lsp = frappe.new_doc("Loan Security Pledge")
 	lsp.applicant_type = 'Customer'
@@ -540,11 +714,13 @@
 	lsp.company = "_Test Company"
 	lsp.loan_application = loan_application
 
+	if loan:
+		lsp.loan = loan
+
 	for pledge in pledges:
 		lsp.append('securities', {
 			"loan_security": pledge['loan_security'],
-			"qty": pledge['qty'],
-			"haircut": pledge['haircut']
+			"qty": pledge['qty']
 		})
 
 	lsp.save()
@@ -582,12 +758,11 @@
 			"valid_upto": to_date
 		}).insert(ignore_permissions=True)
 
-def create_repayment_entry(loan, applicant, posting_date, payment_type, paid_amount):
+def create_repayment_entry(loan, applicant, posting_date, paid_amount):
 
 	lr = frappe.get_doc({
 		"doctype": "Loan Repayment",
 		"against_loan": loan,
-		"payment_type": payment_type,
 		"company": "_Test Company",
 		"posting_date": posting_date or nowdate(),
 		"applicant": applicant,
diff --git a/erpnext/loan_management/doctype/loan_application/loan_application.py b/erpnext/loan_management/doctype/loan_application/loan_application.py
index bac6e63..e59db4c 100644
--- a/erpnext/loan_management/doctype/loan_application/loan_application.py
+++ b/erpnext/loan_management/doctype/loan_application/loan_application.py
@@ -127,6 +127,7 @@
 		target_doc.loan_account = account_details.loan_account
 		target_doc.interest_income_account = account_details.interest_income_account
 		target_doc.penalty_income_account = account_details.penalty_income_account
+		target_doc.loan_application = source_name
 
 
 	doclist = get_mapped_doc("Loan Application", source_name, {
diff --git a/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.json b/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.json
index c437a98..cd5df4d 100644
--- a/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.json
+++ b/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.json
@@ -26,19 +26,24 @@
   {
    "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"
+   "non_negative": 1,
+   "options": "Company:company:default_currency",
+   "reqd": 1
   },
   {
    "fieldname": "amended_from",
@@ -53,17 +58,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 +111,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 +128,10 @@
    "fieldtype": "Column Break"
   }
  ],
+ "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2020-04-29 05:20:41.629911",
+ "modified": "2020-11-06 10:04:30.882322",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Loan Disbursement",
diff --git a/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py b/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py
index 260fada..233862b 100644
--- a/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py
+++ b/erpnext/loan_management/doctype/loan_disbursement/loan_disbursement.py
@@ -17,6 +17,7 @@
 
 	def validate(self):
 		self.set_missing_values()
+		self.validate_disbursal_amount()
 
 	def on_submit(self):
 		self.set_status_and_amounts()
@@ -40,57 +41,21 @@
 		if not self.bank_account and self.applicant_type == "Customer":
 			self.bank_account = frappe.db.get_value("Customer", self.applicant, "default_bank_account")
 
-	def set_status_and_amounts(self, cancel=0):
+	def validate_disbursal_amount(self):
+		possible_disbursal_amount = get_disbursal_amount(self.against_loan)
 
+		if self.disbursed_amount > possible_disbursal_amount:
+			frappe.throw(_("Disbursed Amount cannot be greater than {0}").format(possible_disbursal_amount))
+
+	def set_status_and_amounts(self, cancel=0):
 		loan_details = frappe.get_all("Loan",
 			fields = ["loan_amount", "disbursed_amount", "total_payment", "total_principal_paid", "total_interest_payable",
 				"status", "is_term_loan", "is_secured_loan"], filters= { "name": self.against_loan })[0]
 
 		if cancel:
-			disbursed_amount = loan_details.disbursed_amount - self.disbursed_amount
-			total_payment = loan_details.total_payment
-
-			if loan_details.disbursed_amount > loan_details.loan_amount:
-				topup_amount = loan_details.disbursed_amount - loan_details.loan_amount
-				if topup_amount > self.disbursed_amount:
-					topup_amount = self.disbursed_amount
-
-				total_payment = total_payment - topup_amount
-
-			if disbursed_amount == 0:
-				status = "Sanctioned"
-			elif disbursed_amount >= loan_details.loan_amount:
-				status = "Disbursed"
-			else:
-				status = "Partially Disbursed"
+			disbursed_amount, status, total_payment = self.get_values_on_cancel(loan_details)
 		else:
-			disbursed_amount = self.disbursed_amount + loan_details.disbursed_amount
-			total_payment = loan_details.total_payment
-
-			possible_disbursal_amount = get_disbursal_amount(self.against_loan)
-
-			if self.disbursed_amount > possible_disbursal_amount:
-				frappe.throw(_("Disbursed Amount cannot be greater than {0}").format(possible_disbursal_amount))
-
-			if loan_details.status == "Disbursed" and not loan_details.is_term_loan:
-				process_loan_interest_accrual_for_demand_loans(posting_date=add_days(self.disbursement_date, -1),
-					loan=self.against_loan)
-
-			if disbursed_amount > loan_details.loan_amount:
-				topup_amount = disbursed_amount - loan_details.loan_amount
-
-				if topup_amount < 0:
-					topup_amount = 0
-
-				if topup_amount > self.disbursed_amount:
-					topup_amount = self.disbursed_amount
-
-				total_payment = total_payment + topup_amount
-
-			if flt(disbursed_amount) >= loan_details.loan_amount:
-				status = "Disbursed"
-			else:
-				status = "Partially Disbursed"
+			disbursed_amount, status, total_payment = self.get_values_on_submit(loan_details)
 
 		frappe.db.set_value("Loan", self.against_loan, {
 			"disbursement_date": self.disbursement_date,
@@ -99,6 +64,53 @@
 			"total_payment": total_payment
 		})
 
+	def get_values_on_cancel(self, loan_details):
+		disbursed_amount = loan_details.disbursed_amount - self.disbursed_amount
+		total_payment = loan_details.total_payment
+
+		if loan_details.disbursed_amount > loan_details.loan_amount:
+			topup_amount = loan_details.disbursed_amount - loan_details.loan_amount
+			if topup_amount > self.disbursed_amount:
+				topup_amount = self.disbursed_amount
+
+			total_payment = total_payment - topup_amount
+
+		if disbursed_amount == 0:
+			status = "Sanctioned"
+
+		elif disbursed_amount >= loan_details.loan_amount:
+			status = "Disbursed"
+		else:
+			status = "Partially Disbursed"
+
+		return disbursed_amount, status, total_payment
+
+	def get_values_on_submit(self, loan_details):
+		disbursed_amount = self.disbursed_amount + loan_details.disbursed_amount
+		total_payment = loan_details.total_payment
+
+		if loan_details.status in ("Disbursed", "Partially Disbursed") and not loan_details.is_term_loan:
+			process_loan_interest_accrual_for_demand_loans(posting_date=add_days(self.disbursement_date, -1),
+				loan=self.against_loan, accrual_type="Disbursement")
+
+		if disbursed_amount > loan_details.loan_amount:
+			topup_amount = disbursed_amount - loan_details.loan_amount
+
+			if topup_amount < 0:
+				topup_amount = 0
+
+			if topup_amount > self.disbursed_amount:
+				topup_amount = self.disbursed_amount
+
+			total_payment = total_payment + topup_amount
+
+		if flt(disbursed_amount) >= loan_details.loan_amount:
+			status = "Disbursed"
+		else:
+			status = "Partially Disbursed"
+
+		return disbursed_amount, status, total_payment
+
 	def make_gl_entries(self, cancel=0, adv_adj=0):
 		gle_map = []
 		loan_details = frappe.get_doc("Loan", self.against_loan)
@@ -111,7 +123,7 @@
 				"debit_in_account_currency": self.disbursed_amount,
 				"against_voucher_type": "Loan",
 				"against_voucher": self.against_loan,
-				"remarks": "Against Loan:" + self.against_loan,
+				"remarks": _("Disbursement against loan:") + self.against_loan,
 				"cost_center": self.cost_center,
 				"party_type": self.applicant_type,
 				"party": self.applicant,
@@ -127,10 +139,8 @@
 				"credit_in_account_currency": self.disbursed_amount,
 				"against_voucher_type": "Loan",
 				"against_voucher": self.against_loan,
-				"remarks": "Against Loan:" + self.against_loan,
+				"remarks": _("Disbursement against loan:") + self.against_loan,
 				"cost_center": self.cost_center,
-				"party_type": self.applicant_type,
-				"party": self.applicant,
 				"posting_date": self.disbursement_date
 			})
 		)
@@ -155,7 +165,8 @@
 	pledged_securities = get_pledged_security_qty(loan)
 
 	for security, qty in pledged_securities.items():
-		security_value += (loan_security_price_map.get(security) * qty * hair_cut_map.get(security))/100
+		after_haircut_percentage = 100 - hair_cut_map.get(security)
+		security_value += (loan_security_price_map.get(security) * qty * after_haircut_percentage)/100
 
 	return security_value
 
@@ -173,7 +184,8 @@
 		pending_principal_amount = flt(loan_details.total_payment) - flt(loan_details.total_interest_payable) \
 			- flt(loan_details.total_principal_paid)
 	else:
-		pending_principal_amount = flt(loan_details.disbursed_amount)
+		pending_principal_amount = flt(loan_details.disbursed_amount) - flt(loan_details.total_interest_payable) \
+			- flt(loan_details.total_principal_paid)
 
 	security_value = 0.0
 	if loan_details.is_secured_loan:
@@ -184,6 +196,9 @@
 
 	disbursal_amount = flt(security_value) - flt(pending_principal_amount)
 
+	if loan_details.is_term_loan and (disbursal_amount + loan_details.loan_amount) > loan_details.loan_amount:
+		disbursal_amount = loan_details.loan_amount - loan_details.disbursed_amount
+
 	return disbursal_amount
 
 
diff --git a/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py b/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py
index 2cb2637..a875387 100644
--- a/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py
+++ b/erpnext/loan_management/doctype/loan_disbursement/test_loan_disbursement.py
@@ -8,9 +8,10 @@
 from erpnext.loan_management.doctype.loan.test_loan import (create_loan_type, create_loan_security_pledge, create_repayment_entry, create_loan_application,
 	make_loan_disbursement_entry, create_loan_accounts, create_loan_security_type, create_loan_security, create_demand_loan, create_loan_security_price)
 from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_demand_loans
-from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import days_in_year
+from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import days_in_year, get_per_day_interest
 from erpnext.selling.doctype.customer.test_customer import get_customer_dict
 from erpnext.loan_management.doctype.loan_application.loan_application import create_pledge
+from erpnext.loan_management.doctype.loan_repayment.loan_repayment import calculate_amounts
 
 class TestLoanDisbursement(unittest.TestCase):
 
@@ -60,8 +61,7 @@
 		self.assertRaises(frappe.ValidationError, make_loan_disbursement_entry, loan.name,
 			500000, first_date)
 
-		repayment_entry = create_repayment_entry(loan.name, self.applicant, add_days(get_last_day(nowdate()), 5),
-			"Regular Payment", 611095.89)
+		repayment_entry = create_repayment_entry(loan.name, self.applicant, add_days(get_last_day(nowdate()), 5), 611095.89)
 
 		repayment_entry.submit()
 		loan.reload()
@@ -69,3 +69,50 @@
 		# After repayment loan disbursement entry should go through
 		make_loan_disbursement_entry(loan.name, 500000, disbursement_date=add_days(last_date, 16))
 
+		# check for disbursement accrual
+		loan_interest_accrual = frappe.db.get_value('Loan Interest Accrual', {'loan': loan.name,
+			'accrual_type': 'Disbursement'})
+
+		self.assertTrue(loan_interest_accrual)
+
+	def test_loan_topup_with_additional_pledge(self):
+		pledge = [{
+			"loan_security": "Test Security 1",
+			"qty": 4000.00
+		}]
+
+		loan_application = create_loan_application('_Test Company', self.applicant, 'Demand Loan', pledge)
+		create_pledge(loan_application)
+
+		loan = create_demand_loan(self.applicant, "Demand Loan", loan_application, posting_date='2019-10-01')
+		loan.submit()
+
+		self.assertEquals(loan.loan_amount, 1000000)
+
+		first_date = '2019-10-01'
+		last_date = '2019-10-30'
+
+		# Disbursed 10,00,000 amount
+		make_loan_disbursement_entry(loan.name, loan.loan_amount, disbursement_date=first_date)
+		process_loan_interest_accrual_for_demand_loans(posting_date = last_date)
+		amounts = calculate_amounts(loan.name, add_days(last_date, 1))
+
+		previous_interest = amounts['interest_amount']
+
+		pledge1 = [{
+			"loan_security": "Test Security 1",
+			"qty": 2000.00
+		}]
+
+		create_loan_security_pledge(self.applicant, pledge1, loan=loan.name)
+
+		# Topup 500000
+		make_loan_disbursement_entry(loan.name, 500000, disbursement_date=add_days(last_date, 1))
+		process_loan_interest_accrual_for_demand_loans(posting_date = add_days(last_date, 15))
+		amounts = calculate_amounts(loan.name, add_days(last_date, 15))
+
+		per_day_interest = get_per_day_interest(1500000, 13.5, '2019-10-30')
+		interest = per_day_interest * 15
+
+		self.assertEquals(amounts['pending_principal_amount'], 1500000)
+		self.assertEquals(amounts['interest_amount'], flt(interest + previous_interest, 2))
diff --git a/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.json b/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.json
index 5fc3e8f..f157f0d 100644
--- a/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.json
+++ b/erpnext/loan_management/doctype/loan_interest_accrual/loan_interest_accrual.json
@@ -14,6 +14,7 @@
   "column_break_4",
   "company",
   "posting_date",
+  "accrual_type",
   "is_term_loan",
   "section_break_7",
   "pending_principal_amount",
@@ -22,9 +23,11 @@
   "column_break_14",
   "interest_amount",
   "paid_interest_amount",
+  "penalty_amount",
   "section_break_15",
   "process_loan_interest_accrual",
   "repayment_schedule_name",
+  "last_accrual_date",
   "amended_from"
  ],
  "fields": [
@@ -139,6 +142,7 @@
    "read_only": 1
   },
   {
+   "depends_on": "eval:doc.is_term_loan",
    "fieldname": "paid_principal_amount",
    "fieldtype": "Currency",
    "label": "Paid Principal Amount",
@@ -149,12 +153,32 @@
    "fieldtype": "Currency",
    "label": "Paid Interest Amount",
    "options": "Company:company:default_currency"
+  },
+  {
+   "fieldname": "accrual_type",
+   "fieldtype": "Select",
+   "label": "Accrual Type",
+   "options": "Regular\nRepayment\nDisbursement"
+  },
+  {
+   "fieldname": "penalty_amount",
+   "fieldtype": "Currency",
+   "label": "Penalty Amount",
+   "options": "Company:company:default_currency"
+  },
+  {
+   "fieldname": "last_accrual_date",
+   "fieldtype": "Date",
+   "hidden": 1,
+   "label": "Last Accrual Date",
+   "read_only": 1
   }
  ],
  "in_create": 1,
+ "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2020-04-16 11:24:23.258404",
+ "modified": "2020-11-07 05:49:25.448875",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Loan Interest Accrual",
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 2d959bf..d17f5af 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
@@ -22,6 +22,8 @@
 		if not self.interest_amount and not self.payable_principal_amount:
 			frappe.throw(_("Interest Amount or Principal Amount is mandatory"))
 
+		if not self.last_accrual_date:
+			self.last_accrual_date = get_last_accrual_date(self.loan)
 
 	def on_submit(self):
 		self.make_gl_entries()
@@ -50,7 +52,8 @@
 					"debit_in_account_currency": self.interest_amount,
 					"against_voucher_type": "Loan",
 					"against_voucher": self.loan,
-					"remarks": _("Against Loan:") + self.loan,
+					"remarks": _("Interest accrued from {0} to {1} against loan: {2}").format(
+						self.last_accrual_date, self.posting_date, self.loan),
 					"cost_center": erpnext.get_default_cost_center(self.company),
 					"posting_date": self.posting_date
 				})
@@ -59,14 +62,13 @@
 			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,
+					"remarks": ("Interest accrued from {0} to {1} against loan: {2}").format(
+						self.last_accrual_date, self.posting_date, self.loan),
 					"cost_center": erpnext.get_default_cost_center(self.company),
 					"posting_date": self.posting_date
 				})
@@ -79,19 +81,23 @@
 # For Eg: If Loan disbursement date is '01-09-2019' and disbursed amount is 1000000 and
 # rate of interest is 13.5 then first loan interest accural will be on '01-10-2019'
 # which means interest will be accrued for 30 days which should be equal to 11095.89
-def calculate_accrual_amount_for_demand_loans(loan, posting_date, process_loan_interest):
+def calculate_accrual_amount_for_demand_loans(loan, posting_date, process_loan_interest, accrual_type):
+	from erpnext.loan_management.doctype.loan_repayment.loan_repayment import calculate_amounts
+
 	no_of_days = get_no_of_days_for_interest_accural(loan, posting_date)
+	precision = cint(frappe.db.get_default("currency_precision")) or 2
 
 	if no_of_days <= 0:
 		return
 
 	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 = (pending_principal_amount * loan.rate_of_interest) / (days_in_year(get_datetime(posting_date).year) * 100)
+	interest_per_day = get_per_day_interest(pending_principal_amount, loan.rate_of_interest, posting_date)
 	payable_interest = interest_per_day * no_of_days
 
 	args = frappe._dict({
@@ -102,13 +108,16 @@
 		'loan_account': loan.loan_account,
 		'pending_principal_amount': pending_principal_amount,
 		'interest_amount': payable_interest,
+		'penalty_amount': calculate_amounts(loan.name, posting_date)['penalty_amount'],
 		'process_loan_interest': process_loan_interest,
-		'posting_date': posting_date
+		'posting_date': posting_date,
+		'accrual_type': accrual_type
 	})
 
-	make_loan_interest_accrual_entry(args)
+	if flt(payable_interest, precision) > 0.0:
+		make_loan_interest_accrual_entry(args)
 
-def make_accrual_interest_entry_for_demand_loans(posting_date, process_loan_interest, open_loans=None, loan_type=None):
+def make_accrual_interest_entry_for_demand_loans(posting_date, process_loan_interest, open_loans=None, loan_type=None, accrual_type="Regular"):
 	query_filters = {
 		"status": ('in', ['Disbursed', 'Partially Disbursed']),
 		"docstatus": 1
@@ -123,13 +132,13 @@
 		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:
-		calculate_accrual_amount_for_demand_loans(loan, posting_date, process_loan_interest)
+		calculate_accrual_amount_for_demand_loans(loan, posting_date, process_loan_interest, accrual_type)
 
-def make_accrual_interest_entry_for_term_loans(posting_date, process_loan_interest, term_loan=None, loan_type=None):
+def make_accrual_interest_entry_for_term_loans(posting_date, process_loan_interest, term_loan=None, loan_type=None, accrual_type="Regular"):
 	curr_date = posting_date or add_days(nowdate(), 1)
 
 	term_loans = get_term_loans(curr_date, term_loan, loan_type)
@@ -148,7 +157,8 @@
 			'payable_principal': loan.principal_amount,
 			'process_loan_interest': process_loan_interest,
 			'repayment_schedule_name': loan.payment_entry,
-			'posting_date': posting_date
+			'posting_date': posting_date,
+			'accrual_type': accrual_type
 		})
 
 		make_loan_interest_accrual_entry(args)
@@ -192,31 +202,33 @@
 	loan_interest_accrual.loan_account = args.loan_account
 	loan_interest_accrual.pending_principal_amount = flt(args.pending_principal_amount, precision)
 	loan_interest_accrual.interest_amount = flt(args.interest_amount, precision)
+	loan_interest_accrual.penalty_amount = flt(args.penalty_amount, precision)
 	loan_interest_accrual.posting_date = args.posting_date or nowdate()
 	loan_interest_accrual.process_loan_interest_accrual = args.process_loan_interest
 	loan_interest_accrual.repayment_schedule_name = args.repayment_schedule_name
 	loan_interest_accrual.payable_principal_amount = args.payable_principal
+	loan_interest_accrual.accrual_type = args.accrual_type
 
 	loan_interest_accrual.save()
 	loan_interest_accrual.submit()
 
 
 def get_no_of_days_for_interest_accural(loan, posting_date):
-	last_interest_accrual_date = get_last_accural_date_in_current_month(loan)
+	last_interest_accrual_date = get_last_accrual_date(loan.name)
 
 	no_of_days = date_diff(posting_date or nowdate(), last_interest_accrual_date) + 1
 
 	return no_of_days
 
-def get_last_accural_date_in_current_month(loan):
+def get_last_accrual_date(loan):
 	last_posting_date = frappe.db.sql(""" SELECT MAX(posting_date) from `tabLoan Interest Accrual`
-		WHERE loan = %s""", (loan.name))
+		WHERE loan = %s and docstatus = 1""", (loan))
 
 	if last_posting_date[0][0]:
 		# interest for last interest accrual date is already booked, so add 1 day
 		return add_days(last_posting_date[0][0], 1)
 	else:
-		return loan.disbursement_date
+		return frappe.db.get_value('Loan', loan, 'disbursement_date')
 
 def days_in_year(year):
 	days = 365
@@ -226,3 +238,11 @@
 
 	return days
 
+def get_per_day_interest(principal_amount, rate_of_interest, posting_date=None):
+	if not posting_date:
+		posting_date = getdate()
+
+	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), precision)
+
diff --git a/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py b/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py
index 4b85b21..46a6440 100644
--- a/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py
+++ b/erpnext/loan_management/doctype/loan_interest_accrual/test_loan_interest_accrual.py
@@ -5,7 +5,7 @@
 import frappe
 import unittest
 from frappe.utils import (nowdate, add_days, get_datetime, get_first_day, get_last_day, date_diff, flt, add_to_date)
-from erpnext.loan_management.doctype.loan.test_loan import (create_loan_type, create_loan_security_pledge, create_loan_security_price,
+from erpnext.loan_management.doctype.loan.test_loan import (create_loan_type, create_loan_security_price,
 	make_loan_disbursement_entry, create_loan_accounts, create_loan_security_type, create_loan_security, create_demand_loan, create_loan_application)
 from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_demand_loans
 from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import days_in_year
@@ -57,4 +57,4 @@
 
 		loan_interest_accural = frappe.get_doc("Loan Interest Accrual", {'loan': loan.name})
 
-		self.assertEquals(flt(loan_interest_accural.interest_amount, 2), flt(accrued_interest_amount, 2))
+		self.assertEquals(flt(loan_interest_accural.interest_amount, 0), flt(accrued_interest_amount, 0))
diff --git a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json
index 5942455..2b5df4b 100644
--- a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json
+++ b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json
@@ -10,11 +10,11 @@
   "applicant_type",
   "applicant",
   "loan_type",
-  "payment_type",
   "column_break_3",
   "company",
   "posting_date",
   "is_term_loan",
+  "rate_of_interest",
   "payment_details_section",
   "due_date",
   "pending_principal_amount",
@@ -31,6 +31,7 @@
   "column_break_21",
   "reference_date",
   "principal_amount_paid",
+  "total_interest_paid",
   "repayment_details",
   "amended_from"
  ],
@@ -96,15 +97,6 @@
    "fieldtype": "Column Break"
   },
   {
-   "default": "Regular Payment",
-   "fieldname": "payment_type",
-   "fieldtype": "Select",
-   "in_list_view": 1,
-   "label": "Payment Type",
-   "options": "\nRegular Payment\nLoan Closure",
-   "reqd": 1
-  },
-  {
    "fieldname": "payable_amount",
    "fieldtype": "Currency",
    "label": "Payable Amount",
@@ -116,6 +108,7 @@
    "fieldname": "amount_paid",
    "fieldtype": "Currency",
    "label": "Amount Paid",
+   "non_negative": 1,
    "options": "Company:company:default_currency",
    "reqd": 1
   },
@@ -195,6 +188,7 @@
    "fieldtype": "Currency",
    "hidden": 1,
    "label": "Principal Amount Paid",
+   "options": "Company:company:default_currency",
    "read_only": 1
   },
   {
@@ -217,11 +211,27 @@
    "hidden": 1,
    "label": "Repayment Details",
    "options": "Loan Repayment Detail"
+  },
+  {
+   "fieldname": "total_interest_paid",
+   "fieldtype": "Currency",
+   "hidden": 1,
+   "label": "Total Interest Paid",
+   "options": "Company:company:default_currency",
+   "read_only": 1
+  },
+  {
+   "fetch_from": "loan_type.rate_of_interest",
+   "fieldname": "rate_of_interest",
+   "fieldtype": "Percent",
+   "label": "Rate Of Interest",
+   "read_only": 1
   }
  ],
+ "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2020-05-16 09:40:15.581165",
+ "modified": "2020-11-05 10:06:58.792841",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Loan Repayment",
diff --git a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
index 97dbc44..415ba99 100644
--- a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
+++ b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
@@ -14,14 +14,15 @@
 from erpnext.accounts.general_ledger import make_gl_entries
 from erpnext.loan_management.doctype.loan_security_shortfall.loan_security_shortfall import update_shortfall_status
 from erpnext.loan_management.doctype.process_loan_interest_accrual.process_loan_interest_accrual import process_loan_interest_accrual_for_demand_loans
+from erpnext.loan_management.doctype.loan_interest_accrual.loan_interest_accrual import get_per_day_interest, get_last_accrual_date
 
 class LoanRepayment(AccountsController):
 
 	def validate(self):
-		amounts = calculate_amounts(self.against_loan, self.posting_date, self.payment_type)
+		amounts = calculate_amounts(self.against_loan, self.posting_date)
 		self.set_missing_values(amounts)
 		self.validate_amount()
-		self.allocate_amounts(amounts['pending_accrual_entries'])
+		self.allocate_amounts(amounts)
 
 	def before_submit(self):
 		self.book_unaccrued_interest()
@@ -32,8 +33,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
@@ -72,29 +73,36 @@
 			msg = _("Paid amount cannot be less than {0}").format(self.penalty_amount)
 			frappe.throw(msg)
 
-		if self.payment_type == "Loan Closure" and flt(self.amount_paid, precision) < flt(self.payable_amount, precision):
-			msg = _("Amount of {0} is required for Loan closure").format(self.payable_amount)
-			frappe.throw(msg)
-
 	def book_unaccrued_interest(self):
-		if self.payment_type == 'Loan Closure':
-			total_interest_paid = 0
-			for payment in self.repayment_details:
-				total_interest_paid += payment.paid_interest_amount
+		precision = cint(frappe.db.get_default("currency_precision")) or 2
+		if self.total_interest_paid > self.interest_payable:
+			if not self.is_term_loan:
+				# get last loan interest accrual date
+				last_accrual_date = get_last_accrual_date(self.against_loan)
 
-			if total_interest_paid < self.interest_payable:
-				if not self.is_term_loan:
-					process = process_loan_interest_accrual_for_demand_loans(posting_date=self.posting_date,
-						loan=self.against_loan)
+				# get posting date upto which interest has to be accrued
+				per_day_interest = flt(get_per_day_interest(self.pending_principal_amount,
+					self.rate_of_interest, self.posting_date), 2)
 
-					lia = frappe.db.get_value('Loan Interest Accrual', {'process_loan_interest_accrual':
-						process}, ['name', 'interest_amount', 'payable_principal_amount'], as_dict=1)
+				no_of_days = flt(flt(self.total_interest_paid - self.interest_payable,
+					precision)/per_day_interest, 0) - 1
 
-					self.append('repayment_details', {
-						'loan_interest_accrual': lia.name,
-						'paid_interest_amount': lia.interest_amount,
-						'paid_principal_amount': lia.payable_principal_amount
-					})
+				posting_date = add_days(last_accrual_date, no_of_days)
+
+				# book excess interest paid
+				process = process_loan_interest_accrual_for_demand_loans(posting_date=posting_date,
+					loan=self.against_loan, accrual_type="Repayment")
+
+				# get loan interest accrual to update paid amount
+				lia = frappe.db.get_value('Loan Interest Accrual', {'process_loan_interest_accrual':
+					process}, ['name', 'interest_amount', 'payable_principal_amount'], as_dict=1)
+
+				self.append('repayment_details', {
+					'loan_interest_accrual': lia.name,
+					'paid_interest_amount': flt(self.total_interest_paid - self.interest_payable, precision),
+					'paid_principal_amount': 0.0,
+					'accrual_type': 'Repayment'
+				})
 
 	def update_paid_amount(self):
 		precision = cint(frappe.db.get_default("currency_precision")) or 2
@@ -108,12 +116,6 @@
 				WHERE name = %s""",
 				(flt(payment.paid_principal_amount, precision), flt(payment.paid_interest_amount, precision), payment.loan_interest_accrual))
 
-		if flt(loan.total_principal_paid + self.principal_amount_paid, precision) >= flt(loan.total_payment, precision):
-			if loan.is_secured_loan:
-				frappe.db.set_value("Loan", self.against_loan, "status", "Loan Closure Requested")
-			else:
-				frappe.db.set_value("Loan", self.against_loan, "status", "Closed")
-
 		frappe.db.sql(""" UPDATE `tabLoan` SET total_amount_paid = %s, total_principal_paid = %s
 			WHERE name = %s """, (loan.total_amount_paid + self.amount_paid,
 			loan.total_principal_paid + self.principal_amount_paid, self.against_loan))
@@ -123,6 +125,8 @@
 	def mark_as_unpaid(self):
 		loan = frappe.get_doc("Loan", self.against_loan)
 
+		no_of_repayments = len(self.repayment_details)
+
 		for payment in self.repayment_details:
 			frappe.db.sql(""" UPDATE `tabLoan Interest Accrual`
 				SET paid_principal_amount = `paid_principal_amount` - %s,
@@ -130,6 +134,12 @@
 				WHERE name = %s""",
 				(payment.paid_principal_amount, payment.paid_interest_amount, payment.loan_interest_accrual))
 
+			# Cancel repayment interest accrual
+			# checking idx as a preventive measure, repayment accrual will always be the last entry
+			if payment.accrual_type == 'Repayment' and payment.idx == no_of_repayments:
+				lia_doc = frappe.get_doc('Loan Interest Accrual', payment.loan_interest_accrual)
+				lia_doc.cancel()
+
 		frappe.db.sql(""" UPDATE `tabLoan` SET total_amount_paid = %s, total_principal_paid = %s
 			WHERE name = %s """, (loan.total_amount_paid - self.amount_paid,
 			loan.total_principal_paid - self.principal_amount_paid, self.against_loan))
@@ -137,15 +147,17 @@
 		if loan.status == "Loan Closure Requested":
 			frappe.db.set_value("Loan", self.against_loan, "status", "Disbursed")
 
-	def allocate_amounts(self, paid_entries):
+	def allocate_amounts(self, repayment_details):
+		precision = cint(frappe.db.get_default("currency_precision")) or 2
+
 		self.set('repayment_details', [])
 		self.principal_amount_paid = 0
 		total_interest_paid = 0
 		interest_paid = self.amount_paid - self.penalty_amount
 
-		if self.amount_paid - self.penalty_amount > 0 and paid_entries:
+		if self.amount_paid - self.penalty_amount > 0:
 			interest_paid = self.amount_paid - self.penalty_amount
-			for lia, amounts in iteritems(paid_entries):
+			for lia, amounts in iteritems(repayment_details.get('pending_accrual_entries', [])):
 				if amounts['interest_amount'] + amounts['payable_principal_amount'] <= interest_paid:
 					interest_amount = amounts['interest_amount']
 					paid_principal = amounts['payable_principal_amount']
@@ -169,9 +181,24 @@
 					'paid_principal_amount': paid_principal
 				})
 
-		if self.payment_type == 'Loan Closure' and total_interest_paid < self.interest_payable:
-			unaccrued_interest = self.interest_payable - total_interest_paid
-			interest_paid -= unaccrued_interest
+		if repayment_details['unaccrued_interest'] and interest_paid:
+			# no of days for which to accrue interest
+			# Interest can only be accrued for an entire day and not partial
+			if interest_paid > repayment_details['unaccrued_interest']:
+				per_day_interest = flt(get_per_day_interest(self.pending_principal_amount,
+					self.rate_of_interest, self.posting_date), precision)
+				interest_paid -= repayment_details['unaccrued_interest']
+				total_interest_paid += repayment_details['unaccrued_interest']
+			else:
+				# get no of days for which interest can be paid
+				per_day_interest = flt(get_per_day_interest(self.pending_principal_amount,
+					self.rate_of_interest, self.posting_date), precision)
+
+				no_of_days = cint(interest_paid/per_day_interest)
+				total_interest_paid += no_of_days * per_day_interest
+				interest_paid -= no_of_days * per_day_interest
+
+		self.total_interest_paid = total_interest_paid
 
 		if interest_paid:
 			self.principal_amount_paid += interest_paid
@@ -189,7 +216,7 @@
 					"debit_in_account_currency": self.penalty_amount,
 					"against_voucher_type": "Loan",
 					"against_voucher": self.against_loan,
-					"remarks": _("Against Loan:") + self.against_loan,
+					"remarks": _("Penalty against loan:") + self.against_loan,
 					"cost_center": self.cost_center,
 					"party_type": self.applicant_type,
 					"party": self.applicant,
@@ -205,10 +232,8 @@
 					"credit_in_account_currency": self.penalty_amount,
 					"against_voucher_type": "Loan",
 					"against_voucher": self.against_loan,
-					"remarks": _("Against Loan:") + self.against_loan,
+					"remarks": _("Penalty against loan:") + self.against_loan,
 					"cost_center": self.cost_center,
-					"party_type": self.applicant_type,
-					"party": self.applicant,
 					"posting_date": getdate(self.posting_date)
 				})
 			)
@@ -219,13 +244,11 @@
 				"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,
+				"remarks": _("Repayment against Loan: ") + self.against_loan,
 				"cost_center": self.cost_center,
-				"party_type": self.applicant_type,
-				"party": self.applicant,
 				"posting_date": getdate(self.posting_date)
 			})
 		)
@@ -240,7 +263,7 @@
 				"credit_in_account_currency": self.amount_paid,
 				"against_voucher_type": "Loan",
 				"against_voucher": self.against_loan,
-				"remarks": _("Against Loan:") + self.against_loan,
+				"remarks": _("Repayment against Loan: ") + self.against_loan,
 				"cost_center": self.cost_center,
 				"posting_date": getdate(self.posting_date)
 			})
@@ -273,7 +296,8 @@
 	unpaid_accrued_entries = frappe.db.sql(
 		"""
 			SELECT name, posting_date, interest_amount - paid_interest_amount as interest_amount,
-				payable_principal_amount - paid_principal_amount as payable_principal_amount
+				payable_principal_amount - paid_principal_amount as payable_principal_amount,
+				accrual_type
 			FROM
 				`tabLoan Interest Accrual`
 			WHERE
@@ -282,6 +306,7 @@
 				payable_principal_amount - paid_principal_amount > 0)
 			AND
 				docstatus = 1
+			ORDER BY posting_date
 		""", (against_loan), as_dict=1)
 
 	return unpaid_accrued_entries
@@ -289,7 +314,7 @@
 # This function returns the amounts that are payable at the time of loan repayment based on posting date
 # So it pulls all the unpaid Loan Interest Accrual Entries and calculates the penalty if applicable
 
-def get_amounts(amounts, against_loan, posting_date, payment_type):
+def get_amounts(amounts, against_loan, posting_date):
 	precision = cint(frappe.db.get_default("currency_precision")) or 2
 
 	against_loan_doc = frappe.get_doc("Loan", against_loan)
@@ -311,10 +336,10 @@
 
 		due_date = add_days(entry.posting_date, 1)
 		no_of_late_days = date_diff(posting_date,
-			add_days(due_date, loan_type_details.grace_period_in_days))
+			add_days(due_date, loan_type_details.grace_period_in_days)) + 1
 
-		if no_of_late_days > 0 and (not against_loan_doc.repay_from_salary):
-			penalty_amount += (entry.interest_amount * (loan_type_details.penalty_interest_rate / 100) * no_of_late_days)/365
+		if no_of_late_days > 0 and (not against_loan_doc.repay_from_salary) and entry.accrual_type == 'Regular':
+			penalty_amount += (entry.interest_amount * (loan_type_details.penalty_interest_rate / 100) * no_of_late_days)
 
 		total_pending_interest += entry.interest_amount
 		payable_principal_amount += entry.payable_principal_amount
@@ -324,23 +349,27 @@
 			'payable_principal_amount': flt(entry.payable_principal_amount, precision)
 		})
 
-		if not final_due_date:
+		if due_date and not final_due_date:
 			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
 
-	if payment_type == "Loan Closure":
-		if due_date:
-			pending_days = date_diff(posting_date, due_date) + 1
-		else:
-			pending_days = date_diff(posting_date, against_loan_doc.disbursement_date) + 1
+	unaccrued_interest = 0
+	if due_date:
+		pending_days = date_diff(posting_date, due_date) + 1
+	else:
+		last_accrual_date = get_last_accrual_date(against_loan_doc.name)
+		pending_days = date_diff(posting_date, last_accrual_date) + 1
 
-		payable_principal_amount = pending_principal_amount
-		per_day_interest = (payable_principal_amount * (loan_type_details.rate_of_interest / 100))/365
-		total_pending_interest += (pending_days * per_day_interest)
+	if pending_days > 0:
+		principal_amount = flt(pending_principal_amount, precision)
+		per_day_interest = get_per_day_interest(principal_amount, loan_type_details.rate_of_interest, posting_date)
+		unaccrued_interest += (pending_days * flt(per_day_interest, precision))
 
 	amounts["pending_principal_amount"] = flt(pending_principal_amount, precision)
 	amounts["payable_principal_amount"] = flt(payable_principal_amount, precision)
@@ -348,6 +377,7 @@
 	amounts["penalty_amount"] = flt(penalty_amount, precision)
 	amounts["payable_amount"] = flt(payable_principal_amount + total_pending_interest + penalty_amount, precision)
 	amounts["pending_accrual_entries"] = pending_accrual_entries
+	amounts["unaccrued_interest"] = unaccrued_interest
 
 	if final_due_date:
 		amounts["due_date"] = final_due_date
@@ -355,7 +385,7 @@
 	return amounts
 
 @frappe.whitelist()
-def calculate_amounts(against_loan, posting_date, payment_type):
+def calculate_amounts(against_loan, posting_date, payment_type=''):
 
 	amounts = {
 		'penalty_amount': 0.0,
@@ -363,10 +393,17 @@
 		'pending_principal_amount': 0.0,
 		'payable_principal_amount': 0.0,
 		'payable_amount': 0.0,
+		'unaccrued_interest': 0.0,
 		'due_date': ''
 	}
 
-	amounts = get_amounts(amounts, against_loan, posting_date, payment_type)
+	amounts = get_amounts(amounts, against_loan, posting_date)
+
+	# update values for closure
+	if payment_type == 'Loan Closure':
+		amounts['payable_principal_amount'] = amounts['pending_principal_amount']
+		amounts['interest_amount'] += amounts['unaccrued_interest']
+		amounts['payable_amount'] = amounts['payable_principal_amount'] + amounts['interest_amount']
 
 	return amounts
 
diff --git a/erpnext/loan_management/doctype/loan_repayment_detail/loan_repayment_detail.json b/erpnext/loan_management/doctype/loan_repayment_detail/loan_repayment_detail.json
index cff1dbb..4b9b191 100644
--- a/erpnext/loan_management/doctype/loan_repayment_detail/loan_repayment_detail.json
+++ b/erpnext/loan_management/doctype/loan_repayment_detail/loan_repayment_detail.json
@@ -7,7 +7,8 @@
  "field_order": [
   "loan_interest_accrual",
   "paid_principal_amount",
-  "paid_interest_amount"
+  "paid_interest_amount",
+  "accrual_type"
  ],
  "fields": [
   {
@@ -27,11 +28,20 @@
    "fieldtype": "Currency",
    "label": "Paid Interest Amount",
    "options": "Company:company:default_currency"
+  },
+  {
+   "fetch_from": "loan_interest_accrual.accrual_type",
+   "fetch_if_empty": 1,
+   "fieldname": "accrual_type",
+   "fieldtype": "Select",
+   "label": "Accrual Type",
+   "options": "Regular\nRepayment\nDisbursement"
   }
  ],
+ "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2020-04-15 21:50:03.837019",
+ "modified": "2020-10-23 08:09:18.267030",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Loan Repayment Detail",
diff --git a/erpnext/loan_management/doctype/loan_security/loan_security.json b/erpnext/loan_management/doctype/loan_security/loan_security.json
index 1d0bb30..c698601 100644
--- a/erpnext/loan_management/doctype/loan_security/loan_security.json
+++ b/erpnext/loan_management/doctype/loan_security/loan_security.json
@@ -25,6 +25,7 @@
   },
   {
    "fetch_from": "loan_security_type.haircut",
+   "fetch_if_empty": 1,
    "fieldname": "haircut",
    "fieldtype": "Percent",
    "label": "Haircut %"
@@ -64,8 +65,9 @@
    "reqd": 1
   }
  ],
+ "index_web_pages_for_search": 1,
  "links": [],
- "modified": "2020-04-29 13:21:26.043492",
+ "modified": "2020-10-26 07:34:48.601766",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Loan Security",
diff --git a/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.py b/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.py
index 2bb6fd8..cbc8376 100644
--- a/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.py
+++ b/erpnext/loan_management/doctype/loan_security_pledge/loan_security_pledge.py
@@ -78,7 +78,7 @@
 		self.maximum_loan_value = maximum_loan_value
 
 def update_loan(loan, maximum_value_against_pledge):
-	maximum_loan_value = frappe.db.get_value('Loan', {'name': loan}, ['maximum_loan_value'])
+	maximum_loan_value = frappe.db.get_value('Loan', {'name': loan}, ['maximum_loan_amount'])
 
-	frappe.db.sql(""" UPDATE `tabLoan` SET maximum_loan_value=%s, is_secured_loan=1
+	frappe.db.sql(""" UPDATE `tabLoan` SET maximum_loan_amount=%s, is_secured_loan=1
 		WHERE name=%s""", (maximum_loan_value + maximum_value_against_pledge, loan))
diff --git a/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py b/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py
index 0f42bde..8ec0bfb 100644
--- a/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py
+++ b/erpnext/loan_management/doctype/loan_security_shortfall/loan_security_shortfall.py
@@ -22,7 +22,7 @@
 	if security_value >= loan_security_shortfall.shortfall_amount:
 		frappe.db.set_value("Loan Security Shortfall", loan_security_shortfall.name, {
 			"status": "Completed",
-			"shortfall_value": loan_security_shortfall.shortfall_amount})
+			"shortfall_amount": loan_security_shortfall.shortfall_amount})
 	else:
 		frappe.db.set_value("Loan Security Shortfall", loan_security_shortfall.name,
 			"shortfall_amount", loan_security_shortfall.shortfall_amount - security_value)
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..c29f325 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,18 +42,20 @@
 				"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:
 			pledged_qty = pledge_qty_map.get(security.loan_security, 0)
 			if security.qty > pledged_qty:
-				frappe.throw(_("""Row {0}: {1} {2} of {3} is pledged against Loan {4}.
-					You are trying to unpledge more""").format(security.idx, pledged_qty, security.uom,
-					frappe.bold(security.loan_security), frappe.bold(self.loan)))
+				msg = _("Row {0}: {1} {2} of {3} is pledged against Loan {4}.").format(security.idx, pledged_qty, security.uom,
+					frappe.bold(security.loan_security), frappe.bold(self.loan))
+				msg += "<br>"
+				msg += _("You are trying to unpledge more.")
+				frappe.throw(msg, title=_("Loan Security Unpledge Error"))
 
 			qty_after_unpledge = pledged_qty - security.qty
 			ltv_ratio = ltv_ratio_map.get(security.loan_security_type)
@@ -65,10 +67,18 @@
 			security_value += qty_after_unpledge * current_price
 
 		if not security_value and flt(pending_principal_amount, 2) > 0:
-			frappe.throw("Cannot Unpledge, loan to value ratio is breaching")
+			self._throw(security_value, pending_principal_amount, ltv_ratio)
 
 		if security_value and flt(pending_principal_amount/security_value) * 100 > ltv_ratio:
-			frappe.throw("Cannot Unpledge, loan to value ratio is breaching")
+			self._throw(security_value, pending_principal_amount, ltv_ratio)
+
+	def _throw(self, security_value, pending_principal_amount, ltv_ratio):
+		msg = _("Loan Security Value after unpledge is {0}").format(frappe.bold(security_value))
+		msg += '<br>'
+		msg += _("Pending principal amount is {0}").format(frappe.bold(flt(pending_principal_amount, 2)))
+		msg += '<br>'
+		msg += _("Loan To Security Value ratio must always be {0}").format(frappe.bold(ltv_ratio))
+		frappe.throw(msg, title=_("Loan To Value ratio breach"))
 
 	def on_update_after_submit(self):
 		self.approve()
diff --git a/erpnext/loan_management/doctype/loan_type/loan_type.json b/erpnext/loan_management/doctype/loan_type/loan_type.json
index 669490a..18a9731 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,17 +141,27 @@
    "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-26 07:13:55.029811",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Loan Type",
  "owner": "Administrator",
  "permissions": [
   {
+   "cancel": 1,
    "create": 1,
    "delete": 1,
    "email": 1,
@@ -165,6 +171,7 @@
    "report": 1,
    "role": "Loan Manager",
    "share": 1,
+   "submit": 1,
    "write": 1
   },
   {
diff --git a/erpnext/loan_management/doctype/loan_write_off/__init__.py b/erpnext/loan_management/doctype/loan_write_off/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/loan_management/doctype/loan_write_off/__init__.py
diff --git a/erpnext/loan_management/doctype/loan_write_off/loan_write_off.js b/erpnext/loan_management/doctype/loan_write_off/loan_write_off.js
new file mode 100644
index 0000000..4e3319c
--- /dev/null
+++ b/erpnext/loan_management/doctype/loan_write_off/loan_write_off.js
@@ -0,0 +1,36 @@
+// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+{% include 'erpnext/loan_management/loan_common.js' %};
+
+frappe.ui.form.on('Loan Write Off', {
+	loan: function(frm) {
+		frm.trigger('show_pending_principal_amount');
+	},
+	onload: function(frm) {
+		frm.trigger('show_pending_principal_amount');
+	},
+	refresh: function(frm) {
+		frm.set_query('write_off_account', function(){
+			return {
+				filters: {
+					'company': frm.doc.company,
+					'root_type': 'Expense',
+					'is_group': 0
+				}
+			}
+		});
+	},
+	show_pending_principal_amount: function(frm) {
+		if (frm.doc.loan && frm.doc.docstatus === 0) {
+			frappe.db.get_value('Loan', frm.doc.loan, ['total_payment', 'total_interest_payable',
+				'total_principal_paid', 'written_off_amount'], function(values) {
+				frm.set_df_property('write_off_amount', 'description',
+					"Pending principal amount is " + cstr(flt(values.total_payment - values.total_interest_payable
+						- values.total_principal_paid - values.written_off_amount, 2)));
+				frm.refresh_field('write_off_amount');
+			});
+
+		}
+	}
+});
diff --git a/erpnext/loan_management/doctype/loan_write_off/loan_write_off.json b/erpnext/loan_management/doctype/loan_write_off/loan_write_off.json
new file mode 100644
index 0000000..4617a62
--- /dev/null
+++ b/erpnext/loan_management/doctype/loan_write_off/loan_write_off.json
@@ -0,0 +1,157 @@
+{
+ "actions": [],
+ "autoname": "LM-WO-.#####",
+ "creation": "2020-10-16 11:09:14.495066",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "loan",
+  "applicant_type",
+  "applicant",
+  "column_break_3",
+  "company",
+  "posting_date",
+  "accounting_dimensions_section",
+  "cost_center",
+  "section_break_9",
+  "write_off_account",
+  "column_break_11",
+  "write_off_amount",
+  "amended_from"
+ ],
+ "fields": [
+  {
+   "fieldname": "loan",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Loan",
+   "options": "Loan",
+   "reqd": 1
+  },
+  {
+   "default": "Today",
+   "fieldname": "posting_date",
+   "fieldtype": "Date",
+   "in_list_view": 1,
+   "label": "Posting Date",
+   "reqd": 1
+  },
+  {
+   "fieldname": "column_break_3",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fetch_from": "loan.company",
+   "fieldname": "company",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Company",
+   "options": "Company",
+   "read_only": 1,
+   "reqd": 1
+  },
+  {
+   "fetch_from": "loan.applicant_type",
+   "fieldname": "applicant_type",
+   "fieldtype": "Select",
+   "label": "Applicant Type",
+   "options": "Employee\nMember\nCustomer",
+   "read_only": 1
+  },
+  {
+   "fetch_from": "loan.applicant",
+   "fieldname": "applicant",
+   "fieldtype": "Dynamic Link",
+   "label": "Applicant ",
+   "options": "applicant_type",
+   "read_only": 1
+  },
+  {
+   "collapsible": 1,
+   "fieldname": "accounting_dimensions_section",
+   "fieldtype": "Section Break",
+   "label": "Accounting Dimensions"
+  },
+  {
+   "fieldname": "cost_center",
+   "fieldtype": "Link",
+   "label": "Cost Center",
+   "options": "Cost Center"
+  },
+  {
+   "fieldname": "section_break_9",
+   "fieldtype": "Section Break",
+   "label": "Write Off Details"
+  },
+  {
+   "fieldname": "write_off_account",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Write Off Account",
+   "options": "Account",
+   "reqd": 1
+  },
+  {
+   "fieldname": "write_off_amount",
+   "fieldtype": "Currency",
+   "label": "Write Off Amount",
+   "options": "Company:company:default_currency",
+   "reqd": 1
+  },
+  {
+   "fieldname": "column_break_11",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "amended_from",
+   "fieldtype": "Link",
+   "label": "Amended From",
+   "no_copy": 1,
+   "options": "Loan Write Off",
+   "print_hide": 1,
+   "read_only": 1
+  }
+ ],
+ "index_web_pages_for_search": 1,
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2020-10-26 07:13:43.663924",
+ "modified_by": "Administrator",
+ "module": "Loan Management",
+ "name": "Loan Write Off",
+ "owner": "Administrator",
+ "permissions": [
+  {
+   "cancel": 1,
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "System Manager",
+   "share": 1,
+   "submit": 1,
+   "write": 1
+  },
+  {
+   "cancel": 1,
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Loan Manager",
+   "share": 1,
+   "submit": 1,
+   "write": 1
+  }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/loan_management/doctype/loan_write_off/loan_write_off.py b/erpnext/loan_management/doctype/loan_write_off/loan_write_off.py
new file mode 100644
index 0000000..54a3f2c
--- /dev/null
+++ b/erpnext/loan_management/doctype/loan_write_off/loan_write_off.py
@@ -0,0 +1,88 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe, erpnext
+from frappe import _
+from frappe.utils import getdate, flt, cint
+from erpnext.controllers.accounts_controller import AccountsController
+from erpnext.accounts.general_ledger import make_gl_entries
+
+class LoanWriteOff(AccountsController):
+	def validate(self):
+		self.set_missing_values()
+		self.validate_write_off_amount()
+
+	def set_missing_values(self):
+		if not self.cost_center:
+			self.cost_center = erpnext.get_default_cost_center(self.company)
+
+	def validate_write_off_amount(self):
+		precision = cint(frappe.db.get_default("currency_precision")) or 2
+		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(flt(total_payment) - flt(interest_payable) - flt(principal_paid) - flt(written_off_amount),
+			precision)
+
+		if self.write_off_amount > pending_principal_amount:
+			frappe.throw(_("Write off amount cannot be greater than pending principal amount"))
+
+	def on_submit(self):
+		self.update_outstanding_amount()
+		self.make_gl_entries()
+
+	def on_cancel(self):
+		self.update_outstanding_amount(cancel=1)
+		self.ignore_linked_doctypes = ['GL Entry']
+		self.make_gl_entries(cancel=1)
+
+	def update_outstanding_amount(self, cancel=0):
+		written_off_amount = frappe.db.get_value('Loan', self.loan, 'written_off_amount')
+
+		if cancel:
+			written_off_amount -= self.write_off_amount
+		else:
+			written_off_amount += self.write_off_amount
+
+		frappe.db.set_value('Loan', self.loan, 'written_off_amount', written_off_amount)
+
+
+	def make_gl_entries(self, cancel=0):
+		gl_entries = []
+		loan_details = frappe.get_doc("Loan", self.loan)
+
+		gl_entries.append(
+			self.get_gl_dict({
+				"account": self.write_off_account,
+				"against": loan_details.loan_account,
+				"debit": self.write_off_amount,
+				"debit_in_account_currency": self.write_off_amount,
+				"against_voucher_type": "Loan",
+				"against_voucher": self.loan,
+				"remarks": _("Against Loan:") + self.loan,
+				"cost_center": self.cost_center,
+				"posting_date": getdate(self.posting_date)
+			})
+		)
+
+		gl_entries.append(
+			self.get_gl_dict({
+				"account": loan_details.loan_account,
+				"party_type": loan_details.applicant_type,
+				"party": loan_details.applicant,
+				"against": self.write_off_account,
+				"credit": self.write_off_amount,
+				"credit_in_account_currency": self.write_off_amount,
+				"against_voucher_type": "Loan",
+				"against_voucher": self.loan,
+				"remarks": _("Against Loan:") + self.loan,
+				"cost_center": self.cost_center,
+				"posting_date": getdate(self.posting_date)
+			})
+		)
+
+		make_gl_entries(gl_entries, cancel=cancel, merge_entries=False)
+
+
diff --git a/erpnext/loan_management/doctype/loan_write_off/test_loan_write_off.py b/erpnext/loan_management/doctype/loan_write_off/test_loan_write_off.py
new file mode 100644
index 0000000..9f6700e
--- /dev/null
+++ b/erpnext/loan_management/doctype/loan_write_off/test_loan_write_off.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+# import frappe
+import unittest
+
+class TestLoanWriteOff(unittest.TestCase):
+	pass
diff --git a/erpnext/loan_management/doctype/pledge/pledge.json b/erpnext/loan_management/doctype/pledge/pledge.json
index f22a21e..801e3a3 100644
--- a/erpnext/loan_management/doctype/pledge/pledge.json
+++ b/erpnext/loan_management/doctype/pledge/pledge.json
@@ -1,4 +1,5 @@
 {
+ "actions": [],
  "creation": "2019-09-09 17:06:16.756573",
  "doctype": "DocType",
  "editable_grid": 1,
@@ -49,7 +50,8 @@
    "fieldname": "qty",
    "fieldtype": "Float",
    "in_list_view": 1,
-   "label": "Quantity"
+   "label": "Quantity",
+   "non_negative": 1
   },
   {
    "fieldname": "loan_security_price",
@@ -86,7 +88,8 @@
   }
  ],
  "istable": 1,
- "modified": "2019-12-03 10:59:58.001421",
+ "links": [],
+ "modified": "2020-11-05 10:07:15.424937",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Pledge",
diff --git a/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.json b/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.json
index 0ef098f..828df2e 100644
--- a/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.json
+++ b/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.json
@@ -10,6 +10,7 @@
   "loan_type",
   "loan",
   "process_type",
+  "accrual_type",
   "amended_from"
  ],
  "fields": [
@@ -47,17 +48,27 @@
    "hidden": 1,
    "label": "Process Type",
    "read_only": 1
+  },
+  {
+   "fieldname": "accrual_type",
+   "fieldtype": "Select",
+   "hidden": 1,
+   "label": "Accrual Type",
+   "options": "Regular\nRepayment\nDisbursement",
+   "read_only": 1
   }
  ],
+ "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2020-04-09 22:52:53.911416",
+ "modified": "2020-11-06 13:28:51.478909",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Process Loan Interest Accrual",
  "owner": "Administrator",
  "permissions": [
   {
+   "cancel": 1,
    "create": 1,
    "delete": 1,
    "email": 1,
@@ -67,9 +78,11 @@
    "report": 1,
    "role": "System Manager",
    "share": 1,
+   "submit": 1,
    "write": 1
   },
   {
+   "cancel": 1,
    "create": 1,
    "delete": 1,
    "email": 1,
@@ -79,6 +92,7 @@
    "report": 1,
    "role": "Loan Manager",
    "share": 1,
+   "submit": 1,
    "write": 1
   }
  ],
diff --git a/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.py b/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.py
index 0fa9686..11333dc 100644
--- a/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.py
+++ b/erpnext/loan_management/doctype/process_loan_interest_accrual/process_loan_interest_accrual.py
@@ -20,19 +20,20 @@
 
 		if (not self.loan or not loan_doc.is_term_loan) and self.process_type != 'Term Loans':
 			make_accrual_interest_entry_for_demand_loans(self.posting_date, self.name,
-				open_loans = open_loans, loan_type = self.loan_type)
+				open_loans = open_loans, loan_type = self.loan_type, accrual_type=self.accrual_type)
 
 		if (not self.loan or loan_doc.is_term_loan) and self.process_type != 'Demand Loans':
 			make_accrual_interest_entry_for_term_loans(self.posting_date, self.name, term_loan=self.loan,
-				loan_type=self.loan_type)
+				loan_type=self.loan_type, accrual_type=self.accrual_type)
 
 
-def process_loan_interest_accrual_for_demand_loans(posting_date=None, loan_type=None, loan=None):
+def process_loan_interest_accrual_for_demand_loans(posting_date=None, loan_type=None, loan=None, accrual_type="Regular"):
 	loan_process = frappe.new_doc('Process Loan Interest Accrual')
 	loan_process.posting_date = posting_date or nowdate()
 	loan_process.loan_type = loan_type
 	loan_process.process_type = 'Demand Loans'
 	loan_process.loan = loan
+	loan_process.accrual_type = accrual_type
 
 	loan_process.submit()
 
diff --git a/erpnext/loan_management/doctype/proposed_pledge/proposed_pledge.json b/erpnext/loan_management/doctype/proposed_pledge/proposed_pledge.json
index aee7c2c..3e7e778 100644
--- a/erpnext/loan_management/doctype/proposed_pledge/proposed_pledge.json
+++ b/erpnext/loan_management/doctype/proposed_pledge/proposed_pledge.json
@@ -1,4 +1,5 @@
 {
+ "actions": [],
  "creation": "2019-08-29 22:29:37.628178",
  "doctype": "DocType",
  "editable_grid": 1,
@@ -39,7 +40,8 @@
    "fieldname": "qty",
    "fieldtype": "Float",
    "in_list_view": 1,
-   "label": "Quantity"
+   "label": "Quantity",
+   "non_negative": 1
   },
   {
    "fieldname": "loan_security",
@@ -56,8 +58,10 @@
    "read_only": 1
   }
  ],
+ "index_web_pages_for_search": 1,
  "istable": 1,
- "modified": "2019-12-02 10:23:11.498308",
+ "links": [],
+ "modified": "2020-11-05 10:07:37.542344",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Proposed Pledge",
diff --git a/erpnext/loan_management/doctype/unpledge/unpledge.json b/erpnext/loan_management/doctype/unpledge/unpledge.json
index ee192d7..0035668 100644
--- a/erpnext/loan_management/doctype/unpledge/unpledge.json
+++ b/erpnext/loan_management/doctype/unpledge/unpledge.json
@@ -52,6 +52,7 @@
    "fieldtype": "Float",
    "in_list_view": 1,
    "label": "Quantity",
+   "non_negative": 1,
    "reqd": 1
   },
   {
@@ -62,9 +63,10 @@
    "read_only": 1
   }
  ],
+ "index_web_pages_for_search": 1,
  "istable": 1,
  "links": [],
- "modified": "2020-05-06 10:50:18.448552",
+ "modified": "2020-11-05 10:07:28.106961",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Unpledge",
diff --git a/erpnext/loan_management/loan_common.js b/erpnext/loan_management/loan_common.js
index d9dd415..50b68da 100644
--- a/erpnext/loan_management/loan_common.js
+++ b/erpnext/loan_management/loan_common.js
@@ -8,14 +8,14 @@
 			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() {
 				frappe.route_options = {
 					voucher_no: frm.doc.name,
 					company: frm.doc.company,
-					from_date: frm.doc.posting_date,
+					from_date: moment(frm.doc.posting_date).format('YYYY-MM-DD'),
 					to_date: moment(frm.doc.modified).format('YYYY-MM-DD'),
 					show_cancelled_entries: frm.doc.docstatus === 2
 				};
diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py
index 2ab1b98..8888a96 100644
--- a/erpnext/manufacturing/doctype/bom/bom.py
+++ b/erpnext/manufacturing/doctype/bom/bom.py
@@ -76,6 +76,7 @@
 		self.set_routing_operations()
 		self.validate_operations()
 		self.calculate_cost()
+		self.update_stock_qty()
 		self.update_cost(update_parent=False, from_child_bom=True, save=False)
 
 	def get_context(self, context):
@@ -84,8 +85,6 @@
 	def on_update(self):
 		frappe.cache().hdel('bom_children', self.name)
 		self.check_recursion()
-		self.update_stock_qty()
-		self.update_exploded_items()
 
 	def on_submit(self):
 		self.manage_default_bom()
@@ -237,7 +236,8 @@
 			self.calculate_cost()
 		if save:
 			self.db_update()
-		self.update_exploded_items()
+
+		self.update_exploded_items(save=save)
 
 		# update parent BOMs
 		if self.total_cost != existing_bom_cost and update_parent:
@@ -318,8 +318,6 @@
 				m.uom = m.stock_uom
 				m.qty = m.stock_qty
 
-			m.db_update()
-
 	def validate_uom_is_interger(self):
 		from erpnext.utilities.transaction_base import validate_uom_is_integer
 		validate_uom_is_integer(self, "uom", "qty", "BOM Item")
@@ -372,15 +370,6 @@
 		if raise_exception:
 			frappe.throw(_("BOM recursion: {0} cannot be parent or child of {1}").format(self.name, self.name))
 
-	def update_cost_and_exploded_items(self, bom_list=[]):
-		bom_list = self.traverse_tree(bom_list)
-		for bom in bom_list:
-			bom_obj = frappe.get_doc("BOM", bom)
-			bom_obj.check_recursion(bom_list=bom_list)
-			bom_obj.update_exploded_items()
-
-		return bom_list
-
 	def traverse_tree(self, bom_list=None):
 		def _get_children(bom_no):
 			children = frappe.cache().hget('bom_children', bom_no)
@@ -472,10 +461,10 @@
 			d.rate = rate
 			d.amount = (d.stock_qty or d.qty) * rate
 
-	def update_exploded_items(self):
+	def update_exploded_items(self, save=True):
 		""" Update Flat BOM, following will be correct data"""
 		self.get_exploded_items()
-		self.add_exploded_items()
+		self.add_exploded_items(save=save)
 
 	def get_exploded_items(self):
 		""" Get all raw materials including items from child bom"""
@@ -544,11 +533,13 @@
 				'sourced_by_supplier': d.get('sourced_by_supplier', 0)
 			}))
 
-	def add_exploded_items(self):
+	def add_exploded_items(self, save=True):
 		"Add items to Flat BOM table"
-		frappe.db.sql("""delete from `tabBOM Explosion Item` where parent=%s""", self.name)
 		self.set('exploded_items', [])
 
+		if save:
+			frappe.db.sql("""delete from `tabBOM Explosion Item` where parent=%s""", self.name)
+
 		for d in sorted(self.cur_exploded_items, key=itemgetter(0)):
 			ch = self.append('exploded_items', {})
 			for i in self.cur_exploded_items[d].keys():
@@ -556,7 +547,9 @@
 			ch.amount = flt(ch.stock_qty) * flt(ch.rate)
 			ch.qty_consumed_per_unit = flt(ch.stock_qty) / flt(self.quantity)
 			ch.docstatus = self.docstatus
-			ch.db_insert()
+
+			if save:
+				ch.db_insert()
 
 	def validate_bom_links(self):
 		if not self.is_active:
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.json b/erpnext/manufacturing/doctype/production_plan/production_plan.json
index 850d5ae..7daf706 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.json
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.json
@@ -19,6 +19,7 @@
   "column_break2",
   "from_date",
   "to_date",
+  "sales_order_status",
   "sales_orders_detail",
   "get_sales_orders",
   "sales_orders",
@@ -301,13 +302,20 @@
    "label": "Warehouses",
    "options": "Production Plan Material Request Warehouse",
    "read_only": 1
+  },
+  {
+   "depends_on": "eval: doc.get_items_from == \"Sales Order\"",
+   "fieldname": "sales_order_status",
+   "fieldtype": "Select",
+   "label": "Sales Order Status",
+   "options": "\nTo Deliver and Bill\nTo Bill\nTo Deliver"
   }
  ],
  "icon": "fa fa-calendar",
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2020-10-26 13:00:54.335319",
+ "modified": "2020-11-10 18:01:54.991970",
  "modified_by": "Administrator",
  "module": "Manufacturing",
  "name": "Production Plan",
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py
index a314a15..3833e86 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -571,6 +571,8 @@
 		so_filter += " and so.customer = %(customer)s"
 	if self.project:
 		so_filter += " and so.project = %(project)s"
+	if self.sales_order_status:
+		so_filter += "and so.status = %(sales_order_status)s"
 
 	if self.item_code:
 		item_filter += " and so_item.item_code = %(item)s"
@@ -594,8 +596,8 @@
 			"customer": self.customer,
 			"project": self.project,
 			"item": self.item_code,
-			"company": self.company
-
+			"company": self.company,
+			"sales_order_status": self.sales_order_status
 		}, as_dict=1)
 	return open_so
 
diff --git a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
index fa9d080..27335aa 100644
--- a/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/test_production_plan.py
@@ -137,7 +137,8 @@
 			'from_date': so.transaction_date,
 			'to_date': so.transaction_date,
 			'customer': so.customer,
-			'item_code': item
+			'item_code': item,
+			'sales_order_status': so.status
 		})
 		sales_orders = get_sales_orders(pln) or {}
 		sales_orders = [d.get('name') for d in sales_orders if d.get('name') == sales_order]
diff --git a/erpnext/manufacturing/doctype/work_order/test_work_order.py b/erpnext/manufacturing/doctype/work_order/test_work_order.py
index 5f8a134..e539279 100644
--- a/erpnext/manufacturing/doctype/work_order/test_work_order.py
+++ b/erpnext/manufacturing/doctype/work_order/test_work_order.py
@@ -443,6 +443,11 @@
 		ste1 = frappe.get_doc(make_stock_entry(wo.name, "Manufacture", 1))
 		self.assertEqual(len(ste1.items), 3)
 
+	def test_cost_center_for_manufacture(self):
+		wo_order = make_wo_order_test_record()
+		ste = make_stock_entry(wo_order.name, "Material Transfer for Manufacture", wo_order.qty)
+		self.assertEquals(ste.get("items")[0].get("cost_center"), "_Test Cost Center - _TC")
+
 	def test_operation_time_with_batch_size(self):
 		fg_item = "Test Batch Size Item For BOM"
 		rm1 = "Test Batch Size Item RM 1 For BOM"
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 34dbdd0..25be884 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -733,4 +733,5 @@
 erpnext.patches.v13_0.set_payment_channel_in_payment_gateway_account
 erpnext.patches.v13_0.create_healthcare_custom_fields_in_stock_entry_detail
 erpnext.patches.v13_0.update_reason_for_resignation_in_employee
-execute:frappe.delete_doc("Report", "Quoted Item Comparison")
\ No newline at end of file
+erpnext.patches.v13_0.update_custom_fields_for_shopify
+execute:frappe.delete_doc("Report", "Quoted Item Comparison")
diff --git a/erpnext/patches/v12_0/generate_leave_ledger_entries.py b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
index 7afde37..fe072d7 100644
--- a/erpnext/patches/v12_0/generate_leave_ledger_entries.py
+++ b/erpnext/patches/v12_0/generate_leave_ledger_entries.py
@@ -51,7 +51,7 @@
 
 	for encashment in leave_encashments:
 		if not frappe.db.exists("Leave Ledger Entry", {'transaction_type': 'Leave Encashment', 'transaction_name': encashment.name}):
-			frappe.get_doc("Leave Enchashment", encashment).create_leave_ledger_entry()
+			frappe.get_doc("Leave Encashment", encashment).create_leave_ledger_entry()
 
 def generate_expiry_allocation_ledger_entries():
 	''' fix ledger entries for missing leave allocation transaction '''
diff --git a/erpnext/patches/v13_0/update_custom_fields_for_shopify.py b/erpnext/patches/v13_0/update_custom_fields_for_shopify.py
new file mode 100644
index 0000000..f1d2ea2
--- /dev/null
+++ b/erpnext/patches/v13_0/update_custom_fields_for_shopify.py
@@ -0,0 +1,10 @@
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# MIT License. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+from erpnext.erpnext_integrations.doctype.shopify_settings.shopify_settings import setup_custom_fields
+
+def execute():
+	if frappe.db.get_single_value('Shopify Settings', 'enable_shopify'):
+		setup_custom_fields()
diff --git a/erpnext/payroll/doctype/payroll_entry/payroll_entry.py b/erpnext/payroll/doctype/payroll_entry/payroll_entry.py
index 30ea432..a3d12c3 100644
--- a/erpnext/payroll/doctype/payroll_entry/payroll_entry.py
+++ b/erpnext/payroll/doctype/payroll_entry/payroll_entry.py
@@ -344,9 +344,13 @@
 		employees_to_mark_attendance = []
 		days_in_payroll, days_holiday, days_attendance_marked = 0, 0, 0
 		for employee_detail in self.employees:
-			days_holiday = self.get_count_holidays_of_employee(employee_detail.employee)
-			days_attendance_marked = self.get_count_employee_attendance(employee_detail.employee)
-			days_in_payroll = date_diff(self.end_date, self.start_date) + 1
+			employee_joining_date = frappe.db.get_value("Employee", employee_detail.employee, 'date_of_joining')
+			start_date = self.start_date
+			if employee_joining_date > getdate(self.start_date):
+				start_date = employee_joining_date
+			days_holiday = self.get_count_holidays_of_employee(employee_detail.employee, start_date)
+			days_attendance_marked = self.get_count_employee_attendance(employee_detail.employee, start_date)
+			days_in_payroll = date_diff(self.end_date, start_date) + 1
 			if days_in_payroll > days_holiday + days_attendance_marked:
 				employees_to_mark_attendance.append({
 					"employee": employee_detail.employee,
@@ -354,22 +358,25 @@
 					})
 		return employees_to_mark_attendance
 
-	def get_count_holidays_of_employee(self, employee):
+	def get_count_holidays_of_employee(self, employee, start_date):
 		holiday_list = get_holiday_list_for_employee(employee)
 		holidays = 0
 		if holiday_list:
 			days = frappe.db.sql("""select count(*) from tabHoliday where
 				parent=%s and holiday_date between %s and %s""", (holiday_list,
-				self.start_date, self.end_date))
+				start_date, self.end_date))
 			if days and days[0][0]:
 				holidays = days[0][0]
 		return holidays
 
-	def get_count_employee_attendance(self, employee):
+	def get_count_employee_attendance(self, employee, start_date):
 		marked_days = 0
-		attendances = frappe.db.sql("""select count(*) from tabAttendance where
-			employee=%s and docstatus=1 and attendance_date between %s and %s""",
-			(employee, self.start_date, self.end_date))
+		attendances = frappe.get_all("Attendance",
+				fields = ["count(*)"],
+				filters = {
+					"employee": employee,
+					"attendance_date": ('between', [start_date, self.end_date])
+				}, as_list=1)
 		if attendances and attendances[0][0]:
 			marked_days = attendances[0][0]
 		return marked_days
diff --git a/erpnext/payroll/doctype/salary_slip/salary_slip.py b/erpnext/payroll/doctype/salary_slip/salary_slip.py
index 4ccf564..cecb8cd 100644
--- a/erpnext/payroll/doctype/salary_slip/salary_slip.py
+++ b/erpnext/payroll/doctype/salary_slip/salary_slip.py
@@ -240,7 +240,6 @@
 				self.absent_days += unmarked_days #will be treated as absent
 				self.payment_days -= unmarked_days
 				if include_holidays_in_total_working_days:
-					self.absent_days -= len(holidays)
 					for holiday in holidays:
 						if not frappe.db.exists("Attendance", {"employee": self.employee, "attendance_date": holiday, "docstatus": 1 }):
 							self.payment_days += 1
diff --git a/erpnext/payroll/report/bank_remittance/bank_remittance.py b/erpnext/payroll/report/bank_remittance/bank_remittance.py
index 4b052bf..500543c 100644
--- a/erpnext/payroll/report/bank_remittance/bank_remittance.py
+++ b/erpnext/payroll/report/bank_remittance/bank_remittance.py
@@ -47,33 +47,39 @@
 			"fieldtype": "Int",
 			"fieldname": "employee_account_no",
 			"width": 50
-		},
-		{
+		}
+	]
+
+	if frappe.db.has_column('Employee', 'ifsc_code'):
+		columns.append({
 			"label": _("IFSC Code"),
 			"fieldtype": "Data",
 			"fieldname": "bank_code",
 			"width": 100
-		},
-		{
-			"label": _("Currency"),
-			"fieldtype": "Data",
-			"fieldname": "currency",
-			"width": 50
-		},
-		{
-			"label": _("Net Salary Amount"),
-			"fieldtype": "Currency",
-			"options": "currency",
-			"fieldname": "amount",
-			"width": 100
-		}
-	]
+		})
+
+	columns += [{
+		"label": _("Currency"),
+		"fieldtype": "Data",
+		"fieldname": "currency",
+		"width": 50
+	},
+	{
+		"label": _("Net Salary Amount"),
+		"fieldtype": "Currency",
+		"options": "currency",
+		"fieldname": "amount",
+		"width": 100
+	}]
+
 	data = []
 
 	accounts = get_bank_accounts()
 	payroll_entries = get_payroll_entries(accounts, filters)
 	salary_slips = get_salary_slips(payroll_entries)
-	get_emp_bank_ifsc_code(salary_slips)
+
+	if frappe.db.has_column('Employee', 'ifsc_code'):
+		get_emp_bank_ifsc_code(salary_slips)
 
 	for salary in salary_slips:
 		if salary.bank_name and salary.bank_account_no and salary.debit_acc_no and salary.status in ["Submitted", "Paid"]:
diff --git a/erpnext/regional/doctype/datev_settings/datev_settings.js b/erpnext/regional/doctype/datev_settings/datev_settings.js
index 69747b0..f047059 100644
--- a/erpnext/regional/doctype/datev_settings/datev_settings.js
+++ b/erpnext/regional/doctype/datev_settings/datev_settings.js
@@ -2,7 +2,7 @@
 // For license information, please see license.txt
 
 frappe.ui.form.on('DATEV Settings', {
-	// refresh: function(frm) {
-
-	// }
+	refresh: function(frm) {
+		frm.add_custom_button('Show Report', () => frappe.set_route('query-report', 'DATEV'), "fa fa-table");
+	}
 });
diff --git a/erpnext/regional/doctype/datev_settings/datev_settings.json b/erpnext/regional/doctype/datev_settings/datev_settings.json
index 39486df..713e8e3 100644
--- a/erpnext/regional/doctype/datev_settings/datev_settings.json
+++ b/erpnext/regional/doctype/datev_settings/datev_settings.json
@@ -1,4 +1,5 @@
 {
+ "actions": [],
  "autoname": "field:client",
  "creation": "2019-08-13 23:56:34.259906",
  "doctype": "DocType",
@@ -6,6 +7,7 @@
  "engine": "InnoDB",
  "field_order": [
   "client",
+  "account_number_length",
   "column_break_2",
   "client_number",
   "section_break_4",
@@ -28,8 +30,8 @@
    "fieldtype": "Data",
    "in_list_view": 1,
    "label": "Client ID",
-   "reqd": 1,
-   "length": 5
+   "length": 5,
+   "reqd": 1
   },
   {
    "fieldname": "consultant",
@@ -43,8 +45,8 @@
    "fieldtype": "Data",
    "in_list_view": 1,
    "label": "Consultant ID",
-   "reqd": 1,
-   "length": 7
+   "length": 7,
+   "reqd": 1
   },
   {
    "fieldname": "column_break_2",
@@ -57,9 +59,17 @@
   {
    "fieldname": "column_break_6",
    "fieldtype": "Column Break"
+  },
+  {
+   "default": "4",
+   "fieldname": "account_number_length",
+   "fieldtype": "Int",
+   "label": "Account Number Length",
+   "reqd": 1
   }
  ],
- "modified": "2019-08-14 00:03:26.616460",
+ "links": [],
+ "modified": "2020-11-05 17:52:11.674329",
  "modified_by": "Administrator",
  "module": "Regional",
  "name": "DATEV Settings",
@@ -104,4 +114,4 @@
  "sort_field": "modified",
  "sort_order": "DESC",
  "track_changes": 1
-}
+}
\ No newline at end of file
diff --git a/erpnext/regional/germany/accounts_controller.py b/erpnext/regional/germany/accounts_controller.py
index 193c8e1..5b2b31f 100644
--- a/erpnext/regional/germany/accounts_controller.py
+++ b/erpnext/regional/germany/accounts_controller.py
@@ -15,8 +15,7 @@
 		},
 		{
 			"field_name": "taxes",
-			"regulation": "§ 14 Abs. 4 Nr. 8 UStG",
-			"condition": "not exempt_from_sales_tax"
+			"regulation": "§ 14 Abs. 4 Nr. 8 UStG"
 		},
 		{
 			"field_name": "customer_address",
diff --git a/erpnext/regional/germany/utils/datev/datev_csv.py b/erpnext/regional/germany/utils/datev/datev_csv.py
index cf07a1c..f138a80 100644
--- a/erpnext/regional/germany/utils/datev/datev_csv.py
+++ b/erpnext/regional/germany/utils/datev/datev_csv.py
@@ -106,7 +106,7 @@
 		# M = Start of the fiscal year (Wirtschaftsjahresbeginn)
 		frappe.utils.formatdate(filters.get('fiscal_year_start'), 'yyyyMMdd'),
 		# N = Length of account numbers (Sachkontenlänge)
-		datev_settings.get('account_number_length', '4'),
+		str(filters.get('account_number_length', 4)),
 		# O = Transaction batch start date (YYYYMMDD)
 		frappe.utils.formatdate(filters.get('from_date'), 'yyyyMMdd') if csv_class.DATA_CATEGORY == DataCategory.TRANSACTIONS else '',
 		# P = Transaction batch end date (YYYYMMDD)
diff --git a/erpnext/regional/report/datev/datev.js b/erpnext/regional/report/datev/datev.js
index 55f12cf..4124e3d 100644
--- a/erpnext/regional/report/datev/datev.js
+++ b/erpnext/regional/report/datev/datev.js
@@ -11,14 +11,14 @@
 		{
 			"fieldname": "from_date",
 			"label": __("From Date"),
-			"default": frappe.datetime.month_start(),
+			"default": moment().subtract(1, 'month').startOf('month').format(),
 			"fieldtype": "Date",
 			"reqd": 1
 		},
 		{
 			"fieldname": "to_date",
 			"label": __("To Date"),
-			"default": frappe.datetime.now_date(),
+			"default": moment().subtract(1, 'month').endOf('month').format(),
 			"fieldtype": "Date",
 			"reqd": 1
 		},
@@ -30,9 +30,23 @@
 		}
 	],
 	onload: function(query_report) {
+		let company = frappe.query_report.get_filter_value('company');
+		frappe.db.exists('DATEV Settings', company).then((settings_exist) => {
+			if (!settings_exist) {
+				frappe.confirm(__('DATEV Settings for your Company are missing. Would you like to create them now?'),
+					() => frappe.new_doc('DATEV Settings', {'company': company})
+				);
+			}
+		});
+
 		query_report.page.add_menu_item(__("Download DATEV File"), () => {
 			const filters = JSON.stringify(query_report.get_values());
 			window.open(`/api/method/erpnext.regional.report.datev.datev.download_datev_csv?filters=${filters}`);
 		});
+
+		query_report.page.add_menu_item(__("Change DATEV Settings"), () => {
+			let company = frappe.query_report.get_filter_value('company'); // read company from filters again – it might have changed by now.
+			frappe.set_route('Form', 'DATEV Settings', company);
+		});
 	}
 };
diff --git a/erpnext/regional/report/datev/datev.py b/erpnext/regional/report/datev/datev.py
index dbae230..1e39c57 100644
--- a/erpnext/regional/report/datev/datev.py
+++ b/erpnext/regional/report/datev/datev.py
@@ -94,8 +94,11 @@
 
 def execute(filters=None):
 	"""Entry point for frappe."""
-	validate(filters)
-	return COLUMNS, get_transactions(filters, as_dict=0)
+	data = []
+	if filters and validate(filters):
+		data = get_transactions(filters, as_dict=0)
+
+	return COLUMNS, data
 
 
 def validate(filters):
@@ -114,10 +117,14 @@
 
 	validate_fiscal_year(from_date, to_date, company)
 
-	try:
-		frappe.get_doc('DATEV Settings', filters.get('company'))
-	except frappe.DoesNotExistError:
-		frappe.throw(_('Please create <b>DATEV Settings</b> for Company <b>{}</b>.').format(filters.get('company')))
+	if not frappe.db.exists('DATEV Settings', filters.get('company')):
+		frappe.log_error(_('Please create {} for Company {}.').format(
+			'<a href="desk#List/DATEV%20Settings/List">{}</a>'.format(_('DATEV Settings')),
+			frappe.bold(filters.get('company'))
+		))
+		return False
+
+	return True
 
 
 def validate_fiscal_year(from_date, to_date, company):
@@ -340,6 +347,8 @@
 	coa = frappe.get_value('Company', company, 'chart_of_accounts')
 	filters['skr'] = '04' if 'SKR04' in coa else ('03' if 'SKR03' in coa else '')
 
+	filters['account_number_length'] = frappe.get_value('DATEV Settings', company, 'account_number_length')
+
 	transactions = get_transactions(filters)
 	account_names = get_account_names(filters)
 	customers = get_customers(filters)
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index ec1c823..04d85e5 100755
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -844,7 +844,8 @@
 						"contact_email",
 						"contact_person",
 						"taxes_and_charges",
-						"shipping_address"
+						"shipping_address",
+						"terms"
 					],
 					"validation": {
 						"docstatus": ["=", 1]
@@ -863,7 +864,10 @@
 					"field_no_map": [
 						"rate",
 						"price_list_rate",
-						"item_tax_template"
+						"item_tax_template",
+						"discount_percentage",
+						"discount_amount",
+						"pricing_rules"
 					],
 					"postprocess": update_item,
 					"condition": lambda doc: doc.ordered_qty < doc.stock_qty and doc.supplier == supplier and doc.item_code in items_to_map
@@ -917,7 +921,8 @@
 				"contact_email",
 				"contact_person",
 				"taxes_and_charges",
-				"shipping_address"
+				"shipping_address",
+				"terms"
 			],
 			"validation": {
 				"docstatus": ["=", 1]
@@ -937,7 +942,10 @@
 				"rate",
 				"price_list_rate",
 				"item_tax_template",
-				"supplier"
+				"discount_percentage",
+				"discount_amount",
+				"supplier",
+				"pricing_rules"
 			],
 			"postprocess": update_item,
 			"condition": lambda doc: doc.ordered_qty < doc.stock_qty and doc.item_code in items_to_map
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index a33d401..643e7cf 100644
--- a/erpnext/selling/doctype/sales_order/test_sales_order.py
+++ b/erpnext/selling/doctype/sales_order/test_sales_order.py
@@ -1064,6 +1064,7 @@
 	so.company = args.company or "_Test Company"
 	so.customer = args.customer or "_Test Customer"
 	so.currency = args.currency or "INR"
+	so.po_no = args.po_no or '12345'
 	if args.selling_price_list:
 		so.selling_price_list = args.selling_price_list
 
diff --git a/erpnext/selling/page/point_of_sale/point_of_sale.py b/erpnext/selling/page/point_of_sale/point_of_sale.py
index a690050..062cba1 100644
--- a/erpnext/selling/page/point_of_sale/point_of_sale.py
+++ b/erpnext/selling/page/point_of_sale/point_of_sale.py
@@ -62,6 +62,7 @@
 			`tabItem` item {bin_join_selection}
 		WHERE
 			item.disabled = 0
+			AND item.is_stock_item = 1
 			AND item.has_variants = 0
 			AND item.is_sales_item = 1
 			AND item.is_fixed_asset = 0
diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.json b/erpnext/stock/doctype/delivery_note/delivery_note.json
index ea385c8..3c5129b 100644
--- a/erpnext/stock/doctype/delivery_note/delivery_note.json
+++ b/erpnext/stock/doctype/delivery_note/delivery_note.json
@@ -413,7 +413,8 @@
   {
    "fieldname": "company_address_display",
    "fieldtype": "Small Text",
-   "label": "Company Address"
+   "label": "Company Address",
+   "read_only": 1
   },
   {
    "collapsible": 1,
@@ -1255,7 +1256,7 @@
  "idx": 146,
  "is_submittable": 1,
  "links": [],
- "modified": "2020-08-03 23:18:47.739997",
+ "modified": "2020-11-11 14:57:16.388139",
  "modified_by": "Administrator",
  "module": "Stock",
  "name": "Delivery Note",
diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
index 0168613..9566af7 100644
--- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py
+++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py
@@ -442,9 +442,15 @@
 		self.assertEqual(dn.status, "To Bill")
 		self.assertEqual(dn.per_billed, 0)
 
+		# Testing if Customer's Purchase Order No was rightly copied
+		self.assertEqual(dn.po_no, so.po_no)
+
 		si = make_sales_invoice(dn.name)
 		si.submit()
 
+		# Testing if Customer's Purchase Order No was rightly copied
+		self.assertEqual(dn.po_no, si.po_no)
+
 		dn.load_from_db()
 		self.assertEqual(dn.get("items")[0].billed_amt, 200)
 		self.assertEqual(dn.per_billed, 100)
@@ -461,16 +467,25 @@
 		si.insert()
 		si.submit()
 
+		# Testing if Customer's Purchase Order No was rightly copied
+		self.assertEqual(so.po_no, si.po_no)
+
 		frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1)
 
 		dn1 = make_delivery_note(so.name)
 		dn1.get("items")[0].qty = 2
 		dn1.submit()
 
+		# Testing if Customer's Purchase Order No was rightly copied
+		self.assertEqual(so.po_no, dn1.po_no)
+
 		dn2 = make_delivery_note(so.name)
 		dn2.get("items")[0].qty = 3
 		dn2.submit()
 
+		# Testing if Customer's Purchase Order No was rightly copied
+		self.assertEqual(so.po_no, dn2.po_no)
+
 		dn1.load_from_db()
 		self.assertEqual(dn1.get("items")[0].billed_amt, 200)
 		self.assertEqual(dn1.per_billed, 100)
@@ -492,9 +507,15 @@
 		dn1.get("items")[0].qty = 2
 		dn1.submit()
 
+		# Testing if Customer's Purchase Order No was rightly copied
+		self.assertEqual(dn1.po_no, so.po_no)
+
 		si1 = make_sales_invoice(dn1.name)
 		si1.submit()
 
+		# Testing if Customer's Purchase Order No was rightly copied
+		self.assertEqual(dn1.po_no, si1.po_no)
+
 		dn1.load_from_db()
 		self.assertEqual(dn1.per_billed, 100)
 
@@ -502,10 +523,16 @@
 		si2.get("items")[0].qty = 4
 		si2.submit()
 
+		# Testing if Customer's Purchase Order No was rightly copied
+		self.assertEqual(si2.po_no, so.po_no)
+
 		dn2 = make_delivery_note(so.name)
 		dn2.get("items")[0].qty = 5
 		dn2.submit()
 
+		# Testing if Customer's Purchase Order No was rightly copied
+		self.assertEqual(dn2.po_no, so.po_no)
+
 		dn1.load_from_db()
 		self.assertEqual(dn1.get("items")[0].billed_amt, 200)
 		self.assertEqual(dn1.per_billed, 100)
@@ -525,9 +552,15 @@
 		si = make_sales_invoice(so.name)
 		si.submit()
 
+		# Testing if Customer's Purchase Order No was rightly copied
+		self.assertEqual(so.po_no, si.po_no)
+
 		dn = make_delivery_note(si.name)
 		dn.submit()
 
+		# Testing if Customer's Purchase Order No was rightly copied
+		self.assertEqual(dn.po_no, si.po_no)
+
 		self.assertEqual(dn.get("items")[0].billed_amt, 1000)
 		self.assertEqual(dn.per_billed, 100)
 		self.assertEqual(dn.status, "Completed")
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index 7685267..e3159b9 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -1227,8 +1227,6 @@
 		return item_dict
 
 	def add_to_stock_entry_detail(self, item_dict, bom_no=None):
-		cost_center = frappe.db.get_value("Company", self.company, 'cost_center')
-
 		for d in item_dict:
 			stock_uom = item_dict[d].get("stock_uom") or frappe.db.get_value("Item", d, "stock_uom")
 
@@ -1239,9 +1237,10 @@
 			se_child.uom = item_dict[d]["uom"] if item_dict[d].get("uom") else stock_uom
 			se_child.stock_uom = stock_uom
 			se_child.qty = flt(item_dict[d]["qty"], se_child.precision("qty"))
-			se_child.cost_center = item_dict[d].get("cost_center") or cost_center
 			se_child.allow_alternative_item = item_dict[d].get("allow_alternative_item", 0)
 			se_child.subcontracted_item = item_dict[d].get("main_item_code")
+			se_child.cost_center = (item_dict[d].get("cost_center") or
+				get_default_cost_center(item_dict[d], company = self.company))
 
 			for field in ["idx", "po_detail", "original_item",
 				"expense_account", "description", "item_name"]:
diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py
index 8d8dcb7..08f7a83 100644
--- a/erpnext/stock/get_item_details.py
+++ b/erpnext/stock/get_item_details.py
@@ -559,23 +559,40 @@
 	else:
 		return None
 
-def get_default_cost_center(args, item, item_group, brand, company=None):
+def get_default_cost_center(args, item=None, item_group=None, brand=None, company=None):
 	cost_center = None
+
+	if not company and args.get("company"):
+		company = args.get("company")
+
 	if args.get('project'):
 		cost_center = frappe.db.get_value("Project", args.get("project"), "cost_center", cache=True)
 
-	if not cost_center:
+	if not cost_center and (item and item_group and brand):
 		if args.get('customer'):
 			cost_center = item.get('selling_cost_center') or item_group.get('selling_cost_center') or brand.get('selling_cost_center')
 		else:
 			cost_center = item.get('buying_cost_center') or item_group.get('buying_cost_center') or brand.get('buying_cost_center')
 
-	cost_center = cost_center or args.get("cost_center")
+	elif not cost_center and args.get("item_code") and company:
+		for method in ["get_item_defaults", "get_item_group_defaults", "get_brand_defaults"]:
+			path = "erpnext.stock.get_item_details.{0}".format(method)
+			data = frappe.get_attr(path)(args.get("item_code"), company)
+
+			if data and (data.selling_cost_center or data.buying_cost_center):
+				return data.selling_cost_center or data.buying_cost_center
+
+	if not cost_center and args.get("cost_center"):
+		cost_center = args.get("cost_center")
 
 	if (company and cost_center
 		and frappe.get_cached_value("Cost Center", cost_center, "company") != company):
 		return None
 
+	if not cost_center and company:
+		cost_center = frappe.get_cached_value("Company",
+			company, "cost_center")
+
 	return cost_center
 
 def get_default_supplier(args, item, item_group, brand):
diff --git a/erpnext/stock/report/stock_ageing/stock_ageing.py b/erpnext/stock/report/stock_ageing/stock_ageing.py
index 3dc806f..8aaf7ab 100644
--- a/erpnext/stock/report/stock_ageing/stock_ageing.py
+++ b/erpnext/stock/report/stock_ageing/stock_ageing.py
@@ -20,7 +20,8 @@
 
 		fifo_queue = sorted(filter(_func, item_dict["fifo_queue"]), key=_func)
 		details = item_dict["details"]
-		if not fifo_queue and (not item_dict.get("total_qty")): continue
+
+		if not fifo_queue: continue
 
 		average_age = get_average_age(fifo_queue, to_date)
 		earliest_age = date_diff(to_date, fifo_queue[0][1])