Skip to content

Commit 8489043

Browse files
committed
DREF3 enhancement – is_latest_stage
1 parent 30257d8 commit 8489043

File tree

3 files changed

+76
-4
lines changed

3 files changed

+76
-4
lines changed

dref/serializers.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1712,6 +1712,7 @@ class BaseDref3Serializer(serializers.ModelSerializer):
17121712
sector_national_society_strengthening_budget = serializers.SerializerMethodField()
17131713
sector_national_society_strengthening_people_targeted = serializers.SerializerMethodField()
17141714
public = serializers.SerializerMethodField(read_only=True)
1715+
is_latest_stage = serializers.SerializerMethodField(read_only=True)
17151716
status = serializers.IntegerField(read_only=True)
17161717
status_display = serializers.CharField(source="get_status_display", read_only=True)
17171718
approved = serializers.SerializerMethodField()
@@ -1723,6 +1724,9 @@ class BaseDref3Serializer(serializers.ModelSerializer):
17231724
def get_public(self, obj):
17241725
return self.context.get("public")
17251726

1727+
def get_is_latest_stage(self, obj):
1728+
return self.context.get("is_latest_stage")
1729+
17261730
def get_stage(self, obj):
17271731
return self.context.get("stage")
17281732

@@ -2105,6 +2109,7 @@ class Meta:
21052109
"sector_national_society_strengthening_budget",
21062110
"sector_national_society_strengthening_people_targeted",
21072111
"public",
2112+
"is_latest_stage",
21082113
"status",
21092114
"status_display",
21102115
"approved",

dref/test_dref3_filters.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,3 +204,46 @@ def test_status_display_labels(self):
204204
appeal_a_statuses = {r["status_display"] for r in rows if r["appeal_id"] == "APPEAL_A"}
205205
# Expected labels
206206
assert {"Approved", "Finalized", "Draft"}.issubset(appeal_a_statuses)
207+
208+
def test_is_latest_stage_flag_progression(self):
209+
"""Verify is_latest_stage shifts to the newest approved stage only."""
210+
self.authenticate(self.superuser)
211+
# Initial: all DRAFT -> no latest stage
212+
resp_initial = self.client.get(f"/api/v2/dref3/{self.dref_a.appeal_code}/")
213+
self.assertEqual(resp_initial.status_code, status.HTTP_200_OK)
214+
data_initial = resp_initial.json()
215+
assert all(not row.get("is_latest_stage") for row in data_initial)
216+
217+
# Approve application
218+
self.dref_a.status = Dref.Status.APPROVED
219+
self.dref_a.save(update_fields=["status"])
220+
resp_after_app = self.client.get(f"/api/v2/dref3/{self.dref_a.appeal_code}/")
221+
self.assertEqual(resp_after_app.status_code, status.HTTP_200_OK)
222+
data_after_app = resp_after_app.json()
223+
# Application should be latest stage
224+
latest_flags = [row.get("is_latest_stage") for row in data_after_app]
225+
assert any(latest_flags), "Expected one latest stage after application approval"
226+
app_rows = [row for row in data_after_app if row["stage"] == "Application"]
227+
assert app_rows and app_rows[0]["is_latest_stage"] is True
228+
229+
# Approve operational update -> flag moves
230+
self.op_a1.status = Dref.Status.APPROVED
231+
self.op_a1.save(update_fields=["status"])
232+
resp_after_op = self.client.get(f"/api/v2/dref3/{self.dref_a.appeal_code}/")
233+
self.assertEqual(resp_after_op.status_code, status.HTTP_200_OK)
234+
data_after_op = resp_after_op.json()
235+
app_row = [r for r in data_after_op if r["stage"] == "Application"][0]
236+
op_row = [r for r in data_after_op if r["stage"].startswith("Operational Update")][0]
237+
assert app_row["is_latest_stage"] is False
238+
assert op_row["is_latest_stage"] is True
239+
240+
# Approve final report -> flag moves again
241+
self.final_a.status = Dref.Status.APPROVED
242+
self.final_a.save(update_fields=["status"])
243+
resp_after_fr = self.client.get(f"/api/v2/dref3/{self.dref_a.appeal_code}/")
244+
self.assertEqual(resp_after_fr.status_code, status.HTTP_200_OK)
245+
data_after_fr = resp_after_fr.json()
246+
fr_row = [r for r in data_after_fr if r["stage"] == "Final Report"][0]
247+
op_row = [r for r in data_after_fr if r["stage"].startswith("Operational Update")][0]
248+
assert op_row["is_latest_stage"] is False
249+
assert fr_row["is_latest_stage"] is True

dref/views.py

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -740,9 +740,27 @@ def retrieve(self, request, *args, **kwargs):
740740
allocation_count = 1 # Dref Application is always the first allocation
741741
public = code not in self.get_nonsuperusers_excluded_codes()
742742
a = ["First", "Second", "Third", "Fourth", "Fifth", "Sixth", "Seventh", "Eighth", "Ninth", "Tenth"]
743-
for instance in instances:
743+
744+
# is_latest_stage: the last APPROVED-status instance and next instance either absent or not APPROVED
745+
latest_index = None
746+
for i, inst in enumerate(instances):
747+
if getattr(inst, "status", None) == Dref.Status.APPROVED:
748+
next_inst = instances[i + 1] if i + 1 < len(instances) else None
749+
if next_inst is None or getattr(next_inst, "status", None) != Dref.Status.APPROVED:
750+
latest_index = i
751+
# Build serialized rows with flag
752+
for i, instance in enumerate(instances):
753+
is_latest_stage = i == latest_index
744754
if isinstance(instance, Dref):
745-
serializer = Dref3Serializer(instance, context={"stage": "Application", "allocation": a[0], "public": public})
755+
serializer = Dref3Serializer(
756+
instance,
757+
context={
758+
"stage": "Application",
759+
"allocation": a[0],
760+
"public": public,
761+
"is_latest_stage": is_latest_stage,
762+
},
763+
)
746764
elif isinstance(instance, DrefOperationalUpdate):
747765
ops_update_count += 1
748766
if instance.additional_allocation and len(a) > allocation_count:
@@ -753,15 +771,21 @@ def retrieve(self, request, *args, **kwargs):
753771
serializer = DrefOperationalUpdate3Serializer(
754772
instance,
755773
context={
756-
"stage": "Operational Update " + str(ops_update_count),
774+
"stage": f"Operational Update {ops_update_count}",
757775
"allocation": allocation,
758776
"public": public,
777+
"is_latest_stage": is_latest_stage,
759778
},
760779
)
761780
elif isinstance(instance, DrefFinalReport):
762781
serializer = DrefFinalReport3Serializer(
763782
instance,
764-
context={"stage": "Final Report", "allocation": "No allocation", "public": public},
783+
context={
784+
"stage": "Final Report",
785+
"allocation": "No allocation",
786+
"public": public,
787+
"is_latest_stage": is_latest_stage,
788+
},
765789
)
766790
else:
767791
continue

0 commit comments

Comments
 (0)