-
-
-
-
- {% if on_time < late_come %}
-
- {% else %}
-
- {% endif %}
-
-
{{on_time}}
+
+
+
+
+
+
+
+
+ {{marked_attendances_ratio}}%
+
+
{{marked_attendances}}/{{expected_attendances}}
+
+
-
{{on_time_ratio}}%
-
-
-
-
-
-
-
-
- {% comment %}
100% {% endcomment %}
-
{{marked_attendances_ratio}}%
+
+
+
+
+
+
+ {% if on_time < late_come %}
+
+ {% else %}
+
+ {% endif %}
+
+ {{on_time}}
+
+
{{on_time_ratio}}%
+
+
-
{{marked_attendances}}/{{expected_attendances}}
-
-
-
-
-
-
-
-
-
- {% if late_come < on_time %}
-
- {% else %}
-
- {% endif %}
-
-
-
{{late_come}}
+
+
+
+
+
+
+ {% if late_come < on_time %}
+
+ {% else %}
+
+ {% endif %}
+
+ {{late_come}}
+
+
{{late_come_ratio}}%
+
+
-
{{late_come_ratio}}%
+
+
-
-
-
-
-
-
-
-
-
-

-
-
- Birthday
- Katie Melua
- 29/03/2023
-
-
-
-
-
-

-
-
-
- Birthday
- Katie Melua
- 29/03/2023
-
-
-
-
-
-

-
-
- Birthday
- Katie Melua
- 29/03/2023
-
-
-
-
-
-
-
-
-
-
-
- {% for emp in on_break %}
- -
-
-
-

-
-
{{emp.employee_id}}
+
+
+
-
- {% endfor %}
-
-
-
-
+
+ {% include "dashboard/not_in_yet.html" %}
+
+
+
+
-
+
+
+
+
+
+
+
+ {% if on_break %}
+
+ {% for emp in on_break %}
+ -
+
+
+

+
+
{{emp.employee_id}}
+
+
+ {% endfor %}
+
+ {% else %}
+
+
+

+
{% trans "No employees on Break...." %}
+
+
+ {% endif %}
+
+
+
+
+
+
+
+ {% include "attendance/dashboard/overtime_table.html" %}
+
+
+
+
+
+
+
+ {% include "attendance/dashboard/to_validate_table.html" %}
+
+
+
-
-
+
+
-
+
- {% endblock content %}
\ No newline at end of file
+{% endblock content %}
diff --git a/attendance/templates/attendance/dashboard/overtime_table.html b/attendance/templates/attendance/dashboard/overtime_table.html
new file mode 100644
index 000000000..1bd5df56f
--- /dev/null
+++ b/attendance/templates/attendance/dashboard/overtime_table.html
@@ -0,0 +1,92 @@
+{% load i18n %}
+{% if overtime_attendances %}
+
+
+
+
+
+ {% trans "Employee" %}
+
+
{% trans "Check-In" %}
+
+ {% trans "In Date" %}
+
+
{% trans "Check-Out" %}
+
+ {% trans "Out Date" %}
+
+
+ {% trans "Overtime" %}
+
+
+
+
+ {% for attendance in overtime_attendances %}
+
+
+
+
+
+

+
+
{{attendance.employee_id}}
+
+
+
+ {{attendance.attendance_clock_in}}
+
+
+ {{attendance.attendance_clock_in_date}}
+
+
+ {{attendance.attendance_clock_out}}
+
+
+ {{attendance.attendance_clock_out_date}}
+
+
+ {{attendance.attendance_overtime}}
+
+
+
+
+ {% endfor %}
+
+
+{% else %}
+
+
+

+
{% trans "No Overtime to Validate...." %}
+
+
+{% endif %}
\ No newline at end of file
diff --git a/attendance/templates/attendance/dashboard/to_validate_table.html b/attendance/templates/attendance/dashboard/to_validate_table.html
new file mode 100644
index 000000000..f02471f2f
--- /dev/null
+++ b/attendance/templates/attendance/dashboard/to_validate_table.html
@@ -0,0 +1,142 @@
+{% load i18n %}
+
+
+
+ {% if validate_attendances %}
+
+
+
+
+
+ {% trans "Employee" %}
+
+
+ {% trans "Date" %}
+
+
{% trans "Check-In" %}
+
+ {% trans "In Date" %}
+
+
{% trans "Check-Out" %}
+
+ {% trans "Out Date" %}
+
+
{% trans "Shift" %}
+
{% trans "Work Type" %}
+
{% trans "Min Hour" %}
+
+ {% trans "At Work" %}
+
+
+ {% trans "Pending Hour" %}
+
+
+
+
+ {% for attendance in validate_attendances %}
+
+
+
+
+
+
+

+
+
{{attendance.employee_id}}
+
+
+
{{attendance.attendance_date}}
+
+ {{attendance.attendance_clock_in}}
+
+
+ {{attendance.attendance_clock_in_date}}
+
+
+ {{attendance.attendance_clock_out}}
+
+
+ {{attendance.attendance_clock_out_date}}
+
+
{{attendance.shift_id}}
+
{{attendance.work_type_id}}
+
{{attendance.minimum_hour}}
+
+ {{attendance.attendance_worked_hour}}
+
+
{{attendance.hours_pending}}
+
+
+
+
+ {% endfor %}
+
+
+
+ {% else %}
+
+
+

+
{% trans "All Attendance Validated." %}
+
+
+ {% endif %}
+
+
\ No newline at end of file
diff --git a/attendance/views/dashboard.py b/attendance/views/dashboard.py
index 588b7af50..ef6386c19 100644
--- a/attendance/views/dashboard.py
+++ b/attendance/views/dashboard.py
@@ -15,11 +15,14 @@ from attendance.filters import (
LateComeEarlyOutFilter,
AttendanceOverTimeFilter,
)
-from attendance.models import Attendance, AttendanceLateComeEarlyOut, AttendanceOverTime
+from attendance.models import Attendance, AttendanceLateComeEarlyOut, AttendanceOverTime, AttendanceValidationCondition
+from attendance.views.views import strtime_seconds
from base.methods import filtersubordinates
from base.models import Department, EmployeeShiftSchedule
from employee.models import Employee
+from employee.not_in_out_dashboard import paginator_qry
from horilla.decorators import login_required
+from leave.models import LeaveRequest
def find_on_time(request, today, week_day, department=None):
@@ -29,22 +32,12 @@ def find_on_time(request, today, week_day, department=None):
on_time = 0
attendances = Attendance.objects.filter(attendance_date=today)
- attendances = filtersubordinates(request, attendances, "attendance.view_attendance")
if department is not None:
attendances = attendances.filter(
employee_id__employee_work_info__department_id=department
)
- excepted_attendances = 0
- for attendance in attendances:
- shift = attendance.shift_id
- schedules_today = shift.employeeshiftschedule_set.filter(day__day=week_day)
- if schedules_today.first() is not None:
- excepted_attendances = excepted_attendances + 1
- late_come_obj = attendance.late_come_early_out.filter(
- type="late_come"
- ).first()
- if late_come_obj is None:
- on_time = on_time + 1
+ late_come = AttendanceLateComeEarlyOut.objects.filter(attendance_id__attendance_date=today,type="late_come")
+ on_time = len(attendances) - len(late_come)
return on_time
@@ -52,13 +45,9 @@ def find_expected_attendances(week_day):
"""
This method is used to find count of expected attendances for the week day
"""
- schedules_today = EmployeeShiftSchedule.objects.filter(day__day=week_day)
- expected_attendances = 0
- for schedule in schedules_today:
- shift = schedule.shift_id
- expected_attendances = expected_attendances + len(
- shift.employeeworkinformation_set.all()
- )
+ employees = Employee.objects.filter(is_active=True)
+ on_leave = LeaveRequest.objects.filter(status = "Approved")
+ expected_attendances = len(employees) - len(on_leave)
return expected_attendances
@@ -67,6 +56,8 @@ def dashboard(request):
"""
This method is used to render individual dashboard for attendance module
"""
+ page_number = request.GET.get("page")
+ previous_data = request.GET.urlencode()
employees = Employee.objects.filter(
is_active=True,
).filter(~Q(employee_work_info__shift_id=None))
@@ -76,7 +67,8 @@ def dashboard(request):
week_day = today.strftime("%A").lower()
on_time = find_on_time(request, today=today, week_day=week_day)
- late_come_obj = find_late_come(start_date=today)
+ late_come = find_late_come(start_date=today)
+ late_come_obj = len(late_come)
marked_attendances = late_come_obj + on_time
@@ -85,15 +77,30 @@ def dashboard(request):
late_come_ratio = 0
marked_attendances_ratio = 0
if expected_attendances != 0:
- on_time_ratio = f"{(on_time / expected_attendances) * 100:.1f}"
- late_come_ratio = f"{(late_come_obj / expected_attendances) * 100:.1f}"
+ on_time_ratio = f"{(on_time / expected_attendances) * 100:.2f}"
+ late_come_ratio = f"{(late_come_obj / expected_attendances) * 100:.2f}"
marked_attendances_ratio = (
- f"{(marked_attendances / expected_attendances) * 100:.1f}"
+ f"{(marked_attendances / expected_attendances) * 100:.2f}"
)
early_outs = AttendanceLateComeEarlyOut.objects.filter(
type="early_out", attendance_id__attendance_date=today
)
+ condition = AttendanceValidationCondition.objects.first()
+ min_ot = strtime_seconds("00:00")
+ if condition is not None and condition.minimum_overtime_to_approve is not None:
+ min_ot = strtime_seconds(condition.minimum_overtime_to_approve)
+ ot_attendances = Attendance.objects.filter(
+ overtime_second__gte=min_ot,
+ attendance_validated=True,
+ employee_id__is_active=True,
+ attendance_overtime_approve =False,
+ )
+
+ validate_attendances = Attendance.objects.filter(
+ attendance_validated=False, employee_id__is_active=True
+ )
+
return render(
request,
"attendance/dashboard/dashboard.html",
@@ -107,9 +114,30 @@ def dashboard(request):
"marked_attendances": marked_attendances,
"marked_attendances_ratio": marked_attendances_ratio,
"on_break": early_outs,
+ "overtime_attendances": ot_attendances,
+ "validate_attendances": paginator_qry(validate_attendances, page_number),
+ "pd": previous_data,
},
)
+@login_required
+def validated_attendances_table(request):
+ page_number = request.GET.get("page")
+ previous_data = request.GET.urlencode()
+ validate_attendances = Attendance.objects.filter(
+ attendance_validated=False, employee_id__is_active=True
+ )
+ context = {
+ "validate_attendances": paginator_qry(validate_attendances, page_number),
+ "pd": previous_data,
+ }
+
+ return render(
+ request,
+ "attendance/dashboard/to_validate_table.html",
+ context
+ )
+
def total_attendance(start_date, department, end_date=None):
"""
@@ -138,6 +166,14 @@ def find_late_come(start_date, department=None, end_date=None):
"attendance_date__lte": end_date,
}
).qs
+ else:
+ late_come_obj = LateComeEarlyOutFilter(
+ {
+ "type": "late_come",
+ "attendance_date__gte": start_date,
+ "attendance_date__lte": end_date,
+ }
+ ).qs
return late_come_obj
@@ -322,3 +358,79 @@ def pending_hours(request):
}
return JsonResponse({"data": data})
+
+
+@login_required
+def department_overtime_chart(request):
+ start_date = request.GET.get("date") if request.GET.get("date") else date.today()
+ chart_type = request.GET.get("type") if request.GET.get("type") else "day"
+ end_date = request.GET.get("end_date") if request.GET.get("end_date") else start_date
+
+ if chart_type == "day":
+ start_date = start_date
+ end_date = start_date
+ if chart_type == "weekly":
+ start_date, end_date = get_week_start_end_dates(start_date)
+ if chart_type == "monthly":
+ start_date, end_date = get_month_start_end_dates(start_date)
+ if chart_type == "date_range":
+ start_date = start_date
+ end_date = end_date
+
+ attendance = total_attendance(
+ start_date=start_date, department=None, end_date=end_date
+ )
+
+
+ condition = AttendanceValidationCondition.objects.first()
+ min_ot = strtime_seconds("00:00")
+ if condition is not None and condition.minimum_overtime_to_approve is not None:
+ min_ot = strtime_seconds(condition.minimum_overtime_to_approve)
+ attendances = attendance.filter(
+ overtime_second__gte=min_ot,
+ attendance_validated=True,
+ employee_id__is_active=True,
+ attendance_overtime_approve =True,
+ )
+ departments = []
+ department_total= []
+
+ for attendance in attendances:
+ departments.append(
+ attendance.employee_id.employee_work_info.department_id.department
+ )
+ departments = list(set(departments))
+
+ for depart in departments:
+ department_total.append({"department": depart, "ot_hours": 0})
+
+
+ for attendance in attendances:
+ if attendance.employee_id.employee_work_info.department_id:
+ department = attendance.employee_id.employee_work_info.department_id.department
+ ot = attendance.approved_overtime_second
+ ot_hrs = ot / 3600
+ for depart in department_total:
+ if depart["department"] == department:
+ depart["ot_hours"] += ot_hrs
+
+ dataset = [
+ {
+ "label": "",
+ "data": [],
+ }
+ ]
+
+ for depart_total, depart in zip(department_total, departments):
+ if depart == depart_total["department"]:
+ dataset[0]["data"].append(depart_total["ot_hours"])
+
+ response = {
+ "dataset": dataset,
+ "labels": departments,
+ "department_total": department_total,
+ "message": _("No validated Overtimes were found"),
+ "emptyImageSrc":"/static/images/ui/overtime-icon.png",
+ }
+
+ return JsonResponse(response)
\ No newline at end of file
diff --git a/employee/not_in_out_dashboard.py b/employee/not_in_out_dashboard.py
index 7150ee52b..064c6a546 100644
--- a/employee/not_in_out_dashboard.py
+++ b/employee/not_in_out_dashboard.py
@@ -15,6 +15,17 @@ from horilla.decorators import manager_can_enter, login_required
from horilla import settings
from employee.filters import EmployeeFilter
from recruitment.models import RecruitmentMailTemplate
+from django.core.paginator import Paginator
+
+
+
+def paginator_qry(qryset, page_number):
+ """
+ This method is used to paginate query set
+ """
+ paginator = Paginator(qryset, 20)
+ qryset = paginator.get_page(page_number)
+ return qryset
@login_required
@@ -24,12 +35,15 @@ def not_in_yet(request):
This context processor wil return the employees, if they not marked the attendance
for the day
"""
+ page_number = request.GET.get("page")
+ previous_data = request.GET.urlencode()
emps = (
EmployeeFilter({"not_in_yet": date.today()})
.qs.exclude(employee_work_info__isnull=True)
.filter(is_active=True)
)
- return render(request, "dashboard/not_in_yet.html", {"employees": emps})
+
+ return render(request, "dashboard/not_in_yet.html", {"employees": paginator_qry(emps, page_number),"pd": previous_data,})
@login_required
diff --git a/employee/templates/dashboard/not_in_yet.html b/employee/templates/dashboard/not_in_yet.html
index 7a16654c1..267999482 100644
--- a/employee/templates/dashboard/not_in_yet.html
+++ b/employee/templates/dashboard/not_in_yet.html
@@ -1,10 +1,24 @@
{% load i18n %}
-
+
{% for emp in employees %}
diff --git a/static/images/ui/attendance-validate.png b/static/images/ui/attendance-validate.png
new file mode 100644
index 000000000..8090bced7
Binary files /dev/null and b/static/images/ui/attendance-validate.png differ
diff --git a/static/images/ui/coffee-break.png b/static/images/ui/coffee-break.png
new file mode 100644
index 000000000..aee150c2c
Binary files /dev/null and b/static/images/ui/coffee-break.png differ
diff --git a/static/images/ui/comment.png b/static/images/ui/comment.png
new file mode 100644
index 000000000..54f3ad364
Binary files /dev/null and b/static/images/ui/comment.png differ
diff --git a/static/images/ui/overtime-icon.png b/static/images/ui/overtime-icon.png
new file mode 100644
index 000000000..30e15900a
Binary files /dev/null and b/static/images/ui/overtime-icon.png differ
diff --git a/templates/dashboard.html b/templates/dashboard.html
index bd9e7a05b..3ca455dce 100755
--- a/templates/dashboard.html
+++ b/templates/dashboard.html
@@ -51,7 +51,7 @@
>
-
+
{% if perms.employee.view_employee %}
@@ -144,7 +144,7 @@
{% if perms.candidate.view_employee or request.user|is_reportingmanager %}
@@ -326,7 +326,7 @@
style="width: 100px; color: #5e5c5c"
/>
-
+
{% endif %}
+
+ {% if perms.base.change_shiftrequest or request.user|is_reportingmanager %}
+
+
+
+
+ {% include "request_and_approve/shift_request.html" %}
+
+
+
+ {% endif %}
+ {% if perms.base.change_shiftrequest or request.user|is_reportingmanager %}
+
+
+
+
+ {% include "request_and_approve/work_type_request.html" %}
+
+
+
+ {% endif %}
@@ -539,6 +590,32 @@
+
+
diff --git a/templates/sidebar.html b/templates/sidebar.html
index 1ee3fc5de..f42c8a64e 100755
--- a/templates/sidebar.html
+++ b/templates/sidebar.html
@@ -399,6 +399,11 @@
>
{% endif %}
+
{% if perms.payroll.view_filingstatus %}
+