fix(setup): limit which users an employee can be linked to

This commit is contained in:
Nabin Hait
2026-10-21 12:02:10 +05:30
parent d77dc849fb
commit d9c0cf4306
2 changed files with 75 additions and 0 deletions
@@ -4,6 +4,9 @@ import frappe
from frappe import _, scrub, throw
from frappe.model.naming import set_name_by_naming_series
from frappe.permissions import (
ALL_USER_ROLE,
GUEST_ROLE,
SYSTEM_USER_ROLE,
add_user_permission,
get_doc_permissions,
has_permission,
@@ -69,6 +72,21 @@ class Employee(NestedSet):
self.validate_for_enabled_user_id()
self.validate_duplicate_user_id()
if any(self.has_value_changed(field) for field in ("user_id", "status", "create_user_permission")):
self.validate_user_access()
def validate_user_access(self):
"""Only a System Manager may link or update a User holding roles the editor lacks."""
editor_roles = frappe.get_roles()
if "System Manager" in editor_roles:
return
ignored_roles = {GUEST_ROLE, ALL_USER_ROLE, SYSTEM_USER_ROLE, "Employee"}
if set(frappe.get_roles(self.user_id)) - set(editor_roles) - ignored_roles:
frappe.throw(
_("You are not permitted to link or update User {0}").format(frappe.bold(self.user_id)),
frappe.PermissionError,
)
def update_nsm_model(self):
frappe.utils.nestedset.update_nsm(self)
@@ -36,6 +36,63 @@ class TestEmployee(unittest.TestCase):
employee_doc.save()
self.assertTrue("Employee" not in frappe.get_roles(user))
def test_hr_user_links_only_users_without_extra_roles(self):
from erpnext.tests.permission_test_utils import as_user, make_fenced_user
hr_user = make_fenced_user("employee-hr@example.com", ["HR User"])
manager = make_fenced_user("employee-manager@example.com", ["System Manager"])
staff = make_fenced_user("employee-staff@example.com", ["Employee"])
for user in (manager, staff):
frappe.db.set_value("User", user, "enabled", 1)
frappe.db.delete("Employee", {"user_id": user})
def new_employee(user_id):
return frappe.get_doc(
doctype="Employee",
first_name=user_id,
company="_Test Company",
user_id=user_id,
status="Left",
relieving_date="2024-01-01",
date_of_birth="1990-05-08",
date_of_joining="2013-01-01",
gender="Female",
)
with as_user(hr_user):
self.assertRaises(frappe.PermissionError, new_employee(manager).insert)
new_employee(staff).insert()
self.assertEqual(frappe.db.get_value("User", manager, "enabled"), 1)
self.assertEqual(frappe.db.get_value("User", staff, "enabled"), 0)
def test_hr_user_toggles_user_permission_only_for_users_without_extra_roles(self):
from erpnext.tests.permission_test_utils import as_user, make_fenced_user
hr_user = make_fenced_user("employee-hr@example.com", ["HR User"])
manager = make_fenced_user("employee-manager@example.com", ["System Manager"])
staff = make_fenced_user("employee-staff@example.com", ["Employee"])
employees = {}
for user in (manager, staff):
frappe.db.set_value("User", user, "enabled", 1)
frappe.db.delete("Employee", {"user_id": user})
employees[user] = make_employee(user, company="_Test Company", create_user_permission=1)
with as_user(hr_user):
manager_employee = frappe.get_doc("Employee", employees[manager])
manager_employee.create_user_permission = 0
self.assertRaises(frappe.PermissionError, manager_employee.save)
staff_employee = frappe.get_doc("Employee", employees[staff])
staff_employee.create_user_permission = 0
staff_employee.save()
for user, expected in ((manager, True), (staff, False)):
has_permission = frappe.db.exists(
"User Permission", {"allow": "Employee", "for_value": employees[user], "user": user}
)
self.assertEqual(bool(has_permission), expected)
def test_employee_user_permission(self):
employee1 = make_employee("employee_1_test@company.com", create_user_permission=1)
employee2 = make_employee("employee_2_test@company.com", create_user_permission=1)