Skip to content

Commit

Permalink
Fix duplicate stats generation in country page
Browse files Browse the repository at this point in the history
  • Loading branch information
k9845 committed Jun 20, 2024
1 parent b26019f commit c2d6e47
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 84 deletions.
52 changes: 23 additions & 29 deletions api/drf_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
from api.filter_set import (
Admin2Filter,
AppealDocumentFilter,
AppealHistoryFilter,
AppealFilter,
CountryFilter,
CountryFilterRMD,
CountryKeyDocumentFilter,
Expand Down Expand Up @@ -66,7 +66,6 @@
Admin2,
Appeal,
AppealDocument,
AppealHistory,
AppealType,
Country,
CountryKeyDocument,
Expand Down Expand Up @@ -97,8 +96,8 @@
Admin2Serializer,
AppealDocumentSerializer,
AppealDocumentTableauSerializer,
AppealHistorySerializer,
AppealHistoryTableauSerializer,
AppealSerializer,
AppealTableauSerializer,
CountryDisasterTypeCountSerializer,
CountryDisasterTypeMonthlySerializer,
CountryGeoSerializer,
Expand Down Expand Up @@ -268,18 +267,23 @@ def get_country_figure(self, request, pk):
end_date = request.GET.get("end_date", end_date)
appeal_conditions = Q(atype=AppealType.APPEAL)

all_appealhistory = AppealHistory.objects.select_related("appeal").filter(appeal__code__isnull=False)
all_appealhistory = all_appealhistory.filter(country=country)
all_appeal = Appeal.objects.select_related("country").filter(
code__isnull=False,
)
all_appeal = all_appeal.filter(country=country)
if start_date and end_date:
all_appealhistory = all_appealhistory.filter(start_date__lte=end_date, end_date__gte=start_date)
appeals_aggregated = all_appealhistory.annotate(
all_appeal = all_appeal.filter(
start_date__lte=end_date,
end_date__gte=start_date,
)
appeals_aggregated = all_appeal.annotate(
appeal_with_dref=Count(
Case(
When(Q(atype=AppealType.DREF), then=1),
output_field=IntegerField(),
)
),
appeal_without_dref=Count(Case(When(Q(atype=AppealType.APPEAL), then=1), output_field=IntegerField()), distinct=True),
appeal_without_dref=Count(Case(When(appeal_conditions, then=1), output_field=IntegerField())),
total_population=(
Case(
When(appeal_conditions | Q(atype=AppealType.DREF), then=F("num_beneficiaries")),
Expand All @@ -298,7 +302,7 @@ def get_country_figure(self, request, pk):
output_field=IntegerField(),
)
),
emergencies_count=Count(F("appeal__event_id"), distinct=True),
emergencies_count=Count(F("event_id"), distinct=True),
).aggregate(
active_drefs=Sum("appeal_with_dref"),
active_appeals=Sum("appeal_without_dref"),
Expand Down Expand Up @@ -358,7 +362,7 @@ def get_country_disaster_monthly_count(self, request, pk):
countries__in=[country.id],
dtype__isnull=False,
)
.annotate(date=TruncMonth("created_at"))
.annotate(date=TruncMonth("disaster_start_date"))
.values("date", "countries", "dtype")
.annotate(
appeal_targeted_population=Coalesce(
Expand Down Expand Up @@ -415,7 +419,7 @@ def get_country_historical_disaster(self, request, pk):
countries__in=[country.id],
dtype__isnull=False,
)
.annotate(date=TruncMonth("created_at"))
.annotate(date=TruncMonth("disaster_start_date"))
.values("date", "dtype", "countries")
.annotate(
appeal_targeted_population=Coalesce(
Expand Down Expand Up @@ -744,27 +748,19 @@ def get_serializer_class(self):
class AppealViewset(mixins.ListModelMixin, viewsets.GenericViewSet):
"""Used to get Appeals from AppealHistory. Has no 'read' option, just 'list'."""

# queryset = Appeal.objects.select_related('dtype', 'country', 'region').all()
# queryset = AppealHistory.objects.select_related('appeal__event', 'dtype', 'country', 'region').all()
queryset = AppealHistory.objects.select_related("appeal__event", "dtype", "country", "region").filter(
appeal__code__isnull=False
)
# serializer_class = AppealSerializer
serializer_class = AppealHistorySerializer
queryset = Appeal.objects.select_related("event", "dtype", "country", "region").filter(code__isnull=False)
serializer_class = AppealSerializer
ordering_fields = "__all__"
# filterset_class = AppealFilter
filterset_class = AppealHistoryFilter
filterset_class = AppealFilter
search_fields = (
"appeal__name",
"name",
"code",
) # for /docs

def get_serializer_class(self):
if is_tableau(self.request) is True:
return AppealHistoryTableauSerializer
# return AppealTableauSerializer
return AppealHistorySerializer
# return AppealSerializer
return AppealTableauSerializer
return AppealSerializer

def remove_unconfirmed_event(self, obj):
if obj["needs_confirmation"]:
Expand All @@ -776,9 +772,7 @@ def remove_unconfirmed_events(self, objs):

# Overwrite to exclude the events which require confirmation
def list(self, request, *args, **kwargs):
now = timezone.now()
date = request.GET.get("date", now)
queryset = self.filter_queryset(self.get_queryset()).filter(valid_from__lt=date, valid_to__gt=date)
queryset = self.filter_queryset(self.get_queryset())

page = self.paginate_queryset(queryset)
if page is not None:
Expand Down
24 changes: 24 additions & 0 deletions api/filter_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,14 +204,38 @@ class AppealFilter(filters.FilterSet):
code = filters.CharFilter(field_name="code", lookup_expr="exact")
status = filters.NumberFilter(field_name="status", lookup_expr="exact")
id = filters.NumberFilter(field_name="id", lookup_expr="exact")
appeal_id = filters.NumberFilter(
field_name="appeal_id", lookup_expr="exact", help_text="Use this (or code) for appeal identification."
)
district = filters.ModelMultipleChoiceFilter(
field_name="country__district", queryset=District.objects.all(), label="district", method="get_country_district"
)
admin2 = filters.ModelMultipleChoiceFilter(
field_name="country__district__admin2",
queryset=Admin2.objects.all(),
label="admin2",
method="get_country_admin2",
)

class Meta:
model = Appeal
fields = {
"start_date": ("exact", "gt", "gte", "lt", "lte"),
"end_date": ("exact", "gt", "gte", "lt", "lte"),
"real_data_update": ("exact", "gt", "gte", "lt", "lte"),
"country__iso3": ("exact",),
}

def get_country_district(self, qs, name, value):
if value:
return qs.filter(country__district=value).distinct()
return qs

def get_country_admin2(self, qs, name, value):
if value:
return qs.filter(country__district__admin2=value).distinct()
return qs


class AppealHistoryFilter(filters.FilterSet):
atype = filters.NumberFilter(field_name="atype", lookup_expr="exact")
Expand Down
1 change: 1 addition & 0 deletions api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2118,6 +2118,7 @@ class AggregateHeaderFiguresSerializer(serializers.Serializer):
amount_requested = serializers.IntegerField()
amount_requested_dref_included = serializers.IntegerField()
amount_funded = serializers.IntegerField()
amount_funded_dref_included = serializers.IntegerField()


# SearchPage Serializer
Expand Down
64 changes: 29 additions & 35 deletions api/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import api.models as models
from api.factories.event import (
AppealFactory,
AppealHistoryFactory,
AppealType,
EventFactory,
EventFeaturedDocumentFactory,
Expand Down Expand Up @@ -543,58 +542,53 @@ def test_appeal_key_figure(self):
)
event2 = EventFactory.create(name="test0", dtype=dtype1, num_affected=10000, countries=[country1])
event3 = EventFactory.create(name="test2", dtype=dtype2, num_affected=99999, countries=[country2])
appeal1 = AppealFactory.create(
event=event1, dtype=dtype1, num_beneficiaries=9000, amount_requested=10000, amount_funded=1899999, code=12
)
appeal2 = AppealFactory.create(
event=event2, dtype=dtype2, num_beneficiaries=90023, amount_requested=100440, amount_funded=12299999, code=123
)
appeal3 = AppealFactory.create(
event=event3, dtype=dtype2, num_beneficiaries=91000, amount_requested=10000888, amount_funded=678888, code=1234
)
AppealHistoryFactory.create(
appeal=appeal1,
AppealFactory.create(
event=event1,
dtype=dtype1,
num_beneficiaries=9000,
amount_requested=10000,
amount_funded=1899999,
country=country1,
atype=AppealType.APPEAL,
code=12,
start_date="2024-1-1",
end_date="2024-1-1",
atype=AppealType.APPEAL,
country=country1,
)
AppealHistoryFactory.create(
appeal=appeal2,
AppealFactory.create(
event=event2,
dtype=dtype2,
num_beneficiaries=1,
amount_requested=1,
amount_funded=1,
country=country1,
atype=AppealType.DREF,
num_beneficiaries=90023,
amount_requested=100440,
amount_funded=12299999,
code=123,
start_date="2024-2-2",
end_date="2024-2-2",
atype=AppealType.DREF,
country=country1,
)
AppealHistoryFactory.create(
appeal=appeal3,
AppealFactory.create(
event=event3,
dtype=dtype2,
num_beneficiaries=1,
amount_requested=1,
amount_funded=1,
country=country1,
atype=AppealType.APPEAL,
num_beneficiaries=91000,
amount_requested=10000888,
amount_funded=678888,
code=1234,
start_date="2024-3-3",
end_date="2024-3-3",
atype=AppealType.APPEAL,
country=country1,
)
AppealHistoryFactory.create(
appeal=appeal3,
AppealFactory.create(
event=event3,
dtype=dtype2,
num_beneficiaries=1,
amount_requested=1,
amount_funded=1,
country=country1,
atype=AppealType.APPEAL,
num_beneficiaries=91000,
amount_requested=10000888,
amount_funded=678888,
code=12345,
start_date="2024-4-4",
end_date="2024-4-4",
atype=AppealType.APPEAL,
country=country1,
)
url = f"/api/v2/country/{country1.id}/figure/"
self.client.force_authenticate(self.user)
Expand Down
35 changes: 15 additions & 20 deletions api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,7 @@
from .esconnection import ES_CLIENT
from .indexes import ES_PAGE_NAME
from .logger import logger
from .models import (
Appeal,
AppealHistory,
AppealType,
CronJob,
Event,
FieldReport,
Snippet,
)
from .models import Appeal, AppealType, CronJob, Event, FieldReport, Snippet
from .utils import is_user_ifrc


Expand Down Expand Up @@ -609,25 +601,24 @@ def get(self, request):
now = timezone.now()
date = request.GET.get("date", now)
appeal_conditions = (
(Q(atype=AppealType.APPEAL) | Q(atype=AppealType.INTL)) & Q(end_date__gt=date) & Q(start_date__lt=date)
(Q(atype=AppealType.APPEAL) | Q(atype=AppealType.INTL)) & Q(end_date__gte=date) & Q(start_date__lte=date)
)

all_appealhistory = AppealHistory.objects.select_related("appeal").filter(
valid_from__lt=date, valid_to__gt=date, appeal__code__isnull=False
all_appeal = Appeal.objects.filter(
code__isnull=False,
)

if iso3:
all_appealhistory = all_appealhistory.filter(country__iso3__iexact=iso3)
all_appeal = all_appeal.filter(country__iso3__iexact=iso3)
if country:
all_appealhistory = all_appealhistory.filter(country__id=country)
all_appeal = all_appeal.filter(country__id=country)
if region:
all_appealhistory = all_appealhistory.filter(country__region__id=region)

appeals_aggregated = all_appealhistory.annotate(
all_appeal = all_appeal.filter(country__region__id=region)
appeals_aggregated = all_appeal.annotate(
# Active Appeals with DREF type
actd=Count(
Case(
When(Q(atype=AppealType.DREF) & Q(end_date__gt=date) & Q(start_date__lt=date), then=1),
When(Q(atype=AppealType.DREF) & Q(end_date__gte=date) & Q(start_date__lte=date), then=1),
output_field=IntegerField(),
)
),
Expand All @@ -638,17 +629,20 @@ def get(self, request):
# Active Appeals' target population
tarp=Sum(
Case(
When(Q(end_date__gt=date) & Q(start_date__lt=date), then=F("num_beneficiaries")),
When(Q(end_date__gte=date) & Q(start_date__lte=date), then=F("num_beneficiaries")),
output_field=IntegerField(),
)
),
# Active Appeals' requested amount, which are not DREF
amor=Case(When(appeal_conditions, then=F("amount_requested")), output_field=IntegerField()),
amordref=Case(
When(Q(end_date__gt=date) & Q(start_date__lt=date), then=F("amount_requested")), output_field=IntegerField()
When(Q(end_date__gte=date) & Q(start_date__lte=date), then=F("amount_requested")), output_field=IntegerField()
),
# Active Appeals' funded amount, which are not DREF
amof=Case(When(appeal_conditions, then=F("amount_funded")), output_field=IntegerField()),
amofdref=Case(
When(Q(end_date__gte=date) & Q(start_date__lte=date), then=F("amount_funded")), output_field=IntegerField()
),
).aggregate(
active_drefs=Sum("actd"),
active_appeals=Sum("acta"),
Expand All @@ -657,6 +651,7 @@ def get(self, request):
amount_requested=Sum("amor"),
amount_requested_dref_included=Sum("amordref"),
amount_funded=Sum("amof"),
amount_funded_dref_included=Sum("amofdref"),
)

return Response(AggregateHeaderFiguresSerializer(appeals_aggregated).data)
Expand Down

0 comments on commit c2d6e47

Please sign in to comment.