Skip to content

Commit

Permalink
Merge pull request #4397 from unicef/staging
Browse files Browse the repository at this point in the history
Staging back
  • Loading branch information
domdinicola authored Nov 1, 2024
2 parents 7c9ecdb + 459e6d5 commit 9e2e661
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 56 deletions.
2 changes: 1 addition & 1 deletion src/frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "frontend",
"version": "2.12.0",
"version": "2.12.1",
"private": true,
"type": "module",
"scripts": {
Expand Down
1 change: 1 addition & 0 deletions src/hct_mis_api/apps/household/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1093,6 +1093,7 @@ def get_hash_key(self) -> str:
"given_name",
"middle_name",
"family_name",
"full_name",
"sex",
"birth_date",
"phone_no",
Expand Down
3 changes: 2 additions & 1 deletion src/hct_mis_api/apps/periodic_data_update/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError
from rest_framework.filters import OrderingFilter
from rest_framework.permissions import IsAuthenticated
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.serializers import BaseSerializer
Expand Down Expand Up @@ -192,7 +193,7 @@ class PeriodicFieldViewSet(
GenericViewSet,
):
serializer_class = PeriodicFieldSerializer
permission_classes = [PDUViewListAndDetailsPermission]
permission_classes = [IsAuthenticated]
filter_backends = (OrderingFilter, DjangoFilterBackend)
filterset_class = UpdatedAtFilter

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import logging

from django.db.models import Count

from hct_mis_api.apps.household.models import Household

logger = logging.getLogger(__name__)


def remove_production_duplicates_after_enrollment() -> None:
# Exceptions from the further rules
for household in Household.objects.filter(
id__in=[
"8b9bf768-4837-49aa-a598-5ad3c5822ca8",
"33a7bdf0-650d-49b4-b333-c49a7eb05356",
]
):
household.delete(soft=False)

households_with_duplicates = (
Household.objects.values("unicef_id", "program")
.annotate(household_count=Count("id"))
.filter(household_count__gt=1)
.order_by("copied_from__registration_data_import")
)
logger.info(f"Found {households_with_duplicates.count()} households with duplicates")

for i, entry in enumerate(households_with_duplicates, 1):
unicef_id = entry["unicef_id"]
program = entry["program"]

households = Household.objects.filter(unicef_id=unicef_id, program=program).order_by("created_at")

# Keep the first household and delete the duplicates
first = True
households_to_remove = []
for household in households:
if first:
first = False
continue
if household.payment_set.exists():
logger.info(f"Skipping {household.id} because it has payments")
continue
else:
households_to_remove.append(household)
for duplicate in households_to_remove:
duplicate.delete(soft=False)

if i % 100 == 0:
logger.info(f"Processed {i}/{households_with_duplicates.count()} households")
Original file line number Diff line number Diff line change
Expand Up @@ -57,55 +57,6 @@ def set_up(self, api_client: Callable, afghanistan: BusinessAreaFactory, id_to_b
},
)

@pytest.mark.parametrize(
"permissions, partner_permissions, access_to_program, expected_status",
[
([], [], True, status.HTTP_403_FORBIDDEN),
([Permissions.PDU_VIEW_LIST_AND_DETAILS], [], True, status.HTTP_200_OK),
([], [Permissions.PDU_VIEW_LIST_AND_DETAILS], True, status.HTTP_200_OK),
(
[Permissions.PDU_VIEW_LIST_AND_DETAILS],
[Permissions.PDU_VIEW_LIST_AND_DETAILS],
True,
status.HTTP_200_OK,
),
([], [], False, status.HTTP_403_FORBIDDEN),
([Permissions.PDU_VIEW_LIST_AND_DETAILS], [], False, status.HTTP_403_FORBIDDEN),
([], [Permissions.PDU_VIEW_LIST_AND_DETAILS], False, status.HTTP_403_FORBIDDEN),
(
[Permissions.PDU_VIEW_LIST_AND_DETAILS],
[Permissions.PDU_VIEW_LIST_AND_DETAILS],
False,
status.HTTP_403_FORBIDDEN,
),
],
)
def test_list_periodic_fields_permission(
self,
permissions: list,
partner_permissions: list,
access_to_program: bool,
expected_status: str,
api_client: Callable,
afghanistan: BusinessAreaFactory,
create_user_role_with_permissions: Callable,
create_partner_role_with_permissions: Callable,
update_partner_access_to_program: Callable,
id_to_base64: Callable,
) -> None:
self.set_up(api_client, afghanistan, id_to_base64)
create_user_role_with_permissions(
self.user,
permissions,
self.afghanistan,
)
create_partner_role_with_permissions(self.partner, partner_permissions, self.afghanistan)
if access_to_program:
update_partner_access_to_program(self.partner, self.program1)

response = self.client.get(self.url_list)
assert response.status_code == expected_status

def test_list_periodic_fields(
self,
api_client: Callable,
Expand Down Expand Up @@ -186,7 +137,7 @@ def test_list_periodic_fields_caching(

etag = response.headers["etag"]
assert json.loads(cache.get(etag)[0].decode("utf8")) == response.json()
assert len(ctx.captured_queries) == 11
assert len(ctx.captured_queries) == 6

# Test that reoccurring requests use cached data
with CaptureQueriesContext(connection) as ctx:
Expand All @@ -195,7 +146,7 @@ def test_list_periodic_fields_caching(

etag_second_call = response.headers["etag"]
assert json.loads(cache.get(response.headers["etag"])[0].decode("utf8")) == response.json()
assert len(ctx.captured_queries) == 5
assert len(ctx.captured_queries) == 0

assert etag_second_call == etag

Expand All @@ -208,7 +159,7 @@ def test_list_periodic_fields_caching(

etag_call_after_update = response.headers["etag"]
assert json.loads(cache.get(response.headers["etag"])[0].decode("utf8")) == response.json()
assert len(ctx.captured_queries) == 11
assert len(ctx.captured_queries) == 6

assert etag_call_after_update != etag

Expand All @@ -219,7 +170,7 @@ def test_list_periodic_fields_caching(

etag_call_after_update_second_call = response.headers["etag"]
assert json.loads(cache.get(response.headers["etag"])[0].decode("utf8")) == response.json()
assert len(ctx.captured_queries) == 5
assert len(ctx.captured_queries) == 0

assert etag_call_after_update_second_call == etag_call_after_update

Expand All @@ -232,6 +183,6 @@ def test_list_periodic_fields_caching(

etag_call_after_update_2 = response.headers["etag"]
assert json.loads(cache.get(response.headers["etag"])[0].decode("utf8")) == response.json()
assert len(ctx.captured_queries) == 11
assert len(ctx.captured_queries) == 6

assert etag_call_after_update_2 != etag_call_after_update_second_call
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
from django.test import TestCase

from hct_mis_api.apps.core.fixtures import create_afghanistan
from hct_mis_api.apps.household.fixtures import create_household_and_individuals
from hct_mis_api.apps.household.models import Household, Individual
from hct_mis_api.apps.payment.fixtures import PaymentFactory
from hct_mis_api.apps.program.fixtures import ProgramFactory
from hct_mis_api.one_time_scripts.remove_production_duplicates_after_enrollment import (
remove_production_duplicates_after_enrollment,
)


class TestRemoveProductionDuplicatesAfterEnrollment(TestCase):
def test_remove_production_duplicates_after_enrollment(self) -> None:
business_area = create_afghanistan()
program = ProgramFactory(business_area=business_area)
program2 = ProgramFactory(business_area=business_area)
hh_unicef_id = "HH-20-0000.0001"
household_special_case1, individuals_special_case1 = create_household_and_individuals(
household_data={
"id": "8b9bf768-4837-49aa-a598-5ad3c5822ca8",
"unicef_id": hh_unicef_id,
"business_area": program.business_area,
"program": program,
},
individuals_data=[{}],
)
household_special_case2, individuals_special_case2 = create_household_and_individuals(
household_data={
"id": "33a7bdf0-650d-49b4-b333-c49a7eb05356",
"unicef_id": hh_unicef_id,
"business_area": program.business_area,
"program": program,
},
individuals_data=[{}],
)
household1, individuals1 = create_household_and_individuals(
household_data={
"unicef_id": hh_unicef_id,
"business_area": program.business_area,
"program": program,
},
individuals_data=[{}, {}],
)
household2, individuals2 = create_household_and_individuals(
household_data={
"unicef_id": hh_unicef_id,
"business_area": program.business_area,
"program": program,
},
individuals_data=[{}, {}],
)
household3, individuals3 = create_household_and_individuals(
household_data={
"unicef_id": hh_unicef_id,
"business_area": program.business_area,
"program": program,
},
individuals_data=[{}],
)
PaymentFactory(household=household3)

household4, individuals4 = create_household_and_individuals(
household_data={
"unicef_id": hh_unicef_id,
"business_area": program.business_area,
"program": program,
},
individuals_data=[{}],
)
household_from_another_program, individuals_from_another_program = create_household_and_individuals(
household_data={
"unicef_id": hh_unicef_id,
"business_area": program2.business_area,
"program": program2,
},
individuals_data=[{}],
)

remove_production_duplicates_after_enrollment()

self.assertIsNotNone(Household.all_objects.filter(id=household1.id).first())
self.assertIsNotNone(Individual.all_objects.filter(id=individuals1[0].id).first())
self.assertIsNotNone(Individual.all_objects.filter(id=individuals1[1].id).first())

self.assertIsNone(Household.all_objects.filter(id=household2.id).first())
self.assertIsNone(Individual.all_objects.filter(id=individuals2[0].id).first())
self.assertIsNone(Individual.all_objects.filter(id=individuals2[1].id).first())

self.assertIsNotNone(Individual.all_objects.filter(id=individuals3[0].id).first())
self.assertIsNotNone(Household.all_objects.filter(id=household3.id).first())

self.assertIsNone(Household.all_objects.filter(id=household4.id).first())
self.assertIsNone(Individual.all_objects.filter(id=individuals4[0].id).first())

self.assertIsNotNone(Household.all_objects.filter(id=household_from_another_program.id).first())
self.assertIsNotNone(Individual.all_objects.filter(id=individuals_from_another_program[0].id).first())

self.assertIsNone(Household.all_objects.filter(id=household_special_case1.id).first())
self.assertIsNone(Individual.all_objects.filter(id=individuals_special_case1[0].id).first())

self.assertIsNone(Household.all_objects.filter(id=household_special_case2.id).first())
self.assertIsNone(Individual.all_objects.filter(id=individuals_special_case2[0].id).first())

0 comments on commit 9e2e661

Please sign in to comment.