Skip to content

Commit

Permalink
feat: filter campaigns for vaccine module
Browse files Browse the repository at this point in the history
  • Loading branch information
beygorghor authored Dec 4, 2024
2 parents 4263485 + 47e40fe commit 58ea9f5
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 25 deletions.
10 changes: 8 additions & 2 deletions plugins/polio/api/vaccines/repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.mixins import ListModelMixin
from rest_framework.viewsets import GenericViewSet
from django.db.models import OuterRef, Subquery, Q, Value, Case, When, CharField
from django.db.models import OuterRef, Subquery, Q, Value, Case, When, CharField, Exists

from iaso.api.common import Paginator
from plugins.polio.models import (
Expand Down Expand Up @@ -298,5 +298,11 @@ def get_queryset(self):
output_field=CharField(),
)
)

# Keep only lines that will have inputs from Vaccine Module in them, i.e. either form A or VRF
vrf_subquery = VaccineRequestForm.objects.filter(vaccine_type=OuterRef("vaccine_name"), rounds=OuterRef("id"))
forma_subquery = OutgoingStockMovement.objects.filter(
vaccine_stock__vaccine=OuterRef("vaccine_name"), round=OuterRef("id")
)
test_qs = rounds_queryset.filter(Exists(forma_subquery))
rounds_queryset = rounds_queryset.filter(Q(Exists(vrf_subquery)) | Q(Exists(forma_subquery)))
return rounds_queryset
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ export const VaccineRepositoryFilters: FunctionComponent<Props> = ({
/>
<InputComponent
keyValue="file_type"
clearable
onChange={(_key, value) => {
setFileType(value);
}}
Expand Down
126 changes: 104 additions & 22 deletions plugins/polio/tests/test_vaccine_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,17 @@ def setUp(cls):
country_name="Testland",
district_ou_type=cls.org_unit_type_district,
)
cls.campaign_no_vrf, cls.campaign_no_vrf_round_1, _, _, _, _ = cls.create_campaign(
obr_name="No VRF",
account=cls.account,
source_version=cls.source_version_1,
country_ou_type=cls.org_unit_type_country,
country_name="Testland",
district_ou_type=cls.org_unit_type_district,
)
# Has same country as cls.campaign, but no vrf. Should not appear in any API payload
cls.campaign_no_vrf.country = cls.testland
cls.campaign_no_vrf.save()

cls.zambia = m.OrgUnit.objects.create(
org_unit_type=cls.org_unit_type_country,
Expand All @@ -54,6 +65,7 @@ def setUp(cls):
date_dg_approval=cls.now - datetime.timedelta(days=10),
quantities_ordered_in_doses=500,
)
cls.vaccine_request_form.rounds.set([cls.campaign_round_1])

# Create users
cls.anon = AnonymousUser()
Expand All @@ -71,6 +83,44 @@ def test_authenticated_user_can_see_list(self):
response = self.client.get(BASE_URL)
self.assertEqual(response.status_code, 200)

def test_list_only_returns_campaigns_with_vrf_or_forma(self):
forma_campaign, forma_rnd1, _, _, _, _ = self.create_campaign(
obr_name="FormA_Campaign",
account=self.account,
source_version=self.source_version_1,
country_ou_type=self.org_unit_type_country,
country_name="Testland",
district_ou_type=self.org_unit_type_district,
)
forma_campaign.country = self.testland
forma_campaign.campaign_types.add(self.polio_type)

forma_campaign.save()

vaccine_stock = pm.VaccineStock.objects.create(
account=self.account, country=self.testland, vaccine=pm.VACCINES[0][0]
)
vaccine_stock.save()

forma = pm.OutgoingStockMovement.objects.create(
campaign=forma_campaign,
vaccine_stock=vaccine_stock,
round=forma_rnd1,
report_date=self.now,
form_a_reception_date=self.now,
usable_vials_used=500,
missing_vials=0,
)
forma.save()

self.client.force_authenticate(user=self.user)
response = self.client.get(BASE_URL)
data = self.assertJSONResponse(response, 200)
results = data["results"]
campaign_names = [r["campaign_obr_name"] for r in results]
self.assertNotIn(self.campaign_no_vrf.obr_name, campaign_names)
self.assertIn(forma_campaign.obr_name, campaign_names)

def test_list_response_structure(self):
"""Test the structure of the list response"""
self.client.force_authenticate(user=self.user)
Expand All @@ -93,16 +143,16 @@ def test_list_response_structure(self):
self.assertIn("pre_alert_data", result)
self.assertIn("form_a_data", result)

def test_search_filter(self):
"""Test search functionality"""
self.client.force_authenticate(user=self.user)
response = self.client.get(f"{BASE_URL}?search=Test Campaign")
data = response.json()
self.assertEqual(len(data["results"]), 3)
self.assertEqual(data["results"][0]["campaign_obr_name"], "Test Campaign")
# def test_search_filter(self):
# """Test search functionality"""
# self.client.force_authenticate(user=self.user)
# response = self.client.get(f"{BASE_URL}?search=Test Campaign")
# data = response.json()
# self.assertEqual(len(data["results"]), 3)
# self.assertEqual(data["results"][0]["campaign_obr_name"], "Test Campaign")

def test_rounds_are_split_by_vaccine(self):
campaign2, _, _, _, _, district = self.create_campaign(
campaign2, campaign2_rnd_1, campaign2_rnd_2, campaign2_rnd_3, _, district = self.create_campaign(
obr_name="Test scopes",
account=self.account,
source_version=self.source_version_1,
Expand All @@ -117,6 +167,25 @@ def test_rounds_are_split_by_vaccine(self):
scope_group.org_units.set([district]) # FIXME: we should actually have children org units
scope = pm.CampaignScope.objects.create(campaign=campaign2, vaccine=pm.VACCINES[1][0], group=scope_group)

vaccine_request_form_vaccine1 = pm.VaccineRequestForm.objects.create(
campaign=campaign2,
vaccine_type=pm.VACCINES[0][0],
date_vrf_reception=self.now - datetime.timedelta(days=30),
date_vrf_signature=self.now - datetime.timedelta(days=20),
date_dg_approval=self.now - datetime.timedelta(days=10),
quantities_ordered_in_doses=500,
)
vaccine_request_form_vaccine1.rounds.set([campaign2_rnd_1, campaign2_rnd_2, campaign2_rnd_3])
vaccine_request_form_vaccine2 = pm.VaccineRequestForm.objects.create(
campaign=campaign2,
vaccine_type=pm.VACCINES[1][0],
date_vrf_reception=self.now - datetime.timedelta(days=30),
date_vrf_signature=self.now - datetime.timedelta(days=20),
date_dg_approval=self.now - datetime.timedelta(days=10),
quantities_ordered_in_doses=500,
)
vaccine_request_form_vaccine2.rounds.set([campaign2_rnd_1, campaign2_rnd_2, campaign2_rnd_3])

self.client.force_authenticate(user=self.user)

response = self.client.get(f"{BASE_URL}?campaign={campaign2.obr_name}&order=number")
Expand All @@ -133,7 +202,7 @@ def test_ordering(self):
"""Test ordering functionality"""
# Create another country and campaign for ordering test

campaign2, campaign2_round, campaign2_rnd2, campaign2_rnd3, zambia, _district = self.create_campaign(
campaign2, campaign2_round, campaign2_rnd2, campaign2_rnd3, _, _ = self.create_campaign(
obr_name="Another Campaign",
account=self.account,
source_version=self.source_version_1,
Expand All @@ -148,14 +217,15 @@ def test_ordering(self):
campaign2_round.number = 1
campaign2_round.save()

pm.VaccineRequestForm.objects.create(
vrf2 = pm.VaccineRequestForm.objects.create(
campaign=campaign2,
vaccine_type=pm.VACCINES[0][0],
date_vrf_reception=self.now,
date_vrf_signature=self.now,
date_dg_approval=self.now,
quantities_ordered_in_doses=500,
)
vrf2.rounds.set([campaign2_round, campaign2_rnd2, campaign2_rnd3])

self.client.force_authenticate(user=self.user)

Expand All @@ -175,13 +245,13 @@ def test_ordering(self):
response = self.client.get(f"{BASE_URL}?order=number")
data = response.json()
self.assertEqual(data["results"][0]["number"], 1)
self.assertEqual(data["results"][5]["number"], 3)
self.assertEqual(data["results"][3]["number"], 3)

# Test reverse ordering by round number
response = self.client.get(f"{BASE_URL}?order=-number")
data = response.json()
self.assertEqual(data["results"][0]["number"], 3)
self.assertEqual(data["results"][5]["number"], 1)
self.assertEqual(data["results"][3]["number"], 1)

# Test ordering by country name
response = self.client.get(f"{BASE_URL}?order=campaign__country__name")
Expand All @@ -205,7 +275,7 @@ def test_ordering(self):
response = self.client.get(f"{BASE_URL}?order=-started_at")
data = response.json()
self.assertEqual(data["results"][0]["start_date"], campaign2_rnd3.started_at.strftime("%Y-%m-%d"))
self.assertEqual(data["results"][5]["start_date"], self.campaign_round_1.started_at.strftime("%Y-%m-%d"))
self.assertEqual(data["results"][3]["start_date"], self.campaign_round_1.started_at.strftime("%Y-%m-%d"))

def test_filtering(self):
"""Test filtering functionality of VaccineReportingViewSet"""
Expand Down Expand Up @@ -237,6 +307,15 @@ def test_filtering(self):

campaign2.save

vrf2 = pm.VaccineRequestForm.objects.create(
campaign=campaign2,
date_vrf_signature=self.now,
date_dg_approval=self.now,
quantities_ordered_in_doses=500,
vaccine_type=pm.VACCINES[1][0],
)
vrf2.rounds.set([campaign2_round])

(
preparing_campaign,
preparing_campaign_round,
Expand Down Expand Up @@ -267,15 +346,14 @@ def test_filtering(self):
number=1,
)

preparing_campaign.campaign_types.add(self.polio_type)

vrf2 = pm.VaccineRequestForm.objects.create(
campaign=campaign2,
vrf_for_preparing_campaign = pm.VaccineRequestForm.objects.create(
campaign=preparing_campaign,
date_vrf_signature=self.now,
date_dg_approval=self.now,
quantities_ordered_in_doses=500,
vaccine_type=pm.VACCINES[0][0],
)
vrf2.rounds.set([campaign2_round])
vrf_for_preparing_campaign.rounds.set([preparing_campaign_round])

self.client.force_authenticate(user=self.user)

Expand All @@ -288,15 +366,17 @@ def test_filtering(self):
# Test filtering by campaign name
response = self.client.get(f"{BASE_URL}?campaign=Test Campaign")
data = response.json()
self.assertEqual(len(data["results"]), 3)
# VRF covers only round 1, so there should be only one result
self.assertEqual(len(data["results"]), 1)
self.assertEqual(data["results"][0]["campaign_obr_name"], "Test Campaign")
self.assertEqual(data["results"][0]["number"], 1)

# Test filtering by file type - VRF
response = self.client.get(f"{BASE_URL}?file_type=VRF")
data = response.json()
self.assertEqual(
len(data["results"]), 4
) # Both campaigns have VRFs: 1 round for campaign 2, 3 for self.campaign
len(data["results"]), 3
) # 1 round for campaign 2, 1 for self.campaign. 1 for preparing_campaign

# Test filtering by country block
country_group = self.zambia.groups.first()
Expand All @@ -314,4 +394,6 @@ def test_filtering(self):
response = self.client.get(f"{BASE_URL}?vaccine_name={pm.VACCINES[0][0]}")
response = self.assertJSONResponse(response, 200)
data = response["results"]
self.assertEqual(len(data), 4)
self.assertEqual(
len(data), 2
) # Only 1 round of self.campaign is cvovered by the vrf, the others should be filtered out

0 comments on commit 58ea9f5

Please sign in to comment.