Files
ihrm/pms/filters.py
2025-09-16 10:40:27 +05:30

515 lines
16 KiB
Python

"""
Module: filters.py
This module contains custom Django filters and filter sets for
the PMS (Performance Management System) app.
"""
import datetime
import django
import django_filters
from django import forms
from django_filters import DateFilter
from base.filters import FilterSet
from base.methods import reload_queryset
from pms.models import (
AnonymousFeedback,
BonusPointSetting,
EmployeeBonusPoint,
EmployeeKeyResult,
EmployeeObjective,
Feedback,
KeyResult,
Meetings,
Objective,
)
class DateRangeFilter(django_filters.Filter):
"""
A custom Django filter for filtering querysets based on date ranges.
This filter allows you to filter a queryset based on date ranges such as 'today',
'yesterday', 'week', or 'month' in the 'created_at' field of model.
"""
def filter(self, qs, value):
if value:
if value == "today":
today = datetime.datetime.now().date()
formatted_date = today.strftime("%Y-%m-%d")
qs = qs.filter(created_at__startswith=formatted_date)
if value == "yesterday":
today = datetime.date.today()
yesterday = today - datetime.timedelta(days=1)
formatted_date = yesterday.strftime("%Y-%m-%d")
qs = qs.filter(created_at__startswith=formatted_date)
if value == "week":
today = datetime.date.today()
start_of_week = today - datetime.timedelta(days=today.weekday())
end_of_week = start_of_week + datetime.timedelta(days=6)
qs = qs.filter(created_at__range=[start_of_week, end_of_week])
elif value == "month":
today = datetime.date.today()
start_of_month = datetime.date(today.year, today.month, 1)
end_of_month = start_of_month + datetime.timedelta(days=31)
qs = qs.filter(created_at__range=[start_of_month, end_of_month])
return qs
class CustomFilterSet(django_filters.FilterSet):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
reload_queryset(self.form.fields)
for field_name, field in self.form.fields.items():
filter_widget = self.filters[field_name]
widget = filter_widget.field.widget
if isinstance(
widget, (forms.NumberInput, forms.EmailInput, forms.TextInput)
):
field.widget.attrs.update({"class": "oh-input w-100"})
elif isinstance(widget, (forms.Select,)):
field.widget.attrs.update(
{
"class": "oh-select oh-select-2",
}
)
elif isinstance(widget, (forms.Textarea)):
field.widget.attrs.update({"class": "oh-input w-100"})
elif isinstance(
widget,
(
forms.CheckboxInput,
forms.CheckboxSelectMultiple,
),
):
field.widget.attrs.update({"class": "oh-switch__checkbox"})
elif isinstance(widget, (forms.ModelChoiceField)):
field.widget.attrs.update(
{
"class": "oh-select oh-select-2",
}
)
if isinstance(field, django_filters.CharFilter):
field.lookup_expr = "icontains"
class ActualObjectiveFilter(FilterSet):
"""
ActualObjectiveFilter
"""
search = django_filters.CharFilter(method="search_method")
class Meta:
model = Objective
fields = [
"managers",
"archive",
"assignees",
"duration",
"employee_objective__key_result_id",
]
def search_method(self, queryset, _, value: str):
"""
This method is used to search employees and objective
"""
values = value.split(" ")
empty = queryset.model.objects.none()
for split in values:
empty = empty | (
queryset.filter(managers__employee_first_name__icontains=split)
| queryset.filter(managers__employee_last_name__icontains=split)
| queryset.filter(assignees__employee_first_name__icontains=split)
| queryset.filter(assignees__employee_last_name__icontains=split)
| queryset.filter(title__icontains=split)
)
return empty.distinct()
class ObjectiveFilter(CustomFilterSet):
"""
Custom filter set for EmployeeObjective records.
This filter set allows to filter EmployeeObjective records based on various criteria.
"""
employee_objective = django_filters.CharFilter(field_name="id")
employee_objective__key_result_id = django_filters.CharFilter(
field_name="key_result_id"
)
employee_objective__progress_percentage = django_filters.CharFilter(
field_name="progress_percentage"
)
managers = django_filters.CharFilter(field_name="objective_id__managers")
search = django_filters.CharFilter(method="search_method")
created_at_date_range = DateRangeFilter(field_name="created_at")
created_at = DateFilter(
widget=forms.DateInput(attrs={"type": "date", "class": "oh-input w-100"}),
# add lookup expression here
)
updated_at = DateFilter(
widget=forms.DateInput(attrs={"type": "date", "class": "oh-input w-100"}),
# add lookup expression here
)
start_date = DateFilter(
widget=forms.DateInput(attrs={"type": "date", "class": "oh-input w-100"}),
# add lookup expression here
)
end_date = DateFilter(
widget=forms.DateInput(attrs={"type": "date", "class": "oh-input w-100"}),
# add lookup expression here
)
class Meta:
"""
A nested class that specifies the model and fields for the filter.
"""
model = EmployeeObjective
fields = [
"objective",
"status",
"employee_id",
"created_at",
"start_date",
"updated_at",
"end_date",
"archive",
"objective_id",
]
def search_method(self, queryset, _, value: str):
"""
This method is used to search in managers and objective
"""
values = value.split(" ")
empty = queryset.model.objects.none()
for split in values:
empty = empty | (
queryset.filter(objective_id__title__icontains=split)
| queryset.filter(
objective_id__managers__employee_first_name__icontains=split
)
| queryset.filter(
objective_id__managers__employee_last_name__icontains=split
)
)
return empty
class FeedbackFilter(CustomFilterSet):
"""
Custom filter set for Feedback records.
This filter set allows to filter Feedback records based on various criteria.
"""
id = django_filters.NumberFilter(field_name="id", lookup_expr="exact") # 881
review_cycle = django_filters.CharFilter(lookup_expr="icontains")
created_at_date_range = DateRangeFilter(field_name="created_at")
start_date = DateFilter(
widget=forms.DateInput(attrs={"type": "date", "class": "oh-input w-100"}),
# add lookup expression here
)
end_date = DateFilter(
widget=forms.DateInput(attrs={"type": "date", "class": "oh-input w-100"}),
# add lookup expression here
)
class Meta:
"""
A nested class that specifies the model and fields for the filter.
"""
model = Feedback
fields = "__all__"
def __init__(self, data=None, queryset=None, *, request=None, prefix=None):
super(FeedbackFilter, self).__init__(
data=data, queryset=queryset, request=request, prefix=prefix
)
class AnonymousFeedbackFilter(django_filters.FilterSet):
"""
Custom filter set for AnonymousFeedback records.
This filter set allows to filter AnonymousFeedback records based on various criteria.
"""
created_at_date_range = DateRangeFilter(field_name="created_at")
start_date = django_filters.DateFilter(
field_name="created_at",
lookup_expr="gte",
widget=forms.DateInput(attrs={"type": "date"}),
)
end_date = django_filters.DateFilter(
field_name="created_at",
lookup_expr="lte",
widget=forms.DateInput(attrs={"type": "date"}),
)
class Meta:
"""
A nested class that specifies the model and fields for the filter.
"""
model = AnonymousFeedback
fields = "__all__"
class KeyResultFilter(CustomFilterSet):
class Meta:
model = EmployeeKeyResult
fields = "__all__"
class ActualKeyResultFilter(FilterSet):
"""
Filter through KeyResult model
"""
search = django_filters.CharFilter(method="search_method")
class Meta:
model = KeyResult
fields = ["progress_type", "target_value", "duration", "company_id"]
def search_method(self, queryset, _, value: str):
"""
This method is used to search employees and objective
"""
values = value.split(" ")
empty = queryset.model.objects.none()
for split in values:
empty = empty | (queryset.filter(title__icontains=split))
return empty.distinct()
class ObjectiveReGroup:
"""
Class to keep the field name for group by option
"""
fields = [
("", "select"),
("employee_id", "Owner"),
("status", "Status"),
]
class EmployeeObjectiveFilter(FilterSet):
"""
Filter through EmployeeObjective model
"""
search = django_filters.CharFilter(method="search_method")
start_date_from = django_filters.DateFilter(
field_name="start_date",
lookup_expr="gte",
widget=forms.DateInput(attrs={"type": "date"}),
)
start_date_till = django_filters.DateFilter(
field_name="start_date",
lookup_expr="lte",
widget=forms.DateInput(attrs={"type": "date"}),
)
end_date_from = django_filters.DateFilter(
field_name="end_date",
lookup_expr="gte",
widget=forms.DateInput(attrs={"type": "date"}),
)
end_date_till = django_filters.DateFilter(
field_name="end_date",
lookup_expr="lte",
widget=forms.DateInput(attrs={"type": "date"}),
)
class Meta:
model = EmployeeObjective
fields = [
"status",
"archive",
"key_result_id",
"start_date",
"end_date",
"employee_id",
]
def search_method(self, queryset, _, value: str):
"""
This method is used to search employees and objective
"""
values = value.split(" ")
empty = queryset.model.objects.none()
for split in values:
empty = (
empty
| (queryset.filter(employee_id__employee_first_name__icontains=split))
| (queryset.filter(employee_id__employee_last_name__icontains=split))
| (queryset.filter(objective__icontains=split))
)
return empty.distinct()
class MeetingsFilter(FilterSet):
search = django_filters.CharFilter(field_name="title", lookup_expr="icontains")
date = django_filters.DateFilter(
field_name="date",
lookup_expr="date",
widget=forms.DateInput(attrs={"type": "date"}),
)
date_greater = django_filters.DateFilter(
field_name="date",
lookup_expr="date__gte",
widget=forms.DateInput(attrs={"type": "date"}),
)
date_less = django_filters.DateFilter(
field_name="date",
lookup_expr="date__lte",
widget=forms.DateInput(attrs={"type": "date"}),
)
class Meta:
model = Meetings
fields = [
"employee_id",
"manager",
"question_template",
"is_active",
"employee_id__employee_work_info__department_id",
"employee_id__employee_work_info__company_id",
"employee_id__employee_work_info__job_position_id",
"employee_id__employee_work_info__work_type_id",
"employee_id__employee_work_info__shift_id",
"employee_id__employee_work_info__reporting_manager_id",
]
# def __init__(self, *args, **kwargs):
# super().__init__(*args, **kwargs)
# queryset = self.filters["question_template"].queryset
# choices = [
# ("not_set", "Not Set"),
# ]
# choices.extend([(obj.id, str(obj)) for obj in queryset])
# self.form.fields["question_template"] = (
# forms.MultipleChoiceField(
# choices=choices,
# required=False,
# widget=forms.SelectMultiple(
# attrs={
# "class": "oh-select oh-select-2",
# }
# ),
# )
# )
# 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)
class BonusPointSettingFilter(FilterSet):
"""
Filter through BonusPointSetting model
"""
# search = django_filters.CharFilter(method="search_method")
# start_date_from = django_filters.DateFilter(
# field_name="start_date",
# lookup_expr="gte",
# widget=forms.DateInput(attrs={"type": "date"}),
# )
# start_date_till = django_filters.DateFilter(
# field_name="start_date",
# lookup_expr="lte",
# widget=forms.DateInput(attrs={"type": "date"}),
# )
# end_date_from = django_filters.DateFilter(
# field_name="end_date",
# lookup_expr="gte",
# widget=forms.DateInput(attrs={"type": "date"}),
# )
# end_date_till = django_filters.DateFilter(
# field_name="end_date",
# lookup_expr="lte",
# widget=forms.DateInput(attrs={"type": "date"}),
# )
class Meta:
model = BonusPointSetting
fields = "__all__"
def search_method(self, queryset, _, value: str):
"""
This method is used to search employees and objective
"""
values = value.split(" ")
empty = queryset.model.objects.none()
for split in values:
empty = (
empty
| (queryset.filter(employee_id__employee_first_name__icontains=split))
| (queryset.filter(employee_id__employee_last_name__icontains=split))
)
return empty.distinct()
class EmployeeBonusPointFilter(FilterSet):
"""
Filter through BonusPointSetting model
"""
class Meta:
model = EmployeeBonusPoint
fields = "__all__"
def search_method(self, queryset, _, value: str):
"""
This method is used to search employees and objective
"""
values = value.split(" ")
empty = queryset.model.objects.none()
for split in values:
empty = (
empty
| (queryset.filter(employee_id__employee_first_name__icontains=split))
| (queryset.filter(employee_id__employee_last_name__icontains=split))
)
return empty.distinct()