From 2b210e8879434441bb81fa5ab94a8bc0ec583f7f Mon Sep 17 00:00:00 2001 From: Sushil Tiwari Date: Thu, 9 Jan 2025 20:02:51 +0545 Subject: [PATCH] Add changes on purposed action and fix test cases --- ...ddressed_humanitarian_impacts_and_more.py} | 78 ++++--------------- dref/models.py | 28 +++---- dref/serializers.py | 51 +++++++----- 3 files changed, 53 insertions(+), 104 deletions(-) rename dref/migrations/{0076_dref_contingency_plans_supporting_document_and_more.py => 0076_dref_addressed_humanitarian_impacts_and_more.py} (62%) diff --git a/dref/migrations/0076_dref_contingency_plans_supporting_document_and_more.py b/dref/migrations/0076_dref_addressed_humanitarian_impacts_and_more.py similarity index 62% rename from dref/migrations/0076_dref_contingency_plans_supporting_document_and_more.py rename to dref/migrations/0076_dref_addressed_humanitarian_impacts_and_more.py index bd23e2ea6..d99276e3e 100644 --- a/dref/migrations/0076_dref_contingency_plans_supporting_document_and_more.py +++ b/dref/migrations/0076_dref_addressed_humanitarian_impacts_and_more.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.16 on 2025-01-08 06:35 +# Generated by Django 4.2.16 on 2025-01-09 14:15 import django.db.models.deletion from django.db import migrations, models @@ -12,6 +12,16 @@ class Migration(migrations.Migration): ] operations = [ + migrations.AddField( + model_name="dref", + name="addressed_humanitarian_impacts", + field=models.TextField( + blank=True, + help_text=" Which of the expected severe humanitarian impacts of the hazard are your actions addressing?", + null=True, + verbose_name="Addressed Humanitarian Impacts", + ), + ), migrations.AddField( model_name="dref", name="contingency_plans_supporting_document", @@ -19,7 +29,7 @@ class Migration(migrations.Migration): blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, - related_name="contingency_plans_supporting_document", + related_name="dref_contingency_plans_supporting_document", to="dref.dreffile", verbose_name="Contingency Plans Supporting Document", ), @@ -57,7 +67,7 @@ class Migration(migrations.Migration): blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, - related_name="scenario_supporting_document", + related_name="dref_scenario_supporting_document", to="dref.dreffile", verbose_name="Scenario Analysis Supporting Document", ), @@ -77,56 +87,6 @@ class Migration(migrations.Migration): name="total", field=models.IntegerField(blank=True, null=True, verbose_name="Total"), ), - migrations.AddField( - model_name="dreffinalreport", - name="indirect_cost", - field=models.IntegerField(blank=True, null=True, verbose_name="Indirect Cost"), - ), - migrations.AddField( - model_name="dreffinalreport", - name="sub_total", - field=models.IntegerField(blank=True, null=True, verbose_name="Sub total"), - ), - migrations.AddField( - model_name="dreffinalreport", - name="surge_deployment", - field=models.IntegerField(blank=True, null=True, verbose_name="Surge Deployment"), - ), - migrations.AddField( - model_name="dreffinalreport", - name="total", - field=models.IntegerField(blank=True, null=True, verbose_name="Total"), - ), - migrations.AddField( - model_name="drefoperationalupdate", - name="addressed_humanitarian_impacts", - field=models.TextField( - blank=True, - help_text=" Which of the expected severe humanitarian impacts of the hazard are your actions addressing?", - null=True, - verbose_name="Addressed Humanitarian Impacts", - ), - ), - migrations.AddField( - model_name="drefoperationalupdate", - name="indirect_cost", - field=models.IntegerField(blank=True, null=True, verbose_name="Indirect Cost"), - ), - migrations.AddField( - model_name="drefoperationalupdate", - name="sub_total", - field=models.IntegerField(blank=True, null=True, verbose_name="Sub total"), - ), - migrations.AddField( - model_name="drefoperationalupdate", - name="surge_deployment", - field=models.IntegerField(blank=True, null=True, verbose_name="Surge Deployment"), - ), - migrations.AddField( - model_name="drefoperationalupdate", - name="total", - field=models.IntegerField(blank=True, null=True, verbose_name="Total"), - ), migrations.CreateModel( name="ProposedAction", fields=[ @@ -137,7 +97,7 @@ class Migration(migrations.Migration): choices=[(1, "Early Actions"), (2, "Early Response")], verbose_name="dref proposed action" ), ), - ("budget", models.PositiveIntegerField(blank=True, null=True, verbose_name=" Purpose Action budgets")), + ("budget", models.PositiveIntegerField(blank=True, null=True, verbose_name="Purpose Action Budgets")), ( "activities", models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to="deployments.sector"), @@ -149,14 +109,4 @@ class Migration(migrations.Migration): name="proposed_action", field=models.ManyToManyField(blank=True, to="dref.proposedaction", verbose_name="Proposed Action"), ), - migrations.AddField( - model_name="dreffinalreport", - name="proposed_action", - field=models.ManyToManyField(blank=True, to="dref.proposedaction", verbose_name="Proposed Action"), - ), - migrations.AddField( - model_name="drefoperationalupdate", - name="proposed_action", - field=models.ManyToManyField(blank=True, to="dref.proposedaction", verbose_name="Proposed Action"), - ), ] diff --git a/dref/models.py b/dref/models.py index ebe4e28c2..5cbd818f4 100644 --- a/dref/models.py +++ b/dref/models.py @@ -221,7 +221,7 @@ class Action(models.IntegerChoices): verbose_name=_("dref proposed action"), ) activities = models.ForeignKey(Sector, on_delete=models.SET_NULL, null=True) - budget = models.PositiveIntegerField(verbose_name=_(" Purpose Action budgets"), blank=True, null=True) + budget = models.PositiveIntegerField(verbose_name=_("Purpose Action Budgets"), blank=True, null=True) def __str__(self) -> str: return f"{self.get_proposed_type_display()}- {self.activities}" @@ -630,7 +630,7 @@ class Status(models.IntegerChoices): null=True, blank=True, verbose_name=_("Scenario Analysis Supporting Document"), - related_name="scenario_supporting_document", + related_name="dref_scenario_supporting_document", ) contingency_plans_supporting_document = models.ForeignKey( "DrefFile", @@ -638,7 +638,13 @@ class Status(models.IntegerChoices): null=True, blank=True, verbose_name=_("Contingency Plans Supporting Document"), - related_name="contingency_plans_supporting_document", + related_name="dref_contingency_plans_supporting_document", + ) + addressed_humanitarian_impacts = models.TextField( + verbose_name=_("Addressed Humanitarian Impacts"), + help_text=_(" Which of the expected severe humanitarian impacts of the hazard are your actions addressing?"), + null=True, + blank=True, ) class Meta: @@ -1073,17 +1079,6 @@ class DrefOperationalUpdate(models.Model): reporting_start_date = models.DateField(verbose_name=_("Reporting Start Date"), null=True, blank=True) reporting_end_date = models.DateField(verbose_name=_("Reporting End Date"), null=True, blank=True) source_information = models.ManyToManyField(SourceInformation, blank=True, verbose_name=_("Source Information")) - proposed_action = models.ManyToManyField(ProposedAction, verbose_name=_("Proposed Action"), blank=True) - sub_total = models.IntegerField(verbose_name=_("Sub total"), blank=True, null=True) - surge_deployment = models.IntegerField(verbose_name=_("Surge Deployment"), null=True, blank=True) - indirect_cost = models.IntegerField(verbose_name=_("Indirect Cost"), null=True, blank=True) - total = models.IntegerField(verbose_name=_("Total"), null=True, blank=True) - addressed_humanitarian_impacts = models.TextField( - verbose_name=_("Addressed Humanitarian Impacts"), - help_text=_(" Which of the expected severe humanitarian impacts of the hazard are your actions addressing?"), - null=True, - blank=True, - ) __budget_file_id = None class Meta: @@ -1399,11 +1394,6 @@ class DrefFinalReport(models.Model): operation_end_date = models.DateField(verbose_name=_("Operation End Date"), null=True, blank=True) source_information = models.ManyToManyField(SourceInformation, blank=True, verbose_name=_("Source Information")) __financial_report_id = None - proposed_action = models.ManyToManyField(ProposedAction, verbose_name=_("Proposed Action"), blank=True) - sub_total = models.IntegerField(verbose_name=_("Sub total"), blank=True, null=True) - surge_deployment = models.IntegerField(verbose_name=_("Surge Deployment"), null=True, blank=True) - indirect_cost = models.IntegerField(verbose_name=_("Indirect Cost"), null=True, blank=True) - total = models.IntegerField(verbose_name=_("Total"), null=True, blank=True) class Meta: verbose_name = _("Dref Final Report") diff --git a/dref/serializers.py b/dref/serializers.py index d6144a2b2..239e54b31 100644 --- a/dref/serializers.py +++ b/dref/serializers.py @@ -119,7 +119,6 @@ class Meta: "status", "status_display", "date_of_approval", - "addressed_humanitarian_impacts", ] def get_application_type(self, obj) -> str: @@ -389,11 +388,7 @@ class DrefSerializer(NestedUpdateMixin, NestedCreateMixin, ModelSerializer): source="contingency_plans_supporting_document", read_only=True, required=False, allow_null=True ) - proposed_action = ProposedActionSerializer(many=True, required=True) - sub_total = serializers.IntegerField(required=True) - surge_deployment = serializers.IntegerField(required=True) - indirect_cost = serializers.IntegerField(required=True) - total = serializers.IntegerField(required=True) + proposed_action = ProposedActionSerializer(many=True, required=False) class Meta: model = Dref @@ -401,10 +396,13 @@ class Meta: "modified_by", "created_by", "budget_file_preview", - "anticipatory_actions", - "event_text", ) - exclude = ("cover_image", "event_map", "images", "users") + exclude = ( + "cover_image", + "event_map", + "images", + "users", + ) def get_dref_access_user_list(self, obj) -> List[int]: dref_users_list = get_dref_users() @@ -453,10 +451,23 @@ def validate(self, data): gettext("Operation timeframe can't be greater than %s for assessment_report" % self.MAX_OPERATION_TIMEFRAME) ) - proposed_actions = data.get("proposed_action", None) - proposed_budget = sum([proposed_actions["budget"] for proposed_actions in proposed_actions]) - if proposed_budget != data.get("sub_total"): - raise serializers.ValidationError("Sub-total should be equal to proposed budget") + if data.get("type_of_dref") == Dref.DrefType.IMMINENT: + if not data.get("sub_total"): + raise serializers.ValidationError({"sub_total": gettext("Sub-total is required for Imminent DREF")}) + if not data.get("surge_deployment"): + raise serializers.ValidationError({"surge_deployment": gettext("Surge Deployment is required for Imminent DREF")}) + if not data.get("indirect_cost"): + raise serializers.ValidationError({"indirect_cost": gettext("Indirect Cost is required for Imminent DREF")}) + if not data.get("total"): + raise serializers.ValidationError({"total": gettext("Total is required for Imminent DREF")}) + proposed_actions = data.get("proposed_action", None) + if not proposed_actions: + raise serializers.ValidationError( + {"proposed_action": gettext("Proposed Action is required for type DREF Imminent")} + ) + proposed_budget = sum([action.get("amount") for action in proposed_actions]) + if proposed_budget != data.get("sub_total"): + raise serializers.ValidationError("Sub-total should be equal to proposed budget") return data def validate_images(self, images): @@ -511,14 +522,6 @@ def validate_budget_file_preview(self, budget_file_preview): validate_file_type(budget_file_preview) return budget_file_preview - def validate_sub_total(self, sub_total): - instance = self.get_initial() - proposed_actions = instance.get("proposed_action", None) - proposed_budget = sum([proposed_actions["budget"] for proposed_actions in proposed_actions]) - if proposed_budget != sub_total: - raise serializers.ValidationError("Sub-total should be equal to proposed budget") - return sub_total - def create(self, validated_data): validated_data["created_by"] = self.context["request"].user validated_data["is_active"] = True @@ -744,6 +747,7 @@ def create(self, validated_data): validated_data["operational_update_number"] = 1 # if no any dref operational update created so far validated_data["dref_allocated_so_far"] = dref.amount_requested validated_data["event_description"] = dref.event_description + validated_data["anticipatory_actions"] = dref.anticipatory_actions validated_data["event_scope"] = dref.event_scope validated_data["budget_file"] = dref.budget_file validated_data["country"] = dref.country @@ -769,6 +773,7 @@ def create(self, validated_data): validated_data["date_of_approval"] = dref.date_of_approval validated_data["identified_gaps"] = dref.identified_gaps validated_data["is_man_made_event"] = dref.is_man_made_event + validated_data["event_text"] = dref.event_text validated_data["did_national_society"] = dref.did_national_society operational_update = super().create(validated_data) @@ -857,6 +862,7 @@ def create(self, validated_data): validated_data["new_operational_start_date"] = dref_operational_update.dref.date_of_approval validated_data["dref_allocated_so_far"] = dref_operational_update.total_dref_allocation validated_data["event_description"] = dref_operational_update.event_description + validated_data["anticipatory_actions"] = dref_operational_update.anticipatory_actions validated_data["event_scope"] = dref_operational_update.event_scope validated_data["budget_file"] = dref_operational_update.budget_file validated_data["assessment_report"] = dref_operational_update.assessment_report @@ -885,6 +891,7 @@ def create(self, validated_data): validated_data["date_of_approval"] = dref_operational_update.date_of_approval validated_data["identified_gaps"] = dref_operational_update.identified_gaps validated_data["is_man_made_event"] = dref_operational_update.is_man_made_event + validated_data["event_text"] = dref_operational_update.event_text validated_data["did_national_society"] = dref_operational_update.did_national_society operational_update = super().create(validated_data) # XXX: Copy files from DREF (Only nested serialized fields) @@ -1064,6 +1071,7 @@ def create(self, validated_data): validated_data["created_by"] = self.context["request"].user validated_data["operation_start_date"] = dref_operational_update.dref.date_of_approval validated_data["event_description"] = dref_operational_update.event_description + validated_data["anticipatory_actions"] = dref_operational_update.anticipatory_actions validated_data["event_scope"] = dref_operational_update.event_scope validated_data["country"] = dref_operational_update.country validated_data["risk_security_concern"] = dref_operational_update.risk_security_concern @@ -1076,6 +1084,7 @@ def create(self, validated_data): ) validated_data["event_date"] = dref_operational_update.event_date validated_data["people_in_need"] = dref_operational_update.people_in_need + validated_data["event_text"] = dref_operational_update.event_text validated_data["ns_respond_date"] = dref_operational_update.ns_respond_date validated_data["assessment_report"] = dref_operational_update.assessment_report