diff --git a/api/drf_views.py b/api/drf_views.py index 4efe2c543..84a146810 100644 --- a/api/drf_views.py +++ b/api/drf_views.py @@ -18,6 +18,8 @@ from deployments.models import Personnel from databank.serializers import CountryOverviewSerializer +from eap.models import EAPActivation, EAP, EAPDocument + from .event_sources import SOURCES from .exceptions import BadRequest from .view_filters import ListFilter @@ -230,11 +232,12 @@ def get_databank(self, request, pk): class CountryFilterRMD(filters.FilterSet): region = filters.NumberFilter(field_name='region', lookup_expr='exact') - + class Meta: model = Country fields = ('region', 'record_type',) + class CountryRMDViewset(viewsets.ReadOnlyModelViewSet): queryset = Country.objects.filter(is_deprecated=False).filter(iso3__isnull=False).exclude(iso3="") filterset_class = CountryFilterRMD @@ -245,7 +248,7 @@ class CountryRMDViewset(viewsets.ReadOnlyModelViewSet): class DistrictRMDFilter(filters.FilterSet): class Meta: model = District - fields = ('country','country__name') + fields = ('country', 'country__name') class DistrictRMDViewset(viewsets.ReadOnlyModelViewSet): @@ -914,6 +917,23 @@ def create_event(self, report): report.save() return event + def create_eap_activation(self, data, fieldreport): + eap = EAP.objects.filter(id=data.pop('eap', None)).first() + documents_data = data.pop('documents', None) + eap_activation = EAPActivation.objects.create( + eap=eap, + field_report=fieldreport, + **data + ) + if documents_data: + for data in documents_data: + document = EAPDocument.objects.filter(id=data['id']).first() + document.caption = data['caption'] + document.save(update_fields=['caption']) + # save m2m + eap_activation.documents.add(document) + return eap_activation + def create(self, request, *args, **kwargs): serializer = self.serialize(request.data) if not serializer.is_valid(): @@ -928,7 +948,9 @@ def create(self, request, *args, **kwargs): try: # TODO: Use serializer to create fieldreport + eap_activation_data = data.pop('eap_activation') fieldreport = FieldReport.objects.create(**data) + self.create_eap_activation(eap_activation_data, fieldreport) # activate respected eap for field report CreateFieldReportSerializer.trigger_field_translation(fieldreport) except Exception as e: try: @@ -976,6 +998,28 @@ class UpdateFieldReport(UpdateAPIView, GenericFieldReportView): queryset = FieldReport.objects.all() serializer_class = CreateFieldReportSerializer + # function for updating eap-activate in field report + def update_eap_activation(self, data, fieldreport): + from eap.serializers import EAPActivationSerializer + + eap_id = data.pop('eap', None) + documents_data = data.pop('documents', None) + instance = EAPActivation.objects.get(field_report=fieldreport) + eap_activation = EAPActivationSerializer().update(instance, data) + instance.eap = EAP.objects.filter(id=eap_id).first() + + instance.documents.clear() + if documents_data: + for data in documents_data: + document = EAPDocument.objects.filter(id=data['id']).first() + document.caption = data['caption'] + document.save(update_fields=['caption']) + # save m2m + instance.documents.add(document) + instance.save(update_fields=['eap']) + + return eap_activation + def partial_update(self, request, *args, **kwargs): self.update(request, *args, **kwargs) @@ -989,7 +1033,9 @@ def update(self, request, *args, **kwargs): data, locations, meta, partners = self.map_many_to_many_relations(data) try: - serializer.save() + field_report = serializer.save() + # update respected eap-activation + self.update_eap_activation(request.data['eap_activation'], field_report) except Exception: logger.error('Faild to update field report', exc_info=True) raise BadRequest('Could not update field report') @@ -1045,6 +1091,7 @@ class GoHistoricalViewSet(viewsets.ReadOnlyModelViewSet): def get_queryset(self): return Event.objects.filter(appeals__isnull=False) + class CountryOfFieldReportToReviewViewset(viewsets.ReadOnlyModelViewSet): queryset = CountryOfFieldReportToReview.objects.order_by('country') serializer_class = CountryOfFieldReportToReviewSerializer diff --git a/api/migrations/0157_auto_20220721_0754.py b/api/migrations/0157_auto_20220721_0754.py new file mode 100644 index 000000000..9a632a7eb --- /dev/null +++ b/api/migrations/0157_auto_20220721_0754.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.28 on 2022-07-21 07:54 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0156_appealfilter_comment'), + ] + + operations = [ + migrations.AlterField( + model_name='fieldreport', + name='status', + field=models.IntegerField(choices=[(0, 'Unknown'), (2, 'Two'), (3, 'Three'), (8, 'Early Warning'), (9, 'Event-related'), (10, 'Ten'), (11, 'EAP Activation')], default=0, verbose_name='type'), + ), + ] diff --git a/api/models.py b/api/models.py index e0c494e3b..b4f0f0f22 100644 --- a/api/models.py +++ b/api/models.py @@ -1226,6 +1226,7 @@ class Status(IntegerChoices): EW = 8, _('Early Warning') EVT = 9, _('Event-related') TEN = 10, _('Ten') # legacy usage. Covid? + EAP_ACTV = 11, _('EAP Activation') # EAP Activation user = models.ForeignKey( settings.AUTH_USER_MODEL, verbose_name=_('user'), related_name='user', @@ -1932,8 +1933,8 @@ class EmergencyOperationsFR(EmergencyOperationsBase): raw_shelter_people_targeted = None raw_water_sanitation_and_hygiene_people_targeted = None - # Fields for the cleaned data date_of_disaster = models.DateField(verbose_name=_('date of disaster'), null=True, blank=True) + # Fields for the cleaned data num_of_other_partner_involved = models.TextField(verbose_name=_('number of other partner involved'), null=True, blank=True) num_of_partner_ns_involved = models.TextField(verbose_name=_('number of NS partner involved'), null=True, blank=True) operation_end_date = models.DateField(verbose_name=_('operation end date'), null=True, blank=True) diff --git a/api/serializers.py b/api/serializers.py index 4e3577e73..40500e185 100644 --- a/api/serializers.py +++ b/api/serializers.py @@ -8,6 +8,7 @@ from lang.serializers import ModelSerializer from lang.models import String + from .models import ( DisasterType, ExternalPartner, @@ -54,6 +55,7 @@ ) from notifications.models import Subscription from deployments.models import EmergencyProject +from eap.models import EAPActivation class GeoSerializerMixin: @@ -1071,6 +1073,15 @@ class DetailFieldReportSerializer(FieldReportEnumDisplayMixin, ModelSerializer): districts = MiniDistrictSerializer(many=True) external_partners = ExternalPartnerSerializer(many=True) supported_activities = SupportedActivitySerializer(many=True) + eap_activation = serializers.SerializerMethodField('get_eap_activation') + + @staticmethod + def get_eap_activation(obj): + from eap.serializers import EAPActivationSerializer + + eap_activation = EAPActivation.objects.get(field_report=obj) + eap_activation_data = EAPActivationSerializer(eap_activation).data + return eap_activation_data class Meta: model = FieldReport @@ -1078,6 +1089,7 @@ class Meta: class CreateFieldReportSerializer(FieldReportEnumDisplayMixin, ModelSerializer): + class Meta: model = FieldReport fields = '__all__' @@ -1107,6 +1119,7 @@ class Meta: 'disaster_start_date', 'created_at', 'appeals', ) + class CountryOfFieldReportToReviewSerializer(ModelSerializer): class Meta: model = CountryOfFieldReportToReview diff --git a/api/test_views.py b/api/test_views.py index f20bca429..8ebcf37ee 100644 --- a/api/test_views.py +++ b/api/test_views.py @@ -12,6 +12,8 @@ EventLinkFactory, AppealFactory ) +from eap.factories import EAPFactory, EAPDocumentFactory +from eap.models import EAPActivation class AuthTokenTest(APITestCase): @@ -63,7 +65,6 @@ def test_sit_rep_types(self): # Filter by event response = self.client.get('/api/v2/situation_report/?limit=100&event=%s' % event1.id) - print(response) self.assertEqual(response.status_code, 200) count = response.json()['count'] self.assertEqual(count, 3) @@ -82,6 +83,10 @@ class FieldReportTest(APITestCase): def test_create_and_update(self): user = User.objects.create(username='jo') region = models.Region.objects.create(name=1) + eap1 = EAPFactory.create(created_by=user) + eap2 = EAPFactory.create(created_by=user) + document1 = EAPDocumentFactory.create(created_by=self.user) + document2 = EAPDocumentFactory.create(created_by=self.user) country1 = models.Country.objects.create(name='abc', region=region) country2 = models.Country.objects.create(name='xyz') body = { @@ -105,6 +110,27 @@ def test_create_and_update(self): {'ctype': 'Originator', 'name': 'jo', 'title': 'head', 'email': '123'} ], 'user': user.id, + 'eap_activation': { + 'title': 'eap activation title', + 'eap': eap1.id, + 'description': 'test eap description', + 'trigger_met_date': '2022-11-11 00:00', + 'documents': [ + { + "id": document1.id, + "caption": "test eap" + } + ], + 'originator_name': 'test name', + 'originator_title': 'test originator title', + 'originator_email': 'test@email.com', + 'nsc_name_operational': 'test name operational', + 'nsc_title_operational': 'test nsc operational', + 'nsc_email_operational': 'test nsc operational', + 'ifrc_focal_name': 'test focal name', + 'ifrc_focal_title': 'test focal title', + 'ifrc_focal_email': 'testemail@gmail.com' + } } self.client.force_authenticate(user=user) with self.capture_on_commit_callbacks(execute=True): @@ -137,6 +163,12 @@ def test_create_and_update(self): self.aws_translator._fake_translation('test', 'es', 'en') ) + # check eap-activation data + eap_activation_obj = EAPActivation.objects.get(field_report=created) + self.assertEqual(eap_activation_obj.title, 'eap activation title') + self.assertEqual(eap_activation_obj.eap.id, eap1.id) + self.assertEqual(eap_activation_obj.field_report.id, created.id) + # created an emergency automatically self.assertEqual(created.event.name, 'test') event_pk = created.event.id @@ -149,6 +181,32 @@ def test_create_and_update(self): ] body['actions_taken'] = [] body['visibility'] = models.VisibilityChoices.PUBLIC + body['eap_activation'] = { + 'title': 'eap activation title updated', + 'eap': eap2.id, + 'description': 'test eap description updated', + 'trigger_met_date': '2022-11-11 01:00', + 'documents': [ + { + "id": document1.id, + "caption": "test eap updated" + }, + { + "id": document2.id, + "caption": "test eap updated 2" + } + ], + 'originator_name': 'test name', + 'originator_title': 'test originator title', + 'originator_email': 'test@email.com', + 'nsc_name_operational': 'test name operational', + 'nsc_title_operational': 'test nsc operational', + 'nsc_email_operational': 'test nsc operational', + 'ifrc_focal_name': 'test focal name', + 'ifrc_focal_title': 'test focal title', + 'ifrc_focal_email': 'testemail@gmail.com' + } + response = self.client.put(f'/api/v2/update_field_report/{created.id}/', body, format='json').json() updated = models.FieldReport.objects.get(pk=response['id']) @@ -177,6 +235,12 @@ def test_create_and_update(self): self.aws_translator._fake_translation('this is a test description', 'es', 'en'), ) # This has not been reset + # check eap-activation data + eap_activation_obj = EAPActivation.objects.get(field_report=updated) + self.assertEqual(eap_activation_obj.title, 'eap activation title updated') + self.assertEqual(eap_activation_obj.eap.id, eap2.id) + self.assertEqual(eap_activation_obj.field_report.id, updated.id) + body['summary'] = 'test [updated again]' with self.capture_on_commit_callbacks(execute=True): response = self.client.put(f'/api/v2/update_field_report/{created.id}/', body, format='json').json() diff --git a/api/views.py b/api/views.py index 764e4787e..4d5c83b1e 100644 --- a/api/views.py +++ b/api/views.py @@ -127,7 +127,6 @@ def get(self, request): } } } - results = ES_CLIENT.search( index=index, doc_type='page', diff --git a/eap/admin.py b/eap/admin.py index 8c38f3f3d..08a7ecabd 100644 --- a/eap/admin.py +++ b/eap/admin.py @@ -1,3 +1,45 @@ from django.contrib import admin # Register your models here. + +from .models import ( + EAP, + EAPPartner, + EAPReference, + EAPDocument, + EAPActivation, + EAPActivationReport, +) + + +class ReferenceAdminInline(admin.TabularInline): + model = EAPReference + extra = 0 + + +class PartnerAdminInline(admin.TabularInline): + model = EAPPartner + extra = 0 + + +@admin.register(EAPDocument) +class EAPDocumentAdmin(admin.ModelAdmin): + model = EAPDocument + extra = 0 + + +@admin.register(EAP) +class EAPAdmin(admin.ModelAdmin): + list_display = ('eap_number', 'country', 'status', 'operational_timeframe',) + inlines = [ReferenceAdminInline, PartnerAdminInline] + autocomplete_fields = ('country', 'districts', 'disaster_type', 'created_by', 'modified_by') + + +@admin.register(EAPActivation) +class EAPActivation(admin.ModelAdmin): + model = EAPActivation + + +@admin.register(EAPActivationReport) +class EAPActivationReport(admin.ModelAdmin): + model = EAPActivationReport diff --git a/eap/factories.py b/eap/factories.py new file mode 100644 index 000000000..b0366ad73 --- /dev/null +++ b/eap/factories.py @@ -0,0 +1,151 @@ +import datetime +import factory +from factory import fuzzy +from datetime import timezone + +from django.core.files.base import ContentFile + +from api.factories import ( + disaster_type, + country, + field_report, +) + +from .models import ( + EAP, + EAPDocument, + EAPActivation, + EAPActivationReport, +) + + +class EAPDocumentFactory(factory.django.DjangoModelFactory): + class Meta: + model = EAPDocument + + file = factory.LazyAttribute( + lambda _: ContentFile( + factory.django.ImageField()._make_data( + {'width': 1024, 'height': 768} + ), 'flash_update.jpg' + ) + ) + + +class EAPFactory(factory.django.DjangoModelFactory): + class Meta: + model = EAP + + country = factory.SubFactory(country.CountryFactory) + disaster_type = factory.SubFactory(disaster_type.DisasterTypeFactory) + eap_number = fuzzy.FuzzyText(length=20) + approval_date = fuzzy.FuzzyDateTime(datetime.datetime(2008, 1, 1, tzinfo=timezone.utc)) + status = fuzzy.FuzzyChoice(EAP.Status) + operational_timeframe = fuzzy.FuzzyInteger(0, 2) + lead_time = fuzzy.FuzzyInteger(0, 2) + eap_timeframe = fuzzy.FuzzyInteger(0, 2) + num_of_people = fuzzy.FuzzyInteger(0, 5) + total_budget = fuzzy.FuzzyInteger(0, 5) + readiness_budget = fuzzy.FuzzyInteger(0, 5) + pre_positioning_budget = fuzzy.FuzzyInteger(0, 5) + early_action_budget = fuzzy.FuzzyInteger(0, 5) + trigger_statement = fuzzy.FuzzyText(length=20) + overview = fuzzy.FuzzyText(length=50) + originator_name = fuzzy.FuzzyText(length=50) + originator_title = fuzzy.FuzzyText(length=50) + originator_email = fuzzy.FuzzyText(length=50) + originator_phone = fuzzy.FuzzyInteger(0, 9) + + nsc_name = fuzzy.FuzzyText(length=50) + nsc_title = fuzzy.FuzzyText(length=50) + nsc_email = fuzzy.FuzzyText(length=50) + nsc_phone = fuzzy.FuzzyInteger(0, 9) + + ifrc_focal_name = fuzzy.FuzzyText(length=50) + ifrc_focal_title = fuzzy.FuzzyText(length=50) + ifrc_focal_email = fuzzy.FuzzyText(length=50) + ifrc_focal_phone = fuzzy.FuzzyInteger(0, 9) + + @factory.post_generation + def early_actions(self, create, extracted, **kwargs): + if not create: + return + + if extracted: + for early_action in extracted: + self.early_actions.add(early_action) + + @factory.post_generation + def documents(self, create, extracted, **kwargs): + if not create: + return + + if extracted: + for document in extracted: + self.documents.add(document) + + +class EAPActivationFactory(factory.django.DjangoModelFactory): + class Meta: + model = EAPActivation + + title = fuzzy.FuzzyText(length=20) + field_report = factory.SubFactory(field_report.FieldReportFactory) + eap = factory.SubFactory(EAPFactory) + trigger_met_date = fuzzy.FuzzyDateTime(datetime.datetime(2008, 1, 1, tzinfo=timezone.utc)) + description = fuzzy.FuzzyText(length=50) + + originator_name = fuzzy.FuzzyText(length=50) + description = fuzzy.FuzzyText(length=50) + originator_email = fuzzy.FuzzyText(length=50) + + nsc_name_operational = fuzzy.FuzzyText(length=50) + nsc_title_operational = fuzzy.FuzzyText(length=50) + nsc_email_operational = fuzzy.FuzzyText(length=50) + + nsc_name_secretary = fuzzy.FuzzyText(length=50) + nsc_title_secretary = fuzzy.FuzzyText(length=50) + nsc_email_secretary = fuzzy.FuzzyText(length=50) + + @factory.post_generation + def documents(self, create, extracted, **kwargs): + if not create: + return + + if extracted: + for document in extracted: + self.documents.add(document) + + +class EAPActivationReportFactory(factory.django.DjangoModelFactory): + class Meta: + model = EAPActivationReport + + eap_activation = factory.SubFactory(EAPActivationFactory) + number_of_people_reached = fuzzy.FuzzyInteger(0, 9) + description = fuzzy.FuzzyText(length=20) + overall_objectives = fuzzy.FuzzyText(length=50) + challenges_and_lesson = fuzzy.FuzzyText(length=50) + general_lesson_and_recomendations = fuzzy.FuzzyText(length=50) + + @factory.post_generation + def documents(self, create, extracted, **kwargs): + if not create: + return + + if extracted: + for document in extracted: + self.documents.add(document) + + @factory.post_generation + def operational_plans(self, create, extracted, **kwargs): + if not create: + return + + if extracted: + for plan in extracted: + self.operational_plans.add(plan) + + + + diff --git a/eap/migrations/0001_initial.py b/eap/migrations/0001_initial.py index 20c806194..2412659bd 100644 --- a/eap/migrations/0001_initial.py +++ b/eap/migrations/0001_initial.py @@ -26,7 +26,7 @@ class Migration(migrations.Migration): ('modified_at', models.DateTimeField(auto_now=True, verbose_name='updated at')), ('eap_number', models.CharField(max_length=50, verbose_name='EAP Number')), ('approval_date', models.DateField(verbose_name='Date of EAP Approval')), - ('status', models.CharField(choices=[('approved', 'Approved'), ('in_process', 'In Process')], default=eap.models.EAP.Status('in_process'), max_length=255, verbose_name='EAP Status')), + ('status', models.CharField(choices=[('approved', 'Approved'), ('activated', 'Activated')], default=eap.models.EAP.Status('activated'), max_length=255, verbose_name='EAP Status')), ('operational_timeframe', models.IntegerField(verbose_name='Operational Timeframe (Months)')), ('lead_time', models.IntegerField(verbose_name='Lead Time')), ('eap_timeframe', models.IntegerField(verbose_name='EAP Timeframe (Years)')), @@ -137,4 +137,4 @@ class Migration(migrations.Migration): 'verbose_name_plural': 'Actions', }, ), - ] + ] \ No newline at end of file diff --git a/eap/migrations/0003_auto_20220713_1229.py b/eap/migrations/0003_auto_20220713_1229.py new file mode 100644 index 000000000..14d1931dd --- /dev/null +++ b/eap/migrations/0003_auto_20220713_1229.py @@ -0,0 +1,44 @@ +# Generated by Django 2.2.28 on 2022-07-13 12:29 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import eap.models + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('eap', '0002_auto_20220708_0747'), + ] + + operations = [ + migrations.CreateModel( + name='EAPDocument', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('file', models.FileField(blank=True, null=True, upload_to='')), + ('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='document_created_by', to=settings.AUTH_USER_MODEL, verbose_name='Created by')), + ], + options={ + 'verbose_name': 'Document', + 'verbose_name_plural': 'Documents', + }, + ), + migrations.AlterField( + model_name='eap', + name='document', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='eap_document', to='eap.EAPDocument', verbose_name='EAP Documents'), + ), + migrations.AlterField( + model_name='eap', + name='eap_number', + field=models.CharField(editable=False, max_length=50, verbose_name='EAP Number'), + ), + migrations.AlterField( + model_name='eap', + name='status', + field=models.CharField(choices=[('approved', 'Approved'), ('activated', 'Activated')], default=eap.models.EAP.Status('approved'), max_length=255, verbose_name='EAP Status'), + ), + ] diff --git a/eap/migrations/0004_auto_20220715_1301.py b/eap/migrations/0004_auto_20220715_1301.py new file mode 100644 index 000000000..ebd6dcdc4 --- /dev/null +++ b/eap/migrations/0004_auto_20220715_1301.py @@ -0,0 +1,40 @@ +# Generated by Django 2.2.28 on 2022-07-15 13:01 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('eap', '0003_auto_20220713_1229'), + ] + + operations = [ + migrations.RemoveField( + model_name='earlyaction', + name='prioritized_risk', + ), + migrations.AlterField( + model_name='eap', + name='eap_number', + field=models.CharField(max_length=50, verbose_name='EAP Number'), + ), + migrations.AlterField( + model_name='earlyaction', + name='sector', + field=models.CharField(choices=[('shelter_housing_and_settlements', 'Shelter, Housing And Settlements'), ('livelihoods', 'Livelihoods'), ('multi-purpose_cash', 'Multi-purpose Cash'), ('health_and_care', 'Health And Care'), ('water_sanitation_and_hygiene', 'Water, Sanitation And Hygiene'), ('protection_gender_and_inclusion', 'Protection, Gender And Inclusion'), ('education', 'Education'), ('migration', 'Migration'), ('risk_reduction_climate_adaptation_and_recovery', 'Risk Reduction, Climate Adaptation And Recovery'), ('community_engagement_and _accountability', 'Community Engagement And Accountability'), ('environment_sustainability ', 'Environment Sustainability'), ('shelter_cluster_coordination', 'Shelter Cluster Coordination')], max_length=255, verbose_name='sector'), + ), + migrations.CreateModel( + name='PrioritizedRisk', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('risks', models.TextField(blank=True, null=True)), + ('early_action', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='early_actions_prioritized_risk', to='eap.EarlyAction', verbose_name='early action')), + ], + options={ + 'verbose_name': 'Prioritized risk', + 'verbose_name_plural': 'Prioritized risks', + }, + ), + ] diff --git a/eap/migrations/0005_eapactivation.py b/eap/migrations/0005_eapactivation.py new file mode 100644 index 000000000..e142cf076 --- /dev/null +++ b/eap/migrations/0005_eapactivation.py @@ -0,0 +1,39 @@ +# Generated by Django 2.2.28 on 2022-07-19 11:06 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0156_appealfilter_comment'), + ('eap', '0004_auto_20220715_1301'), + ] + + operations = [ + migrations.CreateModel( + name='EAPActivation', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.CharField(blank=True, max_length=250, null=True)), + ('trigger_met_date', models.DateTimeField(verbose_name='Date the trigger was met')), + ('description', models.TextField(verbose_name='Description of EAP Activation')), + ('originator_name', models.CharField(blank=True, max_length=250, null=True, verbose_name='Originator name')), + ('originator_title', models.CharField(blank=True, max_length=250, null=True, verbose_name='Originator title')), + ('originator_email', models.CharField(blank=True, max_length=250, null=True, verbose_name='Originator email')), + ('nsc_name_operational', models.CharField(blank=True, max_length=250, null=True, verbose_name='National Society Contact (Operational)')), + ('nsc_title_operational', models.CharField(blank=True, max_length=250, null=True, verbose_name='National Society Contact (Operational)')), + ('nsc_email_operational', models.CharField(blank=True, max_length=250, null=True, verbose_name='National Society Contact (Operational)')), + ('nsc_name_secretary', models.CharField(blank=True, max_length=250, null=True, verbose_name='National Society Contact (Secretary)')), + ('nsc_title_secretary', models.CharField(blank=True, max_length=250, null=True, verbose_name='National Society Contact (Secretary)')), + ('nsc_email_secretary', models.CharField(blank=True, max_length=250, null=True, verbose_name='National Society Contact (Secretary)')), + ('ifrc_focal_name', models.CharField(blank=True, max_length=250, null=True, verbose_name='IFRC Focal Point Name')), + ('ifrc_focal_title', models.CharField(blank=True, max_length=250, null=True, verbose_name='IFRC Focal Point Title')), + ('ifrc_focal_email', models.CharField(blank=True, max_length=250, null=True, verbose_name='IFRC Focal Point Email')), + ('document', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='eap_activation_document', to='eap.EAPDocument', verbose_name='EAP Activation Documents')), + ('eap', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='eap_activation', to='eap.EAP', verbose_name='eap')), + ('field_report', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='field_report_eap_activation', to='api.FieldReport', verbose_name='field report')), + ], + ), + ] diff --git a/eap/migrations/0006_auto_20220802_0835.py b/eap/migrations/0006_auto_20220802_0835.py new file mode 100644 index 000000000..29fd51503 --- /dev/null +++ b/eap/migrations/0006_auto_20220802_0835.py @@ -0,0 +1,146 @@ +# Generated by Django 2.2.28 on 2022-08-02 08:35 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0157_auto_20220721_0754'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('eap', '0005_eapactivation'), + ] + + operations = [ + migrations.CreateModel( + name='EAPOperationalPlan', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('budget', models.IntegerField(blank=True, null=True, verbose_name='Budget per sector (CHF)')), + ('value', models.IntegerField(blank=True, null=True, verbose_name='value')), + ('no_of_people_reached', models.IntegerField(blank=True, null=True, verbose_name='People Reached')), + ('readiness_activities_achievements', models.TextField(blank=True, null=True, verbose_name='Readiness Activities Achievements')), + ('prepo_activities_achievements', models.TextField(blank=True, null=True, verbose_name='Pre-positioning Activities Achievements')), + ('client_id', models.CharField(blank=True, max_length=50, null=True)), + ], + options={ + 'verbose_name': 'EAP Operational Plan', + 'verbose_name_plural': 'EAP Operational Plans', + }, + ), + migrations.RemoveField( + model_name='eap', + name='district', + ), + migrations.RemoveField( + model_name='eap', + name='document', + ), + migrations.RemoveField( + model_name='eapactivation', + name='document', + ), + migrations.AddField( + model_name='action', + name='client_id', + field=models.CharField(blank=True, max_length=50, null=True), + ), + migrations.AddField( + model_name='eap', + name='districts', + field=models.ManyToManyField(related_name='eap_district', to='api.District', verbose_name='districts'), + ), + migrations.AddField( + model_name='eap', + name='documents', + field=models.ManyToManyField(blank=True, related_name='eap_document', to='eap.EAPDocument', verbose_name='EAP Documents'), + ), + migrations.AddField( + model_name='eapactivation', + name='documents', + field=models.ManyToManyField(blank=True, related_name='eap_activation_document', to='eap.EAPDocument', verbose_name='EAP Activation Documents'), + ), + migrations.AddField( + model_name='eapdocument', + name='client_id', + field=models.CharField(blank=True, max_length=50, null=True), + ), + migrations.AddField( + model_name='eappartner', + name='client_id', + field=models.CharField(blank=True, max_length=50, null=True), + ), + migrations.AddField( + model_name='eapreference', + name='client_id', + field=models.CharField(blank=True, max_length=50, null=True), + ), + migrations.AddField( + model_name='earlyaction', + name='client_id', + field=models.CharField(blank=True, max_length=50, null=True), + ), + migrations.AddField( + model_name='earlyactionindicator', + name='client_id', + field=models.CharField(blank=True, max_length=50, null=True), + ), + migrations.AddField( + model_name='prioritizedrisk', + name='client_id', + field=models.CharField(blank=True, max_length=50, null=True), + ), + migrations.CreateModel( + name='OperationalPlanIndicator', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('indicator_value', models.IntegerField(blank=True, null=True)), + ('indicator', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='eap.EarlyActionIndicator')), + ('operational_plan', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='operational_plan_indicator', to='eap.EAPOperationalPlan', verbose_name='Operational Plan')), + ], + options={ + 'verbose_name': 'Operational Indicator', + 'verbose_name_plural': 'Operational Indicators', + }, + ), + migrations.AddField( + model_name='eapoperationalplan', + name='early_action', + field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='eap.EarlyAction'), + ), + migrations.CreateModel( + name='EAPActivationReport', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('number_of_people_reached', models.IntegerField(verbose_name='Number Of People Reached')), + ('description', models.TextField(verbose_name='Description of Event & Overview of Implementation')), + ('overall_objectives', models.TextField(verbose_name='Overall Objective of the Intervention')), + ('challenges_and_lesson', models.TextField(verbose_name='Challenges & Lesson Learned per Sector')), + ('general_lesson_and_recomendations', models.TextField(verbose_name='General Lessons Learned and Recomendations')), + ('created_at', models.DateTimeField(auto_now_add=True, verbose_name='Created at')), + ('modified_at', models.DateTimeField(auto_now=True, verbose_name='Updated at')), + ('created_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='eap_act_report_created_by', to=settings.AUTH_USER_MODEL, verbose_name='Created by')), + ('documents', models.ManyToManyField(blank=True, related_name='eap_act_reports', to='eap.EAPDocument', verbose_name='EAP Activation Report Document')), + ('eap_activation', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='eap_activation_report', to='eap.EAPActivation', verbose_name='EAP Activation Report')), + ('ifrc_financial_report', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='eap_activation_ifrc_report', to='eap.EAPDocument', verbose_name='IFRC Financial Report')), + ('modified_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='eap_act_modified_by', to=settings.AUTH_USER_MODEL, verbose_name='Modified by')), + ('operational_plans', models.ManyToManyField(blank=True, to='eap.EAPOperationalPlan', verbose_name='Operational Plans')), + ], + ), + migrations.CreateModel( + name='ActionAchievements', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('early_act_achievement', models.TextField(blank=True, null=True, verbose_name='Early Actions Achievements')), + ('client_id', models.CharField(blank=True, max_length=50, null=True)), + ('action', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='eap.Action')), + ('operational_plan', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='action_achievement', to='eap.EAPOperationalPlan', verbose_name='Action Achievement')), + ], + options={ + 'verbose_name': 'Action Achievement', + 'verbose_name_plural': 'Action Achievements', + }, + ), + ] diff --git a/eap/migrations/0007_auto_20220803_0936.py b/eap/migrations/0007_auto_20220803_0936.py new file mode 100644 index 000000000..63663d481 --- /dev/null +++ b/eap/migrations/0007_auto_20220803_0936.py @@ -0,0 +1,36 @@ +# Generated by Django 2.2.28 on 2022-08-03 09:36 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('eap', '0006_auto_20220802_0835'), + ] + + operations = [ + migrations.CreateModel( + name='ActionAchievement', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('early_act_achievement', models.TextField(blank=True, null=True, verbose_name='Early Actions Achievements')), + ('client_id', models.CharField(blank=True, max_length=50, null=True)), + ('action', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='action_achievement', to='eap.Action')), + ('operational_plan', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='action_achievement', to='eap.EAPOperationalPlan', verbose_name='Action Achievement')), + ], + options={ + 'verbose_name': 'Action Achievement', + 'verbose_name_plural': 'Action Achievements', + }, + ), + migrations.AlterField( + model_name='operationalplanindicator', + name='indicator', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='operational_plan_indicator', to='eap.EarlyActionIndicator'), + ), + migrations.DeleteModel( + name='ActionAchievements', + ), + ] diff --git a/eap/migrations/0008_auto_20220804_0505.py b/eap/migrations/0008_auto_20220804_0505.py new file mode 100644 index 000000000..49ccc26b6 --- /dev/null +++ b/eap/migrations/0008_auto_20220804_0505.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.28 on 2022-08-04 05:05 + +from django.db import migrations, models +import eap.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('eap', '0007_auto_20220803_0936'), + ] + + operations = [ + migrations.AlterField( + model_name='earlyactionindicator', + name='indicator', + field=models.CharField(blank=True, choices=[('indicator_1', 'Indicator 1'), ('indicator_2', 'Indicator 2')], default=eap.models.EarlyActionIndicator.IndicatorChoices('indicator_1'), max_length=255, null=True), + ), + ] diff --git a/eap/migrations/0009_auto_20220811_0836.py b/eap/migrations/0009_auto_20220811_0836.py new file mode 100644 index 000000000..161abfa60 --- /dev/null +++ b/eap/migrations/0009_auto_20220811_0836.py @@ -0,0 +1,23 @@ +# Generated by Django 2.2.28 on 2022-08-11 08:36 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('eap', '0008_auto_20220804_0505'), + ] + + operations = [ + migrations.AddField( + model_name='eapdocument', + name='caption', + field=models.CharField(blank=True, max_length=225, null=True), + ), + migrations.AlterField( + model_name='earlyaction', + name='sector', + field=models.IntegerField(choices=[(0, 'Shelter, Housing And Settlements'), (1, 'Livelihoods'), (2, 'Multi-purpose Cash'), (3, 'Health And Care'), (4, 'Water, Sanitation And Hygiene'), (5, 'Protection, Gender And Inclusion'), (6, 'Education'), (7, 'Migration'), (8, 'Risk Reduction, Climate Adaptation And Recovery'), (9, 'Community Engagement And Accountability'), (10, 'Environment Sustainability'), (11, 'Shelter Cluster Coordination')], verbose_name='sector'), + ), + ] diff --git a/eap/models.py b/eap/models.py index 743753021..faca72af6 100644 --- a/eap/models.py +++ b/eap/models.py @@ -2,13 +2,12 @@ from django.conf import settings from django.utils.translation import ugettext_lazy as _ -from main.enums import TextChoices -from deployments.models import Sectors -from main.enums import IntegerChoices +from main.enums import TextChoices, IntegerChoices from api.models import ( Country, District, DisasterType, + FieldReport, ) @@ -18,10 +17,11 @@ class IndicatorChoices(TextChoices): # TODO these indicator are yet to be provi INDICATOR_2 = 'indicator_2', _('Indicator 2') indicator = models.CharField( - IndicatorChoices.choices, max_length=255, + max_length=255, choices=IndicatorChoices.choices, default=IndicatorChoices.INDICATOR_1, null=True, blank=True ) indicator_value = models.IntegerField(null=True, blank=True) + client_id = models.CharField(max_length=50, null=True, blank=True) class Meta: verbose_name = _('Early Action Indicator') @@ -51,12 +51,10 @@ class Sector(IntegerChoices): sector = models.IntegerField(choices=Sector.choices, verbose_name=_('sector')) budget_per_sector = models.IntegerField(verbose_name=_('Budget per sector (CHF)'), null=True, blank=True) indicators = models.ManyToManyField(EarlyActionIndicator, verbose_name=_('Indicators'), blank=True) - - prioritized_risk = models.TextField(verbose_name=_('Prioritized risk'), null=True, blank=True) targeted_people = models.IntegerField(verbose_name=_('Targeted people'), null=True, blank=True,) - readiness_activities = models.TextField(verbose_name=_('Readiness Activities'), null=True, blank=True) prepositioning_activities = models.TextField(verbose_name=_('Pre-positioning Activities'), null=True, blank=True) + client_id = models.CharField(max_length=50, null=True, blank=True) class Meta: verbose_name = _('Early Action') @@ -66,10 +64,27 @@ def __str__(self): return f'{self.sector}' +class EAPDocument(models.Model): + file = models.FileField(null=True, blank=True) + caption = models.CharField(max_length=225, null=True, blank=True) + created_by = models.ForeignKey( + settings.AUTH_USER_MODEL, verbose_name=_('Created by'), related_name='document_created_by', + null=True, blank=True, on_delete=models.SET_NULL, + ) + client_id = models.CharField(max_length=50, null=True, blank=True) + + class Meta: + verbose_name = _('Document') + verbose_name_plural = _('Documents') + + def __str__(self): + return str(self.id) + + class EAP(models.Model): - class Status(TextChoices): # TODO some more status choices are to be expected by client. + class Status(TextChoices): APPROVED = 'approved', _('Approved') - IN_PROCESS = 'in_process', _('In Process') + ACTIVATED = 'activated', _('Activated') created_by = models.ForeignKey( settings.AUTH_USER_MODEL, verbose_name=_('Created by'), related_name='eap_created_by', @@ -86,9 +101,9 @@ class Status(TextChoices): # TODO some more status choices are to be expected b Country, on_delete=models.SET_NULL, verbose_name=_('Country'), related_name='eap_country', null=True ) - district = models.ForeignKey( - District, on_delete=models.SET_NULL, verbose_name=_('Provience/Region'), - related_name='eap_district', null=True, blank=True + districts = models.ManyToManyField( + District, verbose_name=_('districts'), + related_name='eap_district' ) disaster_type = models.ForeignKey( DisasterType, on_delete=models.SET_NULL, verbose_name=_('Disaster Type'), @@ -97,7 +112,7 @@ class Status(TextChoices): # TODO some more status choices are to be expected b eap_number = models.CharField(max_length=50, verbose_name=_('EAP Number')) approval_date = models.DateField(verbose_name=_('Date of EAP Approval')) status = models.CharField( - max_length=255, choices=Status.choices, default=Status.IN_PROCESS, + max_length=255, choices=Status.choices, default=Status.APPROVED, verbose_name=_('EAP Status') ) operational_timeframe = models.IntegerField(verbose_name=_('Operational Timeframe (Months)')) @@ -110,9 +125,11 @@ class Status(TextChoices): # TODO some more status choices are to be expected b early_action_budget = models.IntegerField(verbose_name=_('Early Actions Budget (CHF)'), null=True, blank=True) trigger_statement = models.TextField(verbose_name=_('Trigger Statement (Threshold for Activation)')) overview = models.TextField(verbose_name=_('EAP Overview')) - document = models.FileField( - verbose_name=_('EAP Documents'), upload_to='eap/documents/', - null=True, blank=True + documents = models.ManyToManyField( + EAPDocument, + verbose_name=_('EAP Documents'), + related_name='eap_document', + blank=True ) early_actions = models.ManyToManyField( EarlyAction, @@ -146,6 +163,7 @@ class EAPPartner(models.Model): eap = models.ForeignKey(EAP, on_delete=models.CASCADE, related_name='eap_partner', verbose_name=_('EAP')) name = models.CharField(max_length=255, verbose_name=_('Name'), null=True, blank=True) url = models.URLField(verbose_name=_('URL'), null=True, blank=True) + client_id = models.CharField(max_length=50, null=True, blank=True) class Meta: verbose_name = _('EAP Partner') @@ -159,6 +177,7 @@ class EAPReference(models.Model): eap = models.ForeignKey(EAP, on_delete=models.CASCADE, related_name='eap_reference', verbose_name=_('EAP')) source = models.CharField(max_length=255, verbose_name=_('Name'), null=True, blank=True) url = models.URLField(verbose_name=_('URL'), null=True, blank=True) + client_id = models.CharField(max_length=50, null=True, blank=True) class Meta: verbose_name = _('EAP Reference') @@ -174,6 +193,7 @@ class Action(models.Model): related_name="action", verbose_name=_('Early Actions') ) early_act = models.TextField(verbose_name=_('Early Actions'), null=True, blank=True) + client_id = models.CharField(max_length=50, null=True, blank=True) class Meta: verbose_name = _('Action') @@ -181,3 +201,176 @@ class Meta: def __str__(self): return f'{self.id}' + + +class PrioritizedRisk(models.Model): + early_action = models.ForeignKey( + EarlyAction, + on_delete=models.CASCADE, + related_name='early_actions_prioritized_risk', + verbose_name=_('early action') + ) + risks = models.TextField(null=True, blank=True) + client_id = models.CharField(max_length=50, null=True, blank=True) + + class Meta: + verbose_name = _('Prioritized risk') + verbose_name_plural = _('Prioritized risks') + + def __str__(self): + return f'{self.id}' + + +class EAPActivation(models.Model): + title = models.CharField(max_length=250, null=True, blank=True) + field_report = models.ForeignKey( + FieldReport, + on_delete=models.SET_NULL, + related_name='field_report_eap_activation', + verbose_name=_('field report'), + null=True, blank=True + ) + eap = models.ForeignKey( + EAP, + on_delete=models.SET_NULL, + related_name='eap_activation', + verbose_name=_('eap'), + null=True, blank=True + ) + trigger_met_date = models.DateTimeField(verbose_name=_('Date the trigger was met')) + description = models.TextField(verbose_name=_('Description of EAP Activation')) + documents = models.ManyToManyField( + EAPDocument, + verbose_name=_('EAP Activation Documents'), + related_name='eap_activation_document', + blank=True + ) + originator_name = models.CharField(max_length=250, verbose_name=_('Originator name'), null=True, blank=True) + originator_title = models.CharField(max_length=250, verbose_name=_('Originator title'), null=True, blank=True) + originator_email = models.CharField(max_length=250, verbose_name=_('Originator email'), null=True, blank=True) + nsc_name_operational = models.CharField(max_length=250, verbose_name=_('National Society Contact (Operational)'), null=True, blank=True) + nsc_title_operational = models.CharField(max_length=250, verbose_name=_('National Society Contact (Operational)'), null=True, blank=True) + nsc_email_operational = models.CharField(max_length=250, verbose_name=_('National Society Contact (Operational)'), null=True, blank=True) + nsc_name_secretary = models.CharField(max_length=250, verbose_name=_('National Society Contact (Secretary)'), null=True, blank=True) + nsc_title_secretary = models.CharField(max_length=250, verbose_name=_('National Society Contact (Secretary)'), null=True, blank=True) + nsc_email_secretary = models.CharField(max_length=250, verbose_name=_('National Society Contact (Secretary)'), null=True, blank=True) + ifrc_focal_name = models.CharField(max_length=250, verbose_name=_('IFRC Focal Point Name'), null=True, blank=True) + ifrc_focal_title = models.CharField(max_length=250, verbose_name=_('IFRC Focal Point Title'), null=True, blank=True) + ifrc_focal_email = models.CharField(max_length=250, verbose_name=_('IFRC Focal Point Email'), null=True, blank=True) + + def __str__(self): + return f'{self.eap.eap_number}' + + +class EAPOperationalPlan(models.Model): + early_action = models.OneToOneField( + EarlyAction, + on_delete=models.SET_NULL, + null=True, + blank=True + ) + budget = models.IntegerField(verbose_name=_('Budget per sector (CHF)'), null=True, blank=True) + value = models.IntegerField(verbose_name=_('value'), null=True, blank=True) + no_of_people_reached = models.IntegerField(verbose_name=_('People Reached'), null=True, blank=True) + readiness_activities_achievements = models.TextField(verbose_name=_('Readiness Activities Achievements'), null=True, blank=True) + prepo_activities_achievements = models.TextField(verbose_name=_('Pre-positioning Activities Achievements'), null=True, blank=True) + client_id = models.CharField(max_length=50, null=True, blank=True) + + class Meta: + verbose_name = _('EAP Operational Plan') + verbose_name_plural = _('EAP Operational Plans') + + def __str__(self): + return f'{self.id}' + + +class OperationalPlanIndicator(models.Model): + operational_plan = models.ForeignKey( + EAPOperationalPlan, on_delete=models.SET_NULL, + related_name="operational_plan_indicator", verbose_name=_('Operational Plan'), + null=True, blank=True + ) + indicator = models.ForeignKey( + EarlyActionIndicator, + on_delete=models.SET_NULL, + related_name='operational_plan_indicator', + null=True, + blank=True + ) + indicator_value = models.IntegerField(null=True, blank=True) + + class Meta: + verbose_name = _('Operational Indicator') + verbose_name_plural = _('Operational Indicators') + + def __str__(self): + return f'{self.indicator.id}' + + +class ActionAchievement(models.Model): + operational_plan = models.ForeignKey( + EAPOperationalPlan, on_delete=models.SET_NULL, + related_name="action_achievement", verbose_name=_('Action Achievement'), + null=True, blank=True + ) + action = models.ForeignKey( + Action, + on_delete=models.SET_NULL, + related_name='action_achievement', + null=True, blank=True + ) + early_act_achievement = models.TextField(verbose_name=_('Early Actions Achievements'), null=True, blank=True) + client_id = models.CharField(max_length=50, null=True, blank=True) + + class Meta: + verbose_name = _('Action Achievement') + verbose_name_plural = _('Action Achievements') + + def __str__(self): + return f'{self.id}' + + +class EAPActivationReport(models.Model): + eap_activation = models.ForeignKey( + EAPActivation, + on_delete=models.SET_NULL, + verbose_name=_('EAP Activation Report'), + related_name='eap_activation_report', + null=True, blank=True + ) + number_of_people_reached = models.IntegerField(verbose_name=_('Number Of People Reached')) + description = models.TextField(verbose_name=_('Description of Event & Overview of Implementation')) + overall_objectives = models.TextField(verbose_name=_('Overall Objective of the Intervention')) + documents = models.ManyToManyField( + EAPDocument, + verbose_name=_('EAP Activation Report Document'), + related_name='eap_act_reports', + blank=True + ) + challenges_and_lesson = models.TextField(verbose_name=_('Challenges & Lesson Learned per Sector')) + general_lesson_and_recomendations = models.TextField(verbose_name=_('General Lessons Learned and Recomendations')) + ifrc_financial_report = models.ForeignKey( + EAPDocument, + on_delete=models.SET_NULL, + verbose_name=_('IFRC Financial Report'), + related_name='eap_activation_ifrc_report', + null=True, blank=True + ) + operational_plans = models.ManyToManyField( + EAPOperationalPlan, + verbose_name=_('Operational Plans'), + blank=True + ) + created_by = models.ForeignKey( + settings.AUTH_USER_MODEL, verbose_name=_('Created by'), related_name='eap_act_report_created_by', + null=True, blank=True, on_delete=models.SET_NULL, + ) + modified_by = models.ForeignKey( + settings.AUTH_USER_MODEL, verbose_name=_('Modified by'), related_name='eap_act_modified_by', + null=True, blank=True, on_delete=models.SET_NULL, + ) + created_at = models.DateTimeField(verbose_name=_('Created at'), auto_now_add=True) + modified_at = models.DateTimeField(verbose_name=_('Updated at'), auto_now=True) + + def __str__(self): + return f'{self.eap_activation.title}' diff --git a/eap/serializers.py b/eap/serializers.py new file mode 100644 index 000000000..20099c57c --- /dev/null +++ b/eap/serializers.py @@ -0,0 +1,213 @@ +from django.utils.translation import ugettext + +from rest_framework import serializers + +from api.serializers import ( + UserNameSerializer, + DisasterTypeSerializer, + CountrySerializer, + MiniDistrictSerializer, +) +from api.models import District + +from eap.models import ( + EAP, + Action, + EAPPartner, + EAPReference, + EarlyAction, + EarlyActionIndicator, + EAPDocument, + PrioritizedRisk, + EAPActivation, + EAPOperationalPlan, + ActionAchievement, + EAPActivationReport, + OperationalPlanIndicator, +) + +from main.writable_nested_serializers import ( + NestedCreateMixin, + NestedUpdateMixin, +) + + +class EAPReferenceSerializer(serializers.ModelSerializer): + class Meta: + model = EAPReference + fields = '__all__' + read_only_fields = ('eap',) + + +class EAPPartnerSerializer(serializers.ModelSerializer): + class Meta: + model = EAPPartner + fields = '__all__' + read_only_fields = ('eap',) + + +class EarlyActionIndicatorSerializer(serializers.ModelSerializer): + indicator_display = serializers.CharField(source='get_indicator_display', read_only=True) + + class Meta: + model = EarlyActionIndicator + fields = '__all__' + + +class ActionSerializer(serializers.ModelSerializer): + class Meta: + model = Action + fields = ('__all__') + read_only_fields = ('early_action',) + + +class PrioritizedRiskSerializer(serializers.ModelSerializer): + class Meta: + model = PrioritizedRisk + fields = ('__all__') + read_only_fields = ('early_action',) + + +class EarlyActionSerializer( + NestedUpdateMixin, + NestedCreateMixin, + serializers.ModelSerializer +): + indicators = EarlyActionIndicatorSerializer(many=True, required=False) + actions = ActionSerializer(source='action', many=True, required=False) + prioritized_risks = PrioritizedRiskSerializer(source='early_actions_prioritized_risk', many=True, required=False) + sector_display = serializers.CharField(source='get_sector_display', read_only=True) + + class Meta: + model = EarlyAction + fields = ('__all__') + + +class EAPActionSerializer(serializers.ModelSerializer): + class Meta: + model = Action + fields = ('__all__') + read_only_fields = ('early_action',) + + +class EAPDocumentSerializer(serializers.ModelSerializer): + + class Meta: + model = EAPDocument + fields = ['id', 'file', 'caption', ] + + def create(self, validated_data): + validated_data['created_by'] = self.context['request'].user + return super().create(validated_data) + + +class EAPSerializer( + NestedUpdateMixin, + NestedCreateMixin, + serializers.ModelSerializer +): + country_details = CountrySerializer(source='country', read_only=True) + districts_details = MiniDistrictSerializer(source='districts', many=True, read_only=True) + references = EAPReferenceSerializer(source='eap_reference', many=True, required=False) + partners = EAPPartnerSerializer(source='eap_partner', many=True, required=False) + early_actions = EarlyActionSerializer(many=True) + created_by_details = UserNameSerializer(source='created_by', read_only=True) + modified_by_details = UserNameSerializer(source='modified_by', read_only=True) + hazard_type_details = DisasterTypeSerializer(source='disaster_type', read_only=True) + documents = EAPDocumentSerializer(many=True, required=False) + status_display = serializers.CharField(source='get_status_display', read_only=True) + + class Meta: + model = EAP + fields = ('__all__') + + def validate(self, data): + if 'districts' in data: + districts = data.get('districts') or [] + country = data.get('country') + for district in districts: + if district.country != country: + raise serializers.ValidationError({ + 'districts': ugettext('Different districts found for given country') + }) + return data + + def create(self, validated_data): + validated_data['created_by'] = self.context['request'].user + return super().create(validated_data) + + def update(self, instance, validated_data): + validated_data['modified_by'] = self.context['request'].user + return super().update(instance, validated_data) + + +class EAPActivationSerializer(serializers.ModelSerializer): + document_details = serializers.SerializerMethodField('get_eap_documents') + + @staticmethod + def get_eap_documents(obj): + eap_documents = obj.documents.all() + return [ + { + 'id': document.id, + 'file': document.file.url, + 'caption': document.caption + } for document in eap_documents + ] + + class Meta: + model = EAPActivation + exclude = ('eap', 'field_report') + + +class ActionAchievementSerializer(serializers.ModelSerializer): + + class Meta: + model = ActionAchievement + exclude = ('operational_plan',) + + +class OperationalPlanIndicatorSerializer(serializers.ModelSerializer): + + class Meta: + model = OperationalPlanIndicator + exclude = ('operational_plan',) + + +class OperationalPlanSerializer( + NestedUpdateMixin, + NestedCreateMixin, + serializers.ModelSerializer +): + indicators = OperationalPlanIndicatorSerializer(source='operational_plan_indicator', many=True, required=False) + early_actions_achievements = ActionAchievementSerializer(source='action_achievement', many=True, required=False) + + class Meta: + model = EAPOperationalPlan + fields = ('__all__') + + +class EAPActivationReportSerializer( + NestedUpdateMixin, + NestedCreateMixin, + serializers.ModelSerializer +): + operational_plans = OperationalPlanSerializer(many=True) + created_by_details = UserNameSerializer(source='created_by', read_only=True) + modified_by_details = UserNameSerializer(source='modified_by', read_only=True) + documents = EAPDocumentSerializer(many=True, required=False) + ifrc_financial_report_details = EAPDocumentSerializer(source='ifrc_financial_report', read_only=True) + + class Meta: + model = EAPActivationReport + fields = '__all__' + + def create(self, validated_data): + validated_data['created_by'] = self.context['request'].user + final_report = super().create(validated_data) + return final_report + + def update(self, instance, validated_data): + validated_data['modified_by'] = self.context['request'].user + final_report = super().update(instance, validated_data) + return final_report diff --git a/eap/test_views.py b/eap/test_views.py new file mode 100644 index 000000000..fa75af8fe --- /dev/null +++ b/eap/test_views.py @@ -0,0 +1,441 @@ +import os + +from django.conf import settings +from django.contrib.auth.models import User + +from main.test_case import APITestCase +from eap.models import ( + EAP, + Action, + EarlyAction, + EAPDocument, + EAPActivationReport, +) + +from api.factories.country import CountryFactory +from api.factories.district import DistrictFactory +from api.factories.disaster_type import DisasterTypeFactory +from deployments.factories.user import UserFactory + +from .factories import ( + EAPDocumentFactory, + EAPFactory, + EAPActivationFactory, + EAPActivationReportFactory, +) + + +class EAPTest(APITestCase): + + def setUp(self): + self.user = UserFactory.create(username='jo') + self.country1 = CountryFactory.create(name='abc') + self.country2 = CountryFactory.create(name='xyz') + self.district1 = DistrictFactory.create(name='test district1', country=self.country1) + self.district2 = DistrictFactory.create(name='test district2', country=self.country2) + self.document1 = EAPDocumentFactory.create(created_by=self.user) + self.document2 = EAPDocumentFactory.create(created_by=self.user) + self.disaster_type = DisasterTypeFactory.create(name="test earthquake") + self.disaster_type_updated = DisasterTypeFactory.create(name="test flood") + self.eap_activation = EAPActivationFactory.create() + + path = os.path.join(settings.TEST_DIR, 'documents') + self.file = os.path.join(path, 'go.png') + + self.body = { + "references": [ + { + "source": "test", + "url": "https://jsonformatter.org/" + }, + { + "source": "test 2", + "url": "https://jsonformatter.org/" + } + ], + "partners": [ + { + "name": "test name", + "url": "https://jsonformatter2.org/" + }, + { + "name": "test name 2", + "url": "https://jsonformatter2.org/" + } + ], + "eap_number": "1", + "approval_date": "2022-11-11", + "status": "approved", + "operational_timeframe": 5, + "lead_time": 5, + "eap_timeframe": 5, + "num_of_people": 1000, + "total_budget": 10000, + "readiness_budget": 5000, + "pre_positioning_budget": 3000, + "early_action_budget": 2000, + "trigger_statement": "test", + "overview": "test", + "documents": [ + { + "id": self.document1.id, + "caption": "test caption" + }, + { + "id": self.document2.id, + "caption": "test caption 2" + }, + ], + "originator_name": "eap name", + "originator_title": "eap title", + "originator_email": "eap@gmail.com", + "originator_phone": "1245145241", + "nsc_name": "eap ns name", + "nsc_title": "eap ns title", + "nsc_email": "eap_ns@gmail.com", + "nsc_phone": "8547458745", + "ifrc_focal_name": "ifrc name", + "ifrc_focal_title": "ifrc title", + "ifrc_focal_email": "eap_ifrc@gmail.com", + "ifrc_focal_phone": "5685471584", + "country": self.country1.id, + "districts": [self.district1.id], + "disaster_type": self.disaster_type.id, + "early_actions": [ + { + "sector": EarlyAction.Sector.LIVELIHOODS, + "budget_per_sector": 1000, + "prioritized_risks": [ + { + "risks": "test1" + }, + { + "risks": "test2" + } + ], + "targeted_people": 100, + "readiness_activities": "test", + "prepositioning_activities": "test", + "indicators": [ + { + "indicator": "indicator_1", + "indicator_value": 1 + }, + { + "indicator": "indicator_2", + "indicator_value": 2 + } + ], + "actions": [ + { + "early_act": "test" + }, + { + "early_act": "test 2" + } + ] + + }, + { + "sector": EarlyAction.Sector.MIGRATION, + "budget_per_sector": 1000, + "prioritized_risks": [ + { + "risks": "test1" + }, + { + "risks": "test2" + } + ], + "targeted_people": 200, + "readiness_activities": "test", + "prepositioning_activities": "test", + "indicators": [ + { + "indicator": "indicator_1", + "indicator_value": 1 + }, + { + "indicator": "indicator_2", + "indicator_value": 2 + } + ], + "actions": [ + { + "early_act": " early_acttest" + }, + { + "early_act": "early_act test 2" + } + ] + + } + ] + } + self.eap_act_report_body = { + "eap_activation": self.eap_activation.id, + "number_of_people_reached": 1000, + "description": "test eap activation report", + "overall_objectives": "test eap activation report", + "documents": [ + { + "id": self.document1.id, + "caption": "test caption" + }, + { + "id": self.document2.id, + "caption": "test caption 2" + }, + ], + "challenges_and_lesson": "test eap activation report", + "general_lesson_and_recomendations": "test eap activation report", + "ifrc_financial_report": self.document1.id, + "operational_plans": [ + { + "budget": 200000, + "value": 100, + "no_of_people_reached": 100, + "readiness_activities_achievements": "test", + "prepo_activities_achievements": "test", + "early_actions_achievements": [ + { + "early_act_achievement": "test 1" + }, + { + "early_act_achievement": "test 2" + } + ], + "indicators": [ + { + "indicator_value": 200 + }, + { + "indicator_value": 300 + } + ] + }, + ] + } + super().setUp() + + def test_create_and_update_eap(self): + self.client.force_authenticate(user=self.user) + # create eap + with self.capture_on_commit_callbacks(execute=True): + response = self.client.post('/api/v2/eap/', self.body, format='json').json() + created = EAP.objects.get(id=response['id']) + self.assertEqual(created.created_by.id, self.user.id) + self.assertEqual(created.country.id, self.country1.id) + self.assertEqual(created.disaster_type, self.disaster_type) + self.assertEqual(response['country'], self.country1.id) + self.assertEqual(created.status, EAP.Status.APPROVED) + self.assertEqual(created.early_actions.count(), 2) + self.assertEqual(len(response['references']), 2) + self.assertEqual(len(response['partners']), 2) + + # update eap + data = self.body + data['country'] = self.country2.id + data['districts'] = [self.district2.id] + data['references'] = [ + { + "source": "test updated", + "url": "https://jsonformatter.org/" + } + ] + data['partners'] = [ + { + "name": "test name updated", + "url": "https://jsonformatter2.org/" + } + ] + + data['disaster_type'] = str(self.disaster_type_updated.id) + data['status'] = EAP.Status.ACTIVATED + data['reference'] = self.document1.id + + response = self.client.put(f'/api/v2/eap/{created.id}/', data, format='json').json() + updated = EAP.objects.get(id=response['id']) + self.assertEqual(updated.id, created.id) + self.assertEqual(updated.modified_by, self.user) + self.assertEqual(updated.status, EAP.Status.ACTIVATED) + self.assertEqual(updated.disaster_type, self.disaster_type_updated) + self.assertEqual(updated.early_actions.count(), 2) + self.assertEqual(len(response['references']), 1) + self.assertEqual(len(response['partners']), 1) + + # test patch + data = {'status': EAP.Status.APPROVED} + response = self.client.patch(f'/api/v2/eap/{created.id}/', data=data, format='json').json() + pached = EAP.objects.get(id=response['id']) + self.assertEqual(pached.status, EAP.Status.APPROVED) + + def test_get_eap(self): + user1 = UserFactory.create(username='abc') + eap1, eap2, eap3 = EAPFactory.create_batch(3, created_by=user1) + self.client.force_authenticate(user=user1) + response1 = self.client.get('/api/v2/eap/').json() + self.assertEqual(response1['results'][0]['created_by'], user1.id) + + assert all(item in [data['id'] for data in response1['results']] for item in [eap1.id, eap2.id, eap3.id]) + + # query single eap + response = self.client.get(f'/api/v2/eap/{eap1.id}/').json() + self.assertEqual(response['created_by'], user1.id) + self.assertEqual(response['id'], eap1.id) + + # try with another user + user2 = User.objects.create(username='xyz') + self.client.force_authenticate(user=user2) + eap4, eap5 = EAPFactory.create_batch(2, created_by=user2) + response2 = self.client.get('/api/v2/eap/').json() + self.assertEqual(response2['results'][0]['created_by'], user2.id) + self.assertIn(eap4.id, [data['id'] for data in response2['results']]) + self.assertNotIn([data['id'] for data in response2['results']], [data['id'] for data in response1['results']]) + + # try with users who has no any eap created + user3 = User.objects.create(username='ram') + self.client.force_authenticate(user=user3) + response3 = self.client.get('/api/v2/eap/').json() + self.assertEqual(response3['count'], 6) + + def test_create_and_update_eap_activation_report(self): + self.client.force_authenticate(user=self.user) + # create eap + with self.capture_on_commit_callbacks(execute=True): + eap_resp = self.client.post('/api/v2/eap/', self.body, format='json').json() + early_action = EarlyAction.objects.get(id=eap_resp['early_actions'][0]['id']) + + actions = list(Action.objects.filter(early_action=early_action).values_list('id', flat=True)) + actions_indicators = early_action.indicators.all().values_list('id', flat=True) + self.eap_act_report_body['operational_plans'][0]['early_action'] = early_action.id + self.eap_act_report_body['operational_plans'][0]['early_actions_achievements'][0]['action'] = actions[0] + self.eap_act_report_body['operational_plans'][0]['early_actions_achievements'][1]['action'] = actions[1] + + self.eap_act_report_body['operational_plans'][0]['indicators'][0]['indicator'] = actions_indicators[0] + self.eap_act_report_body['operational_plans'][0]['indicators'][1]['indicator'] = actions_indicators[1] + # create eap_report + with self.capture_on_commit_callbacks(execute=True): + final_report_resp = self.client.post( + '/api/v2/eap-activation-report/', + self.eap_act_report_body, + format='json' + ).json() + created = EAPActivationReport.objects.get(id=final_report_resp['id']) + self.assertEqual(created.created_by.id, self.user.id) + self.assertEqual(final_report_resp['eap_activation'], self.eap_activation.id) + self.assertEqual(final_report_resp['ifrc_financial_report'], self.document1.id) + self.assertEqual(len(final_report_resp['documents']), 2) + self.assertEqual(len(final_report_resp['operational_plans']), 1) + self.assertEqual(len(final_report_resp['operational_plans'][0]['early_actions_achievements']), 2) + self.assertEqual(len(final_report_resp['operational_plans'][0]['indicators']), 2) + + # update eap_report + data = self.eap_act_report_body + data['description'] = 'updated description' + data['documents'] = [ + { + "id": self.document2.id, + "caption": "test caption updated" + }, + { + "id": self.document1.id, + "caption": "test caption updated" + } + ] + data['ifrc_financial_report'] = self.document2.id + data['operational_plans'] = [ + { + "budget": 500000, + "value": 500, + "no_of_people_reached": 500, + "readiness_activities_achievements": "test updated", + "prepo_activities_achievements": "test updated", + "early_actions_achievements": [ + { + 'action': actions[0], + "early_act_achievement": "test updated" + }, + { + 'action': actions[1], + "early_act_achievement": "test 2 updated" + } + ], + "indicators": [ + { + "indicator": actions_indicators[0], + "indicator_value": 500 + }, + { + 'indicator': actions_indicators[1], + "indicator_value": 500 + } + ] + }, + ] + with self.capture_on_commit_callbacks(execute=True): + final_report_updated_resp = self.client.put( + f'/api/v2/eap-activation-report/{created.id}/', + data, + format='json' + ).json() + updated = EAPActivationReport.objects.get(id=final_report_updated_resp['id']) + self.assertEqual(updated.created_by.id, self.user.id) + self.assertEqual(final_report_updated_resp['eap_activation'], self.eap_activation.id) + self.assertEqual(final_report_updated_resp['ifrc_financial_report'], self.document2.id) + self.assertEqual(len(final_report_updated_resp['operational_plans']), 1) + self.assertEqual(len(final_report_updated_resp['operational_plans'][0]['early_actions_achievements']), 2) + self.assertEqual(len(final_report_updated_resp['operational_plans'][0]['indicators']), 2) + + # test patch + data = {'ifrc_financial_report': self.document1.id} + with self.capture_on_commit_callbacks(execute=True): + final_report_patched_resp = self.client.patch( + f'/api/v2/eap-activation-report/{created.id}/', + data, + format='json' + ).json() + updated = EAPActivationReport.objects.get(id=final_report_patched_resp['id']) + self.assertEqual(final_report_patched_resp['ifrc_financial_report'], self.document1.id) + + def test_get_eap_activation_report(self): + user1 = UserFactory.create(username='abc') + report1, report2, report3 = EAPActivationReportFactory.create_batch(3, created_by=user1) + self.client.force_authenticate(user=user1) + response1 = self.client.get('/api/v2/eap-activation-report/').json() + self.assertEqual(response1['results'][0]['created_by'], user1.id) + self.assertEqual(len(response1['results']), 3) + assert all(item in [data['id'] for data in response1['results']] for item in [report1.id, report2.id, report3.id]) + + # query single eap + response = self.client.get(f'/api/v2/eap-activation-report/{report1.id}/').json() + self.assertEqual(response['created_by'], user1.id) + self.assertEqual(response['id'], report1.id) + + # try with another user + user2 = User.objects.create(username='xyz') + self.client.force_authenticate(user=user2) + report4, report5 = EAPActivationReportFactory.create_batch(2, created_by=user2) + response2 = self.client.get('/api/v2/eap-activation-report/').json() + self.assertEqual(response2['results'][0]['created_by'], user2.id) + self.assertIn(report4.id, [data['id'] for data in response2['results']]) + self.assertNotIn([data['id'] for data in response2['results']], [data['id'] for data in response1['results']]) + + # try with users who has no any eap created + user3 = User.objects.create(username='ram') + self.client.force_authenticate(user=user3) + response3 = self.client.get('/api/v2/eap-activation-report/').json() + self.assertEqual(response3['count'], 5) + + def test_eap_upload_multiple_file(self): + file_count = EAPDocument.objects.count() + url = '/api/v2/eap-file/multiple/' + data = { + 'file': [open(self.file, 'rb'), open(self.file, 'rb'), open(self.file, 'rb')] + } + + self.authenticate() + response = self.client.post(url, data, format='multipart') + self.assert_201(response) + self.assertEqual(EAPDocument.objects.count(), file_count + 3) + diff --git a/eap/views.py b/eap/views.py index 91ea44a21..30fcd1ebc 100644 --- a/eap/views.py +++ b/eap/views.py @@ -1,3 +1,125 @@ -from django.shortcuts import render - # Create your views here. +from rest_framework import ( + views, + viewsets, + response, + permissions, + mixins, + status, +) +from rest_framework.decorators import action +from .models import ( + EarlyActionIndicator, + EAP, + EAPDocument, + EarlyAction, + EAPActivationReport, +) +from .serializers import ( + EAPSerializer, + EAPDocumentSerializer, + EAPActivationReportSerializer, +) + + +class EAPDocumentViewSet( + mixins.ListModelMixin, + mixins.CreateModelMixin, + viewsets.GenericViewSet +): + permission_class = [permissions.IsAuthenticated] + serializer_class = EAPDocumentSerializer + + def get_queryset(self): + return EAPDocument.objects.all() + + @action( + detail=False, + url_path='multiple', + methods=['POST'], + permission_classes=[permissions.IsAuthenticated], + ) + def multiple_file(self, request, pk=None, version=None): + # converts querydict to original dict + files = dict((request.data).lists())['file'] + data = [{'file': file} for file in files] + file_serializer = EAPDocumentSerializer(data=data, context={'request': request}, many=True) + if file_serializer.is_valid(): + file_serializer.save() + return response.Response(file_serializer.data, status=status.HTTP_201_CREATED) + else: + return response.Response(file_serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + +class EAPViewSet(viewsets.ModelViewSet): + serializer_class = EAPSerializer + permission_classes = [permissions.IsAuthenticated] + + def get_queryset(self): + result = EAP.objects.all().order_by( + '-created_at' + ).select_related( + 'country', + 'created_by', + 'modified_by', + 'disaster_type', + ).prefetch_related( + 'districts', + 'districts__country', + 'documents', + 'early_actions', + 'early_actions__action', + 'early_actions__early_actions_prioritized_risk', + 'early_actions__indicators', + 'eap_reference', + 'eap_partner', + ) + return result + + +class EAPActivationReportViewSet(viewsets.ModelViewSet): + serializer_class = EAPActivationReportSerializer + permission_classes = [permissions.IsAuthenticated] + + def get_queryset(self): + return EAPActivationReport.objects.all().order_by( + '-created_at' + ).select_related( + 'created_by', + 'modified_by', + 'eap_activation', + 'ifrc_financial_report', + ).prefetch_related( + 'documents', + 'operational_plans', + ) + + +class EAPOptionsView(views.APIView): + """ + Options for various attribute related to eap + """ + permission_classes = [permissions.IsAuthenticated] + + def get(self, request, version=None): + options = { + "status": [ + { + "key": status.value, + "value": status.label + } for status in EAP.Status + ], + "early_actions_indicators": [ + { + "key": indicator.value, + "value": indicator.label + } for indicator in EarlyActionIndicator.IndicatorChoices + ], + "sectors": [ + { + "key": sector.value, + "value": sector.label + } for sector in EarlyAction.Sector + ], + } + return response.Response(options) diff --git a/main/settings.py b/main/settings.py index 98fbca79d..82328901a 100644 --- a/main/settings.py +++ b/main/settings.py @@ -176,7 +176,8 @@ ), 'DEFAULT_RENDERER_CLASSES': ( 'rest_framework.renderers.JSONRenderer', - 'rest_framework.renderers.BrowsableAPIRenderer', + # 'rest_framework.renderers.BrowsableAPIRenderer', # it is comment out to reduce load time in browsable api + 'main.utils.BrowsableAPIRendererWithRawForms', # it is added to remove html form and reduce load time in browsable api 'rest_framework_csv.renderers.PaginatedCSVRenderer', ), 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema', diff --git a/main/urls.py b/main/urls.py index de6a821c3..ef86c8625 100644 --- a/main/urls.py +++ b/main/urls.py @@ -68,6 +68,7 @@ from rest_framework.documentation import include_docs_urls from api import drf_views as api_views from flash_update import views as flash_views +from eap import views as eap_views from per import drf_views as per_views from deployments import drf_views as deployment_views from notifications import drf_views as notification_views @@ -148,6 +149,10 @@ router.register(r'donor', flash_views.DonorsViewSet, basename='donor') router.register(r'share-flash-update', flash_views.ShareFlashUpdateViewSet, basename='share_flash_update') +router.register(r'eap', eap_views.EAPViewSet, basename='eap') +router.register(r'eap-activation-report', eap_views.EAPActivationReportViewSet, basename='eap-activation-report') +router.register(r'eap-file', eap_views.EAPDocumentViewSet, basename='eap_file') + # Dref apis router.register(r'dref', dref_views.DrefViewSet, basename='dref') router.register(r'dref-files', dref_views.DrefFileViewSet, basename='dref_files') @@ -177,6 +182,7 @@ url(r'^api/v2/add_cronjob_log/', AddCronJobLog.as_view()), url(r'^api/v2/flash-update-options/', flash_views.FlashUpdateOptions.as_view()), url(r'^api/v2/export-flash-update/(?P\d+)/', flash_views.ExportFlashUpdateView.as_view()), + url(r'^api/v2/eap-options/', eap_views.EAPOptionsView.as_view()), url(r'^register', NewRegistration.as_view()), # url(r'^createperform', CreatePerForm.as_view()), url(r'^updateperform', UpdatePerForm.as_view()), diff --git a/main/utils.py b/main/utils.py index c6e3951cc..c06a50d02 100644 --- a/main/utils.py +++ b/main/utils.py @@ -1,5 +1,7 @@ from collections import defaultdict +from rest_framework.renderers import BrowsableAPIRenderer + def is_tableau(request): """ Checking the request for the 'tableau' parameter @@ -24,3 +26,21 @@ def get_merged_items_by_fields(items, fields, seperator=', '): field: seperator.join(data[field]) for field in fields } + + +class BrowsableAPIRendererWithRawForms(BrowsableAPIRenderer): # It is done to reduce load time in browsable api. + """ + Renders the browsable api, but excludes the normal forms. + Only show raw form. + """ + + def get_context(self, *args, **kwargs): + ctx = super().get_context(*args, **kwargs) + ctx['post_form'] = None + return ctx + + def get_rendered_html_form(self, data, view, method, request): + """Why render _any_ forms at all. This method should return + rendered HTML, so let's simply return an empty string. + """ + return "" diff --git a/test b/test new file mode 100644 index 000000000..4b2bbcd91 --- /dev/null +++ b/test @@ -0,0 +1,32 @@ +"id", + "created_at", + "modified_at", + "eap_number", + "approval_date", + "status", + "operational_timeframe", + "lead_time", + "eap_timeframe", + "num_of_people", + "total_budget", + "readiness_budget", + "pre_positioning_budget", + "early_action_budget", + "trigger_statement", + "overview", + "originator_name", + "originator_title", + "originator_email", + "originator_phone", + "nsc_name", + "nsc_title", + "nsc_email", + "nsc_phone", + "ifrc_focal_name", + "ifrc_focal_title", + "ifrc_focal_email", + "ifrc_focal_phone", + "created_by", + "modified_by", + "country", + "disaster_type",