Skip to content

Commit

Permalink
Merge pull request #168 from wilsonc86/4881_dashboard_work
Browse files Browse the repository at this point in the history
4881 dashboard work
  • Loading branch information
wilsonc86 committed Apr 15, 2019
2 parents 9ceb9f7 + 0e8f4b4 commit fb9dc25
Show file tree
Hide file tree
Showing 12 changed files with 262 additions and 84 deletions.
155 changes: 142 additions & 13 deletions wildlifecompliance/components/applications/api.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import traceback
import os
from datetime import datetime, timedelta
from django.db.models import Q
from django.db import transaction
from django.core.files.base import ContentFile
Expand All @@ -18,6 +19,7 @@
MissingFieldsException,
get_activity_schema
)
from wildlifecompliance.components.applications.models import Application
from wildlifecompliance.components.main.utils import checkout, set_session_application, delete_session_application
from wildlifecompliance.helpers import is_customer, is_internal
from wildlifecompliance.components.applications.models import (
Expand Down Expand Up @@ -57,6 +59,12 @@
SearchReferenceSerializer
)

from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination
from rest_framework_datatables.pagination import DatatablesPageNumberPagination
from rest_framework_datatables.filters import DatatablesFilterBackend
from rest_framework_datatables.renderers import DatatablesRenderer
from rest_framework.filters import BaseFilterBackend


class GetEmptyList(views.APIView):
renderer_classes = [JSONRenderer, ]
Expand All @@ -65,6 +73,140 @@ def get(self, request, format=None):
return Response([])


class ApplicationFilterBackend(DatatablesFilterBackend):
"""
Custom filters
"""
def filter_queryset(self, request, queryset, view):

# Get built-in DRF datatables queryset first to join with search text, then apply additional filters
super_queryset = super(ApplicationFilterBackend, self).filter_queryset(request, queryset, view).distinct()

total_count = queryset.count()
date_from = request.GET.get('date_from')
date_to = request.GET.get('date_to')
category_name = request.GET.get('category_name')
processing_status = request.GET.get('processing_status')
customer_status = request.GET.get('customer_status')
submitter = request.GET.get('submitter')
search_text = request.GET.get('search[value]')
if queryset.model is Application:

# search_text filter, join all custom search columns
# where ('searchable: false' in the datatable definiton)
if search_text:
search_text = search_text.lower()
# join queries for the search_text search
search_text_app_ids = []
for application in queryset:
if (search_text in application.licence_category.lower()
or search_text in ', '.join(application.licence_purpose_names).lower()
or search_text in application.applicant
or search_text in application.processing_status
or search_text in application.customer_status
or search_text in application.payment_status):
search_text_app_ids.append(application.id)
# if applicant is not an organisation, also search against the user's email address
if (application.applicant_type == Application.APPLICANT_TYPE_PROXY and
search_text in application.proxy_applicant.email):
search_text_app_ids.append(application.id)
if (application.applicant_type == Application.APPLICANT_TYPE_SUBMITTER and
search_text in application.submitter.email):
search_text_app_ids.append(application.id)
# use pipe to join both custom and built-in DRF datatables querysets (returned by super call below)
# (otherwise they will filter on top of each other)
queryset = queryset.filter(id__in=search_text_app_ids).distinct() | super_queryset

# apply user selected filters
category_name = category_name.lower() if category_name else 'all'
if category_name != 'all':
category_name = category_name.lower()
category_name_app_ids = []
for application in queryset:
if category_name in application.licence_category.lower():
category_name_app_ids.append(application.id)
queryset = queryset.filter(id__in=category_name_app_ids)
processing_status = processing_status.lower() if processing_status else 'all'
if processing_status != 'all':
processing_status = processing_status.lower()
processing_status_app_ids = []
for application in queryset:
if processing_status in application.processing_status.lower():
processing_status_app_ids.append(application.id)
queryset = queryset.filter(id__in=processing_status_app_ids)
customer_status = customer_status.lower() if customer_status else 'all'
if customer_status != 'all':
customer_status = customer_status.lower()
customer_status_app_ids = []
for application in queryset:
if customer_status in application.customer_status.lower():
customer_status_app_ids.append(application.id)
queryset = queryset.filter(id__in=customer_status_app_ids)
if date_from:
queryset = queryset.filter(lodgement_date__gte=date_from)
if date_to:
date_to = datetime.strptime(date_to, '%Y-%m-%d') + timedelta(days=1)
queryset = queryset.filter(lodgement_date__lte=date_to)
if submitter and submitter != 'All':
queryset = queryset.filter(submitter__email__iexact=submitter)

setattr(view, '_datatables_total_count', total_count)
return queryset


class ApplicationRenderer(DatatablesRenderer):
def render(self, data, accepted_media_type=None, renderer_context=None):
if 'view' in renderer_context and hasattr(renderer_context['view'], '_datatables_total_count'):
data['recordsTotal'] = renderer_context['view']._datatables_total_count
return super(ApplicationRenderer, self).render(data, accepted_media_type, renderer_context)


class ApplicationPaginatedViewSet(viewsets.ModelViewSet):
filter_backends = (ApplicationFilterBackend,)
pagination_class = DatatablesPageNumberPagination
renderer_classes = (ApplicationRenderer,)
queryset = Application.objects.none()
serializer_class = DTExternalApplicationSerializer
page_size = 10

def get_queryset(self):
user = self.request.user
if is_internal(self.request):
return Application.objects.all()
elif is_customer(self.request):
user_orgs = [
org.id for org in user.wildlifecompliance_organisations.all()]
return Application.objects.filter(Q(org_applicant_id__in=user_orgs) | Q(
proxy_applicant=user) | Q(submitter=user))
return Application.objects.none()

@list_route(methods=['GET', ])
def internal_datatable_list(self, request, *args, **kwargs):
queryset = self.get_queryset()
queryset = self.filter_queryset(queryset)
self.paginator.page_size = queryset.count()
result_page = self.paginator.paginate_queryset(queryset, request)
serializer = DTInternalApplicationSerializer(result_page, context={'request': request}, many=True)
return self.paginator.get_paginated_response(serializer.data)

@list_route(methods=['GET', ])
def external_datatable_list(self, request, *args, **kwargs):
user_orgs = [
org.id for org in request.user.wildlifecompliance_organisations.all()]
queryset = self.get_queryset().filter(
Q(submitter=request.user) |
Q(proxy_applicant=request.user) |
Q(org_applicant_id__in=user_orgs)
).computed_exclude(
processing_status=Application.PROCESSING_STATUS_DISCARDED
).distinct()
queryset = self.filter_queryset(queryset)
self.paginator.page_size = queryset.count()
result_page = self.paginator.paginate_queryset(queryset, request)
serializer = DTExternalApplicationSerializer(result_page, context={'request': request}, many=True)
return self.paginator.get_paginated_response(serializer.data)


class ApplicationViewSet(viewsets.ModelViewSet):
queryset = Application.objects.all()
serializer_class = ApplicationSerializer
Expand All @@ -86,19 +228,6 @@ def list(self, request, *args, **kwargs):
queryset, many=True, context={'request': request})
return Response(serializer.data)

# @detail_route(methods=['GET',])
# def is_editable_fields(self, request, *args, **kwargs):
# try:
# instance = self.get_object()
# editable_items = {}
# for i in instance.activities:
# editable_items.update({i.activity_name:get_activity_sys_answers(i)})
# return Response([editable_items])
# #return Response(['a','b'])
# except Exception as e:
# print(traceback.print_exc())
# raise serializers.ValidationError(str(e))

@detail_route(methods=['POST'])
@renderer_classes((JSONRenderer,))
def process_document(self, request, *args, **kwargs):
Expand Down
6 changes: 6 additions & 0 deletions wildlifecompliance/components/applications/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,12 @@ def licence_activity_names(self):
'licence_activity__short_name', flat=True
).distinct())

@property
def licence_purpose_names(self):
return [purpose.licence_activity.short_name + ' - ' + purpose.short_name
for purpose in self.licence_purposes.all()
.order_by('licence_activity','short_name')]

@property
def licence_type_name(self):
from wildlifecompliance.components.licences.models import LicenceActivity
Expand Down
9 changes: 8 additions & 1 deletion wildlifecompliance/components/applications/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ class BaseApplicationSerializer(serializers.ModelSerializer):
category_name = serializers.SerializerMethodField(read_only=True)
activity_names = serializers.SerializerMethodField(read_only=True)
activity_purpose_string = serializers.SerializerMethodField(read_only=True)
purpose_string = serializers.SerializerMethodField(read_only=True)
amendment_requests = serializers.SerializerMethodField(read_only=True)
can_current_user_edit = serializers.SerializerMethodField(read_only=True)
payment_status = serializers.SerializerMethodField(read_only=True)
Expand Down Expand Up @@ -231,6 +232,7 @@ class Meta:
'category_name',
'activity_names',
'activity_purpose_string',
'purpose_string',
'can_current_user_edit',
'payment_status',
'assigned_officer',
Expand All @@ -255,7 +257,10 @@ def get_category_name(self, obj):

def get_activity_purpose_string(self, obj):
activity_names = obj.licence_type_name.split(' - ')[1] if ' - ' in obj.licence_type_name else obj.licence_type_name
return activity_names.replace('), ', ')\n')
return activity_names

def get_purpose_string(self, obj):
return ', '.join(obj.licence_purpose_names)

def get_activity_names(self, obj):
return obj.licence_activity_names
Expand Down Expand Up @@ -338,6 +343,7 @@ class Meta:
'category_name',
'activity_names',
'activity_purpose_string',
'purpose_string',
'can_user_view',
'can_current_user_edit',
'payment_status',
Expand Down Expand Up @@ -375,6 +381,7 @@ class Meta:
'category_name',
'activity_names',
'activity_purpose_string',
'purpose_string',
'can_user_view',
'can_current_user_edit',
'payment_status',
Expand Down
1 change: 1 addition & 0 deletions wildlifecompliance/frontend/wildlifecompliance/src/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ module.exports = {
countries: "https://restcountries.eu/rest/v1/?fullText=true/",
application_type:"/api/application_type/",
applications:"/api/application/",
applications_paginated:"/api/application_paginated/",
licences:"/api/licences/",
returns:"/api/returns/",
application_standard_conditions:"/api/application_standard_conditions/",
Expand Down
Loading

0 comments on commit fb9dc25

Please sign in to comment.