Skip to content

Commit 56c61f3

Browse files
authored
Merge pull request #2689 from IFRCGo/feature/eap-feedbacks
2 parents ed61db0 + 36903d6 commit 56c61f3

13 files changed

Lines changed: 593 additions & 290 deletions

assets

eap/admin.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@
1414
@admin.register(EAPFile)
1515
class EAPFileAdmin(admin.ModelAdmin):
1616
search_fields = ("caption",)
17+
list_select_related = True
18+
autocomplete_fields = (
19+
"created_by",
20+
"modified_by",
21+
)
1722

1823

1924
@admin.register(EAPRegistration)
@@ -85,12 +90,13 @@ class SimplifiedEAPAdmin(admin.ModelAdmin):
8590
"eap_registration__country__name",
8691
"eap_registration__disaster_type__name",
8792
)
88-
list_display = ("simplifed_eap_application", "version", "is_locked")
93+
list_display = ("simplifed_eap_application", "eap_registration", "version", "is_locked")
8994
autocomplete_fields = (
9095
"eap_registration",
9196
"created_by",
9297
"modified_by",
9398
"admin2",
99+
"partners",
94100
)
95101
readonly_fields = (
96102
"cover_image",
@@ -159,6 +165,7 @@ def get_queryset(self, request):
159165
)
160166
.prefetch_related(
161167
"admin2",
168+
"partners",
162169
"partner_contacts",
163170
)
164171
)
@@ -176,12 +183,13 @@ class FullEAPAdmin(admin.ModelAdmin):
176183
"eap_registration__country__name",
177184
"eap_registration__disaster_type__name",
178185
)
179-
list_display = ("eap_registration",)
186+
list_display = ("full_eap_application", "eap_registration", "version", "is_locked")
180187
autocomplete_fields = (
181188
"eap_registration",
182189
"created_by",
183190
"modified_by",
184191
"admin2",
192+
"partners",
185193
)
186194
readonly_fields = (
187195
"partner_contacts",
@@ -244,6 +252,9 @@ def regenerate_diff_pdf_file(self, request, queryset):
244252

245253
regenerate_diff_pdf_file.short_description = "Regenerate EAP diff PDF files for selected Full EAPs"
246254

255+
def full_eap_application(self, obj):
256+
return f"{obj.eap_registration.national_society.society_name} - {obj.eap_registration.disaster_type.name}"
257+
247258
def get_queryset(self, request):
248259
return (
249260
super()
@@ -258,6 +269,7 @@ def get_queryset(self, request):
258269
)
259270
.prefetch_related(
260271
"admin2",
272+
"partners",
261273
"partner_contacts",
262274
"key_actors",
263275
"risk_analysis_source_of_information",

eap/factories.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,6 @@ class Meta:
138138

139139
approach = fuzzy.FuzzyChoice(EnablingApproach.Approach)
140140
budget_per_approach = fuzzy.FuzzyInteger(1000, 1000000)
141-
ap_code = fuzzy.FuzzyInteger(100, 999)
142141

143142
@factory.post_generation
144143
def readiness_activities(self, create, extracted, **kwargs):
@@ -175,7 +174,6 @@ class Meta:
175174
sector = fuzzy.FuzzyChoice(PlannedOperation.Sector)
176175
people_targeted = fuzzy.FuzzyInteger(100, 100000)
177176
budget_per_sector = fuzzy.FuzzyInteger(1000, 1000000)
178-
ap_code = fuzzy.FuzzyInteger(100, 999)
179177

180178
@factory.post_generation
181179
def readiness_activities(self, create, extracted, **kwargs):
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Generated by Django 4.2.29 on 2026-03-16 09:00
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('eap', '0006_fulleap_meal_source_of_information_and_more'),
10+
]
11+
12+
operations = [
13+
migrations.RemoveField(
14+
model_name='eapregistration',
15+
name='activated_at',
16+
),
17+
migrations.AddField(
18+
model_name='fulleap',
19+
name='lead_timeframe_unit',
20+
field=models.IntegerField(blank=True, choices=[(10, 'Years'), (20, 'Months'), (30, 'Days'), (40, 'Hours')], null=True, verbose_name='Lead Timeframe Unit'),
21+
),
22+
migrations.AlterField(
23+
model_name='eapregistration',
24+
name='status',
25+
field=models.IntegerField(choices=[(10, 'Under Development'), (20, 'Under Review'), (30, 'NS Addressing Comments'), (40, 'Technically Validated'), (50, 'Approved(Pending PFA)'), (60, 'Approved')], default=10, help_text='Select the current status of the EAP development process.', verbose_name='EAP Status'),
26+
),
27+
migrations.AlterField(
28+
model_name='enablingapproach',
29+
name='ap_code',
30+
field=models.IntegerField(default=1, verbose_name='AP Code'),
31+
preserve_default=False,
32+
),
33+
]
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Generated by Django 4.2.28 on 2026-04-03 09:16
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('api', '0228_merge_20260123_0806'),
10+
('eap', '0007_remove_eapregistration_activated_at_and_more'),
11+
]
12+
13+
operations = [
14+
migrations.RemoveField(
15+
model_name='enablingapproach',
16+
name='ap_code',
17+
),
18+
migrations.RemoveField(
19+
model_name='plannedoperation',
20+
name='ap_code',
21+
),
22+
migrations.AddField(
23+
model_name='fulleap',
24+
name='partners',
25+
field=models.ManyToManyField(blank=True, help_text='Select any partner NS involved in the EAP development.', related_name='+', to='api.country', verbose_name='Partners'),
26+
),
27+
migrations.AddField(
28+
model_name='simplifiedeap',
29+
name='partners',
30+
field=models.ManyToManyField(blank=True, help_text='Select any partner NS involved in the EAP development.', related_name='+', to='api.country', verbose_name='Partners'),
31+
),
32+
migrations.AlterField(
33+
model_name='plannedoperation',
34+
name='sector',
35+
field=models.IntegerField(choices=[(101, 'Shelter, Settlement and Housing'), (102, 'Livelihoods'), (103, 'Protection, Gender and Inclusion'), (104, 'Health and Care'), (105, 'Risk Reduction, Climate Adaptation and Recovery'), (106, 'Multipurpose Cash'), (107, 'Water, Sanitation And Hygiene'), (109, 'Education'), (110, 'Migration'), (111, 'Environment Sustainability'), (112, 'Community Engagement And Accountability')], verbose_name='sector'),
36+
),
37+
]

eap/models.py

Lines changed: 54 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -386,16 +386,30 @@ class Sector(models.IntegerChoices):
386386
RISK_REDUCTION_CLIMATE_ADAPTATION_AND_RECOVERY = 105, _("Risk Reduction, Climate Adaptation and Recovery")
387387
MULTIPURPOSE_CASH = 106, _("Multipurpose Cash")
388388
WATER_SANITATION_AND_HYGIENE = 107, _("Water, Sanitation And Hygiene")
389-
WASH = 108, _("WASH")
390389
EDUCATION = 109, _("Education")
391390
MIGRATION = 110, _("Migration")
392391
ENVIRONMENT_SUSTAINABILITY = 111, _("Environment Sustainability")
393392
COMMUNITY_ENGAGEMENT_AND_ACCOUNTABILITY = 112, _("Community Engagement And Accountability")
394393

394+
@classmethod
395+
def get_sector_ap_codes(cls) -> dict[int, list[str]]:
396+
return {
397+
cls.SHELTER_SETTLEMENT_AND_HOUSING: ["AP101", "AP103", "AP104"],
398+
cls.LIVELIHOODS: ["AP007"],
399+
cls.PROTECTION_GENDER_AND_INCLUSION: ["AP114", "AP116", "AP117"],
400+
cls.HEALTH_AND_CARE: ["AP107", "AP108", "AP109"],
401+
cls.RISK_REDUCTION_CLIMATE_ADAPTATION_AND_RECOVERY: ["AP101", "AP103", "AP104", "AP105", "AP106"],
402+
cls.MULTIPURPOSE_CASH: ["AP081"],
403+
cls.WATER_SANITATION_AND_HYGIENE: ["AP110", "AP111"],
404+
cls.EDUCATION: ["AP115"],
405+
cls.MIGRATION: ["AP112", "AP113"],
406+
cls.ENVIRONMENT_SUSTAINABILITY: ["AP102"],
407+
cls.COMMUNITY_ENGAGEMENT_AND_ACCOUNTABILITY: ["AP129"],
408+
}
409+
395410
sector = models.IntegerField(choices=Sector.choices, verbose_name=_("sector"))
396411
people_targeted = models.IntegerField(verbose_name=_("People Targeted"))
397412
budget_per_sector = models.IntegerField(verbose_name=_("Budget per sector (CHF)"))
398-
ap_code = models.IntegerField(verbose_name=_("AP Code"))
399413
previous_id = models.PositiveIntegerField(verbose_name=_("Previous ID"), null=True, blank=True)
400414

401415
indicators = models.ManyToManyField(
@@ -439,9 +453,24 @@ class Approach(models.IntegerChoices):
439453
NATIONAL_SOCIETY_STRENGTHENING = 20, _("National Society Strengthening")
440454
PARTNERSHIP_AND_COORDINATION = 30, _("Partnership And Coordination")
441455

456+
@classmethod
457+
def get_approach_ap_codes(cls) -> dict[int, list[str]]:
458+
return {
459+
cls.SECRETARIAT_SERVICES: ["AP122"],
460+
cls.NATIONAL_SOCIETY_STRENGTHENING: ["AP124", "AP125", "AP126"],
461+
cls.PARTNERSHIP_AND_COORDINATION: [
462+
"AP049",
463+
"AP118",
464+
"AP119",
465+
"AP120",
466+
"AP121",
467+
"AP127",
468+
"AP128",
469+
],
470+
}
471+
442472
approach = models.IntegerField(choices=Approach.choices, verbose_name=_("Approach"))
443473
budget_per_approach = models.IntegerField(verbose_name=_("Budget per approach (CHF)"))
444-
ap_code = models.IntegerField(verbose_name=_("AP Code"), null=True, blank=True)
445474
previous_id = models.PositiveIntegerField(verbose_name=_("Previous ID"), null=True, blank=True)
446475

447476
indicators = models.ManyToManyField(
@@ -553,7 +582,7 @@ class EAPStatus(models.IntegerChoices):
553582
IFRC can change status to NS_ADDRESSING_COMMENTS or PENDING_PFA.
554583
"""
555584

556-
PENDING_PFA = 50, _("Pending PFA")
585+
PENDING_PFA = 50, _("Approved(Pending PFA)")
557586
"""EAP is in the process of signing the PFA between IFRC and NS.
558587
"""
559588

@@ -562,9 +591,6 @@ class EAPStatus(models.IntegerChoices):
562591
Cannot be changed back to previous statuses.
563592
"""
564593

565-
ACTIVATED = 70, _("Activated")
566-
"""EAP has been activated"""
567-
568594

569595
# BASE MODEL FOR EAP
570596
class EAPRegistration(EAPBaseModel):
@@ -722,12 +748,6 @@ class EAPRegistration(EAPBaseModel):
722748
verbose_name=_("pending pfa at"),
723749
help_text=_("Timestamp when the EAP was marked as pending PFA."),
724750
)
725-
activated_at = models.DateTimeField(
726-
null=True,
727-
blank=True,
728-
verbose_name=_("activated at"),
729-
help_text=_("Timestamp when the EAP was activated."),
730-
)
731751

732752
# EAP submission deadline
733753
deadline = models.DateField(
@@ -808,6 +828,14 @@ class CommonEAPFields(models.Model):
808828
related_name="+",
809829
)
810830

831+
partners = models.ManyToManyField(
832+
Country,
833+
verbose_name=_("Partners"),
834+
help_text=_("Select any partner NS involved in the EAP development."),
835+
related_name="+",
836+
blank=True,
837+
)
838+
811839
people_targeted = models.IntegerField(
812840
verbose_name=_("People Targeted."),
813841
blank=True,
@@ -1247,7 +1275,7 @@ class Meta:
12471275
]
12481276

12491277
def __str__(self):
1250-
return f"Simplified EAP for {self.eap_registration}- version:{self.version}"
1278+
return f"{self.eap_registration} (VERSION {self.version})"
12511279

12521280
def generate_snapshot(self):
12531281
"""
@@ -1263,6 +1291,7 @@ def generate_snapshot(self):
12631291
overrides={
12641292
"parent_id": self.id,
12651293
"version": self.version + 1,
1294+
"is_locked": False,
12661295
"created_by_id": self.created_by_id,
12671296
"modified_by_id": self.modified_by_id,
12681297
"review_checklist_file": None,
@@ -1272,6 +1301,7 @@ def generate_snapshot(self):
12721301
},
12731302
exclude_clone_m2m_fields={
12741303
"admin2",
1304+
"partners",
12751305
"cover_image",
12761306
"hazard_impact_images",
12771307
"risk_selected_protocols_images",
@@ -1449,13 +1479,19 @@ class FullEAP(EAPBaseModel, CommonEAPFields):
14491479
)
14501480

14511481
# NOTE: In days
1452-
# TODO(susilnem): add unit for lead time
14531482
lead_time = models.IntegerField(
14541483
verbose_name=_("Lead Time"),
14551484
null=True,
14561485
blank=True,
14571486
)
14581487

1488+
lead_timeframe_unit = models.IntegerField(
1489+
choices=TimeFrame.choices,
1490+
verbose_name=_("Lead Timeframe Unit"),
1491+
null=True,
1492+
blank=True,
1493+
)
1494+
14591495
trigger_statement_source_of_information = models.ManyToManyField(
14601496
SourceInformation,
14611497
verbose_name=_("Trigger Statement Source of Forecast"),
@@ -1788,7 +1824,7 @@ class Meta:
17881824
]
17891825

17901826
def __str__(self):
1791-
return f"Full EAP for {self.eap_registration}- version:{self.version}"
1827+
return f"{self.eap_registration} (VERSION {self.version})"
17921828

17931829
def generate_snapshot(self):
17941830
"""
@@ -1803,6 +1839,7 @@ def generate_snapshot(self):
18031839
overrides={
18041840
"parent_id": self.id,
18051841
"version": self.version + 1,
1842+
"is_locked": False,
18061843
"created_by_id": self.created_by_id,
18071844
"modified_by_id": self.modified_by_id,
18081845
"review_checklist_file": None,
@@ -1812,6 +1849,7 @@ def generate_snapshot(self):
18121849
},
18131850
exclude_clone_m2m_fields={
18141851
"admin2",
1852+
"partners",
18151853
"cover_image",
18161854
# Files
18171855
"hazard_selection_images",

0 commit comments

Comments
 (0)