Skip to content
Snippets Groups Projects
Commit 6a8a4868 authored by Todd Dembrey's avatar Todd Dembrey Committed by Fredrik Jonsson
Browse files

Add ability to filter and order reports on project table

parent 74603261
No related branches found
No related tags found
No related merge requests found
import django_filters as filters import django_filters as filters
from django import forms from django import forms
from django.contrib.auth import get_user_model 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 ( from hypha.apply.funds.tables import (
Select2ModelMultipleChoiceFilter, Select2ModelMultipleChoiceFilter,
...@@ -9,6 +11,8 @@ from hypha.apply.funds.tables import ( ...@@ -9,6 +11,8 @@ from hypha.apply.funds.tables import (
) )
from .models import ( from .models import (
CLOSING,
IN_PROGRESS,
PROJECT_STATUS_CHOICES, PROJECT_STATUS_CHOICES,
REQUEST_STATUS_CHOICES, REQUEST_STATUS_CHOICES,
PaymentRequest, PaymentRequest,
...@@ -34,15 +38,36 @@ class PaymentRequestListFilter(filters.FilterSet): ...@@ -34,15 +38,36 @@ class PaymentRequestListFilter(filters.FilterSet):
class ProjectListFilter(filters.FilterSet): class ProjectListFilter(filters.FilterSet):
REPORTING_CHOICES = (
(0, 'Up to date'),
(1, 'Behind schedule'),
)
fund = Select2ModelMultipleChoiceFilter(label='Funds', queryset=get_used_funds) fund = Select2ModelMultipleChoiceFilter(label='Funds', queryset=get_used_funds)
lead = Select2ModelMultipleChoiceFilter(label='Lead', queryset=get_project_leads) lead = Select2ModelMultipleChoiceFilter(label='Lead', queryset=get_project_leads)
status = Select2MultipleChoiceFilter(label='Status', choices=PROJECT_STATUS_CHOICES) status = Select2MultipleChoiceFilter(label='Status', choices=PROJECT_STATUS_CHOICES)
query = filters.CharFilter(field_name='title', lookup_expr="icontains", widget=forms.HiddenInput) 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: class Meta:
fields = ['status', 'lead', 'fund'] fields = ['status', 'lead', 'fund']
model = Project 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): class DateRangeInputWidget(filters.widgets.SuffixedMultiWidget):
template_name = 'application_projects/filters/widgets/date_range_input_widget.html' template_name = 'application_projects/filters/widgets/date_range_input_widget.html'
......
...@@ -13,9 +13,19 @@ from django.contrib.postgres.fields import JSONField ...@@ -13,9 +13,19 @@ from django.contrib.postgres.fields import JSONField
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.core.validators import MinValueValidator from django.core.validators import MinValueValidator
from django.db import models from django.db import models
from django.db.models import Case, ExpressionWrapper, F, Max, OuterRef, Q, Subquery, Sum from django.db.models import (
from django.db.models import Value as V Count,
from django.db.models import When Case,
F,
ExpressionWrapper,
Max,
OuterRef,
Q,
Subquery,
Sum,
Value as V,
When,
)
from django.db.models.functions import Cast, Coalesce from django.db.models.functions import Cast, Coalesce
from django.db.models.signals import post_delete from django.db.models.signals import post_delete
from django.dispatch.dispatcher import receiver from django.dispatch.dispatcher import receiver
...@@ -307,6 +317,18 @@ class ProjectQuerySet(models.QuerySet): ...@@ -307,6 +317,18 @@ class ProjectQuerySet(models.QuerySet):
last_payment_request=Max('payment_requests__requested_at'), 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): def with_start_date(self):
return self.annotate( return self.annotate(
start=Cast( start=Cast(
...@@ -322,7 +344,7 @@ class ProjectQuerySet(models.QuerySet): ...@@ -322,7 +344,7 @@ class ProjectQuerySet(models.QuerySet):
) )
def for_table(self): 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', 'report_config',
'submission__page', 'submission__page',
'lead', 'lead',
......
...@@ -77,6 +77,13 @@ class BaseProjectsTable(tables.Table): ...@@ -77,6 +77,13 @@ class BaseProjectsTable(tables.Table):
end_date = tables.DateColumn(verbose_name='End Date', accessor='proposed_end') end_date = tables.DateColumn(verbose_name='End Date', accessor='proposed_end')
fund_allocation = tables.Column(verbose_name='Fund Allocation', accessor='value') 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): def render_fund_allocation(self, record):
return f'${intcomma(record.amount_paid)} / ${intcomma(record.value)}' return f'${intcomma(record.amount_paid)} / ${intcomma(record.value)}'
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment