diff --git a/api/filter_set.py b/api/filter_set.py index d486a8660..625c4da7a 100644 --- a/api/filter_set.py +++ b/api/filter_set.py @@ -284,6 +284,17 @@ class AppealHistoryFilter(filters.FilterSet): label="admin2", method="get_country_admin2", ) + needs_confirmation = filters.BooleanFilter( + field_name="needs_confirmation", + label="needs_confirmation", + lookup_expr="exact", + ) + has_event = filters.BooleanFilter( + field_name="appeal__event", + lookup_expr="isnull", + label="has_event", + exclude=True, + ) class Meta: model = AppealHistory diff --git a/api/serializers.py b/api/serializers.py index f86f18e4a..351749947 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -1610,10 +1610,26 @@ class Meta: ) +class EventDetailsSerializer(ModelSerializer): + ifrc_severity_level_display = serializers.CharField(source="get_ifrc_severity_level_display", read_only=True) + + class Meta: + model = Event + fields = ( + "id", + "name", + "ifrc_severity_level", + "ifrc_severity_level_display", + "ifrc_severity_level_update_date", + "updated_at", + ) + + class AppealHistorySerializer(ModelSerializer): country = MiniCountrySerializer(read_only=True) dtype = DisasterTypeSerializer(read_only=True) region = RegionSerializer(read_only=True) + event_details = EventDetailsSerializer(source="appeal.event", read_only=True) atype_display = serializers.CharField(source="get_atype_display", read_only=True) status_display = serializers.CharField(source="get_status_display", read_only=True) code = serializers.CharField(source="appeal.code", read_only=True) @@ -1650,6 +1666,7 @@ class Meta: "country", "region", "id", + "event_details", ) diff --git a/assets b/assets index be88b0a95..cece1600a 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit be88b0a95eb28d1652cd2e2791332d84ef6ae30b +Subproject commit cece1600a646c7ed85fe681be757886eff7888ce diff --git a/deployments/drf_views.py b/deployments/drf_views.py index 6860183c1..e86168385 100644 --- a/deployments/drf_views.py +++ b/deployments/drf_views.py @@ -1021,6 +1021,7 @@ class ERUReadinessFilter(filters.FilterSet): eru_owner = filters.NumberFilter(field_name="eru_owner", lookup_expr="exact") eru_type = filters.NumberFilter(field_name="eru_types__type", lookup_expr="exact") eru_type__in = ListFilter(field_name="eru_types__type") + ns_contribution = filters.NumberFilter(field_name="eru_types__ns_contribution", lookup_expr="exact") class ERUReadinessViewSet(RevisionMixin, viewsets.ModelViewSet): diff --git a/deployments/enums.py b/deployments/enums.py index 97da79815..42b0ed30d 100644 --- a/deployments/enums.py +++ b/deployments/enums.py @@ -11,4 +11,5 @@ "emergency_project_status": models.EmergencyProject.ActivityStatus, "emergency_project_activity_people_households": models.EmergencyProjectActivity.PeopleHouseholds, "eru_readiness_status": models.ERUReadinessType.ReadinessStatus, + "eru_readiness_ns_contribution": models.ERUReadinessType.NationalSocietyContribution, } diff --git a/deployments/factories/emergency_project.py b/deployments/factories/emergency_project.py index 922927f36..f7ad9429e 100644 --- a/deployments/factories/emergency_project.py +++ b/deployments/factories/emergency_project.py @@ -116,3 +116,4 @@ class Meta: people_readiness = fuzzy.FuzzyChoice(ERUReadinessType.ReadinessStatus) funding_readiness = fuzzy.FuzzyChoice(ERUReadinessType.ReadinessStatus) comment = fuzzy.FuzzyText(length=10, prefix="comment-") + ns_contribution = fuzzy.FuzzyChoice(ERUReadinessType.NationalSocietyContribution) diff --git a/deployments/migrations/0094_erureadinesstype_ns_contribution.py b/deployments/migrations/0094_erureadinesstype_ns_contribution.py new file mode 100644 index 000000000..1dc1b897d --- /dev/null +++ b/deployments/migrations/0094_erureadinesstype_ns_contribution.py @@ -0,0 +1,19 @@ +# Generated by Django 4.2.29 on 2026-03-18 05:13 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('deployments', '0093_sector_title_ar_sector_title_en_sector_title_es_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='erureadinesstype', + name='ns_contribution', + field=models.IntegerField(choices=[(1, 'Confirm that you have the capacity to hold this type of ERU'), (2, 'Confirm that you have the capacity to support this type of ERU')], default=1, verbose_name='National Society Contribution'), + preserve_default=False, + ), + ] diff --git a/deployments/models.py b/deployments/models.py index 988f3713d..1441be0f0 100644 --- a/deployments/models.py +++ b/deployments/models.py @@ -927,6 +927,18 @@ class ReadinessStatus(models.IntegerChoices): PARTIAL_CAPACITY = 2, _("Partial capacity") NO_CAPACITY = 3, _("No capacity") + class NationalSocietyContribution(models.IntegerChoices): + """ + Note:The enum values are intentionally written in a longer form so the frontend design and + labels can directly use and reflect them. + """ + + HOLDS = 1, _("Confirm that you have the capacity to hold this type of ERU") + """The National Society owns and maintains the ERU and is responsible for its readiness.""" + + SUPPORTS = 2, _("Confirm that you have the capacity to support this type of ERU") + """The National Society provides support to the ERU but does not hold it.""" + type = models.IntegerField(choices=ERUType.choices, verbose_name=_("ERU type")) equipment_readiness = models.IntegerField( choices=ReadinessStatus.choices, @@ -941,6 +953,10 @@ class ReadinessStatus(models.IntegerChoices): verbose_name=_("funding readiness"), ) comment = models.TextField(verbose_name=_("comment"), blank=True, null=True) + ns_contribution = models.IntegerField( + choices=NationalSocietyContribution.choices, + verbose_name=_("National Society Contribution"), + ) class Meta: verbose_name = _("ERU Readiness Type") diff --git a/deployments/serializers.py b/deployments/serializers.py index 76a5a00c6..d6b26a5dd 100644 --- a/deployments/serializers.py +++ b/deployments/serializers.py @@ -1056,6 +1056,7 @@ class ERUReadinessTypeSerializer(serializers.ModelSerializer): equipment_readiness_display = serializers.CharField(source="get_equipment_readiness_display", read_only=True) people_readiness_display = serializers.CharField(source="get_people_readiness_display", read_only=True) funding_readiness_display = serializers.CharField(source="get_funding_readiness_display", read_only=True) + ns_contribution_display = serializers.CharField(source="get_ns_contribution_display", read_only=True) class Meta: model = ERUReadinessType diff --git a/deployments/tests.py b/deployments/tests.py index 667bf8dc5..456f8fac7 100644 --- a/deployments/tests.py +++ b/deployments/tests.py @@ -491,6 +491,7 @@ def test_eru_readiness_list(self): "equipment_readiness": ERUReadinessType.ReadinessStatus.READY, "people_readiness": ERUReadinessType.ReadinessStatus.READY, "funding_readiness": ERUReadinessType.ReadinessStatus.READY, + "ns_contribution": ERUReadinessType.NationalSocietyContribution.HOLDS, } eru_readiness_type_1, eru_readiness_type_2 = ERUReadinessTypeFactory.create_batch( 2, @@ -531,6 +532,7 @@ def test_eru_readiness_create(self): "equipment_readiness": ERUReadinessType.ReadinessStatus.READY, "people_readiness": ERUReadinessType.ReadinessStatus.READY, "funding_readiness": ERUReadinessType.ReadinessStatus.READY, + "ns_contribution": ERUReadinessType.NationalSocietyContribution.SUPPORTS, } eru_readiness_type_1 = ERUReadinessTypeFactory.create( type=ERUType.OSH, @@ -549,12 +551,14 @@ def test_eru_readiness_create(self): "equipment_readiness": eru_readiness_type_1.equipment_readiness, "people_readiness": eru_readiness_type_1.people_readiness, "funding_readiness": eru_readiness_type_1.funding_readiness, + "ns_contribution": eru_readiness_type_1.ns_contribution, }, { "type": eru_readiness_type_2.type, "equipment_readiness": eru_readiness_type_2.equipment_readiness, "people_readiness": eru_readiness_type_2.people_readiness, "funding_readiness": eru_readiness_type_2.funding_readiness, + "ns_contribution": eru_readiness_type_2.ns_contribution, }, ], } @@ -571,6 +575,7 @@ def test_eru_readiness_update(self): "equipment_readiness": ERUReadinessType.ReadinessStatus.READY, "people_readiness": ERUReadinessType.ReadinessStatus.READY, "funding_readiness": ERUReadinessType.ReadinessStatus.READY, + "ns_contribution": ERUReadinessType.NationalSocietyContribution.HOLDS, } eru_readiness_type_1 = ERUReadinessTypeFactory.create( type=ERUType.OSH, @@ -598,6 +603,7 @@ def test_eru_readiness_update(self): "equipment_readiness": ERUReadinessType.ReadinessStatus.NO_CAPACITY, "people_readiness": ERUReadinessType.ReadinessStatus.NO_CAPACITY, "funding_readiness": ERUReadinessType.ReadinessStatus.NO_CAPACITY, + "ns_contribution": ERUReadinessType.NationalSocietyContribution.SUPPORTS, }, { "id": eru_readiness_type_2.id, @@ -605,6 +611,7 @@ def test_eru_readiness_update(self): "equipment_readiness": ERUReadinessType.ReadinessStatus.READY, "people_readiness": ERUReadinessType.ReadinessStatus.READY, "funding_readiness": ERUReadinessType.ReadinessStatus.READY, + "ns_contribution": ERUReadinessType.NationalSocietyContribution.SUPPORTS, }, # Add new ERU type { @@ -612,6 +619,7 @@ def test_eru_readiness_update(self): "equipment_readiness": ERUReadinessType.ReadinessStatus.PARTIAL_CAPACITY, "people_readiness": ERUReadinessType.ReadinessStatus.PARTIAL_CAPACITY, "funding_readiness": ERUReadinessType.ReadinessStatus.PARTIAL_CAPACITY, + "ns_contribution": ERUReadinessType.NationalSocietyContribution.HOLDS, }, ], } @@ -640,23 +648,29 @@ def test_eru_readiness_update(self): response.data["eru_types"][0]["equipment_readiness"], response.data["eru_types"][0]["people_readiness"], response.data["eru_types"][0]["funding_readiness"], + response.data["eru_types"][0]["ns_contribution"], response.data["eru_types"][1]["equipment_readiness"], response.data["eru_types"][1]["people_readiness"], response.data["eru_types"][1]["funding_readiness"], + response.data["eru_types"][1]["ns_contribution"], response.data["eru_types"][2]["equipment_readiness"], response.data["eru_types"][2]["people_readiness"], response.data["eru_types"][2]["funding_readiness"], + response.data["eru_types"][2]["ns_contribution"], }, { ERUReadinessType.ReadinessStatus.NO_CAPACITY, ERUReadinessType.ReadinessStatus.NO_CAPACITY, ERUReadinessType.ReadinessStatus.NO_CAPACITY, + ERUReadinessType.NationalSocietyContribution.SUPPORTS, ERUReadinessType.ReadinessStatus.READY, ERUReadinessType.ReadinessStatus.READY, ERUReadinessType.ReadinessStatus.READY, + ERUReadinessType.NationalSocietyContribution.SUPPORTS, ERUReadinessType.ReadinessStatus.PARTIAL_CAPACITY, ERUReadinessType.ReadinessStatus.PARTIAL_CAPACITY, ERUReadinessType.ReadinessStatus.PARTIAL_CAPACITY, + ERUReadinessType.NationalSocietyContribution.HOLDS, }, )