fix: employee advance return through multiple additional salaries (#27438)

* fix: employee advance return through multiple additional salaries

* test: test repay unclaimed amount from salary

* fix: sorting in imports
diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.js b/erpnext/hr/doctype/employee_advance/employee_advance.js
index fa4b06a..7d1c7cb 100644
--- a/erpnext/hr/doctype/employee_advance/employee_advance.js
+++ b/erpnext/hr/doctype/employee_advance/employee_advance.js
@@ -73,7 +73,7 @@
 					frm.trigger('make_return_entry');
 				}, __('Create'));
 			} else if (frm.doc.repay_unclaimed_amount_from_salary == 1 && frappe.model.can_create("Additional Salary")) {
-				frm.add_custom_button(__("Deduction from salary"), function() {
+				frm.add_custom_button(__("Deduction from Salary"), function() {
 					frm.events.make_deduction_via_additional_salary(frm);
 				}, __('Create'));
 			}
diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.json b/erpnext/hr/doctype/employee_advance/employee_advance.json
index ea25aa7..0475453 100644
--- a/erpnext/hr/doctype/employee_advance/employee_advance.json
+++ b/erpnext/hr/doctype/employee_advance/employee_advance.json
@@ -170,7 +170,7 @@
    "default": "0",
    "fieldname": "repay_unclaimed_amount_from_salary",
    "fieldtype": "Check",
-   "label": "Repay unclaimed amount from salary"
+   "label": "Repay Unclaimed Amount from Salary"
   },
   {
    "depends_on": "eval:cur_frm.doc.employee",
@@ -200,10 +200,11 @@
  ],
  "is_submittable": 1,
  "links": [],
- "modified": "2021-03-31 22:31:53.746659",
+ "modified": "2021-09-11 18:38:38.617478",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "Employee Advance",
+ "naming_rule": "By \"Naming Series\" field",
  "owner": "Administrator",
  "permissions": [
   {
diff --git a/erpnext/hr/doctype/employee_advance/employee_advance.py b/erpnext/hr/doctype/employee_advance/employee_advance.py
index 87d42d3..8d90bcc 100644
--- a/erpnext/hr/doctype/employee_advance/employee_advance.py
+++ b/erpnext/hr/doctype/employee_advance/employee_advance.py
@@ -172,7 +172,10 @@
 @frappe.whitelist()
 def create_return_through_additional_salary(doc):
 	import json
-	doc = frappe._dict(json.loads(doc))
+
+	if isinstance(doc, str):
+		doc = frappe._dict(json.loads(doc))
+
 	additional_salary = frappe.new_doc('Additional Salary')
 	additional_salary.employee = doc.employee
 	additional_salary.currency = doc.currency
diff --git a/erpnext/hr/doctype/employee_advance/test_employee_advance.py b/erpnext/hr/doctype/employee_advance/test_employee_advance.py
index f8e5f53..c439d45 100644
--- a/erpnext/hr/doctype/employee_advance/test_employee_advance.py
+++ b/erpnext/hr/doctype/employee_advance/test_employee_advance.py
@@ -12,8 +12,11 @@
 from erpnext.hr.doctype.employee.test_employee import make_employee
 from erpnext.hr.doctype.employee_advance.employee_advance import (
 	EmployeeAdvanceOverPayment,
+	create_return_through_additional_salary,
 	make_bank_entry,
 )
+from erpnext.payroll.doctype.salary_component.test_salary_component import create_salary_component
+from erpnext.payroll.doctype.salary_structure.test_salary_structure import make_salary_structure
 
 
 class TestEmployeeAdvance(unittest.TestCase):
@@ -33,6 +36,46 @@
 		journal_entry1 = make_payment_entry(advance)
 		self.assertRaises(EmployeeAdvanceOverPayment, journal_entry1.submit)
 
+	def test_repay_unclaimed_amount_from_salary(self):
+		employee_name = make_employee("_T@employe.advance")
+		advance = make_employee_advance(employee_name, {"repay_unclaimed_amount_from_salary": 1})
+
+		args = {"type": "Deduction"}
+		create_salary_component("Advance Salary - Deduction", **args)
+		make_salary_structure("Test Additional Salary for Advance Return", "Monthly", employee=employee_name)
+
+		# additional salary for 700 first
+		advance.reload()
+		additional_salary = create_return_through_additional_salary(advance)
+		additional_salary.salary_component = "Advance Salary - Deduction"
+		additional_salary.payroll_date = nowdate()
+		additional_salary.amount = 700
+		additional_salary.insert()
+		additional_salary.submit()
+
+		advance.reload()
+		self.assertEqual(advance.return_amount, 700)
+
+		# additional salary for remaining 300
+		additional_salary = create_return_through_additional_salary(advance)
+		additional_salary.salary_component = "Advance Salary - Deduction"
+		additional_salary.payroll_date = nowdate()
+		additional_salary.amount = 300
+		additional_salary.insert()
+		additional_salary.submit()
+
+		advance.reload()
+		self.assertEqual(advance.return_amount, 1000)
+
+		# update advance return amount on additional salary cancellation
+		additional_salary.cancel()
+		advance.reload()
+		self.assertEqual(advance.return_amount, 700)
+
+	def tearDown(self):
+		frappe.db.rollback()
+
+
 def make_payment_entry(advance):
 	journal_entry = frappe.get_doc(make_bank_entry("Employee Advance", advance.name))
 	journal_entry.cheque_no = "123123"
@@ -41,7 +84,7 @@
 
 	return journal_entry
 
-def make_employee_advance(employee_name):
+def make_employee_advance(employee_name, args=None):
 	doc = frappe.new_doc("Employee Advance")
 	doc.employee = employee_name
 	doc.company  = "_Test company"
@@ -51,6 +94,10 @@
 	doc.advance_amount = 1000
 	doc.posting_date = nowdate()
 	doc.advance_account = "_Test Employee Advance - _TC"
+
+	if args:
+		doc.update(args)
+
 	doc.insert()
 	doc.submit()
 
diff --git a/erpnext/payroll/doctype/additional_salary/additional_salary.py b/erpnext/payroll/doctype/additional_salary/additional_salary.py
index ed10f2b..7c0a8ea 100644
--- a/erpnext/payroll/doctype/additional_salary/additional_salary.py
+++ b/erpnext/payroll/doctype/additional_salary/additional_salary.py
@@ -14,12 +14,11 @@
 
 class AdditionalSalary(Document):
 	def on_submit(self):
-		if self.ref_doctype == "Employee Advance" and self.ref_docname:
-			frappe.db.set_value("Employee Advance", self.ref_docname, "return_amount", self.amount)
-
+		self.update_return_amount_in_employee_advance()
 		self.update_employee_referral()
 
 	def on_cancel(self):
+		self.update_return_amount_in_employee_advance()
 		self.update_employee_referral(cancel=True)
 
 	def validate(self):
@@ -98,6 +97,17 @@
 				frappe.throw(_("Additional Salary for referral bonus can only be created against Employee Referral with status {0}").format(
 					frappe.bold("Accepted")))
 
+	def update_return_amount_in_employee_advance(self):
+		if self.ref_doctype == "Employee Advance" and self.ref_docname:
+			return_amount = frappe.db.get_value("Employee Advance", self.ref_docname, "return_amount")
+
+			if self.docstatus == 2:
+				return_amount -= self.amount
+			else:
+				return_amount += self.amount
+
+			frappe.db.set_value("Employee Advance", self.ref_docname, "return_amount", return_amount)
+
 	def update_employee_referral(self, cancel=False):
 		if self.ref_doctype == "Employee Referral":
 			status = "Unpaid" if cancel else "Paid"