feat: Full and Final Settlement and Gratuity Fix (#26364)

* feat: Full and Final Settlement

* removed option to pay via salary slip

* feat: Create JV

* test:fnf

* fix: tracking asset movement

* fix: sider and test

* fix: changes Requested

* fix: changes requested

* fix: valication for Asset

* fix: add filter for reference document only if relevant field is present

* fix: doctype cleanup

- add more fields to the list view and standard filter

- set title field

- incorrect field labels

* feat: add list view settings for FNF

* fix: incorrect reference type set in Journal Entry

* fix: validation message

* chore: add Full and Final Statement link to Workspace

Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py
index 7264875..dc341d7 100644
--- a/erpnext/accounts/doctype/journal_entry/journal_entry.py
+++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py
@@ -66,6 +66,7 @@
 		self.update_expense_claim()
 		self.update_inter_company_jv()
 		self.update_invoice_discounting()
+		self.update_status_for_full_and_final_statement()
 		check_if_stock_and_account_balance_synced(self.posting_date,
 			self.company, self.doctype, self.name)
 
@@ -83,6 +84,7 @@
 		self.unlink_inter_company_jv()
 		self.unlink_asset_adjustment_entry()
 		self.update_invoice_discounting()
+		self.update_status_for_full_and_final_statement()
 
 	def get_title(self):
 		return self.pay_to_recd_from or self.accounts[0].account
@@ -98,6 +100,15 @@
 			for voucher_no in list(set(order_list)):
 				frappe.get_doc(voucher_type, voucher_no).set_total_advance_paid()
 
+	def update_status_for_full_and_final_statement(self):
+		for entry in self.accounts:
+			if entry.reference_type == "Full and Final Statement":
+				if self.docstatus == 1:
+					frappe.db.set_value("Full and Final Statement", entry.reference_name, "status", "Paid")
+				elif self.docstatus == 2:
+					frappe.db.set_value("Full and Final Statement", entry.reference_name, "status", "Unpaid")
+
+
 	def validate_inter_company_accounts(self):
 		if self.voucher_type == "Inter Company Journal Entry" and self.inter_company_journal_entry_reference:
 			doc = frappe.get_doc("Journal Entry", self.inter_company_journal_entry_reference)
diff --git a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json
index a89fefd..dff883a 100644
--- a/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json
+++ b/erpnext/accounts/doctype/journal_entry_account/journal_entry_account.json
@@ -202,7 +202,7 @@
    "fieldname": "reference_type",
    "fieldtype": "Select",
    "label": "Reference Type",
-   "options": "\nSales Invoice\nPurchase Invoice\nJournal Entry\nSales Order\nPurchase Order\nExpense Claim\nAsset\nLoan\nPayroll Entry\nEmployee Advance\nExchange Rate Revaluation\nInvoice Discounting\nFees"
+   "options": "\nSales Invoice\nPurchase Invoice\nJournal Entry\nSales Order\nPurchase Order\nExpense Claim\nAsset\nLoan\nPayroll Entry\nEmployee Advance\nExchange Rate Revaluation\nInvoice Discounting\nFees\nFull and Final Statement"
   },
   {
    "fieldname": "reference_name",
@@ -280,7 +280,7 @@
  "idx": 1,
  "istable": 1,
  "links": [],
- "modified": "2020-06-26 14:06:54.833738",
+ "modified": "2021-08-30 21:27:32.200299",
  "modified_by": "Administrator",
  "module": "Accounts",
  "name": "Journal Entry Account",
diff --git a/erpnext/hr/doctype/employee_referral/employee_referral.js b/erpnext/hr/doctype/employee_referral/employee_referral.js
index 9c99bbb..8722019 100644
--- a/erpnext/hr/doctype/employee_referral/employee_referral.js
+++ b/erpnext/hr/doctype/employee_referral/employee_referral.js
@@ -43,8 +43,6 @@
 			});
 		}
 
-
-
 	},
 	create_job_applicant: function(frm) {
 		frappe.model.open_mapped_doc({
diff --git a/erpnext/hr/doctype/full_and_final_asset/__init__.py b/erpnext/hr/doctype/full_and_final_asset/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/hr/doctype/full_and_final_asset/__init__.py
diff --git a/erpnext/hr/doctype/full_and_final_asset/full_and_final_asset.js b/erpnext/hr/doctype/full_and_final_asset/full_and_final_asset.js
new file mode 100644
index 0000000..1965b46
--- /dev/null
+++ b/erpnext/hr/doctype/full_and_final_asset/full_and_final_asset.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Full and Final Asset', {
+	// refresh: function(frm) {
+
+	// }
+});
diff --git a/erpnext/hr/doctype/full_and_final_asset/full_and_final_asset.json b/erpnext/hr/doctype/full_and_final_asset/full_and_final_asset.json
new file mode 100644
index 0000000..3ad8335
--- /dev/null
+++ b/erpnext/hr/doctype/full_and_final_asset/full_and_final_asset.json
@@ -0,0 +1,64 @@
+{
+ "actions": [],
+ "creation": "2021-06-28 13:36:58.658985",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "reference",
+  "asset_name",
+  "date",
+  "status",
+  "description"
+ ],
+ "fields": [
+  {
+   "fieldname": "reference",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Reference",
+   "options": "Asset Movement",
+   "read_only": 1,
+   "reqd": 1
+  },
+  {
+   "fieldname": "status",
+   "fieldtype": "Select",
+   "in_list_view": 1,
+   "label": "Status",
+   "options": "Owned\nReturned",
+   "reqd": 1
+  },
+  {
+   "fieldname": "description",
+   "fieldtype": "Small Text",
+   "label": "Description"
+  },
+  {
+   "fieldname": "asset_name",
+   "fieldtype": "Data",
+   "in_list_view": 1,
+   "label": "Asset Name",
+   "read_only": 1
+  },
+  {
+   "fieldname": "date",
+   "fieldtype": "Datetime",
+   "in_list_view": 1,
+   "label": "Date",
+   "read_only": 1
+  }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-07-15 15:17:31.309834",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Full and Final Asset",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/full_and_final_asset/full_and_final_asset.py b/erpnext/hr/doctype/full_and_final_asset/full_and_final_asset.py
new file mode 100644
index 0000000..2337224
--- /dev/null
+++ b/erpnext/hr/doctype/full_and_final_asset/full_and_final_asset.py
@@ -0,0 +1,8 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+# import frappe
+from frappe.model.document import Document
+
+class FullandFinalAsset(Document):
+	pass
diff --git a/erpnext/hr/doctype/full_and_final_asset/test_full_and_final_asset.py b/erpnext/hr/doctype/full_and_final_asset/test_full_and_final_asset.py
new file mode 100644
index 0000000..6d59c99
--- /dev/null
+++ b/erpnext/hr/doctype/full_and_final_asset/test_full_and_final_asset.py
@@ -0,0 +1,8 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+
+# import frappe
+import unittest
+
+class TestFullandFinalAsset(unittest.TestCase):
+	pass
diff --git a/erpnext/hr/doctype/full_and_final_outstanding_statement/__init__.py b/erpnext/hr/doctype/full_and_final_outstanding_statement/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/hr/doctype/full_and_final_outstanding_statement/__init__.py
diff --git a/erpnext/hr/doctype/full_and_final_outstanding_statement/full_and_final_outstanding_statement.json b/erpnext/hr/doctype/full_and_final_outstanding_statement/full_and_final_outstanding_statement.json
new file mode 100644
index 0000000..be242e2
--- /dev/null
+++ b/erpnext/hr/doctype/full_and_final_outstanding_statement/full_and_final_outstanding_statement.json
@@ -0,0 +1,96 @@
+{
+ "actions": [],
+ "creation": "2021-06-28 13:32:02.167317",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "component",
+  "reference_document_type",
+  "reference_document",
+  "account",
+  "paid_via_salary_slip",
+  "column_break_4",
+  "amount",
+  "status",
+  "remark"
+ ],
+ "fields": [
+  {
+   "fieldname": "column_break_4",
+   "fieldtype": "Column Break"
+  },
+  {
+   "columns": 2,
+   "default": "Unsettled",
+   "fieldname": "status",
+   "fieldtype": "Select",
+   "in_list_view": 1,
+   "label": "Status",
+   "options": "Settled\nUnsettled"
+  },
+  {
+   "fieldname": "remark",
+   "fieldtype": "Small Text",
+   "label": "Remark"
+  },
+  {
+   "columns": 2,
+   "depends_on": "reference_document_type",
+   "fieldname": "reference_document",
+   "fieldtype": "Dynamic Link",
+   "in_list_view": 1,
+   "label": "Reference Document",
+   "mandatory_depends_on": "reference_document_type",
+   "options": "reference_document_type",
+   "search_index": 1
+  },
+  {
+   "columns": 2,
+   "fieldname": "component",
+   "fieldtype": "Data",
+   "in_list_view": 1,
+   "label": "Component",
+   "reqd": 1
+  },
+  {
+   "fieldname": "account",
+   "fieldtype": "Link",
+   "label": "Account",
+   "options": "Account"
+  },
+  {
+   "columns": 2,
+   "fieldname": "amount",
+   "fieldtype": "Currency",
+   "in_list_view": 1,
+   "label": "Amount"
+  },
+  {
+   "columns": 2,
+   "fieldname": "reference_document_type",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Reference Document Type",
+   "options": "DocType"
+  },
+  {
+   "default": "0",
+   "fieldname": "paid_via_salary_slip",
+   "fieldtype": "Check",
+   "label": "Paid via Salary Slip"
+  }
+ ],
+ "index_web_pages_for_search": 1,
+ "istable": 1,
+ "links": [],
+ "modified": "2021-07-20 16:59:34.447934",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Full and Final Outstanding Statement",
+ "owner": "Administrator",
+ "permissions": [],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/full_and_final_outstanding_statement/full_and_final_outstanding_statement.py b/erpnext/hr/doctype/full_and_final_outstanding_statement/full_and_final_outstanding_statement.py
new file mode 100644
index 0000000..d53cd91
--- /dev/null
+++ b/erpnext/hr/doctype/full_and_final_outstanding_statement/full_and_final_outstanding_statement.py
@@ -0,0 +1,8 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+# import frappe
+from frappe.model.document import Document
+
+class FullandFinalOutstandingStatement(Document):
+	pass
diff --git a/erpnext/hr/doctype/full_and_final_statement/__init__.py b/erpnext/hr/doctype/full_and_final_statement/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/hr/doctype/full_and_final_statement/__init__.py
diff --git a/erpnext/hr/doctype/full_and_final_statement/full_and_final_statement.js b/erpnext/hr/doctype/full_and_final_statement/full_and_final_statement.js
new file mode 100644
index 0000000..074d85b
--- /dev/null
+++ b/erpnext/hr/doctype/full_and_final_statement/full_and_final_statement.js
@@ -0,0 +1,115 @@
+// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Full and Final Statement', {
+	refresh: function(frm) {
+		frm.events.set_queries(frm, "payables");
+		frm.events.set_queries(frm, "receivables");
+
+		if (frm.doc.docstatus == 1 && frm.doc.status == "Unpaid") {
+			frm.add_custom_button(__("Create Journal Entry"), function () {
+				frm.events.create_journal_entry(frm);
+			});
+		}
+	},
+
+	set_queries: function(frm, type) {
+		frm.set_query("reference_document_type", type, function () {
+			let modules = ["HR", "Payroll", "Loan Management"];
+			return {
+				filters: {
+					istable: 0,
+					issingle: 0,
+					module: ["In", modules]
+				}
+			};
+		});
+
+		let filters = {};
+
+		frm.set_query('reference_document', type, function(doc, cdt, cdn) {
+			let fnf_doc = frappe.get_doc(cdt, cdn);
+
+			frappe.model.with_doctype(fnf_doc.reference_document_type, function() {
+				if (frappe.model.is_tree(fnf_doc.reference_document_type)) {
+					filters['is_group'] = 0;
+				}
+
+				if (frappe.meta.has_field(fnf_doc.reference_document_type, 'company')) {
+					filters['company'] = frm.doc.company;
+				}
+
+				if (frappe.meta.has_field(fnf_doc.reference_document_type, 'employee')) {
+					filters['employee'] = frm.doc.employee;
+				}
+			});
+
+			return {
+				filters: filters
+			};
+		});
+	},
+
+	employee: function(frm) {
+		frm.events.get_outstanding_statements(frm);
+	},
+
+	get_outstanding_statements: function(frm) {
+		if (frm.doc.employee) {
+			frappe.call({
+				method: "get_outstanding_statements",
+				doc: frm.doc,
+				callback: function() {
+					frm.refresh();
+				}
+			});
+		}
+	},
+
+	create_journal_entry: function(frm) {
+		frappe.call({
+			method: "create_journal_entry",
+			doc: frm.doc,
+			callback: function(r) {
+				var doclist = frappe.model.sync(r.message);
+				frappe.set_route("Form", doclist[0].doctype, doclist[0].name);
+			}
+		});
+	}
+});
+
+frappe.ui.form.on("Full and Final Outstanding Statement", {
+	reference_document: function(frm, cdt, cdn) {
+		var child = locals[cdt][cdn];
+		if (child.reference_document_type && child.reference_document) {
+			frappe.call({
+				method: "erpnext.hr.doctype.full_and_final_statement.full_and_final_statement.get_account_and_amount",
+				args: {
+					ref_doctype: child.reference_document_type,
+					ref_document: child.reference_document
+				},
+				callback: function(r) {
+					if (r.message) {
+						frappe.model.set_value(cdt, cdn, "account", r.message[0]);
+						frappe.model.set_value(cdt, cdn, "amount", r.message[1]);
+					}
+				}
+			});
+		}
+	},
+
+	amount: function(frm) {
+		var total_payable_amount = 0;
+		var total_receivable_amount = 0;
+
+		frm.doc.payables.forEach(element => {
+			total_payable_amount = total_payable_amount + element.amount;
+		});
+
+		frm.doc.receivables.forEach(element => {
+			total_receivable_amount = total_receivable_amount + element.amount;
+		});
+		frm.set_value("total_payable_amount", flt(total_payable_amount));
+		frm.set_value("total_receivable_amount", flt(total_receivable_amount));
+	}
+});
diff --git a/erpnext/hr/doctype/full_and_final_statement/full_and_final_statement.json b/erpnext/hr/doctype/full_and_final_statement/full_and_final_statement.json
new file mode 100644
index 0000000..ebcf36d
--- /dev/null
+++ b/erpnext/hr/doctype/full_and_final_statement/full_and_final_statement.json
@@ -0,0 +1,231 @@
+{
+ "actions": [],
+ "autoname": "HR-FNF-.YYYY.-.#####",
+ "creation": "2021-06-28 13:17:36.050459",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "employee",
+  "employee_name",
+  "transaction_date",
+  "column_break_12",
+  "company",
+  "status",
+  "amended_from",
+  "employee_details_section",
+  "date_of_joining",
+  "relieving_date",
+  "column_break_4",
+  "designation",
+  "department",
+  "section_break_8",
+  "payables",
+  "section_break_10",
+  "receivables",
+  "totals_section",
+  "total_payable_amount",
+  "column_break_21",
+  "total_receivable_amount",
+  "section_break_15",
+  "assets_allocated"
+ ],
+ "fields": [
+  {
+   "fieldname": "employee",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Employee",
+   "options": "Employee",
+   "reqd": 1
+  },
+  {
+   "fetch_from": "employee.employee_name",
+   "fieldname": "employee_name",
+   "fieldtype": "Data",
+   "label": "Employee Name",
+   "read_only": 1
+  },
+  {
+   "fetch_from": "employee.designation",
+   "fieldname": "designation",
+   "fieldtype": "Link",
+   "label": "Designation",
+   "options": "Designation",
+   "read_only": 1
+  },
+  {
+   "fieldname": "column_break_4",
+   "fieldtype": "Column Break"
+  },
+  {
+   "default": "Unpaid",
+   "fieldname": "status",
+   "fieldtype": "Select",
+   "label": "Status",
+   "options": "Paid\nUnpaid",
+   "read_only": 1
+  },
+  {
+   "fetch_from": "employee.department",
+   "fieldname": "department",
+   "fieldtype": "Link",
+   "label": "Department",
+   "options": "Department",
+   "read_only": 1
+  },
+  {
+   "fieldname": "amended_from",
+   "fieldtype": "Link",
+   "label": "Amended From",
+   "no_copy": 1,
+   "options": "Full and Final Statement",
+   "print_hide": 1,
+   "read_only": 1
+  },
+  {
+   "fieldname": "section_break_8",
+   "fieldtype": "Section Break",
+   "label": "Payables"
+  },
+  {
+   "fieldname": "section_break_10",
+   "fieldtype": "Section Break",
+   "label": "Receivables"
+  },
+  {
+   "fieldname": "assets_allocated",
+   "fieldtype": "Table",
+   "options": "Full and Final Asset"
+  },
+  {
+   "fetch_from": "employee.relieving_date",
+   "fieldname": "relieving_date",
+   "fieldtype": "Date",
+   "label": "Relieving Date ",
+   "read_only": 1,
+   "reqd": 1
+  },
+  {
+   "fetch_from": "employee.date_of_joining",
+   "fieldname": "date_of_joining",
+   "fieldtype": "Date",
+   "label": "Date of Joining",
+   "read_only": 1
+  },
+  {
+   "fieldname": "section_break_15",
+   "fieldtype": "Section Break",
+   "label": "Assets Allocated"
+  },
+  {
+   "fetch_from": "employee.company",
+   "fieldname": "company",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "in_standard_filter": 1,
+   "label": "Company",
+   "options": "Company",
+   "read_only": 1
+  },
+  {
+   "fieldname": "column_break_12",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "payables",
+   "fieldtype": "Table",
+   "options": "Full and Final Outstanding Statement"
+  },
+  {
+   "fieldname": "receivables",
+   "fieldtype": "Table",
+   "options": "Full and Final Outstanding Statement"
+  },
+  {
+   "fieldname": "employee_details_section",
+   "fieldtype": "Section Break",
+   "label": "Employee Details"
+  },
+  {
+   "fieldname": "transaction_date",
+   "fieldtype": "Date",
+   "in_standard_filter": 1,
+   "label": "Transaction Date",
+   "reqd": 1
+  },
+  {
+   "fieldname": "totals_section",
+   "fieldtype": "Section Break",
+   "label": "Totals"
+  },
+  {
+   "fieldname": "total_payable_amount",
+   "fieldtype": "Currency",
+   "in_list_view": 1,
+   "label": "Total Payable Amount",
+   "read_only": 1
+  },
+  {
+   "fieldname": "column_break_21",
+   "fieldtype": "Column Break"
+  },
+  {
+   "fieldname": "total_receivable_amount",
+   "fieldtype": "Currency",
+   "in_list_view": 1,
+   "label": "Total Receivable Amount",
+   "read_only": 1
+  }
+ ],
+ "index_web_pages_for_search": 1,
+ "is_submittable": 1,
+ "links": [],
+ "modified": "2021-08-30 21:11:09.892560",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Full and Final Statement",
+ "owner": "Administrator",
+ "permissions": [
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "System Manager",
+   "share": 1,
+   "write": 1
+  },
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "HR User",
+   "share": 1,
+   "write": 1
+  },
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "HR Manager",
+   "share": 1,
+   "write": 1
+  }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "employee_name",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/hr/doctype/full_and_final_statement/full_and_final_statement.py b/erpnext/hr/doctype/full_and_final_statement/full_and_final_statement.py
new file mode 100644
index 0000000..4c98cf1
--- /dev/null
+++ b/erpnext/hr/doctype/full_and_final_statement/full_and_final_statement.py
@@ -0,0 +1,176 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+import frappe
+from frappe import _
+from frappe.utils import get_link_to_form, today, flt
+from frappe.model.document import Document
+
+class FullandFinalStatement(Document):
+	def validate(self):
+		self.get_outstanding_statements()
+		if self.docstatus == 1:
+			self.validate_settlement("payables")
+			self.validate_settlement("receivables")
+			self.validate_asset()
+
+	def validate_settlement(self, component_type):
+		for data in self.get(component_type, []):
+			if data.status == "Unsettled":
+				frappe.throw(_("Settle all Payables and Receivables before submission"))
+
+	def validate_asset(self):
+		for data in self.assets_allocated:
+			if data.status == "Owned":
+				frappe.throw(_("All allocated assets should be returned before submission"))
+
+	@frappe.whitelist()
+	def get_outstanding_statements(self):
+		if self.relieving_date:
+			if not len(self.get("payables", [])):
+				components = self.get_payable_component()
+				self.create_component_row(components, "payables")
+			if not len(self.get("receivables", [])):
+				components = self.get_receivable_component()
+				self.create_component_row(components, "receivables")
+
+			if not len(self.get("assets_allocated", [])):
+				for data in self.get_assets_movement():
+					self.append("assets_allocated", data)
+		else:
+			frappe.throw(_("Set Relieving Date for Employee: {0}").format(get_link_to_form("Employee", self.employee)))
+
+	def create_component_row(self, components, component_type):
+		for component in components:
+			self.append(component_type, {
+				"status": "Unsettled",
+				"reference_document_type": component if component != "Bonus" else "Additional Salary",
+				"component": component
+			})
+
+
+	def get_payable_component(self):
+		return [
+			"Salary Slip",
+			"Gratuity",
+			"Expense Claim",
+			"Bonus",
+			"Leave Encashment",
+		]
+
+	def get_receivable_component(self):
+		return [
+			"Loan",
+			"Employee Advance",
+		]
+
+	def get_assets_movement(self):
+		asset_movements = frappe.get_all("Asset Movement Item",
+			filters = {"docstatus": 1},
+			fields = ["asset", "from_employee", "to_employee", "parent", "asset_name"],
+			or_filters = {
+				"from_employee": self.employee,
+				"to_employee": self.employee
+			}
+		)
+
+		data = []
+		inward_movements = []
+		outward_movements = []
+		for movement in asset_movements:
+			if movement.to_employee and movement.to_employee == self.employee:
+				inward_movements.append(movement)
+
+			if movement.from_employee and movement.from_employee == self.employee:
+				outward_movements.append(movement)
+
+		for movement in inward_movements:
+			outwards_count = [movement.asset for movement in outward_movements].count(movement.asset)
+			inwards_counts = [movement.asset for movement in inward_movements].count(movement.asset)
+
+			if inwards_counts > outwards_count:
+				data.append({
+					"reference": movement.parent,
+					"asset_name": movement.asset_name,
+					"date": frappe.db.get_value("Asset Movement", movement.parent, "transaction_date"),
+					"status": "Owned"
+				})
+		return data
+
+	@frappe.whitelist()
+	def create_journal_entry(self):
+		precision = frappe.get_precision("Journal Entry Account", "debit_in_account_currency")
+		jv = frappe.new_doc("Journal Entry")
+		jv.company = self.company
+		jv.voucher_type = "Bank Entry"
+		jv.posting_date = today()
+
+		difference = self.total_payable_amount - self.total_receivable_amount
+
+		for data in self.payables:
+			if data.amount > 0 and not data.paid_via_salary_slip:
+				account_dict = {
+					"account": data.account,
+					"debit_in_account_currency": flt(data.amount, precision)
+				}
+				if data.reference_document_type == "Expense Claim":
+					account_dict["party_type"] = "Employee"
+					account_dict["party"] = self.employee
+
+				jv.append("accounts", account_dict)
+
+		for data in self.receivables:
+			if data.amount > 0:
+				account_dict = {
+					"account": data.account,
+					"credit_in_account_currency": flt(data.amount, precision)
+				}
+				if data.reference_document_type == "Employee Advance":
+					account_dict["party_type"] = "Employee"
+					account_dict["party"] = self.employee
+
+				jv.append("accounts", account_dict)
+
+		jv.append("accounts", {
+			"credit_in_account_currency": difference if difference > 0 else 0,
+			"debit_in_account_currency": -(difference) if difference < 0 else 0,
+			"reference_type": self.doctype,
+			"reference_name": self.name
+		})
+		return jv
+
+@frappe.whitelist()
+def get_account_and_amount(ref_doctype, ref_document):
+	if not ref_doctype or not ref_document:
+		return None
+
+	if ref_doctype == "Salary Slip":
+		salary_details = frappe.db.get_value("Salary Slip", ref_document, ["payroll_entry", "net_pay"], as_dict=1)
+		amount = salary_details.net_pay
+		payable_account = frappe.db.get_value("Payroll Entry", salary_details.payroll_entry, "payroll_payable_account") if salary_details.payroll_entry else None
+		return [payable_account, amount]
+
+	if ref_doctype == "Gratuity":
+		payable_account, amount = frappe.db.get_value("Gratuity", ref_document, ["payable_account", "amount"])
+		return [payable_account, amount]
+
+	if ref_doctype == "Expense Claim":
+		details = frappe.db.get_value("Expense Claim", ref_document,
+			["payable_account", "grand_total", "total_amount_reimbursed", "total_advance_amount"], as_dict=True)
+		payable_account = details.payable_account
+		amount = details.grand_total - (details.total_amount_reimbursed + details.total_advance_amount)
+		return [payable_account, amount]
+
+	if ref_doctype == "Loan":
+		details = frappe.db.get_value("Loan", ref_document,
+			["payment_account", "total_payment", "total_amount_paid"], as_dict=1)
+		payment_account = details.payment_account
+		amount = details.total_payment - details.total_amount_paid
+		return [payment_account, amount]
+
+	if ref_doctype == "Employee Advance":
+		details = frappe.db.get_value("Employee Advance", ref_document,
+			["advance_account","paid_amount", "claimed_amount", "return_amount"], as_dict = 1)
+		payment_account = details.advance_account
+		amount = details.paid_amount - (details.claimed_amount + details.return_amount)
+		return [payment_account, amount]
diff --git a/erpnext/hr/doctype/full_and_final_statement/full_and_final_statement_list.js b/erpnext/hr/doctype/full_and_final_statement/full_and_final_statement_list.js
new file mode 100644
index 0000000..4aedec7
--- /dev/null
+++ b/erpnext/hr/doctype/full_and_final_statement/full_and_final_statement_list.js
@@ -0,0 +1,11 @@
+frappe.listview_settings["Full and Final Statement"] = {
+	get_indicator: function(doc) {
+		var colors = {
+			"Draft": "red",
+			"Unpaid": "orange",
+			"Paid": "green",
+			"Cancelled": "red"
+		};
+		return [__(doc.status), colors[doc.status], "status,=," + doc.status];
+	}
+};
diff --git a/erpnext/hr/doctype/full_and_final_statement/test_full_and_final_statement.py b/erpnext/hr/doctype/full_and_final_statement/test_full_and_final_statement.py
new file mode 100644
index 0000000..8ecc129
--- /dev/null
+++ b/erpnext/hr/doctype/full_and_final_statement/test_full_and_final_statement.py
@@ -0,0 +1,71 @@
+# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+
+import frappe
+from erpnext.hr.doctype.employee.test_employee import make_employee
+from erpnext.assets.doctype.asset.test_asset import create_asset_data
+from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
+from frappe.utils import today, add_days
+import unittest
+
+class TestFullandFinalStatement(unittest.TestCase):
+
+	def setUp(self):
+		create_asset_data()
+
+	def tearDown(self):
+		frappe.db.sql("Delete from `tabFull and Final Statement`")
+		frappe.db.sql("Delete from `tabAsset`")
+		frappe.db.sql("Delete from `tabAsset Movement`")
+
+	def test_check_bootstraped_data_asset_movement_and_jv_creation(self):
+		employee = make_employee("test_fnf@example.com", company="_Test Company")
+		movement = create_asset_movement(employee)
+		frappe.db.set_value("Employee", employee, "relieving_date", add_days(today(), 30))
+		fnf = create_full_and_final_statement(employee)
+
+		payables_bootstraped_component = ["Salary Slip", "Gratuity",
+			"Expense Claim", "Bonus", "Leave Encashment"]
+
+		receivable_bootstraped_component = ["Loan", "Employee Advance"]
+
+		#checking payable s and receivables bootstraped value
+		self.assertEqual([payable.component for payable in fnf.payables], payables_bootstraped_component)
+		self.assertEqual([receivable.component for receivable in fnf.receivables], receivable_bootstraped_component)
+
+		#checking allocated asset
+		self.assertIn(movement, [asset.reference for asset in fnf.assets_allocated])
+
+def create_full_and_final_statement(employee):
+	fnf = frappe.new_doc("Full and Final Statement")
+	fnf.employee = employee
+	fnf.transaction_date = today()
+	fnf.save()
+	return fnf
+
+def create_asset_movement(employee):
+	asset_name = create_asset()
+	movement = frappe.new_doc("Asset Movement")
+	movement.company = "_Test Company"
+	movement.purpose = "Issue"
+	movement.transaction_date = today()
+
+	movement.append("assets", {
+		"asset": asset_name,
+		"to_employee": employee
+	})
+
+	movement.save()
+	movement.submit()
+	return movement.name
+
+def create_asset():
+	pr = make_purchase_receipt(item_code="Macbook Pro",
+			qty=1, rate=100000.0, location="Test Location")
+
+	asset_name = frappe.db.get_value("Asset", {"purchase_receipt": pr.name}, "name")
+	asset = frappe.get_doc("Asset", asset_name)
+	asset.calculate_depreciation = 0
+	asset.available_for_use_date = today()
+	asset.submit()
+	return asset_name
diff --git a/erpnext/hr/workspace/hr/hr.json b/erpnext/hr/workspace/hr/hr.json
index 575fa7b..9c5d0c1 100644
--- a/erpnext/hr/workspace/hr/hr.json
+++ b/erpnext/hr/workspace/hr/hr.json
@@ -224,6 +224,17 @@
    "type": "Link"
   },
   {
+   "dependencies": "Employee",
+   "hidden": 0,
+   "is_query_report": 0,
+   "label": "Full and Final Statement",
+   "link_count": 0,
+   "link_to": "Full and Final Statement",
+   "link_type": "DocType",
+   "onboard": 0,
+   "type": "Link"
+  },
+  {
    "hidden": 0,
    "is_query_report": 0,
    "label": "Shift Management",
@@ -931,7 +942,7 @@
    "type": "Link"
   }
  ],
- "modified": "2021-08-05 12:15:59.842918",
+ "modified": "2021-08-31 12:18:59.842918",
  "modified_by": "Administrator",
  "module": "HR",
  "name": "HR",
diff --git a/erpnext/payroll/doctype/gratuity/gratuity.js b/erpnext/payroll/doctype/gratuity/gratuity.js
index 377f3c6..d4f7c9c 100644
--- a/erpnext/payroll/doctype/gratuity/gratuity.js
+++ b/erpnext/payroll/doctype/gratuity/gratuity.js
@@ -3,13 +3,6 @@
 
 frappe.ui.form.on('Gratuity', {
 	setup: function (frm) {
-		frm.set_query('salary_component', function () {
-			return {
-				filters: {
-					type: "Earning"
-				}
-			};
-		});
 		frm.set_query("expense_account", function () {
 			return {
 				filters: {
@@ -31,7 +24,7 @@
 		});
 	},
 	refresh: function (frm) {
-		if (frm.doc.docstatus === 1 && frm.doc.pay_via_salary_slip === 0 && frm.doc.status === "Unpaid") {
+		if (frm.doc.docstatus == 1 && frm.doc.status == "Unpaid") {
 			frm.add_custom_button(__("Create Payment Entry"), function () {
 				return frappe.call({
 					method: 'erpnext.accounts.doctype.payment_entry.payment_entry.get_payment_entry',
diff --git a/erpnext/payroll/doctype/gratuity/gratuity.json b/erpnext/payroll/doctype/gratuity/gratuity.json
index 5cffd7e..48a9ce4 100644
--- a/erpnext/payroll/doctype/gratuity/gratuity.json
+++ b/erpnext/payroll/doctype/gratuity/gratuity.json
@@ -16,9 +16,6 @@
   "company",
   "gratuity_rule",
   "section_break_5",
-  "pay_via_salary_slip",
-  "payroll_date",
-  "salary_component",
   "payable_account",
   "expense_account",
   "mode_of_payment",
@@ -50,26 +47,12 @@
    "reqd": 1
   },
   {
-   "default": "1",
-   "fieldname": "pay_via_salary_slip",
-   "fieldtype": "Check",
-   "label": "Pay via Salary Slip"
-  },
-  {
    "fieldname": "posting_date",
    "fieldtype": "Date",
    "label": "Posting date",
    "reqd": 1
   },
   {
-   "depends_on": "eval: doc.pay_via_salary_slip == 1",
-   "fieldname": "salary_component",
-   "fieldtype": "Link",
-   "label": "Salary Component",
-   "mandatory_depends_on": "eval: doc.pay_via_salary_slip == 1",
-   "options": "Salary Component"
-  },
-  {
    "default": "0",
    "fieldname": "current_work_experience",
    "fieldtype": "Int",
@@ -95,20 +78,18 @@
    "reqd": 1
   },
   {
-   "depends_on": "eval: doc.pay_via_salary_slip == 0",
    "fieldname": "expense_account",
    "fieldtype": "Link",
    "label": "Expense Account",
-   "mandatory_depends_on": "eval: doc.pay_via_salary_slip == 0",
-   "options": "Account"
+   "options": "Account",
+   "reqd": 1
   },
   {
-   "depends_on": "eval: doc.pay_via_salary_slip == 0",
    "fieldname": "mode_of_payment",
    "fieldtype": "Link",
    "label": "Mode of Payment",
-   "mandatory_depends_on": "eval: doc.pay_via_salary_slip == 0",
-   "options": "Mode of Payment"
+   "options": "Mode of Payment",
+   "reqd": 1
   },
   {
    "fieldname": "gratuity_rule",
@@ -162,13 +143,6 @@
    "fieldtype": "Column Break"
   },
   {
-   "depends_on": "eval: doc.pay_via_salary_slip == 1",
-   "fieldname": "payroll_date",
-   "fieldtype": "Date",
-   "label": "Payroll Date",
-   "mandatory_depends_on": "eval: doc.pay_via_salary_slip == 1"
-  },
-  {
    "default": "0",
    "depends_on": "eval:doc.pay_via_salary_slip == 0",
    "fieldname": "paid_amount",
@@ -177,26 +151,23 @@
    "read_only": 1
   },
   {
-   "depends_on": "eval: doc.pay_via_salary_slip == 0",
    "fieldname": "payable_account",
    "fieldtype": "Link",
    "label": "Payable Account",
-   "mandatory_depends_on": "eval: doc.pay_via_salary_slip == 0",
-   "options": "Account"
+   "options": "Account",
+   "reqd": 1
   },
   {
-   "depends_on": "eval: doc.pay_via_salary_slip == 0",
    "fieldname": "cost_center",
    "fieldtype": "Link",
    "label": "Cost Center",
-   "mandatory_depends_on": "eval: doc.pay_via_salary_slip == 0",
    "options": "Cost Center"
   }
  ],
  "index_web_pages_for_search": 1,
  "is_submittable": 1,
  "links": [],
- "modified": "2020-11-02 18:21:11.971488",
+ "modified": "2021-07-02 15:05:57.396398",
  "modified_by": "Administrator",
  "module": "Payroll",
  "name": "Gratuity",
diff --git a/erpnext/payroll/doctype/gratuity/gratuity.py b/erpnext/payroll/doctype/gratuity/gratuity.py
index 31a6af3..8217bc3 100644
--- a/erpnext/payroll/doctype/gratuity/gratuity.py
+++ b/erpnext/payroll/doctype/gratuity/gratuity.py
@@ -19,10 +19,7 @@
 			self.status = "Unpaid"
 
 	def on_submit(self):
-		if self.pay_via_salary_slip:
-			self.create_additional_salary()
-		else:
-			self.create_gl_entries()
+		self.create_gl_entries()
 
 	def on_cancel(self):
 		self.ignore_linked_doctypes = ['GL Entry']
@@ -65,19 +62,6 @@
 
 		return gl_entry
 
-	def create_additional_salary(self):
-		if self.pay_via_salary_slip:
-			additional_salary = frappe.new_doc('Additional Salary')
-			additional_salary.employee = self.employee
-			additional_salary.salary_component = self.salary_component
-			additional_salary.overwrite_salary_structure_amount = 0
-			additional_salary.amount = self.amount
-			additional_salary.payroll_date = self.payroll_date
-			additional_salary.company = self.company
-			additional_salary.ref_doctype = self.doctype
-			additional_salary.ref_docname = self.name
-			additional_salary.submit()
-
 	def set_total_advance_paid(self):
 		paid_amount = frappe.db.sql("""
 			select ifnull(sum(debit_in_account_currency), 0) as paid_amount
diff --git a/erpnext/payroll/doctype/gratuity/gratuity_dashboard.py b/erpnext/payroll/doctype/gratuity/gratuity_dashboard.py
index 483e346..23c99b1 100644
--- a/erpnext/payroll/doctype/gratuity/gratuity_dashboard.py
+++ b/erpnext/payroll/doctype/gratuity/gratuity_dashboard.py
@@ -11,10 +11,6 @@
 			{
 				'label': _('Payment'),
 				'items': ['Payment Entry']
-			},
-			{
-				'label': _('Additional Salary'),
-				'items': ['Additional Salary']
 			}
 		]
 	}
diff --git a/erpnext/payroll/doctype/gratuity/test_gratuity.py b/erpnext/payroll/doctype/gratuity/test_gratuity.py
index 6c3b6fb..8cb4728 100644
--- a/erpnext/payroll/doctype/gratuity/test_gratuity.py
+++ b/erpnext/payroll/doctype/gratuity/test_gratuity.py
@@ -22,19 +22,18 @@
 
 	def setUp(self):
 		frappe.db.sql("DELETE FROM `tabGratuity`")
-		frappe.db.sql("DELETE FROM `tabAdditional Salary` WHERE ref_doctype = 'Gratuity'")
 
 	def test_get_last_salary_slip_should_return_none_for_new_employee(self):
 		new_employee = make_employee("new_employee@salary.com", company='_Test Company')
 		salary_slip = get_last_salary_slip(new_employee)
 		assert salary_slip is None
 
-	def test_check_gratuity_amount_based_on_current_slab_and_additional_salary_creation(self):
+	def test_check_gratuity_amount_based_on_current_slab(self):
 		employee, sal_slip = create_employee_and_get_last_salary_slip()
 
 		rule = get_gratuity_rule("Rule Under Unlimited Contract on termination (UAE)")
 
-		gratuity = create_gratuity(pay_via_salary_slip = 1, employee=employee, rule=rule.name)
+		gratuity = create_gratuity(employee=employee, rule=rule.name)
 
 		#work experience calculation
 		date_of_joining, relieving_date = frappe.db.get_value('Employee', employee, ['date_of_joining', 'relieving_date'])
@@ -62,9 +61,6 @@
 
 		self.assertEqual(flt(gratuity_amount, 2), flt(gratuity.amount, 2))
 
-		#additional salary creation (Pay via salary slip)
-		self.assertTrue(frappe.db.exists("Additional Salary", {"ref_docname": gratuity.name}))
-
 	def test_check_gratuity_amount_based_on_all_previous_slabs(self):
 		employee, sal_slip = create_employee_and_get_last_salary_slip()
 		rule = get_gratuity_rule("Rule Under Limited Contract (UAE)")
@@ -142,14 +138,9 @@
 	gratuity.employee = args.employee
 	gratuity.posting_date = getdate()
 	gratuity.gratuity_rule = args.rule or "Rule Under Limited Contract (UAE)"
-	gratuity.pay_via_salary_slip = args.pay_via_salary_slip or 0
-	if gratuity.pay_via_salary_slip:
-		gratuity.payroll_date = getdate()
-		gratuity.salary_component = "Performance Bonus"
-	else:
-		gratuity.expense_account =  args.expense_account or 'Payment Account - _TC'
-		gratuity.payable_account = args.payable_account or get_payable_account("_Test Company")
-		gratuity.mode_of_payment = args.mode_of_payment or 'Cash'
+	gratuity.expense_account = args.expense_account or 'Payment Account - _TC'
+	gratuity.payable_account = args.payable_account or get_payable_account("_Test Company")
+	gratuity.mode_of_payment = args.mode_of_payment or 'Cash'
 
 	gratuity.save()
 	gratuity.submit()