Skip to content

Commit

Permalink
Add Opslearning stats
Browse files Browse the repository at this point in the history
 #Change the api and testcase according pr review
  • Loading branch information
sudip-khanal committed Dec 11, 2024
1 parent b03b6f1 commit 3e73ced
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 2 deletions.
60 changes: 58 additions & 2 deletions per/drf_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
import pytz
from django.conf import settings
from django.db import transaction
from django.db.models import Prefetch, Q
from django.db.models import Count, F, Prefetch, Q
from django.db.models.functions import ExtractYear
from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from django.utils.translation import get_language as django_get_language
Expand All @@ -20,7 +21,7 @@
from rest_framework.response import Response
from rest_framework.settings import api_settings

from api.models import Country
from api.models import AppealType, Country, Region
from deployments.models import SectorTag
from main.permissions import DenyGuestUserMutationPermission, DenyGuestUserPermission
from main.utils import SpreadSheetContentNegotiation
Expand Down Expand Up @@ -921,6 +922,61 @@ def summary(self, request):
)
return response.Response(OpsLearningSummarySerializer(ops_learning_summary_instance).data)

@action(
detail=False,
methods=["GET"],
permission_classes=[DenyGuestUserMutationPermission, OpsLearningPermission],
url_path="stats",
)
def stats(self, request):
"""
Get the Ops Learning stats based on the filters
"""
ops_data = OpsLearning.objects.aggregate(
operations_included=Count("appeal_code", distinct=True),
learning_extracts=Count("id", filter=Q(is_validated=True), distinct=True),
sector_covered=Count("sector_validated", distinct=True),
source_used=Count("appeal_code__appealdocument", distinct=True),
)

learning_by_sector = (
SectorTag.objects.filter(title__isnull=False)
.annotate(count=Count("validated_sectors", distinct=True))
.values("id", "title", "count")
)
learning_by_region = (
Region.objects.annotate(count=Count("appeal__opslearning", distinct=True))
.values("id", "label", "count")
.order_by("label")
)

learning_by_country = (
Country.objects.annotate(operation_count=Count("appeal__opslearning", distinct=True))
.values("id", "name", "operation_count")
.order_by("name")
)

sources_overtime = {
str(appeal_type_label): OpsLearning.objects.filter(appeal_code__atype=appeal_type)
.annotate(year=ExtractYear(F("appeal_code__start_date")))
.values("year")
.annotate(count=Count("appeal_code__appealdocument", distinct=True))
.order_by("year")
for appeal_type, appeal_type_label in AppealType.choices
}

data = {
"operations_included": ops_data["operations_included"],
"learning_extracts": ops_data["learning_extracts"],
"sectors_covered": ops_data["sector_covered"],
"sources_used": ops_data["source_used"],
"learning_by_region": learning_by_region,
"learning_by_sector": learning_by_sector,
"sources_overtime": sources_overtime,
"learning_by_country": learning_by_country,
}
return response.Response(data)


class PerDocumentUploadViewSet(viewsets.ModelViewSet):
queryset = PerDocumentUpload.objects.all()
Expand Down
19 changes: 19 additions & 0 deletions per/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import factory
from factory import fuzzy

from api.factories.country import CountryFactory
from api.models import Appeal, AppealDocument
from deployments.factories.project import SectorTagFactory
from per.models import (
AssessmentType,
Expand Down Expand Up @@ -105,12 +107,22 @@ class Meta:
model = FormPrioritization


class AppealFactory(factory.django.DjangoModelFactory):
class Meta:
model = Appeal

country = factory.SubFactory(CountryFactory)


class OpsLearningFactory(factory.django.DjangoModelFactory):
learning = fuzzy.FuzzyText(length=50)

class Meta:
model = OpsLearning

appeal_code = factory.SubFactory(AppealFactory)
is_validated = fuzzy.FuzzyChoice([True, False])


class OpsLearningCacheResponseFactory(factory.django.DjangoModelFactory):
used_filters_hash = fuzzy.FuzzyText(length=20)
Expand Down Expand Up @@ -141,3 +153,10 @@ class OpsLearningComponentCacheResponseFactory(factory.django.DjangoModelFactory

class Meta:
model = OpsLearningComponentCacheResponse


class AppealDocumentFactory(factory.django.DjangoModelFactory):
class Meta:
model = AppealDocument

appeal = factory.SubFactory(AppealFactory)
95 changes: 95 additions & 0 deletions per/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,19 @@
from unittest import mock

from api.factories.country import CountryFactory
from api.factories.region import RegionFactory
from api.models import AppealType
from main.test_case import APITestCase
from per.factories import (
AppealDocumentFactory,
AppealFactory,
FormAreaFactory,
FormComponentFactory,
FormPrioritizationFactory,
OpsLearningFactory,
OverviewFactory,
PerWorkPlanFactory,
SectorTagFactory,
)

from .models import WorkPlanStatus
Expand Down Expand Up @@ -224,3 +229,93 @@ def test_summary_generation(self, generate_summary):
}
self.check_response_id(url=url, data=filters)
self.assertTrue(generate_summary.assert_called)


class OpsLearningStatsTestCase(APITestCase):

@classmethod
def setUpTestData(cls):
cls.region = RegionFactory.create(label="Region A")
cls.country = CountryFactory.create(region=cls.region, name="Country A")

cls.sector1 = SectorTagFactory.create(title="Sector 1")
cls.sector2 = SectorTagFactory.create(title="Sector 2")

cls.appeal1 = AppealFactory.create(
region=cls.region, country=cls.country, code="APP001", atype=0, start_date="2023-01-01"
)
cls.appeal2 = AppealFactory.create(
region=cls.region, country=cls.country, code="APP002", atype=1, start_date="2023-02-01"
)
AppealDocumentFactory.create(appeal=cls.appeal1)
AppealDocumentFactory.create(appeal=cls.appeal2)

cls.ops_learning1 = OpsLearningFactory.create(is_validated=True, appeal_code=cls.appeal1)
cls.ops_learning1.sector_validated.set([cls.sector1])

cls.ops_learning2 = OpsLearningFactory.create(is_validated=False, appeal_code=cls.appeal2)
cls.ops_learning2.sector_validated.set([cls.sector2])

cls.ops_learning3 = OpsLearningFactory.create(is_validated=False, appeal_code=cls.appeal2)
cls.ops_learning3.sector_validated.set([cls.sector2])

def test_ops_learning_stats(self):
url = "/api/v2/ops-learning/stats/"
response = self.client.get(url)

self.assertEqual(response.status_code, 200)

# Validate keys in response
expected_keys = [
"operations_included",
"sources_used",
"learning_extracts",
"sectors_covered",
"sources_overtime",
"learning_by_region",
"learning_by_sector",
"learning_by_country",
]
for key in expected_keys:
self.assertIn(key, response.data)
print(response.data)

# Validate counts
self.assertEqual(response.data["operations_included"], 2)
self.assertEqual(response.data["sources_used"], 2)
self.assertEqual(response.data["learning_extracts"], 1)
self.assertEqual(response.data["sectors_covered"], 2)

# Validate learning_by_region
region_data = response.data["learning_by_region"]
self.assertEqual(len(region_data), 1)
self.assertEqual(region_data[0]["label"], "Region A")
self.assertEqual(region_data[0]["count"], 3)

# Validate learning_by_sector
sector_data = response.data["learning_by_sector"]
self.assertEqual(len(sector_data), 2)
self.assertEqual(sector_data[0]["title"], "Sector 1")
self.assertEqual(sector_data[0]["count"], 1)
self.assertEqual(sector_data[1]["title"], "Sector 2")
self.assertEqual(sector_data[1]["count"], 2)

# Validate learning_by_country
country_data = response.data["learning_by_country"]
self.assertEqual(len(country_data), 1)
self.assertEqual(country_data[0]["name"], "Country A")
self.assertEqual(country_data[0]["operation_count"], 3)

# Validate sources_overtime
for appeal_type, label in AppealType.choices:
self.assertIn(label, response.data["sources_overtime"])
for item in response.data["sources_overtime"][label]:
self.assertIn("year", item)
self.assertIn("count", item)

if label == "DREF":
self.assertEqual(item["year"], 2023)
self.assertEqual(item["count"], 1)
elif label == "Emergency Appeal":
self.assertEqual(item["year"], 2023)
self.assertEqual(item["count"], 1)

0 comments on commit 3e73ced

Please sign in to comment.