Skip to content

Commit a447e04

Browse files
committed
Merge pull request #2595 from IFRCGo/feat/add-full-eap-model
Add Full EAP model
2 parents 46c9801 + 0206f5e commit a447e04

17 files changed

Lines changed: 3050 additions & 356 deletions
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Generated by Django 4.2.26 on 2025-11-26 10:03
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
dependencies = [
8+
("api", "0227_alter_export_export_type"),
9+
]
10+
11+
operations = [
12+
migrations.AlterField(
13+
model_name="export",
14+
name="export_type",
15+
field=models.CharField(
16+
choices=[
17+
("dref-applications", "DREF Application"),
18+
("dref-operational-updates", "DREF Operational Update"),
19+
("dref-final-reports", "DREF Final Report"),
20+
("old-dref-final-reports", "Old DREF Final Report"),
21+
("per", "Per"),
22+
("simplified-eap", "Simplified EAP"),
23+
("full-eap", "Full EAP"),
24+
],
25+
max_length=255,
26+
verbose_name="Export Type",
27+
),
28+
),
29+
]

api/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2561,6 +2561,7 @@ class ExportType(models.TextChoices):
25612561
OLD_FINAL_REPORT = "old-dref-final-reports", _("Old DREF Final Report")
25622562
PER = "per", _("Per")
25632563
SIMPLIFIED_EAP = "simplified-eap", _("Simplified EAP")
2564+
FULL_EAP = "full-eap", _("Full EAP")
25642565

25652566
export_id = models.IntegerField(verbose_name=_("Export Id"))
25662567
export_type = models.CharField(verbose_name=_("Export Type"), max_length=255, choices=ExportType.choices)

api/serializers.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from api.utils import CountryValidator, RegionValidator
1616
from deployments.models import EmergencyProject, Personnel, PersonnelDeployment
1717
from dref.models import Dref, DrefFinalReport, DrefOperationalUpdate
18-
from eap.models import SimplifiedEAP
18+
from eap.models import FullEAP, SimplifiedEAP
1919
from lang.models import String
2020
from lang.serializers import ModelSerializer
2121
from local_units.models import DelegationOffice
@@ -2573,6 +2573,9 @@ def create(self, validated_data):
25732573
title = (
25742574
f"{simplified_eap.eap_registration.national_society.name}-{simplified_eap.eap_registration.disaster_type.name}"
25752575
)
2576+
elif export_type == Export.ExportType.FULL_EAP:
2577+
full_eap = FullEAP.objects.filter(id=export_id).first()
2578+
title = f"{full_eap.eap_registration.national_society.name}-{full_eap.eap_registration.disaster_type.name}"
25762579
else:
25772580
title = "Export"
25782581
user = self.context["request"].user

api/tasks.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ def generate_url(url, export_id, user, title, language):
120120
file_name = f'PER {title} ({datetime.now().strftime("%Y-%m-%d %H-%M-%S")}).pdf'
121121
elif export.export_type == Export.ExportType.SIMPLIFIED_EAP:
122122
file_name = f'SIMPLIFIED EAP {title} ({datetime.now().strftime("%Y-%m-%d %H-%M-%S")}).pdf'
123+
elif export.export_type == Export.ExportType.FULL_EAP:
124+
file_name = f'FULL EAP {title} ({datetime.now().strftime("%Y-%m-%d %H-%M-%S")}).pdf'
123125
else:
124126
file_name = f'DREF {title} ({datetime.now().strftime("%Y-%m-%d %H-%M-%S")}).pdf'
125127
file = ContentFile(

eap/admin.py

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
from django.contrib import admin
22

3-
from eap.models import EAPRegistration, SimplifiedEAP
3+
from eap.models import EAPFile, EAPRegistration, FullEAP, KeyActor, SimplifiedEAP
4+
5+
6+
@admin.register(EAPFile)
7+
class EAPFileAdmin(admin.ModelAdmin):
8+
search_fields = ("caption",)
49

510

611
@admin.register(EAPRegistration)
@@ -94,3 +99,69 @@ def get_queryset(self, request):
9499
"admin2",
95100
)
96101
)
102+
103+
104+
@admin.register(KeyActor)
105+
class KeyActorAdmin(admin.ModelAdmin):
106+
list_display = ("national_society",)
107+
108+
109+
@admin.register(FullEAP)
110+
class FullEAPAdmin(admin.ModelAdmin):
111+
list_select_related = True
112+
search_fields = (
113+
"eap_registration__country__name",
114+
"eap_registration__disaster_type__name",
115+
)
116+
list_display = ("eap_registration",)
117+
autocomplete_fields = (
118+
"eap_registration",
119+
"created_by",
120+
"modified_by",
121+
"admin2",
122+
)
123+
readonly_fields = (
124+
"cover_image",
125+
"planned_operations",
126+
"enable_approaches",
127+
"planned_operations",
128+
"hazard_selection_images",
129+
"theory_of_change_table_file",
130+
"exposed_element_and_vulnerability_factor_images",
131+
"prioritized_impact_images",
132+
"risk_analysis_relevant_files",
133+
"forecast_selection_images",
134+
"definition_and_justification_impact_level_images",
135+
"identification_of_the_intervention_area_images",
136+
"trigger_model_relevant_files",
137+
"early_action_selection_process_images",
138+
"evidence_base_relevant_files",
139+
"early_action_implementation_images",
140+
"trigger_activation_system_images",
141+
"activation_process_relevant_files",
142+
"meal_relevant_files",
143+
"capacity_relevant_files",
144+
)
145+
146+
def get_queryset(self, request):
147+
return (
148+
super()
149+
.get_queryset(request)
150+
.select_related(
151+
"created_by",
152+
"modified_by",
153+
"cover_image",
154+
"eap_registration__country",
155+
"eap_registration__national_society",
156+
"eap_registration__disaster_type",
157+
)
158+
.prefetch_related(
159+
"admin2",
160+
"key_actors",
161+
"risk_analysis_source_of_information",
162+
"trigger_statement_source_of_information",
163+
"trigger_model_source_of_information",
164+
"evidence_base_source_of_information",
165+
"activation_process_source_of_information",
166+
)
167+
)

eap/enums.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
"eap_status": models.EAPStatus,
55
"eap_type": models.EAPType,
66
"sector": models.PlannedOperation.Sector,
7-
"timeframe": models.OperationActivity.TimeFrame,
8-
"years_timeframe_value": models.OperationActivity.YearsTimeFrameChoices,
9-
"months_timeframe_value": models.OperationActivity.MonthsTimeFrameChoices,
10-
"days_timeframe_value": models.OperationActivity.DaysTimeFrameChoices,
11-
"hours_timeframe_value": models.OperationActivity.HoursTimeFrameChoices,
7+
"timeframe": models.TimeFrame,
8+
"years_timeframe_value": models.YearsTimeFrameChoices,
9+
"months_timeframe_value": models.MonthsTimeFrameChoices,
10+
"days_timeframe_value": models.DaysTimeFrameChoices,
11+
"hours_timeframe_value": models.HoursTimeFrameChoices,
1212
"approach": models.EnableApproach.Approach,
1313
}

eap/factories.py

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,44 @@
22
from factory import fuzzy
33

44
from eap.models import (
5+
EAPFile,
56
EAPRegistration,
67
EAPStatus,
78
EAPType,
89
EnableApproach,
10+
FullEAP,
11+
KeyActor,
912
OperationActivity,
1013
PlannedOperation,
1114
SimplifiedEAP,
15+
TimeFrame,
1216
)
1317

1418

19+
class EAPFileFactory(factory.django.DjangoModelFactory):
20+
class Meta:
21+
model = EAPFile
22+
23+
caption = fuzzy.FuzzyText(length=10, prefix="EAPFile-")
24+
file = factory.django.FileField(filename="eap_file.txt")
25+
26+
@classmethod
27+
def _create_image(cls, *args, **kwargs) -> EAPFile:
28+
return cls.create(
29+
file=factory.django.FileField(filename="eap_image.jpeg", data=b"fake image data"),
30+
caption="EAP Image",
31+
**kwargs,
32+
)
33+
34+
@classmethod
35+
def _create_file(cls, *args, **kwargs) -> EAPFile:
36+
return cls.create(
37+
file=factory.django.FileField(filename="eap_document.pdf", data=b"fake pdf data"),
38+
caption="EAP Document",
39+
**kwargs,
40+
)
41+
42+
1543
class EAPRegistrationFactory(factory.django.DjangoModelFactory):
1644
class Meta:
1745
model = EAPRegistration
@@ -38,6 +66,10 @@ class Meta:
3866
readiness_budget = fuzzy.FuzzyInteger(1000, 1000000)
3967
pre_positioning_budget = fuzzy.FuzzyInteger(1000, 1000000)
4068
early_action_budget = fuzzy.FuzzyInteger(1000, 1000000)
69+
people_targeted = fuzzy.FuzzyInteger(100, 100000)
70+
seap_lead_timeframe_unit = fuzzy.FuzzyInteger(TimeFrame.MONTHS)
71+
seap_lead_time = fuzzy.FuzzyInteger(1, 12)
72+
operational_timeframe = fuzzy.FuzzyInteger(1, 12)
4173

4274
@factory.post_generation
4375
def enable_approaches(self, create, extracted, **kwargs):
@@ -63,7 +95,7 @@ class Meta:
6395
model = OperationActivity
6496

6597
activity = fuzzy.FuzzyText(length=50, prefix="Activity-")
66-
timeframe = fuzzy.FuzzyChoice(OperationActivity.TimeFrame)
98+
timeframe = fuzzy.FuzzyChoice(TimeFrame)
6799

68100

69101
class EnableApproachFactory(factory.django.DjangoModelFactory):
@@ -138,3 +170,22 @@ def early_action_activities(self, create, extracted, **kwargs):
138170
if extracted:
139171
for activity in extracted:
140172
self.early_action_activities.add(activity)
173+
174+
175+
class KeyActorFactory(factory.django.DjangoModelFactory):
176+
class Meta:
177+
model = KeyActor
178+
179+
description = fuzzy.FuzzyText(length=5, prefix="KeyActor-")
180+
181+
182+
class FullEAPFactory(factory.django.DjangoModelFactory):
183+
class Meta:
184+
model = FullEAP
185+
186+
seap_timeframe = fuzzy.FuzzyInteger(5)
187+
total_budget = fuzzy.FuzzyInteger(1000, 1000000)
188+
readiness_budget = fuzzy.FuzzyInteger(1000, 1000000)
189+
pre_positioning_budget = fuzzy.FuzzyInteger(1000, 1000000)
190+
early_action_budget = fuzzy.FuzzyInteger(1000, 1000000)
191+
people_targeted = fuzzy.FuzzyInteger(100, 100000)

eap/filter_set.py

Lines changed: 66 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,37 @@
11
import django_filters as filters
22

33
from api.models import Country, DisasterType
4-
from eap.models import EAPRegistration, EAPStatus, EAPType, SimplifiedEAP
4+
from eap.models import EAPRegistration, EAPStatus, EAPType, FullEAP, SimplifiedEAP
55

66

7-
class BaseEAPFilterSet(filters.FilterSet):
8-
created_at__lte = filters.DateFilter(field_name="created_at", lookup_expr="lte", input_formats=["%Y-%m-%d"])
9-
created_at__gte = filters.DateFilter(field_name="created_at", lookup_expr="gte", input_formats=["%Y-%m-%d"])
7+
class BaseFilterSet(filters.FilterSet):
8+
created_at = filters.DateFilter(
9+
field_name="created_at",
10+
lookup_expr="exact",
11+
input_formats=["%Y-%m-%d"],
12+
)
13+
created_at__lte = filters.DateFilter(
14+
field_name="created_at",
15+
lookup_expr="lte",
16+
input_formats=["%Y-%m-%d"],
17+
)
18+
created_at__gte = filters.DateFilter(
19+
field_name="created_at",
20+
lookup_expr="gte",
21+
input_formats=["%Y-%m-%d"],
22+
)
23+
24+
25+
class EAPRegistrationFilterSet(BaseFilterSet):
26+
eap_type = filters.ChoiceFilter(
27+
choices=EAPType.choices,
28+
label="EAP Type",
29+
)
30+
status = filters.ChoiceFilter(
31+
choices=EAPStatus.choices,
32+
label="EAP Status",
33+
)
34+
1035
# Country
1136
country = filters.ModelMultipleChoiceFilter(
1237
field_name="country",
@@ -16,7 +41,10 @@ class BaseEAPFilterSet(filters.FilterSet):
1641
field_name="national_society",
1742
queryset=Country.objects.all(),
1843
)
19-
region = filters.NumberFilter(field_name="country__region_id", label="Region")
44+
region = filters.NumberFilter(
45+
field_name="country__region_id",
46+
label="Region",
47+
)
2048
partners = filters.ModelMultipleChoiceFilter(
2149
field_name="partners",
2250
queryset=Country.objects.all(),
@@ -28,23 +56,45 @@ class BaseEAPFilterSet(filters.FilterSet):
2856
queryset=DisasterType.objects.all(),
2957
)
3058

59+
class Meta:
60+
model = EAPRegistration
61+
fields = ()
3162

32-
class EAPRegistrationFilterSet(BaseEAPFilterSet):
33-
eap_type = filters.ChoiceFilter(
34-
choices=EAPType.choices,
35-
label="EAP Type",
63+
64+
class BaseEAPFilterSet(BaseFilterSet):
65+
eap_registration = filters.ModelMultipleChoiceFilter(
66+
field_name="eap_registration",
67+
queryset=EAPRegistration.objects.all(),
3668
)
37-
status = filters.ChoiceFilter(
38-
choices=EAPStatus.choices,
39-
label="EAP Status",
69+
70+
seap_timeframe = filters.NumberFilter(
71+
field_name="seap_timeframe",
72+
label="SEAP Timeframe (in Years)",
4073
)
4174

42-
class Meta:
43-
model = EAPRegistration
44-
fields = ()
75+
national_society = filters.ModelMultipleChoiceFilter(
76+
field_name="eap_registration__national_society",
77+
queryset=Country.objects.all(),
78+
)
79+
80+
country = filters.ModelMultipleChoiceFilter(
81+
field_name="eap_registration__country",
82+
queryset=Country.objects.all(),
83+
)
4584

85+
disaster_type = filters.ModelMultipleChoiceFilter(
86+
field_name="eap_registration__disaster_type",
87+
queryset=DisasterType.objects.all(),
88+
)
4689

47-
class SimplifiedEAPFilterSet(BaseEAPFilterSet):
90+
91+
class SimplifiedEAPFilterSet(BaseEAPFilterSet, BaseFilterSet):
4892
class Meta:
4993
model = SimplifiedEAP
5094
fields = ("eap_registration",)
95+
96+
97+
class FullEAPFilterSet(BaseEAPFilterSet):
98+
class Meta:
99+
model = FullEAP
100+
fields = ("eap_registration",)

0 commit comments

Comments
 (0)