""" Module containing custom filter classes for various models. """ import uuid import django_filters from django import forms from django.db.models import Q from django_filters import FilterSet from base.methods import reload_queryset from .models import Asset, AssetAssignment, AssetCategory, AssetRequest class CustomFilterSet(FilterSet): """ Custom FilterSet class that applies specific CSS classes to filter widgets. The class applies CSS classes to different types of filter widgets, such as NumberInput, EmailInput, TextInput, Select, Textarea, CheckboxInput, CheckboxSelectMultiple, and ModelChoiceField. The CSS classes are applied to enhance the styling and behavior of the filter widgets. """ 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, ), ): filter_widget.field.widget.attrs.update( {"class": "oh-switch__checkbox"} ) elif isinstance(widget, (forms.ModelChoiceField)): field.widget.attrs.update( { "class": "oh-select oh-select-2 ", } ) elif isinstance(widget, (forms.DateField)): field.widget.attrs.update({"type": "date", "class": "oh-input w-100"}) if isinstance(field, django_filters.CharFilter): field.lookup_expr = "icontains" class AssetExportFilter(CustomFilterSet): """ Custom filter class for exporting filtered Asset data. """ class Meta: """ A nested class that specifies the configuration for the filter. model(class): The Asset model is used to filter. fields (str): A special value "__all__" to include all fields of the model in the filter. """ model = Asset fields = "__all__" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.form.fields["asset_purchase_date"].widget.attrs.update({"type": "date"}) class AssetFilter(CustomFilterSet): """ Custom filter set for Asset instances. """ search = django_filters.CharFilter(method="search_method") category = django_filters.CharFilter(field_name="asset_category_id") class Meta: """ A nested class that specifies the configuration for the filter. model(class): The Asset model is used to filter. fields (str): A special value "__all__" to include all fields of the model in the filter. """ model = Asset fields = "__all__" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) for visible in self.form.visible_fields(): visible.field.widget.attrs["id"] = str(uuid.uuid4()) def search_method(self, queryset, _, value): """ Search method """ return ( queryset.filter(asset_name__icontains=value) | queryset.filter(asset_category_id__asset_category_name__icontains=value) ).distinct() class CustomAssetFilter(CustomFilterSet): """ Custom filter set for asset assigned to employees instances. """ asset_id__asset_name = django_filters.CharFilter(lookup_expr="icontains") class Meta: """ Specifies the model and fields to be used for filtering AssetAssignment instances. Attributes: model (class): The model class AssetAssignment to be filtered. fields (list): The fields to include in the filter, referring to related AssetAssignment fields. """ model = AssetAssignment fields = [ "asset_id__asset_name", "asset_id__asset_status", ] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) for visible in self.form.visible_fields(): visible.field.widget.attrs["id"] = str(uuid.uuid4()) class AssetRequestFilter(CustomFilterSet): """ Custom filter set for AssetRequest instances. """ search = django_filters.CharFilter(method="search_method") def search_method(self, queryset, _, value: str): """ This method is used to search employees """ values = value.split(" ") empty = queryset.model.objects.none() for split in values: empty = empty | ( queryset.filter( requested_employee_id__employee_first_name__icontains=split ) | queryset.filter( requested_employee_id__employee_last_name__icontains=split ) ) return empty.distinct() class Meta: """ Specifies the model and fields to be used for filtering AssetRequest instances. Attributes: model (class): The model class AssetRequest to be filtered. fields (str): A special value "__all__" to include all fields of the model in the filter. """ model = AssetRequest fields = "__all__" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) for visible in self.form.visible_fields(): visible.field.widget.attrs["id"] = str(uuid.uuid4()) class AssetAllocationFilter(CustomFilterSet): """ Custom filter set for AssetAllocation instances. """ search = django_filters.CharFilter(method="search_method") def search_method(self, queryset, _, value: str): """ This method is used to search employees """ values = value.split(" ") empty = queryset.model.objects.none() for split in values: empty = empty | ( queryset.filter( assigned_to_employee_id__employee_first_name__icontains=split ) | queryset.filter( assigned_to_employee_id__employee_last_name__icontains=split ) ) return empty.distinct() class Meta: """ Specifies the model and fields to be used for filtering AssetAllocation instances. Attributes: model (class): The model class AssetAssignment to be filtered. fields (str): A special value "__all__" to include all fields of the model in the filter. """ model = AssetAssignment fields = "__all__" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) for visible in self.form.visible_fields(): visible.field.widget.attrs["id"] = str(uuid.uuid4()) class AssetCategoryFilter(CustomFilterSet): """ Custom filter set for AssetCategory instances. """ search = django_filters.CharFilter(method="search_method") class Meta: model = AssetCategory fields = "__all__" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) for visible in self.form.visible_fields(): visible.field.widget.attrs["id"] = str(uuid.uuid4()) def search_method(self, queryset, name, value): """ Search method to filter by asset category name or related asset name. """ if not value: return queryset # Return unfiltered queryset if no search term is provided return queryset.filter( Q(asset_category_name__icontains=value) | Q(asset__asset_name__icontains=value) ).distinct() def filter_queryset(self, queryset): """ Filters queryset and applies AssetFilter if necessary. """ # Get the base filtered queryset queryset = super().filter_queryset(queryset) # Filter by assets if asset data is present in the GET request if self.data and "asset__pk" in self.data: assets = AssetFilter(data=self.data).qs queryset = queryset.filter( asset__pk__in=assets.values_list("pk", flat=True) ) return queryset.distinct() class AssetRequestReGroup: """ Class to keep the field name for group by option """ fields = [ ("", "Select"), ("requested_employee_id", "Employee"), ("asset_category_id", "Asset Category"), ("asset_request_date", "Request Date"), ("asset_request_status", "Status"), ] class AssetAllocationReGroup: """ Class to keep the field name for group by option """ fields = [ ("", "Select"), ("assigned_to_employee_id", "Employee"), ("assigned_date", "Assigned Date"), ("return_date", "Return Date"), ] class AssetHistoryFilter(CustomFilterSet): """ Custom filter set for AssetAssignment instances for filtering in asset history view. """ search = django_filters.CharFilter( field_name="asset_id__asset_name", lookup_expr="icontains" ) returned_assets = django_filters.CharFilter( field_name="return_status", method="exclude_none" ) return_date_gte = django_filters.DateFilter( field_name="return_date", lookup_expr="gte", widget=forms.DateInput(attrs={"type": "date"}), ) return_date_lte = django_filters.DateFilter( field_name="return_date", lookup_expr="lte", widget=forms.DateInput(attrs={"type": "date"}), ) assigned_date_gte = django_filters.DateFilter( field_name="assigned_date", lookup_expr="gte", widget=forms.DateInput(attrs={"type": "date"}), ) assigned_date_lte = django_filters.DateFilter( field_name="assigned_date", lookup_expr="lte", widget=forms.DateInput(attrs={"type": "date"}), ) def exclude_none(self, queryset, name, value): """ Exclude objects with a null return_status from the queryset if value is "True" """ if value == "True": queryset = queryset.filter(return_status__isnull=False) return queryset class Meta: """ Specifies the model and fields to be used for filtering AssetAllocation instances. Attributes: model (class): The model class AssetAssignment to be filtered. fields (str): A special value "__all__" to include all fields of the model in the filter. """ model = AssetAssignment fields = "__all__" class AssetHistoryReGroup: """ Class to keep the field name for group by option """ fields = [ ("", "Select"), ("asset_id", "Asset"), ("assigned_to_employee_id", "Employee"), ("assigned_date", "Assigned Date"), ("return_date", "Return Date"), ]