diff --git a/erpnext/payroll/doctype/gratuity/gratuity.js b/erpnext/payroll/doctype/gratuity/gratuity.js index d4f7c9ca091..3d69c46e55a 100644 --- a/erpnext/payroll/doctype/gratuity/gratuity.js +++ b/erpnext/payroll/doctype/gratuity/gratuity.js @@ -3,6 +3,14 @@ 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: { @@ -24,7 +32,7 @@ frappe.ui.form.on('Gratuity', { }); }, refresh: function (frm) { - if (frm.doc.docstatus == 1 && frm.doc.status == "Unpaid") { + if (frm.doc.docstatus == 1 && !frm.doc.pay_via_salary_slip && 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 197089567df..1fd1cecaaaa 100644 --- a/erpnext/payroll/doctype/gratuity/gratuity.json +++ b/erpnext/payroll/doctype/gratuity/gratuity.json @@ -1,7 +1,7 @@ { "actions": [], "autoname": "HR-GRA-PAY-.#####", - "creation": "2020-08-05 20:52:13.024683", + "creation": "2022-01-27 16:24:28.200061", "doctype": "DocType", "editable_grid": 1, "engine": "InnoDB", @@ -16,6 +16,9 @@ "company", "gratuity_rule", "section_break_5", + "pay_via_salary_slip", + "payroll_date", + "salary_component", "payable_account", "expense_account", "mode_of_payment", @@ -78,18 +81,20 @@ "reqd": 1 }, { + "depends_on": "eval: !doc.pay_via_salary_slip", "fieldname": "expense_account", "fieldtype": "Link", "label": "Expense Account", - "options": "Account", - "reqd": 1 + "mandatory_depends_on": "eval: !doc.pay_via_salary_slip", + "options": "Account" }, { + "depends_on": "eval: !doc.pay_via_salary_slip", "fieldname": "mode_of_payment", "fieldtype": "Link", "label": "Mode of Payment", - "options": "Mode of Payment", - "reqd": 1 + "mandatory_depends_on": "eval: !doc.pay_via_salary_slip", + "options": "Mode of Payment" }, { "fieldname": "gratuity_rule", @@ -151,23 +156,45 @@ "read_only": 1 }, { + "depends_on": "eval: !doc.pay_via_salary_slip", "fieldname": "payable_account", "fieldtype": "Link", "label": "Payable Account", - "options": "Account", - "reqd": 1 + "mandatory_depends_on": "eval: !doc.pay_via_salary_slip", + "options": "Account" }, { "fieldname": "cost_center", "fieldtype": "Link", "label": "Cost Center", "options": "Cost Center" + }, + { + "default": "1", + "fieldname": "pay_via_salary_slip", + "fieldtype": "Check", + "label": "Pay via Salary Slip" + }, + { + "depends_on": "pay_via_salary_slip", + "fieldname": "payroll_date", + "fieldtype": "Date", + "label": "Payroll Date", + "mandatory_depends_on": "pay_via_salary_slip" + }, + { + "depends_on": "pay_via_salary_slip", + "fieldname": "salary_component", + "fieldtype": "Link", + "label": "Salary Component", + "mandatory_depends_on": "pay_via_salary_slip", + "options": "Salary Component" } ], "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2022-01-19 12:54:37.306145", + "modified": "2022-02-02 14:00:45.536152", "modified_by": "Administrator", "module": "Payroll", "name": "Gratuity", diff --git a/erpnext/payroll/doctype/gratuity/gratuity.py b/erpnext/payroll/doctype/gratuity/gratuity.py index 476990a88e1..939634a9310 100644 --- a/erpnext/payroll/doctype/gratuity/gratuity.py +++ b/erpnext/payroll/doctype/gratuity/gratuity.py @@ -21,7 +21,10 @@ class Gratuity(AccountsController): self.status = "Unpaid" def on_submit(self): - self.create_gl_entries() + if self.pay_via_salary_slip: + self.create_additional_salary() + else: + self.create_gl_entries() def on_cancel(self): self.ignore_linked_doctypes = ['GL Entry'] @@ -64,6 +67,19 @@ class Gratuity(AccountsController): 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 aeadba186d0..771a6fea84a 100644 --- a/erpnext/payroll/doctype/gratuity/gratuity_dashboard.py +++ b/erpnext/payroll/doctype/gratuity/gratuity_dashboard.py @@ -10,7 +10,7 @@ def get_data(): 'transactions': [ { 'label': _('Payment'), - 'items': ['Payment Entry'] + 'items': ['Payment Entry', 'Additional Salary'] } ] } diff --git a/erpnext/payroll/doctype/gratuity/test_gratuity.py b/erpnext/payroll/doctype/gratuity/test_gratuity.py index 93cba06da15..90e8061fed8 100644 --- a/erpnext/payroll/doctype/gratuity/test_gratuity.py +++ b/erpnext/payroll/doctype/gratuity/test_gratuity.py @@ -18,27 +18,25 @@ from erpnext.regional.united_arab_emirates.setup import create_gratuity_rule test_dependencies = ["Salary Component", "Salary Slip", "Account"] class TestGratuity(unittest.TestCase): - @classmethod - def setUpClass(cls): + def setUp(self): + frappe.db.delete("Gratuity") + frappe.db.delete("Additional Salary", {"ref_doctype": "Gratuity"}) + make_earning_salary_component(setup=True, test_tax=True, company_list=['_Test Company']) make_deduction_salary_component(setup=True, test_tax=True, company_list=['_Test Company']) - def setUp(self): - frappe.db.sql("DELETE FROM `tabGratuity`") - 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(self): + def test_check_gratuity_amount_based_on_current_slab_and_additional_salary_creation(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 + # work experience calculation date_of_joining, relieving_date = frappe.db.get_value('Employee', employee, ['date_of_joining', 'relieving_date']) employee_total_workings_days = (get_datetime(relieving_date) - get_datetime(date_of_joining)).days @@ -64,6 +62,9 @@ class TestGratuity(unittest.TestCase): 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)") @@ -117,8 +118,8 @@ class TestGratuity(unittest.TestCase): self.assertEqual(flt(gratuity.paid_amount,2), flt(gratuity.amount, 2)) def tearDown(self): - frappe.db.sql("DELETE FROM `tabGratuity`") - frappe.db.sql("DELETE FROM `tabAdditional Salary` WHERE ref_doctype = 'Gratuity'") + frappe.db.rollback() + def get_gratuity_rule(name): rule = frappe.db.exists("Gratuity Rule", name) @@ -141,9 +142,14 @@ def create_gratuity(**args): gratuity.employee = args.employee gratuity.posting_date = getdate() gratuity.gratuity_rule = args.rule or "Rule Under Limited Contract (UAE)" - 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.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.save() gratuity.submit()