From 6a8a48686b871b0bd6ee68d0f162e726ff1b551c Mon Sep 17 00:00:00 2001 From: Todd Dembrey <todd.dembrey@torchbox.com> Date: Tue, 12 Nov 2019 17:19:50 +0000 Subject: [PATCH] Add ability to filter and order reports on project table --- hypha/apply/projects/filters.py | 25 +++++++++++++++++++++++++ hypha/apply/projects/models.py | 30 ++++++++++++++++++++++++++---- hypha/apply/projects/tables.py | 7 +++++++ 3 files changed, 58 insertions(+), 4 deletions(-) diff --git a/hypha/apply/projects/filters.py b/hypha/apply/projects/filters.py index 4917e4c27..a817fdf4d 100644 --- a/hypha/apply/projects/filters.py +++ b/hypha/apply/projects/filters.py @@ -1,6 +1,8 @@ import django_filters as filters from django import forms from django.contrib.auth import get_user_model +from django.db.models import Q +from django_select2.forms import Select2Widget from hypha.apply.funds.tables import ( Select2ModelMultipleChoiceFilter, @@ -9,6 +11,8 @@ from hypha.apply.funds.tables import ( ) from .models import ( + CLOSING, + IN_PROGRESS, PROJECT_STATUS_CHOICES, REQUEST_STATUS_CHOICES, PaymentRequest, @@ -34,15 +38,36 @@ class PaymentRequestListFilter(filters.FilterSet): class ProjectListFilter(filters.FilterSet): + REPORTING_CHOICES = ( + (0, 'Up to date'), + (1, 'Behind schedule'), + ) + fund = Select2ModelMultipleChoiceFilter(label='Funds', queryset=get_used_funds) lead = Select2ModelMultipleChoiceFilter(label='Lead', queryset=get_project_leads) status = Select2MultipleChoiceFilter(label='Status', choices=PROJECT_STATUS_CHOICES) query = filters.CharFilter(field_name='title', lookup_expr="icontains", widget=forms.HiddenInput) + reporting = filters.ChoiceFilter( + choices=REPORTING_CHOICES, + method="filter_reporting", + widget=Select2Widget(attrs={ + 'data-placeholder': 'Reporting', + 'data-minimum-results-for-search': -1, + }), + ) class Meta: fields = ['status', 'lead', 'fund'] model = Project + def filter_reporting(self, queryset, name, value): + if value == '1': + return queryset.filter(outstanding_reports__gt=0) + return queryset.filter( + Q(outstanding_reports__lt=1) | Q(outstanding_reports__isnull=True), + status__in=(IN_PROGRESS, CLOSING), + ) + class DateRangeInputWidget(filters.widgets.SuffixedMultiWidget): template_name = 'application_projects/filters/widgets/date_range_input_widget.html' diff --git a/hypha/apply/projects/models.py b/hypha/apply/projects/models.py index 66d02a763..060a684a1 100644 --- a/hypha/apply/projects/models.py +++ b/hypha/apply/projects/models.py @@ -13,9 +13,19 @@ from django.contrib.postgres.fields import JSONField from django.core.exceptions import ValidationError from django.core.validators import MinValueValidator from django.db import models -from django.db.models import Case, ExpressionWrapper, F, Max, OuterRef, Q, Subquery, Sum -from django.db.models import Value as V -from django.db.models import When +from django.db.models import ( + Count, + Case, + F, + ExpressionWrapper, + Max, + OuterRef, + Q, + Subquery, + Sum, + Value as V, + When, +) from django.db.models.functions import Cast, Coalesce from django.db.models.signals import post_delete from django.dispatch.dispatcher import receiver @@ -307,6 +317,18 @@ class ProjectQuerySet(models.QuerySet): last_payment_request=Max('payment_requests__requested_at'), ) + def with_outstanding_reports(self): + return self.annotate( + outstanding_reports=Subquery( + Report.objects.filter( + project=OuterRef('pk'), + ).to_do().order_by().values('project').annotate( + count=Count('pk'), + ).values('count'), + output_field=models.IntegerField(), + ) + ) + def with_start_date(self): return self.annotate( start=Cast( @@ -322,7 +344,7 @@ class ProjectQuerySet(models.QuerySet): ) def for_table(self): - return self.with_amount_paid().with_last_payment().select_related( + return self.with_amount_paid().with_last_payment().with_outstanding_reports().select_related( 'report_config', 'submission__page', 'lead', diff --git a/hypha/apply/projects/tables.py b/hypha/apply/projects/tables.py index 2c86e162e..82219029c 100644 --- a/hypha/apply/projects/tables.py +++ b/hypha/apply/projects/tables.py @@ -77,6 +77,13 @@ class BaseProjectsTable(tables.Table): end_date = tables.DateColumn(verbose_name='End Date', accessor='proposed_end') fund_allocation = tables.Column(verbose_name='Fund Allocation', accessor='value') + def order_reporting(self, qs, is_descending): + direction = '-' if is_descending else '' + + qs = qs.order_by(f'{direction}outstanding_reports') + + return qs, True + def render_fund_allocation(self, record): return f'${intcomma(record.amount_paid)} / ${intcomma(record.value)}' -- GitLab