fix: Loan securiyt unpledge fixes
diff --git a/erpnext/loan_management/doctype/loan/loan.py b/erpnext/loan_management/doctype/loan/loan.py
index c7a2fba..c550d49 100644
--- a/erpnext/loan_management/doctype/loan/loan.py
+++ b/erpnext/loan_management/doctype/loan/loan.py
@@ -233,7 +233,7 @@
 		return repayment_entry
 
 @frappe.whitelist()
-def create_loan_security_unpledge(loan, applicant_type, applicant, company):
+def create_loan_security_unpledge(loan, applicant_type, applicant, company, as_dict=1):
 	loan_security_pledge_details = frappe.db.sql("""
 		SELECT p.parent, p.loan_security, p.qty as qty FROM `tabLoan Security Pledge` lsp , `tabPledge` p
 		WHERE p.parent = lsp.name AND lsp.loan = %s AND lsp.docstatus = 1
@@ -252,7 +252,10 @@
 			"against_pledge": loan_security.parent
 		})
 
-	return unpledge_request.as_dict()
+	if as_dict:
+		return unpledge_request.as_dict()
+	else:
+		return unpledge_request
 
 
 
diff --git a/erpnext/loan_management/doctype/loan/test_loan.py b/erpnext/loan_management/doctype/loan/test_loan.py
index 90b8534..77a1fcc 100644
--- a/erpnext/loan_management/doctype/loan/test_loan.py
+++ b/erpnext/loan_management/doctype/loan/test_loan.py
@@ -14,6 +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 create_loan_security_unpledge
 
 class TestLoan(unittest.TestCase):
 	def setUp(self):
@@ -276,6 +277,56 @@
 		frappe.db.sql(""" UPDATE `tabLoan Security Price` SET loan_security_price = 250
 			where loan_security='Test Security 2'""")
 
+	def test_loan_security_unpledge(self):
+		pledges = []
+		pledges.append({
+			"loan_security": "Test Security 1",
+			"qty": 4000.00,
+			"haircut": 50
+		})
+
+		loan_security_pledge = create_loan_security_pledge(self.applicant2, pledges)
+		loan = create_demand_loan(self.applicant2, "Demand Loan", loan_security_pledge.name,
+			posting_date=get_first_day(nowdate()))
+		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 += 6
+
+		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)
+
+		repayment_entry = create_repayment_entry(loan.name, self.applicant2, add_days(last_date, 5),
+			"Loan Closure", 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'])
+
+		loan.load_from_db()
+		self.assertEquals(loan.status, "Loan Closure Requested")
+
+		unpledge_request = create_loan_security_unpledge(loan.name, loan.applicant_type, loan.applicant, loan.company, as_dict=0)
+		unpledge_request.submit()
+		unpledge_request.status = 'Approved'
+		unpledge_request.save()
+
+		loan_security_pledge.load_from_db()
+		loan.load_from_db()
+
+		self.assertEqual(loan.status, 'Closed')
+		for security in loan_security_pledge.securities:
+			self.assertEquals(security.qty, 0)
+
 
 def create_loan_accounts():
 	if not frappe.db.exists("Account", "Loans and Advances (Assets) - _TC"):
diff --git a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
index 5979ee3..452c836 100644
--- a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
+++ b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.py
@@ -78,7 +78,10 @@
 				(flt(payment.paid_principal_amount), flt(payment.paid_interest_amount), payment.loan_interest_accrual))
 
 		if flt(loan.total_principal_paid + self.principal_amount_paid, 2) >= flt(loan.total_payment, 2):
-			frappe.db.set_value("Loan", self.against_loan, "status", "Loan Closure Requested")
+			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,
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 eb61358..f97e596 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
@@ -13,6 +13,7 @@
 class LoanSecurityPledge(Document):
 	def validate(self):
 		self.set_pledge_amount()
+		self.validate_duplicate_securities()
 
 	def on_submit(self):
 		if self.loan:
@@ -21,6 +22,15 @@
 			update_shortfall_status(self.loan, self.total_security_value)
 			update_loan(self.loan, self.maximum_loan_value)
 
+	def validate_duplicate_securities(self):
+		security_list = []
+		for security in self.securities:
+			if security.loan_security not in security_list:
+				security_list.append(security.loan_security)
+			else:
+				frappe.throw(_('Loan Security {0} added multiple times').format(frappe.bold(
+					security.loan_security)))
+
 	def set_pledge_amount(self):
 		total_security_value = 0
 		maximum_loan_value = 0
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 ab040f1..8ca6e3e 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
@@ -53,7 +53,7 @@
 
 	loans = frappe.db.sql(""" SELECT l.name, l.loan_amount, l.total_principal_paid, lp.loan_security, lp.haircut, lp.qty, lp.loan_security_type
 		FROM `tabLoan` l, `tabPledge` lp , `tabLoan Security Pledge`p WHERE lp.parent = p.name and p.loan = l.name and l.docstatus = 1
-		and l.is_secured_loan and l.status = 'Disbursed' and p.status in ('Pledged', 'Partially Unpledged')""", as_dict=1)
+		and l.is_secured_loan and l.status = 'Disbursed' and p.status = 'Pledged'""", as_dict=1)
 
 	loan_security_map = {}
 
diff --git a/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.json b/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.json
index ba94855..aece46f 100644
--- a/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.json
+++ b/erpnext/loan_management/doctype/loan_security_unpledge/loan_security_unpledge.json
@@ -1,4 +1,5 @@
 {
+ "actions": [],
  "autoname": "LSU-.{applicant}.-.#####",
  "creation": "2019-09-21 13:23:16.117028",
  "doctype": "DocType",
@@ -15,7 +16,6 @@
   "status",
   "loan_security_details_section",
   "securities",
-  "unpledge_type",
   "amended_from"
  ],
  "fields": [
@@ -47,6 +47,7 @@
   {
    "allow_on_submit": 1,
    "default": "Requested",
+   "depends_on": "eval:doc.docstatus == 1",
    "fieldname": "status",
    "fieldtype": "Select",
    "label": "Status",
@@ -81,13 +82,6 @@
    "reqd": 1
   },
   {
-   "fieldname": "unpledge_type",
-   "fieldtype": "Data",
-   "hidden": 1,
-   "label": "Unpledge Type",
-   "read_only": 1
-  },
-  {
    "fieldname": "company",
    "fieldtype": "Link",
    "label": "Company",
@@ -104,7 +98,8 @@
   }
  ],
  "is_submittable": 1,
- "modified": "2019-10-28 07:41:47.084882",
+ "links": [],
+ "modified": "2020-05-05 07:23:18.440058",
  "modified_by": "Administrator",
  "module": "Loan Management",
  "name": "Loan Security Unpledge",
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 02b1ecb..b2bb22a 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
@@ -13,31 +13,43 @@
 class LoanSecurityUnpledge(Document):
 	def validate(self):
 		self.validate_pledges()
+		self.validate_duplicate_securities()
+
+	def on_cancel(self):
+		self.update_loan_security_pledge(cancel=1)
+		self.update_loan_status(cancel=1)
+		self.db_set('status', 'Requested')
+
+	def validate_duplicate_securities(self):
+		security_list = []
+		for d in self.securities:
+			security = [d.loan_security, d.against_pledge]
+			if security not in security_list:
+				security_list.append(security)
+			else:
+				frappe.throw(_("Row {0}: Loan Security {1} against Loan Security Pledge {2} added multiple times").format(
+					d.idx, frappe.bold(d.loan_security), frappe.bold(d.against_pledge)))
 
 	def validate_pledges(self):
-		pledge_details = self.get_pledge_details()
-
+		pledge_qty_map = self.get_pledge_details()
 		loan = frappe.get_doc("Loan", self.loan)
 
-		pledge_qty_map = {}
 		remaining_qty = 0
 		unpledge_value = 0
 
-		for pledge in pledge_details:
-			pledge_qty_map.setdefault((pledge.parent, pledge.loan_security), pledge.qty)
-
 		for security in self.securities:
 			pledged_qty = pledge_qty_map.get((security.against_pledge, security.loan_security), 0)
 			if not pledged_qty:
-				frappe.throw(_("Zero qty of {0} pledged against loan {0}").format(frappe.bold(security.loan_security),
+				frappe.throw(_("Zero qty of {0} pledged against loan {1}").format(frappe.bold(security.loan_security),
 					frappe.bold(self.loan)))
 
 			unpledge_qty = pledged_qty - security.qty
 			security_price = security.qty * get_loan_security_price(security.loan_security)
 
 			if unpledge_qty < 0:
-				frappe.throw(_("Cannot unpledge more than {0} qty of {0}").format(frappe.bold(pledged_qty),
-					frappe.bold(security.loan_security)))
+				frappe.throw(_("""Row {0}: Cannot unpledge more than {1} qty of {2} against
+					Loan Security Pledge {3}""").format(security.idx, frappe.bold(pledged_qty),
+					frappe.bold(security.loan_security), frappe.bold(security.against_pledge)))
 
 			remaining_qty += unpledge_qty
 			unpledge_value += security_price - flt(security_price * security.haircut/100)
@@ -45,41 +57,57 @@
 		if unpledge_value > loan.total_principal_paid:
 			frappe.throw(_("Cannot Unpledge, loan security value is greater than the repaid amount"))
 
-		if not remaining_qty:
-			self.db_set('unpledge_type', 'Unpledged')
-		else:
-			self.db_set('unpledge_type', 'Partially Pledged')
-
-
 	def get_pledge_details(self):
+		pledge_qty_map = {}
+
 		pledge_details = frappe.db.sql("""
-			SELECT p.parent, p.loan_security, p.qty as qty FROM
+			SELECT p.parent, p.loan_security, p.qty FROM
 				`tabLoan Security Pledge` lsp,
 				`tabPledge` p
 			WHERE
 				p.parent = lsp.name
 				AND lsp.loan = %s
 				AND lsp.docstatus = 1
-				AND lsp.status = "Pledged"
-		""",(self.loan), as_dict=1)
+				AND lsp.status in ('Pledged', 'Partially Pledged')
+		""", (self.loan), as_dict=1)
 
-		return pledge_details
+		for pledge in pledge_details:
+			pledge_qty_map.setdefault((pledge.parent, pledge.loan_security), pledge.qty)
+
+		return pledge_qty_map
 
 	def on_update_after_submit(self):
 		if self.status == "Approved":
-			frappe.db.sql("""
-				UPDATE
-					`tabPledge` p, `tabUnpledge` u, `tabLoan Security Pledge` lsp,
-					`tabLoan Security Unpledge` lsu SET p.qty = (p.qty - u.qty)
-				WHERE
-					lsp.loan = %s
-					AND lsu.status = 'Requested'
-					AND u.parent = %s
-					AND p.parent = u.against_pledge
-					AND p.loan_security = u.loan_security""",(self.loan, self.name))
+			self.update_loan_security_pledge()
+			self.update_loan_status()
 
-			frappe.db.sql("""UPDATE `tabLoan Security Pledge`
-				SET status = %s WHERE loan = %s""", (self.unpledge_type, self.loan))
+	def update_loan_security_pledge(self, cancel=0):
+		if cancel:
+			new_qty = 'p.qty + u.qty'
+		else:
+			new_qty = 'p.qty - u.qty'
 
-			if self.unpledge_type == 'Unpledged':
-				frappe.db.set_value("Loan", self.loan, 'status', 'Closed')
+		frappe.db.sql("""
+			UPDATE
+				`tabPledge` p, `tabUnpledge` u, `tabLoan Security Pledge` lsp, `tabLoan Security Unpledge` lsu
+					SET p.qty = {new_qty}
+			WHERE
+				lsp.loan = %s
+				AND p.parent = u.against_pledge
+				AND p.parent = lsp.name
+				AND lsp.docstatus = 1
+				AND p.loan_security = u.loan_security""".format(new_qty=new_qty),(self.loan))
+
+	def update_loan_status(self, cancel=0):
+		if cancel:
+			loan_status = frappe.get_value('Loan', self.loan, 'status')
+			if loan_status == 'Closed':
+				frappe.db.set_value('Loan', self.loan, 'status', 'Loan Closure Requested')
+		else:
+			pledge_qty = frappe.db.sql("""SELECT SUM(c.qty)
+				FROM `tabLoan Security Pledge` p, `tabPledge` c
+				WHERE p.loan = %s AND c.parent = p.name""", (self.loan))[0][0]
+
+			if not pledge_qty:
+				frappe.db.set_value('Loan', self.loan, 'status', 'Closed')
+