""" filters.py This page is used to register filter for employee models """ import datetime import uuid import django import django_filters from django import forms from django.utils.translation import gettext as _ from django_filters import CharFilter # from attendance.models import Attendance from employee.models import DisciplinaryAction, Employee, Policy from horilla.filters import FilterSet, filter_by_name from horilla_documents.models import Document class EmployeeFilter(FilterSet): """ Filter set class for Candidate model Args: FilterSet (class): custom filter set class to apply styling """ search = django_filters.CharFilter(method="filter_by_name") selected_search_field = django_filters.ChoiceFilter( label="Search Field", choices=[ ("employee", _("Search in : Employee")), ("reporting_manager", _("Search in : Reporting manager")), ("department", _("Search in : Department")), ("job_position", _("Search in : Job Position")), ], method="filter_by_name_and_field", widget=forms.Select( attrs={ "size": 4, "class": "oh-input__icon", "style": "border: none; overflow: hidden; display: flex; position: absolute; z-index: 999; margin-left:8%;", "onclick": "$('.filterButton')[0].click();", } ), ) employee_first_name = django_filters.CharFilter(lookup_expr="icontains") employee_last_name = django_filters.CharFilter(lookup_expr="icontains") country = django_filters.CharFilter(lookup_expr="icontains") department = django_filters.CharFilter( field_name="employee_work_info__department_id__department", lookup_expr="icontains", ) is_active = django_filters.ChoiceFilter( field_name="is_active", label="Is Active", choices=[ (True, "Yes"), (False, "No"), ], ) working_today = django_filters.BooleanFilter( label="Working", method="get_working_today" ) not_in_yet = django_filters.DateFilter( method="not_in_yet_func", widget=forms.DateInput(attrs={"type": "date"}), ) not_out_yet = django_filters.DateFilter( method="not_out_yet_func", widget=forms.DateInput(attrs={"type": "date"}), ) class Meta: """ Meta class to add the additional info """ model = Employee fields = [ "employee_first_name", "employee_last_name", "email", "badge_id", "phone", "country", "gender", "is_active", "employee_work_info__job_position_id", "employee_work_info__department_id", "department", "employee_work_info__work_type_id", "employee_work_info__employee_type_id", "employee_work_info__job_role_id", "employee_work_info__reporting_manager_id", "employee_work_info__company_id", "employee_work_info__shift_id", "employee_work_info__tags", "employee_user_id__groups", "employee_user_id__user_permissions", ] def not_in_yet_func(self, queryset, _, value): """ The method to filter out the not check-in yet employees """ # Getting the queryset for those employees dont have any attendance for the date # in value. queryset1 = queryset.exclude( employee_attendances__attendance_date=value, ) queryset2 = queryset.filter( employee_attendances__attendance_date=value, employee_attendances__attendance_clock_out__isnull=False, ) queryset = (queryset1 | queryset2).distinct() return queryset def not_out_yet_func(self, queryset, _, value): """ The method to filter out the not check-in yet employees """ # Getting the queryset for those employees dont have any attendance for the date # in value. queryset = queryset.filter( employee_attendances__attendance_date=value, employee_attendances__attendance_clock_out__isnull=True, ) return queryset def filter_queryset(self, queryset): """ Override the default filtering behavior to handle None option. """ from django.db.models import Q data = self.form.cleaned_data not_set_dict = {} for key, value in data.items(): if isinstance(value, (list, django.db.models.query.QuerySet)): if value and "not_set" in value: not_set_dict[key] = value if not_set_dict: q_objects = Q() for key, values in not_set_dict.items(): for value in values: if value == "not_set": q_objects |= Q(**{f"{key}__isnull": True}) else: q_objects |= Q(**{key: value}) return queryset.filter(q_objects) return super().filter_queryset(queryset) # Continue with the default behavior for other filters def get_working_today(self, queryset, _, value): today = datetime.datetime.now().date() yesterday = today - datetime.timedelta(days=1) # working_employees = Attendance.objects.filter( # attendance_date__gte=yesterday, # attendance_date__lte=today, # attendance_clock_out_date__isnull=True, # ).values_list("employee_id", flat=True) working_employees = [] if value: queryset = queryset.filter(id__in=working_employees) else: queryset = queryset.exclude(id__in=working_employees) return queryset def filter_by_name(self, queryset, _, value): """ Filter queryset by first name or last name. """ filter_method = { "department": "employee_work_info__department_id__department__icontains", "job_position": "employee_work_info__job_position_id__job_position__icontains", "job_role": "employee_work_info__job_role_id__job_role__icontains", "shift": "employee_work_info__shift_id__employee_shift__icontains", "work_type": "employee_work_info__work_type_id__work_type__icontains", "company": "employee_work_info__company_id__company__icontains", } search_field = self.data.get("search_field") # Split the search value into first name and last name if not search_field: parts = value.split() first_name = parts[0] last_name = " ".join(parts[1:]) if len(parts) > 1 else "" # Filter the queryset by first name and last name if first_name and last_name: queryset = queryset.filter( employee_first_name__icontains=first_name, employee_last_name__icontains=last_name, ) elif first_name: queryset = queryset.filter(employee_first_name__icontains=first_name) elif last_name: queryset = queryset.filter(employee_last_name__icontains=last_name) else: if search_field == "reporting_manager": parts = value.split() first_name = parts[0] last_name = " ".join(parts[1:]) if len(parts) > 1 else "" if first_name and last_name: queryset = queryset.filter( employee_work_info__reporting_manager_id__employee_first_name__icontains=first_name, employee_work_info__reporting_manager_id__employee_last_name__icontains=last_name, ) elif first_name: queryset = queryset.filter( employee_work_info__reporting_manager_id__employee_first_name__icontains=first_name ) elif last_name: queryset = queryset.filter( employee_work_info__reporting_manager_id__employee_last_name__icontains=last_name ) else: filter = filter_method.get(search_field) queryset = queryset.filter(**{filter: value}) return queryset def __init__(self, data=None, queryset=None, *, request=None, prefix=None): super().__init__(data=data, queryset=queryset, request=request, prefix=prefix) self.form.fields["is_active"].initial = True self.form.fields["email"].widget.attrs["autocomplete"] = "email" self.form.fields["phone"].widget.attrs["autocomplete"] = "phone" self.form.fields["country"].widget.attrs["autocomplete"] = "country" for field in self.form.fields.keys(): self.form.fields[field].widget.attrs["id"] = f"{uuid.uuid4()}" self.model_choice_filters = [ filter for filter in self.filters.values() if isinstance(filter, django_filters.ModelMultipleChoiceFilter) ] for model_choice_filter in self.model_choice_filters: queryset = ( model_choice_filter.queryset.filter(is_active=True) if model_choice_filter.queryset.model == Employee else model_choice_filter.queryset ) choices = [ ("not_set", _("Not Set")), ] choices.extend([(obj.id, str(obj)) for obj in queryset]) self.form.fields[model_choice_filter.field_name] = ( forms.MultipleChoiceField( choices=choices, required=False, widget=forms.SelectMultiple( attrs={ "class": "oh-select oh-select-2 select2-hidden-accessible", "id": uuid.uuid4(), } ), ) ) class EmployeeReGroup: """ Class to keep the field name for group by option """ fields = [ ("", "select"), ("employee_work_info__job_position_id", "Job Position"), ("employee_work_info__department_id", "Department"), ("employee_work_info__shift_id", "Shift"), ("employee_work_info__work_type_id", "Work Type"), ("employee_work_info__job_role_id", "Job Role"), ("employee_work_info__reporting_manager_id", "Reporting Manager"), ("employee_work_info__company_id", "Company"), ] class PolicyFilter(FilterSet): """ PolicyFilter filterset class """ search = django_filters.CharFilter(field_name="title", lookup_expr="icontains") class Meta: model = Policy fields = "__all__" class DocumentRequestFilter(FilterSet): """ Custom filter for Document Requests. """ search = CharFilter(field_name="title", lookup_expr="icontains") class Meta: """ A nested class that specifies the model and fields for the filter. """ model = Document fields = [ "employee_id", "document_request_id", "status", "employee_id__employee_first_name", "employee_id__employee_last_name", "employee_id__is_active", "employee_id__gender", "employee_id__employee_work_info__job_position_id", "employee_id__employee_work_info__department_id", "employee_id__employee_work_info__work_type_id", "employee_id__employee_work_info__employee_type_id", "employee_id__employee_work_info__job_role_id", "employee_id__employee_work_info__reporting_manager_id", "employee_id__employee_work_info__company_id", "employee_id__employee_work_info__shift_id", ] class DisciplinaryActionFilter(FilterSet): """ Custom filter for Disciplinary Action. """ search = CharFilter(method=filter_by_name) start_date = django_filters.DateFilter( widget=forms.DateInput(attrs={"type": "date"}), ) class Meta: model = DisciplinaryAction ordering = ["-id"] fields = [ "employee_id", "action", "employee_id__employee_work_info__job_position_id", "employee_id__employee_work_info__department_id", "employee_id__employee_work_info__work_type_id", "employee_id__employee_work_info__job_role_id", "employee_id__employee_work_info__reporting_manager_id", "employee_id__employee_work_info__company_id", "employee_id__employee_work_info__shift_id", ]