Skip to content

Commit

Permalink
Merge pull request #2735 from frappe/mergify/bp/version-15-hotfix/pr-…
Browse files Browse the repository at this point in the history
…2486

feat: toggle self leave approval for employees from HR settings (backport #2486)
  • Loading branch information
asmitahase authored Jan 30, 2025
2 parents 6624b9d + 4c77806 commit 757bc20
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 3 deletions.
9 changes: 8 additions & 1 deletion hrms/hr/doctype/hr_settings/hr_settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"leave_status_notification_template",
"leave_approver_mandatory_in_leave_application",
"restrict_backdated_leave_application",
"prevent_self_leave_approval",
"role_allowed_to_create_backdated_leave_application",
"column_break_29",
"expense_approver_mandatory_in_expense_claim",
Expand Down Expand Up @@ -329,13 +330,19 @@
"fieldname": "unlink_payment_on_cancellation_of_employee_advance",
"fieldtype": "Check",
"label": " Unlink Payment on Cancellation of Employee Advance"
},
{
"default": "0",
"fieldname": "prevent_self_leave_approval",
"fieldtype": "Check",
"label": "Prevent self approval for leaves even if user has permissions"
}
],
"icon": "fa fa-cog",
"idx": 1,
"issingle": 1,
"links": [],
"modified": "2024-09-29 12:49:16.175079",
"modified": "2025-01-30 12:41:22.594071",
"modified_by": "Administrator",
"module": "HR",
"name": "HR Settings",
Expand Down
26 changes: 24 additions & 2 deletions hrms/hr/doctype/leave_application/leave_application.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ frappe.ui.form.on("Leave Application", {
},
};
});

frm.set_query("employee", erpnext.queries.employee);
},

Expand Down Expand Up @@ -91,7 +90,6 @@ frappe.ui.form.on("Leave Application", {

refresh: function (frm) {
hrms.leave_utils.add_view_ledger_button(frm);

if (frm.is_new()) {
frm.trigger("calculate_total_days");
}
Expand All @@ -114,6 +112,7 @@ frappe.ui.form.on("Leave Application", {
if (frm.doc.docstatus === 0) {
frm.trigger("make_dashboard");
}
frm.trigger("set_form_buttons");
},

async set_employee(frm) {
Expand Down Expand Up @@ -255,6 +254,29 @@ frappe.ui.form.on("Leave Application", {
});
}
},

set_form_buttons: async function (frm) {
let self_approval_not_allowed = frm.doc.__onload
? frm.doc.__onload.self_leave_approval_not_allowed
: 0;
let current_employee = await hrms.get_current_employee();
if (
frm.doc.docstatus === 0 &&
!frm.is_dirty() &&
!frappe.model.has_workflow(frm.doctype)
) {
if (self_approval_not_allowed && current_employee == frm.doc.employee) {
frm.set_df_property("status", "read_only", 1);
frm.trigger("show_save_button");
}
}
},
show_save_button: function (frm) {
frm.page.set_primary_action("Save", () => {
frm.save();
});
$(".form-message").prop("hidden", true);
},
});

frappe.tour["Leave Application"] = [
Expand Down
21 changes: 21 additions & 0 deletions hrms/hr/doctype/leave_application/leave_application.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import frappe
from frappe import _
from frappe.model.workflow import get_workflow_name
from frappe.query_builder.functions import Max, Min, Sum
from frappe.utils import (
add_days,
Expand All @@ -23,6 +24,7 @@
from erpnext.setup.doctype.employee.employee import get_holiday_list_for_employee

import hrms
from hrms.api import get_current_employee_info
from hrms.hr.doctype.leave_block_list.leave_block_list import get_applicable_block_dates
from hrms.hr.doctype.leave_ledger_entry.leave_ledger_entry import create_leave_ledger_entry
from hrms.hr.utils import (
Expand Down Expand Up @@ -102,6 +104,7 @@ def on_submit(self):

self.validate_back_dated_application()
self.update_attendance()
self.validate_for_self_approval()

# notify leave applier about approval
if frappe.db.get_single_value("HR Settings", "send_leave_notification"):
Expand Down Expand Up @@ -793,6 +796,24 @@ def create_ledger_entry_for_intermediate_allocation_expiry(self, expiry_date, su
args.update(dict(from_date=start_date, to_date=self.to_date, leaves=leaves * -1))
create_leave_ledger_entry(self, args, submit)

def validate_for_self_approval(self):
self_leave_approval_not_allowed = frappe.db.get_single_value(
"HR Settings", "prevent_self_leave_approval"
)
employee_user = frappe.db.get_value("Employee", self.employee, "user_id")
if (
self_leave_approval_not_allowed
and employee_user == frappe.session.user
and not get_workflow_name("Leave Application")
):
frappe.throw(_("Self-approval for leaves is not allowed"))

def onload(self):
self.set_onload(
"self_leave_approval_not_allowed",
frappe.db.get_single_value("HR Settings", "prevent_self_leave_approval"),
)


def get_allocation_expiry_for_cf_leaves(
employee: str, leave_type: str, to_date: datetime.date, from_date: datetime.date
Expand Down
78 changes: 78 additions & 0 deletions hrms/hr/doctype/leave_application/test_leave_application.py
Original file line number Diff line number Diff line change
Expand Up @@ -967,6 +967,84 @@ def test_leave_approver_perms(self):
employee.leave_approver = ""
employee.save()

def test_self_leave_approval_allowed(self):
frappe.db.set_single_value("HR Settings", "prevent_self_leave_approval", 0)

leave_approver = "[email protected]"
make_employee(leave_approver, "_Test Company")

employee = get_employee()
if not employee.user_id:
employee.user_id = "[email protected]"
employee.leave_approver = leave_approver
employee.save()

from frappe.utils.user import add_role

add_role(employee.user_id, "Leave Approver")

make_allocation_record(employee.name)
application = frappe.get_doc(
doctype="Leave Application",
employee=employee.name,
leave_type="_Test Leave Type",
from_date="2014-06-01",
to_date="2014-06-02",
posting_date="2014-05-30",
description="_Test Reason",
company="_Test Company",
leave_approver=leave_approver,
)
application.insert()
application.status = "Approved"

frappe.set_user(employee.user_id)
application.submit()

self.assertEqual(1, application.docstatus)

frappe.set_user("Administrator")

def test_self_leave_approval_not_allowed(self):
frappe.db.set_single_value("HR Settings", "prevent_self_leave_approval", 1)

leave_approver = "[email protected]"
make_employee(leave_approver, "_Test Company")

employee = get_employee()
employee.leave_approver = leave_approver
if not employee.user_id:
employee.user_id = "[email protected]"
employee.save()

from frappe.utils.user import add_role

add_role(employee.user_id, "Leave Approver")

make_allocation_record(employee.name)
application = application = frappe.get_doc(
doctype="Leave Application",
employee=employee.name,
leave_type="_Test Leave Type",
from_date="2014-06-03",
to_date="2014-06-04",
posting_date="2014-05-30",
description="_Test Reason",
company="_Test Company",
leave_approver=leave_approver,
)
application.insert()
application.status = "Approved"

frappe.set_user(employee.user_id)
self.assertRaises(frappe.ValidationError, application.submit)

add_role(leave_approver, "Leave Approver")
frappe.set_user(leave_approver)
application.reload()
application.submit()
self.assertEqual(1, application.docstatus)

@set_holiday_list("Salary Slip Test Holiday List", "_Test Company")
def test_get_leave_details_for_dashboard(self):
employee = get_employee()
Expand Down

0 comments on commit 757bc20

Please sign in to comment.