Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: toggle self leave approval for employees from HR settings (backport #2486) #2734

Closed
wants to merge 12 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions 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 @@ -296,13 +297,66 @@
"fieldname": "shift_settings_section",
"fieldtype": "Section Break",
"label": "Shift Settings"
<<<<<<< HEAD
=======
},
{
"default": "1",
"fieldname": "allow_employee_checkin_from_mobile_app",
"fieldtype": "Check",
"label": "Allow Employee Checkin from Mobile App"
},
{
"default": "0",
"fieldname": "allow_geolocation_tracking",
"fieldtype": "Check",
"label": "Allow Geolocation Tracking"
},
{
"fieldname": "attendance_settings_section",
"fieldtype": "Section Break",
"label": "Attendance Settings"
},
{
"fieldname": "unlink_payment_section",
"fieldtype": "Section Break",
"label": "Unlink Payment"
},
{
"default": "0",
"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",
<<<<<<< HEAD
"label": "Enable Self-Approval For Leaves"
>>>>>>> c74d2bb2 (feat: new hr setting to enable/disable self-leave approval)
=======
"label": "Prevent self approval for leaves even if user has permissions"
>>>>>>> 52b5e1f9 (fix: status fields becomes read only if self leave approval is prevented)
}
],
"icon": "fa fa-cog",
"idx": 1,
"issingle": 1,
"links": [],
<<<<<<< HEAD
<<<<<<< HEAD
<<<<<<< HEAD
"modified": "2024-06-26 15:20:17.802079",
=======
"modified": "2024-12-02 13:25:31.843494",
>>>>>>> c74d2bb2 (feat: new hr setting to enable/disable self-leave approval)
=======
"modified": "2024-12-11 12:34:33.019189",
>>>>>>> 52b5e1f9 (fix: status fields becomes read only if self leave approval is prevented)
=======
"modified": "2025-01-30 12:41:22.594071",
>>>>>>> e49c5a72 (fix: prevent_self_leave_approval should be false by deafult)
"modified_by": "Administrator",
"module": "HR",
"name": "HR Settings",
Expand Down
39 changes: 38 additions & 1 deletion 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 @@ -90,6 +89,10 @@ frappe.ui.form.on("Leave Application", {
},

refresh: function (frm) {
<<<<<<< HEAD
=======
hrms.leave_utils.add_view_ledger_button(frm);
>>>>>>> bb15010d (fix: removed action buttons)
if (frm.is_new()) {
frm.trigger("calculate_total_days");
}
Expand All @@ -109,6 +112,17 @@ frappe.ui.form.on("Leave Application", {
}

frm.trigger("set_employee");
<<<<<<< HEAD
=======
if (frm.doc.docstatus === 0) {
frm.trigger("make_dashboard");
}
<<<<<<< HEAD
frm.trigger("prevent_self_leave_approval");
>>>>>>> 4acf169c (feat: Enable/disable leave applicants from approving their own leaves based on the leave approval HR setting)
=======
frm.trigger("set_form_buttons");
>>>>>>> 52b5e1f9 (fix: status fields becomes read only if self leave approval is prevented)
},

async set_employee(frm) {
Expand Down Expand Up @@ -250,6 +264,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
25 changes: 25 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 @@ -22,6 +23,11 @@
from erpnext.buying.doctype.supplier_scorecard.supplier_scorecard import daterange
from erpnext.setup.doctype.employee.employee import get_holiday_list_for_employee

<<<<<<< HEAD
=======
import hrms
from hrms.api import get_current_employee_info
>>>>>>> 4acf169c (feat: Enable/disable leave applicants from approving their own leaves based on the leave approval HR setting)
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 @@ -94,6 +100,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 @@ -775,6 +782,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
Loading