Skip to content

Commit

Permalink
Advance search (#573)
Browse files Browse the repository at this point in the history
* Advance search for QBO

* advanced search bug fix

* test case for advanced search

* removed unused code

* comment resolved

* remove flake errors
  • Loading branch information
Ashutosh619-sudo authored Feb 26, 2024
1 parent e11cac8 commit ea66c23
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 8 deletions.
64 changes: 63 additions & 1 deletion apps/fyle/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@
from typing import List, Union

import requests

import django_filters
from django.conf import settings
from django.db.models import Q

from apps.fyle.models import ExpenseFilter, ExpenseGroupSettings, Expense
from apps.fyle.models import ExpenseFilter, ExpenseGroup, ExpenseGroupSettings, Expense
from apps.tasks.models import TaskLog
from apps.workspaces.models import WorkspaceGeneralSettings


logger = logging.getLogger(__name__)
logger.level = logging.INFO

Expand Down Expand Up @@ -245,3 +248,62 @@ def get_batched_expenses(batched_payload: List[dict], workspace_id: int) -> List
"""
expense_ids = [expense['id'] for expense in batched_payload]
return Expense.objects.filter(expense_id__in=expense_ids, workspace_id=workspace_id)


class AdvanceSearchFilter(django_filters.FilterSet):
def filter_queryset(self, queryset):
or_filtered_queryset = queryset.none()
or_filter_fields = getattr(self.Meta, 'or_fields', [])
or_field_present = False

for field_name in self.Meta.fields:
value = self.data.get(field_name)
if value:
if field_name == 'is_skipped':
value = True if str(value) == 'true' else False
filter_instance = self.filters[field_name]
queryset = filter_instance.filter(queryset, value)

for field_name in or_filter_fields:
value = self.data.get(field_name)
if value:
or_field_present = True
filter_instance = self.filters[field_name]
field_filtered_queryset = filter_instance.filter(queryset, value)
or_filtered_queryset |= field_filtered_queryset

if or_field_present:
queryset = queryset & or_filtered_queryset
return queryset

return queryset


class ExpenseGroupSearchFilter(AdvanceSearchFilter):
exported_at__gte = django_filters.DateTimeFilter(lookup_expr='gte', field_name='exported_at')
exported_at__lte = django_filters.DateTimeFilter(lookup_expr='lte', field_name='exported_at')
tasklog__status = django_filters.CharFilter()
expenses__expense_number = django_filters.CharFilter(field_name='expenses__expense_number', lookup_expr='icontains')
expenses__employee_name = django_filters.CharFilter(field_name='expenses__employee_name', lookup_expr='icontains')
expenses__employee_email = django_filters.CharFilter(field_name='expenses__employee_email', lookup_expr='icontains')
expenses__claim_number = django_filters.CharFilter(field_name='expenses__claim_number', lookup_expr='icontains')

class Meta:
model = ExpenseGroup
fields = ['exported_at__gte', 'exported_at__lte', 'tasklog__status']
or_fields = ['expenses__expense_number', 'expenses__employee_name', 'expenses__employee_email', 'expenses__claim_number']


class ExpenseSearchFilter(AdvanceSearchFilter):
org_id = django_filters.CharFilter()
is_skipped = django_filters.BooleanFilter()
updated_at = django_filters.DateTimeFromToRangeFilter()
expense_number = django_filters.CharFilter(field_name='expense_number', lookup_expr='icontains')
employee_name = django_filters.CharFilter(field_name='employee_name', lookup_expr='icontains')
employee_email = django_filters.CharFilter(field_name='employee_email', lookup_expr='icontains')
claim_number = django_filters.CharFilter(field_name='claim_number', lookup_expr='icontains')

class Meta:
model = Expense
fields = ['org_id', 'is_skipped', 'updated_at']
or_fields = ['expense_number', 'employee_name', 'employee_email', 'claim_number']
12 changes: 6 additions & 6 deletions apps/fyle/views.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import logging
from apps.fyle.helpers import ExpenseGroupSearchFilter, ExpenseSearchFilter

from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import generics
Expand Down Expand Up @@ -34,10 +35,10 @@ class ExpenseGroupView(LookupFieldMixin, generics.ListCreateAPIView):
List Fyle Expenses
"""

queryset = ExpenseGroup.objects.all().order_by("-exported_at")
queryset = ExpenseGroup.objects.all().order_by("-exported_at").distinct()
serializer_class = ExpenseGroupSerializer
filter_backends = (DjangoFilterBackend,)
filterset_fields = {"exported_at": {"gte", "lte"}, "tasklog__status": {"exact"}}
filterset_class = ExpenseGroupSearchFilter


class ExportableExpenseGroupsView(generics.RetrieveAPIView):
Expand Down Expand Up @@ -158,16 +159,15 @@ class ExpenseFilterDeleteView(generics.DestroyAPIView):
serializer_class = ExpenseFilterSerializer


class ExpenseView(generics.ListAPIView):
class ExpenseView(LookupFieldMixin, generics.ListAPIView):
"""
Expense view
"""

queryset = Expense.objects.all()
queryset = Expense.objects.all().order_by("-updated_at").distinct()
serializer_class = ExpenseSerializer
filter_backends = (DjangoFilterBackend,)
filterset_fields = {'org_id': {'exact'}, 'is_skipped': {'exact'}, 'updated_at': {'gte', 'lte'}}
ordering_fields = ('-updated_at',)
filterset_class = ExpenseSearchFilter


class CustomFieldView(generics.RetrieveAPIView):
Expand Down
54 changes: 53 additions & 1 deletion tests/test_fyle/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def test_expense_group_view(api_client, test_connection):

api_client.credentials(HTTP_AUTHORIZATION='Bearer {}'.format(access_token))

response = api_client.get(url, {'exported_at__gte': '2022-05-23 13:03:06', 'exported_at__lte': '2022-05-23 13:03:48'})
response = api_client.get(url, {'exported_at__gte': '2022-05-23T13:03:06Z', 'exported_at__lte': '2022-05-23T13:03:48Z'})
assert response.status_code == 200

response = json.loads(response.content)
Expand All @@ -26,6 +26,58 @@ def test_expense_group_view(api_client, test_connection):
TaskLog.objects.update_or_create(workspace_id=3, type='FETCHING_EXPENSES', defaults={'status': 'IN_PROGRESS'})


def test_export_log_advanced_search(api_client, test_connection):
access_token = test_connection.access_token

url = reverse('expense-groups', kwargs={'workspace_id': 3})

api_client.credentials(HTTP_AUTHORIZATION='Bearer {}'.format(access_token))

response = api_client.get(url,{'tasklog__status':'COMPLETE'})
assert response.status_code == 200

response = json.loads(response.content)
assert response['count'] == 17

response = api_client.get(url, {'expenses__expense_number': 'E/2021/04/T/277'})
assert response.status_code == 200

response = json.loads(response.content)
assert response['count'] == 1

response = api_client.get(url, {'expenses__expense_number': 'E/2021/04/T/'})
assert response.status_code == 200

response = json.loads(response.content)
assert response['count'] == 11

response = api_client.get(url, {'expenses__claim_number': 'C/2021/04/R/38'})
assert response.status_code == 200

response = json.loads(response.content)
assert response['count'] == 4

response = api_client.get(url, {'expenses__employee_email': '[email protected]'})
assert response.status_code == 200

response = json.loads(response.content)
assert response['count'] == 4

response = api_client.get(url, {'expenses__employee_name': 'Joanna'})
assert response.status_code == 200

response = json.loads(response.content)
assert response['count'] == 5

response = api_client.get(url, {'tasklog__status':'COMPLETE', 'expenses__employee_name': 'Joanna', 'expenses__employee_email': '[email protected]'})
assert response.status_code == 200

response = json.loads(response.content)
assert response['count'] == 9

TaskLog.objects.update_or_create(workspace_id=3, type='FETCHING_EXPENSES', defaults={'status': 'IN_PROGRESS'})


def test_expense_group_settings(api_client, test_connection):
access_token = test_connection.access_token

Expand Down

0 comments on commit ea66c23

Please sign in to comment.