diff --git a/attendance/admin.py b/attendance/admin.py index 67b561010..279a495b9 100644 --- a/attendance/admin.py +++ b/attendance/admin.py @@ -4,7 +4,6 @@ admin.py This page is used to register attendance models with admins site. """ -from django.apps import apps from django.contrib import admin from .models import ( diff --git a/attendance/apps.py b/attendance/apps.py index 392d772d3..aac5f595f 100644 --- a/attendance/apps.py +++ b/attendance/apps.py @@ -1,7 +1,18 @@ +""" +This module defines the configuration for the 'attendance' app within the Horilla HRMS project. +""" + from django.apps import AppConfig class AttendanceConfig(AppConfig): + """ + Configures the 'attendance' app and performs additional setup during the app's + initialization. This includes appending the 'attendance' URL patterns to the + project's main urlpatterns and dynamically adding the 'AttendanceMiddleware' + to the middleware stack if it's not already present. + """ + default_auto_field = "django.db.models.BigAutoField" name = "attendance" diff --git a/attendance/filters.py b/attendance/filters.py index fc135987a..8ab046a01 100644 --- a/attendance/filters.py +++ b/attendance/filters.py @@ -9,8 +9,6 @@ import uuid import django_filters from django import forms -from django.apps import apps -from django.db.models import OuterRef, Subquery from django.forms import DateTimeInput from django.utils.translation import gettext_lazy as _ @@ -416,6 +414,11 @@ class AttendanceFilters(FilterSet): ) def filter_pending_hour(self, queryset, name, value): + """ + This method calculates the pending hours for each attendance record in the + queryset and filters the records based on whether the pending hours are less + than or equal to (`pending_hour__lte`) or greater than the specified value. + """ if value is not None: value = strtime_seconds(value) filtered_attendance = [] @@ -484,12 +487,18 @@ class AttendanceFilters(FilterSet): def filter_by_name(self, queryset, name, value): # Call the imported function + """ + This method allows filtering by the employee's first and/or last name or by other + fields such as day, shift, work type, department, job position, or company, depending + on the value of `search_field` provided in the request data. + """ filter_method = { "day": "attendance_day__day__icontains", "shift": "shift_id__employee_shift__icontains", "work_type": "work_type_id__work_type__icontains", "department": "employee_id__employee_work_info__department_id__department__icontains", - "job_position": "employee_id__employee_work_info__job_position_id__job_position__icontains", + "job_position": "employee_id__employee_work_info__\ + job_position_id__job_position__icontains", "company": "employee_id__employee_work_info__company_id__company__icontains", } search_field = self.data.get("search_field") diff --git a/attendance/forms.py b/attendance/forms.py index e61774663..6c57a533c 100644 --- a/attendance/forms.py +++ b/attendance/forms.py @@ -45,7 +45,6 @@ from attendance.models import ( AttendanceLateComeEarlyOut, AttendanceOverTime, AttendanceRequestComment, - AttendanceRequestFile, AttendanceValidationCondition, GraceTime, WorkRecords, @@ -53,9 +52,8 @@ from attendance.models import ( strtime_seconds, validate_time_format, ) -from base.forms import MultipleFileField from base.methods import get_working_days, reload_queryset -from base.models import Company, EmployeeShift +from base.models import Company from employee.filters import EmployeeFilter from employee.models import Employee from horilla import horilla_middlewares @@ -129,14 +127,14 @@ class ModelForm(forms.ModelForm): try: self.fields["employee_id"].initial = request.user.employee_get - except: + except Exception: pass try: self.fields["company_id"].initial = ( request.user.employee_get.get_company ) - except: + except Exception: pass @@ -371,7 +369,7 @@ class AttendanceForm(ModelForm): if existing_attendance.exists(): raise ValidationError( { - "employee_id": f"""Already attendance exists for {list(existing_attendance.values_list("employee_id__employee_first_name",flat=True))} employees""" + "employee_id": f"""Already attendance exists for{list(existing_attendance.values_list("employee_id__employee_first_name",flat=True))} employees""" } ) @@ -387,8 +385,9 @@ class AttendanceForm(ModelForm): if attendance is not None: raise ValidationError( _( - "Attendance for the date is already exist for %(emp)s" - % {"emp": emp} + ("Attendance for the date already exists for {emp}").format( + emp=emp + ) ) ) if employee.first() is None: @@ -752,6 +751,12 @@ excluded_fields = [ class AttendanceExportForm(forms.Form): + """ + This form allows users to choose which fields of the `Attendance` model + they want to include in the export excel file as column. The fields are + presented as a list of checkboxes, and the user can select multiple fields. + """ + model_fields = Attendance._meta.get_fields() field_choices = [ (field.name, field.verbose_name) @@ -778,6 +783,12 @@ class AttendanceExportForm(forms.Form): class LateComeEarlyOutExportForm(forms.Form): + """ + This form allows users to choose fields from both the `AttendanceLateComeEarlyOut` + model and the related `Attendance` model to include in the export excel file. + The fields are presented as checkboxes, and users can select multiple fields. + """ + model_fields = AttendanceLateComeEarlyOut._meta.get_fields() field_choices_1 = [ (field.name, field.verbose_name) @@ -808,6 +819,12 @@ class LateComeEarlyOutExportForm(forms.Form): class AttendanceActivityExportForm(forms.Form): + """ + This form allows users to choose specific fields from the `AttendanceActivity` + model to include in the export excel file. The fields are presented as checkboxes, + enabling users to select multiple fields. + """ + model_fields = AttendanceActivity._meta.get_fields() field_choices = [ (field.name, field.verbose_name) @@ -829,6 +846,12 @@ class AttendanceActivityExportForm(forms.Form): class AttendanceOverTimeExportForm(forms.Form): + """ + This form allows users to choose specific fields from the `AttendanceOverTime` + model to include in the export. The fields are presented as checkboxes, + enabling users to select multiple fields. + """ + model_fields = AttendanceOverTime._meta.get_fields() field_choices = [ (field.name, field.verbose_name) @@ -855,6 +878,10 @@ class GraceTimeForm(ModelForm): """ class Meta: + """ + Meta class for additional options + """ + model = GraceTime fields = "__all__" widgets = { @@ -1063,7 +1090,6 @@ class BulkAttendanceRequestForm(ModelForm): "attendance_date": date, "attendance_clock_in_date": date, "attendance_clock_out_date": date, - "attendance_clock_in_date": date, } ) form = NewRequestForm(data=initial_data) diff --git a/attendance/middleware.py b/attendance/middleware.py index a129f1db6..dc933678a 100644 --- a/attendance/middleware.py +++ b/attendance/middleware.py @@ -1,3 +1,7 @@ +""" +Middleware to automatically trigger employee clock-out based on shift schedules +""" + from datetime import datetime, timedelta from django.utils import timezone @@ -7,10 +11,25 @@ from attendance.methods.utils import Request class AttendanceMiddleware(MiddlewareMixin): + """ + This middleware checks for employees who haven't clocked out by the end of their + scheduled shift and automatically performs the clock-out action if the auto punch-out + is enabled for their shift. It processes this during each request. + """ + def process_request(self, request): + """ + Triggers the `trigger_function` on each request. + """ self.trigger_function() def trigger_function(self): + """ + Retrieves shift schedules with auto punch-out enabled and checks if there are + any attendance activities that haven't been clocked out. If the scheduled + auto punch-out time has passed, the function attempts to clock out the employee + automatically by invoking the `clock_out` function. + """ from attendance.models import Attendance, AttendanceActivity from attendance.views.clock_in_out import clock_out from base.models import EmployeeShiftSchedule diff --git a/attendance/models.py b/attendance/models.py index be10a3741..72dbfdc11 100644 --- a/attendance/models.py +++ b/attendance/models.py @@ -8,15 +8,13 @@ This module is used to register models for recruitment app import contextlib import datetime as dt import json -from collections.abc import Iterable from datetime import date, datetime, timedelta -import pandas as pd from django.apps import apps from django.core.exceptions import ValidationError from django.db import models from django.db.models import Q -from django.db.models.signals import post_save, pre_delete, pre_save +from django.db.models.signals import post_save, pre_delete from django.dispatch import receiver from django.utils import timezone from django.utils.translation import gettext_lazy as _ @@ -29,7 +27,6 @@ from attendance.methods.utils import ( strtime_seconds, validate_hh_mm_ss_format, validate_time_format, - validate_time_in_minutes, ) from base.horilla_company_manager import HorillaCompanyManager from base.methods import is_company_leave, is_holiday @@ -264,9 +261,8 @@ class Attendance(HorillaModel): pending_seconds = minimum_hours - worked_hour if pending_seconds < 0: return "00:00" - else: - pending_hours = format_time(pending_seconds) - return pending_hours + pending_hours = format_time(pending_seconds) + return pending_hours def save(self, *args, **kwargs): minimum_hour = self.minimum_hour @@ -300,12 +296,14 @@ class Attendance(HorillaModel): leaves.append(current_date.strftime("%Y-%m-%d")) current_date += timedelta(days=1) - # Checking attendance date is in holiday list, if found making the minimum hour to 00:00 + # Checking attendance date is in holiday list, + # if found making the minimum hour to 00:00 if is_holiday(self.attendance_date): self.minimum_hour = "00:00" self.is_holiday = True - # Checking attendance date is in company leave list, if found making the minimum hour to 00:00 + # Checking attendance date is in company leave list, + # if found making the minimum hour to 00:00 if is_company_leave(self.attendance_date): self.minimum_hour = "00:00" self.is_holiday = True diff --git a/attendance/sidebar.py b/attendance/sidebar.py index ef4566d86..2cfddda3c 100644 --- a/attendance/sidebar.py +++ b/attendance/sidebar.py @@ -4,7 +4,6 @@ attendance/sidebar.py from datetime import datetime -from django.apps import apps from django.urls import reverse from django.utils.translation import gettext_lazy as trans @@ -57,27 +56,42 @@ SUBMENUS = [ def attendances_accessibility(request, submenu, user_perms, *args, **kwargs): + """ + Check if the user has permission to view attendance or is a reporting manager. + """ return request.user.has_perm("attendance.view_attendance") or is_reportingmanager( request.user ) def hour_account_accessibility(request, submenu, user_perms, *args, **kwargs): + """ + Modify the submenu redirect URL to include the current year as a query parameter. + """ submenu["redirect"] = submenu["redirect"] + f"?year={datetime.now().year}" return True def work_record_accessibility(request, submenu, user_perms, *args, **kwargs): + """ + Check if the user has permission to view attendance or is a reporting manager. + """ return request.user.has_perm("attendance.view_attendance") or is_reportingmanager( request.user ) def dashboard_accessibility(request, submenu, user_perms, *args, **kwargs): + """ + Check if the user has permission to view attendance or is a reporting manager. + """ return request.user.has_perm("attendance.view_attendance") or is_reportingmanager( request.user ) def tracking_accessibility(request, submenu, user_perms, *args, **kwargs): + """ + Determine if late come/early out tracking is enabled. + """ return enable_late_come_early_out_tracking(None).get("tracking") diff --git a/attendance/templates/attendance/attendance/attendance_nav.html b/attendance/templates/attendance/attendance/attendance_nav.html index 2de937bf6..39dbc01ed 100644 --- a/attendance/templates/attendance/attendance/attendance_nav.html +++ b/attendance/templates/attendance/attendance/attendance_nav.html @@ -308,6 +308,7 @@ {% trans "Delete" %} diff --git a/attendance/templates/attendance/attendance_account/nav.html b/attendance/templates/attendance/attendance_account/nav.html index 477ffff4e..152707260 100644 --- a/attendance/templates/attendance/attendance_account/nav.html +++ b/attendance/templates/attendance/attendance_account/nav.html @@ -135,6 +135,7 @@ {% trans "Delete" %} diff --git a/attendance/templates/attendance/attendance_activity/nav.html b/attendance/templates/attendance/attendance_activity/nav.html index 8fe236358..670d6aba7 100644 --- a/attendance/templates/attendance/attendance_activity/nav.html +++ b/attendance/templates/attendance/attendance_activity/nav.html @@ -84,7 +84,7 @@ {% endif %} {% if perms.attendance.delete_attendanceactivity %}
  • - {% trans "Delete" %}
  • {% endif %} diff --git a/attendance/templates/attendance/late_come_early_out/nav.html b/attendance/templates/attendance/late_come_early_out/nav.html index c0e58e588..2350ca390 100644 --- a/attendance/templates/attendance/late_come_early_out/nav.html +++ b/attendance/templates/attendance/late_come_early_out/nav.html @@ -76,7 +76,7 @@ {% endif %} {% if perms.attendance.delete_attendancelatecomeearlyout %}
  • - {% trans "Delete" %} + {% trans "Delete" %}
  • {% endif %} diff --git a/attendance/urls.py b/attendance/urls.py index e82eae859..2fbb8be0a 100644 --- a/attendance/urls.py +++ b/attendance/urls.py @@ -5,7 +5,6 @@ This page is used to map request or url path with function """ -from django.apps import apps from django.urls import path import attendance.views.clock_in_out