Skip to content
Merged
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
6 changes: 6 additions & 0 deletions hrms/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,7 @@ def get_currency_symbols() -> dict:

@frappe.whitelist()
def get_company_cost_center_and_expense_account(company: str) -> dict:
frappe.has_permission("Company", "read", company, throw=True)
return frappe.db.get_value(
"Company", company, ["cost_center", "default_expense_claim_payable_account"], as_dict=True
)
Expand Down Expand Up @@ -779,6 +780,11 @@ def upload_base64_file(

@frappe.whitelist()
def delete_attachment(filename: str):
attached_to_doctype, attached_to_name = frappe.db.get_value(
"File", filename, ["attached_to_doctype", "attached_to_name"]
)
if attached_to_doctype and attached_to_name:
frappe.has_permission(attached_to_doctype, "write", attached_to_name, throw=True)
frappe.delete_doc("File", filename)


Expand Down
1 change: 1 addition & 0 deletions hrms/api/roster.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ def get_events(

@frappe.whitelist()
def get_schedule_from_assignment(shift_schedule_assignment: str):
frappe.has_permission("Shift Schedule Assignment", "read", shift_schedule_assignment, throw=True)
shift_schedule = frappe.db.get_value(
"Shift Schedule Assignment", shift_schedule_assignment, "shift_schedule"
)
Expand Down
1 change: 1 addition & 0 deletions hrms/controllers/employee_boarding_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ def on_cancel(self):

@frappe.whitelist()
def get_onboarding_details(parent: str, parenttype: str):
frappe.has_permission(parenttype, "read", parent, throw=True)
return frappe.get_all(
"Employee Boarding Activity",
fields=[
Expand Down
1 change: 1 addition & 0 deletions hrms/hr/doctype/appraisal/appraisal.py
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ def set_goal_score(self, update=False):

@frappe.whitelist()
def get_feedback_history(employee: str, appraisal: str) -> dict:
frappe.has_permission("Appraisal", "read", appraisal, throw=True)
data = frappe._dict()
data.feedback_history = frappe.get_list(
"Employee Performance Feedback",
Expand Down
4 changes: 4 additions & 0 deletions hrms/hr/doctype/appraisal_cycle/appraisal_cycle.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ def check_if_appraisals_exist(self):
@frappe.whitelist()
def set_employees(self):
"""Pull employees in appraisee list based on selected filters"""
self.check_permission("write")
employees = self.get_employees_for_appraisal()
appraisal_templates = self.get_appraisal_template_map()

Expand Down Expand Up @@ -234,6 +235,7 @@ def validate_active_appraisal_cycle(appraisal_cycle: str) -> None:

@frappe.whitelist()
def get_appraisal_cycle_summary(cycle_name: str) -> dict:
frappe.has_permission("Appraisal Cycle", "read", cycle_name, throw=True)
summary = frappe._dict()

summary["appraisees"] = frappe.db.count(
Expand Down Expand Up @@ -283,6 +285,8 @@ def get_employees_without_feedback(cycle_name: str | None = None) -> int:
"Appraisal Cycle", {"status": "In Progress"}, order_by="start_date desc"
)

frappe.has_permission("Appraisal Cycle", "read", cycle_name, throw=True)

filtered_records = SubQuery(
frappe.qb.from_(Feedback)
.select(Feedback.employee)
Expand Down
1 change: 1 addition & 0 deletions hrms/hr/doctype/attendance/attendance.py
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,7 @@ def process_bulk_attendance_in_batches(data, chunk_size=20):
def get_unmarked_days(
employee: str, from_date: str | date, to_date: str | date, exclude_holidays: str | int = 0
) -> list:
frappe.has_permission("Employee", "read", employee, throw=True)
joining_date, relieving_date = frappe.get_cached_value(
"Employee", employee, ["date_of_joining", "relieving_date"]
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ def mark_employee_attendance(
attendance.insert()
attendance.submit()
if mark_half_day:
frappe.has_permission("Attendance", "write", throw=True)
if isinstance(half_day_employee_list, str):
half_day_employee_list = json.loads(half_day_employee_list)
Attendance = frappe.qb.DocType("Attendance")
Expand Down
6 changes: 6 additions & 0 deletions hrms/hr/doctype/employee_checkin/employee_checkin.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,12 @@ def add_log_based_on_employee_field(
if not employee_field_value or not timestamp:
frappe.throw(_("'employee_field_value' and 'timestamp' are required."))

allowed_employee_fieldnames = {"name", "employee", "attendance_device_id"}
if employee_fieldname not in allowed_employee_fieldnames:
frappe.throw(
_("'employee_fieldname' must be one of {0}.").format(", ".join(allowed_employee_fieldnames))
)

employee = frappe.db.get_values(
"Employee",
{employee_fieldname: employee_field_value},
Expand Down
1 change: 1 addition & 0 deletions hrms/hr/doctype/employee_onboarding/employee_onboarding.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ def on_cancel(self):

@frappe.whitelist()
def mark_onboarding_as_completed(self):
self.check_permission("write")
for activity in self.activities:
frappe.db.set_value("Task", activity.task, "status", "Completed")
frappe.db.set_value("Project", self.project, "status", "Completed")
Expand Down
10 changes: 10 additions & 0 deletions hrms/hr/doctype/expense_claim/expense_claim.js
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,16 @@ frappe.ui.form.on("Expense Claim Detail", {
if (!d.expense_type) {
return;
}

// Fetch description only if empty
if (!d.description) {
frappe.db.get_value("Expense Claim Type", d.expense_type, "description").then((r) => {
if (r.message && r.message.description) {
frappe.model.set_value(cdt, cdn, "description", r.message.description);
}
});
}

return frappe.call({
method: "hrms.hr.doctype.expense_claim.expense_claim.get_expense_claim_account_and_cost_center",
args: {
Expand Down
2 changes: 2 additions & 0 deletions hrms/hr/doctype/expense_claim/expense_claim.py
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,7 @@ def get_advances(expense_claim: str | dict | Document, advance_id: str | None =
if isinstance(expense_claim, str):
expense_claim = frappe._dict(json.loads(expense_claim))
expense_claim_doc = frappe.get_doc(expense_claim)
frappe.has_permission("Employee", "read", expense_claim_doc.employee, throw=True)
expense_claim_doc.advances = []

advance = frappe.qb.DocType("Employee Advance")
Expand Down Expand Up @@ -714,6 +715,7 @@ def get_advances(expense_claim: str | dict | Document, advance_id: str | None =

@frappe.whitelist()
def get_expense_claim(employee_advance: str | dict) -> Document:
frappe.has_permission("Employee Advance", "read", employee_advance, throw=True)
if isinstance(employee_advance, str):
employee_advance = frappe.get_doc("Employee Advance", employee_advance)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,6 @@
"read_only": 1
},
{
"fetch_from": "expense_type.description",
"fetch_if_empty": 1,
"fieldname": "description",
"fieldtype": "Text Editor",
"in_list_view": 1,
Expand Down Expand Up @@ -155,7 +153,7 @@
"idx": 1,
"istable": 1,
"links": [],
"modified": "2025-09-10 19:21:50.625260",
"modified": "2026-06-15 16:46:22.402968",
"modified_by": "Administrator",
"module": "HR",
"name": "Expense Claim Detail",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,8 @@ def get_account_and_amount(ref_doctype: str, ref_document: str, company: str) ->
if not ref_doctype or not ref_document:
return None

frappe.has_permission(ref_doctype, "read", ref_document, throw=True)

if ref_doctype == "Salary Slip":
salary_details = frappe.db.get_value(
"Salary Slip", ref_document, ["payroll_entry", "net_pay"], as_dict=1
Expand Down
3 changes: 3 additions & 0 deletions hrms/hr/doctype/interview/interview.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ def on_discard(self):

@frappe.whitelist()
def get_interviewers(interview_type: str) -> list[dict]:
frappe.has_permission("Interview Type", "read", interview_type, throw=True)
return frappe.get_all("Interviewer", filters={"parent": interview_type}, fields=["user as interviewer"])


Expand Down Expand Up @@ -202,6 +203,7 @@ def get_feedback(interview: str) -> list[dict]:

@frappe.whitelist()
def get_skill_wise_average_rating(interview: str) -> list[dict]:
frappe.has_permission("Interview", "read", interview, throw=True)
skill_assessment = frappe.qb.DocType("Skill Assessment")
interview_feedback = frappe.qb.DocType("Interview Feedback")
return (
Expand Down Expand Up @@ -340,6 +342,7 @@ def send_daily_feedback_reminder():

@frappe.whitelist()
def get_expected_skill_set(interview_type: str):
frappe.has_permission("Interview Type", "read", interview_type, throw=True)
return frappe.get_all(
"Expected Skill Set", filters={"parent": interview_type}, fields=["skill"], order_by="idx"
)
Expand Down
1 change: 1 addition & 0 deletions hrms/hr/doctype/interview_feedback/interview_feedback.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,5 @@ def update_interview_average_rating(self):

@frappe.whitelist()
def get_applicable_interviewers(interview: str) -> list[str]:
frappe.has_permission("Interview", "read", interview, throw=True)
return frappe.get_all("Interview Detail", filters={"parent": interview}, pluck="interviewer")
1 change: 1 addition & 0 deletions hrms/hr/doctype/job_applicant/job_applicant.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ def create_interview(job_applicant: str, interview_type: str) -> Document:

@frappe.whitelist()
def get_interview_details(job_applicant: str) -> dict:
frappe.has_permission("Job Applicant", "read", job_applicant, throw=True)
interview_details = frappe.db.get_all(
"Interview",
filters={"job_applicant": job_applicant, "docstatus": ["!=", 2]},
Expand Down
1 change: 1 addition & 0 deletions hrms/hr/doctype/job_requisition/job_requisition.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ def check_duplicate_job_requisition(self):

@frappe.whitelist()
def associate_job_opening(self, job_opening: str) -> None:
frappe.has_permission("Job Opening", "write", job_opening, throw=True)
frappe.db.set_value(
"Job Opening", job_opening, {"job_requisition": self.name, "vacancies": self.no_of_positions}
)
Expand Down
4 changes: 2 additions & 2 deletions hrms/hr/doctype/leave_adjustment/leave_adjustment.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ def get_leave_allocation_for_posting_date(
"""
Returns the leave allocation for the given employee, leave type and posting date.
"""
return frappe.get_all(
return frappe.get_list(
"Leave Allocation",
{
"employee": employee,
Expand All @@ -151,7 +151,7 @@ def get_allocated_leave_types(
"""
Returns the leave types allocated to the given employee
"""
return frappe.get_all(
return frappe.get_list(
"Leave Allocation",
{
"employee": filters.get("employee"),
Expand Down
13 changes: 10 additions & 3 deletions hrms/hr/doctype/leave_application/leave_application.py
Original file line number Diff line number Diff line change
Expand Up @@ -968,6 +968,7 @@ def get_number_of_leave_days(
) -> float:
"""Returns number of leave days between 2 dates after considering half day and holidays
(Based on the include_holiday setting in Leave Type)"""
validate_leave_access(employee)
number_of_days = date_diff(to_date, from_date) + 1

if cint(half_day) == 1:
Expand Down Expand Up @@ -1020,7 +1021,7 @@ def get_leave_details(employee: str, date: str | datetime.date, for_salary_slip:

return {
"leave_allocation": leave_allocation,
"leave_approver": get_leave_approver(employee),
"leave_approver": get_employee_leave_approver(employee),
"lwps": lwp,
}

Expand Down Expand Up @@ -1338,6 +1339,7 @@ def get_leave_entries(employee, leave_type, from_date, to_date):
@frappe.whitelist()
def get_holidays(employee: str, from_date: str | datetime.date, to_date: str | datetime.date) -> int:
"""get holidays between two dates for the given employee"""
validate_leave_access(employee)
holidays = get_holiday_dates_between_range(employee, from_date, to_date)
return len(holidays)

Expand Down Expand Up @@ -1526,6 +1528,11 @@ def get_approved_leaves_for_period(employee, leave_type, from_date, to_date):

@frappe.whitelist()
def get_leave_approver(employee: str) -> str:
validate_leave_access(employee)
return get_employee_leave_approver(employee)


def get_employee_leave_approver(employee: str) -> str:
leave_approver, department = frappe.db.get_value("Employee", employee, ["leave_approver", "department"])

if not leave_approver and department:
Expand All @@ -1549,13 +1556,13 @@ def get_leave_approver_and_mandatory(employee: str) -> dict:

return {
"is_mandatory": 1 if mandatory else 0,
"leave_approver": get_leave_approver(employee),
"leave_approver": get_employee_leave_approver(employee),
}


def validate_leave_access(employee):
employee_user = frappe.db.get_value("Employee", employee, "user_id")
leave_approver = get_leave_approver(employee)
leave_approver = get_employee_leave_approver(employee)

if frappe.session.user not in (employee_user, leave_approver) and (
not frappe.has_permission("Employee", "read", employee)
Expand Down
2 changes: 2 additions & 0 deletions hrms/hr/doctype/leave_ledger_entry/leave_ledger_entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,8 @@ def expire_allocation(allocation: str | Document | frappe._dict, expiry_date: da
allocation = json.loads(allocation)
allocation = frappe.get_doc("Leave Allocation", allocation["name"])

frappe.has_permission("Leave Allocation", "write", allocation.name, throw=True)

leaves = get_remaining_leaves(allocation)
expiry_date = expiry_date if expiry_date else allocation.to_date

Expand Down
2 changes: 2 additions & 0 deletions hrms/hr/doctype/staffing_plan/staffing_plan.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,8 @@ def get_active_staffing_plan_details(
from_date: str | datetime.date | None = None,
to_date: str | datetime.date | None = None,
) -> list[dict] | None:
frappe.has_permission("Staffing Plan", "read", throw=True)

if from_date is None:
from_date = getdate(nowdate())
if to_date is None:
Expand Down
1 change: 1 addition & 0 deletions hrms/hr/doctype/training_result/training_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,5 @@ def on_submit(self):

@frappe.whitelist()
def get_employees(training_event: str):
frappe.has_permission("Training Event", "read", training_event, throw=True)
return frappe.get_doc("Training Event", training_event).employees
Loading
Loading