[Solved] Employee Attendance Timestamp and Custom Status

Hi, I have a customization request.

In order to ensure employees comply strictly to attendance policies, I am implementing a self-entry/evaluation system for attendance. Employees are allowed to enter their daily attendance in ERNext but can only do so from their workstations. However, the attendance doctype does not show the exact time the attendance entry is made just the date. Hence if the employee is one hour late for instance the report will not capture it.

Also tied to this are employees who may arrive late to work for official or cogent reasons. I want to be able to create custom attendance status for these reasons so while the system captures their resumption time, a more appropriate status is used beyond present, absent or half day (these custom status do not need to impact on payroll or leave or any other doctype or process).

Can the doctype be modified to include these customization or would this require some backend script? I would appreciate advice on this.

@flexy2ky
You can add custom fields to capture Time but to make it automated you need to write a custom script on Validate

Regards,
@hereabdulla

@hereabdulla Thank you for your reply. Your response above prompted me to customize the doctype and i was able to get the time in:

and it validated on submit:

However i can’t get the custom status to validate with the document as i receive the following error when any of the status is selected:

With the other pre-defined statuses i can’t seem to find the script or function that validates them so i can replicate. Seems these are hard-coded but i would appreciate confirmation of this. One objective has been achieved so it will be great if i can achieve the other as well.

Hi Flexy2ky

How are you able to ensure that they are keying in from their workstations and not from home ?

@flexy2ky

I dont know it can be changed through custom script but I edited the attendance.py

I set IP restrictions to specific users to ensure they are only able to login from the office even though my setup is in GCP. This way their authentication is thrown out if they login from anywhere outside the office.

Ok,

I thought you had a way of restricting to a particular workshop

Hi can you point me to the location of this file? can’t seem to find it anywhere.

it is nothing but https://github.com/frappe/erpnext/blob/develop/erpnext/hr/doctype/attendance/attendance.py

Thanks. i found the file and added the custom status Out of Office:

However i still got validation issues:

Checking the validation script in attendance.py, i realized that the validation is sought from erpnext.controllers.status_updater so i located the file erpnext/controllers/status_updater.py and i checked through the script but i could not find the validation for attendance or any other HR validation controls. I have tried to figure out if there’s another status_updater controller that contains HR validation controls but so far i have been unsuccessful.

Appreciate your help on this.

did u restarted bench??

1 Like

My bad. I didn’t do that earlier. I just did and now it works!!! Thank you.

I however got the following errors on the attendance report:

Traceback (most recent call last):
File “/home/frappe/frappe-bench/apps/frappe/frappe/app.py”, line 62, in application
response = frappe.handler.handle()
File “/home/frappe/frappe-bench/apps/frappe/frappe/handler.py”, line 22, in handle
data = execute_cmd(cmd)
File “/home/frappe/frappe-bench/apps/frappe/frappe/handler.py”, line 53, in execute_cmd
return frappe.call(method, **frappe.form_dict)
File “/home/frappe/frappe-bench/apps/frappe/frappe/init.py”, line 939, in call
return fn(*args, **newargs)
File “/home/frappe/frappe-bench/apps/frappe/frappe/desk/query_report.py”, line 96, in run
res = frappe.get_attr(method_name)(frappe._dict(filters))
File “/home/frappe/frappe-bench/apps/erpnext/erpnext/hr/report/monthly_attendance_sheet/monthly_attendance_sheet.py”, line 41, in execute
row.append(status_map[status])
KeyError: u’Out of Office’

So i added the following values to monthly_attendance_sheet.py:

row = [emp, emp_det.employee_name, emp_det.branch, emp_det.department, emp_det.designation,
emp_det.company]
total_p = total_a = total_l = 0.0
for day in range(filters[“total_days_in_month”]):
status = att_map.get(emp).get(day + 1, “None”)
status_map = {“Present”: “P”, “Absent”: “A”, “Out of Office”: “OA”, “Half Day”: “HD”, "On $
if status == “None” and holiday_map:
emp_holiday_list = emp_det.holiday_list if emp_det.holiday_list else default_holid$
if emp_holiday_list in holiday_map and (day+1) in holiday_map[emp_holiday_list]:
status = “Holiday”
row.append(status_map[status])
if status == “Present”:
total_p += 1
elif status == “Absent”:
total_a += 1
elif status == “Out of Office”
total_oa += 1
elif status == “On Leave”:
total_l += 1
elif status == “Half Day”:
total_p += 0.5
total_a += 0.5
row += [total_p, total_l, total_a]
data.append(row)

and then i now have this error:

Seems as though the filter query for year has been altered as i can no longer select the year filter. i have checked everything else and nothing seems amiss and i did not alter any other script.

I also noticed that the attendance doctype does not automatically register employees whose leave application have been approved. They still need to manually enter their attendance and select leave for their attendance to be registered.

@hereabdulla , after much investigation and unable to find the source of the issue, i had a do-over: i reverted the changes and modified both attendance.py

def validate(self):
from erpnext.controllers.status_updater import validate_status
validate_status(self.status, [“Present”, “Absent”, “Out of Office”, “On Leave”, “Half Day”])
self.validate_attendance_date()
self.validate_duplicate_record()
self.check_leave_record()

and monthly_attendance_sheet.py

row = [emp, emp_det.employee_name, emp_det.branch, emp_det.department, emp_det.designation,
emp_det.company]
total_p = total_a = total_l = 0.0
for day in range(filters[“total_days_in_month”]):
status = att_map.get(emp).get(day + 1, “None”)
status_map = {“Present”: “P”, “Absent”: “A”, “Out of Office”: “OA”, “Half Day”: “HD”, "On $
if status == “None” and holiday_map:
emp_holiday_list = emp_det.holiday_list if emp_det.holiday_list else default_holid$
if emp_holiday_list in holiday_map and (day+1) in holiday_map[emp_holiday_list]:
status = “Holiday”
row.append(status_map[status])
if status == “Present”:
total_p += 1
elif status == “Absent”:
total_a += 1
elif status == “Out of Office”:
total_p += 1
elif status == “On Leave”:
total_l += 1
elif status == “Half Day”:
total_p += 0.5
total_a += 0.5
row += [total_p, total_l, total_a]
data.append(row)

def get_columns(filters):
columns = [
_(“Employee”) + “:Link/Employee:120”, _(“Employee Name”) + “::140”, _(“Branch”)+ ":Link/Branch:120$
_(“Department”) + “:Link/Department:120”, _(“Designation”) + “:Link/Designation:120”,
(“Company”) + “:Link/Company:120”
]
for day in range(filters[“total_days_in_month”]):
columns.append(cstr(day+1) +“::20”)
columns += [
(“Total Present”) + “:Float:80”, _(“Total Leaves”) + “:Float:80”, _(“Total Absent”) + “:Float:80”, _(“Total Out of Office”) + “:Float:80”]$
return columns

and i was able to validate the attendance status “Out of Office”:

and the monthly attendance report captured the attendance accordingly:

My issue has now been resolved as i have achieved the customization i wanted. It would however be nice if there’s a way for an approved leave day to automatically reflect on the attendance report.

7 Likes

This has now been achieved…Thanks to the devs who took notice. However, Casual leave doesn’t affect attendance entry. I have tried it for sick leave and it works. I don’t know what could be wrong there.

1 Like

Thank you, I followed your guide step by step and I achieved the customization

1 Like

Thanks, but how do i add time stamp at monthly attendance sheet?

Newbie here and I have been reading along with this customization you did for the attendance.
If you do version upgrades, will it be overwritten?
If yes is the answer then, what is the best way to customize doctypes?

1 Like

@irukandji Yes if you do version upgrades your customisation will be lost if it is a server-side customisation. best way to preserve your code is to do it in a custom app and use hooks.py to inject your code.

Watch the video below if you don’t know how to create custom apps:

1 Like

Then,how can we write the code to add to the attendance status and then inject it into hooks cause in order to add to the status, we had to edit both the attendance.py and monthly_attendance_sheet.py
So, how do we do that then.