Skip to content

Commit f8a87d3

Browse files
Fix grant pending status sync issue (#4431)
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com> Co-authored-by: Marco Acierno <[email protected]>
1 parent 000670b commit f8a87d3

File tree

8 files changed

+84
-24
lines changed

8 files changed

+84
-24
lines changed

backend/custom_admin/admin.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,13 @@ def wrapper(modeladmin, request, queryset):
6060
def confirm_pending_status(modeladmin, request, queryset):
6161
queryset.update(
6262
status=F("pending_status"),
63+
pending_status=None,
6364
)
6465

6566

6667
@admin.action(description="Reset pending status to status")
6768
@validate_single_conference_selection
6869
def reset_pending_status_back_to_status(modeladmin, request, queryset):
6970
queryset.update(
70-
pending_status=F("status"),
71+
pending_status=None,
7172
)

backend/grants/admin.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -652,8 +652,8 @@ def get_queryset(self, request):
652652
return (
653653
super()
654654
.get_queryset(request)
655-
.exclude(
656-
pending_status=F("status"),
655+
.filter(
656+
pending_status__isnull=False,
657657
)
658658
)
659659

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 5.1.4 on 2025-07-27 14:16
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('grants', '0028_remove_grant_pretix_voucher_id_and_more'),
10+
]
11+
12+
operations = [
13+
migrations.AlterField(
14+
model_name='grant',
15+
name='pending_status',
16+
field=models.CharField(blank=True, choices=[('pending', 'Pending'), ('rejected', 'Rejected'), ('approved', 'Approved'), ('waiting_list', 'Waiting List'), ('waiting_list_maybe', 'Waiting List, Maybe'), ('waiting_for_confirmation', 'Waiting for confirmation'), ('refused', 'Refused'), ('confirmed', 'Confirmed'), ('did_not_attend', 'Did Not Attend')], max_length=30, null=True, verbose_name='pending status'),
17+
),
18+
]

backend/grants/models.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ class ApprovedType(models.TextChoices):
149149
_("pending status"),
150150
choices=Status.choices,
151151
max_length=30,
152-
default=Status.pending,
152+
null=True,
153153
blank=True,
154154
)
155155
approved_type = models.CharField(
@@ -229,9 +229,6 @@ def save(self, *args, **kwargs):
229229
self._update_country_type()
230230
self._calculate_grant_amounts()
231231

232-
if self.pending_status == self._original_status:
233-
self.pending_status = self.status
234-
235232
update_fields = kwargs.get("update_fields", None)
236233
if update_fields:
237234
update_fields.append("total_amount")
@@ -249,7 +246,7 @@ def save(self, *args, **kwargs):
249246
self._original_status = self.status
250247

251248
def _calculate_grant_amounts(self):
252-
if self.pending_status != Grant.Status.approved:
249+
if self.current_or_pending_status != Grant.Status.approved:
253250
return
254251

255252
if (
@@ -332,6 +329,10 @@ def has_approved_accommodation(self):
332329
or self.approved_type == Grant.ApprovedType.ticket_travel_accommodation
333330
)
334331

332+
@property
333+
def current_or_pending_status(self):
334+
return self.pending_status or self.status
335+
335336

336337
class GrantConfirmPendingStatusProxy(Grant):
337338
class Meta:

backend/grants/tests/test_admin.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,11 @@ def test_confirm_pending_status_action(rf):
485485
assert grant_1.status == Grant.Status.confirmed
486486
assert grant_2.status == Grant.Status.waiting_list
487487
assert grant_3.status == Grant.Status.waiting_list_maybe
488+
489+
assert grant_1.pending_status is None
490+
assert grant_2.pending_status is None
491+
assert grant_3.pending_status is None
492+
488493
# Left out from the action
489494
assert grant_4.status == Grant.Status.waiting_list_maybe
490495

@@ -524,13 +529,13 @@ def test_reset_pending_status_back_to_status_action(rf):
524529
grant_4.refresh_from_db()
525530

526531
assert grant_1.status == Grant.Status.pending
527-
assert grant_1.pending_status == Grant.Status.pending
532+
assert grant_1.pending_status is None
528533

529534
assert grant_2.status == Grant.Status.rejected
530-
assert grant_2.pending_status == Grant.Status.rejected
535+
assert grant_2.pending_status is None
531536

532537
assert grant_3.status == Grant.Status.waiting_list
533-
assert grant_3.pending_status == Grant.Status.waiting_list
538+
assert grant_3.pending_status is None
534539

535540
# Left out from the action
536541
assert grant_4.status == Grant.Status.waiting_list_maybe

backend/grants/tests/test_models.py

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ def test_sets_country_type_does_nothing_if_unset():
162162
assert grant.country_type is None
163163

164164

165-
def test_syncs_pending_status_on_change():
165+
def test_pending_status_no_longer_syncs_with_status():
166166
grant = GrantFactory(
167167
pending_status=Grant.Status.pending,
168168
status=Grant.Status.pending,
@@ -171,10 +171,10 @@ def test_syncs_pending_status_on_change():
171171
grant.status = Grant.Status.approved
172172
grant.save(update_fields=["status"])
173173

174-
# Pending status should be updated to match the status
174+
# Pending status should remain unchanged when status changes
175175
grant.refresh_from_db()
176176

177-
assert grant.pending_status == Grant.Status.approved
177+
assert grant.pending_status == Grant.Status.pending # Should remain unchanged
178178
assert grant.status == Grant.Status.approved
179179

180180

@@ -192,3 +192,34 @@ def test_doesnt_sync_pending_status_if_different_values():
192192

193193
assert grant.pending_status == Grant.Status.refused
194194
assert grant.status == Grant.Status.waiting_for_confirmation
195+
196+
197+
def test_pending_status_none_means_no_pending_change():
198+
grant = GrantFactory(
199+
pending_status=None,
200+
status=Grant.Status.approved,
201+
)
202+
203+
# When pending_status is None, the effective status should be the current status
204+
# This affects the _calculate_grant_amounts method
205+
grant.approved_type = Grant.ApprovedType.ticket_only
206+
grant.departure_country = "IT"
207+
grant.save()
208+
209+
# Since effective status is approved (from status field), amounts should be calculated
210+
assert grant.ticket_amount is not None
211+
212+
213+
def test_pending_status_set_overrides_current_status():
214+
grant = GrantFactory(
215+
pending_status=Grant.Status.approved,
216+
status=Grant.Status.pending,
217+
)
218+
219+
# When pending_status is set, it should be used as the effective status
220+
grant.approved_type = Grant.ApprovedType.ticket_only
221+
grant.departure_country = "IT"
222+
grant.save()
223+
224+
# Since effective status is approved (from pending_status), amounts should be calculated
225+
assert grant.ticket_amount is not None

backend/reviews/admin.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ def go_to_review_screen(self, obj):
160160

161161
return mark_safe(
162162
f"""
163-
<a href="{reverse('admin:reviews-start', kwargs={'review_session_id': obj.id})}">
163+
<a href="{reverse("admin:reviews-start", kwargs={"review_session_id": obj.id})}">
164164
Go to review screen
165165
</a>
166166
"""
@@ -176,7 +176,7 @@ def go_to_recap_screen(self, obj):
176176

177177
return mark_safe(
178178
f"""
179-
<a href="{reverse('admin:reviews-recap', kwargs={'review_session_id': obj.id})}">
179+
<a href="{reverse("admin:reviews-recap", kwargs={"review_session_id": obj.id})}">
180180
Go to recap screen
181181
</a>
182182
"""
@@ -282,7 +282,11 @@ def _review_grants_recap_view(self, request, review_session):
282282

283283
approved_type = approved_type_decisions.get(grant.id, "")
284284

285-
grant.pending_status = decision
285+
if decision != grant.status:
286+
grant.pending_status = decision
287+
elif decision == grant.status:
288+
grant.pending_status = None
289+
286290
grant.approved_type = (
287291
approved_type if decision == Grant.Status.approved else None
288292
)
@@ -736,7 +740,7 @@ def _render_proposal_review(
736740
seen=request.GET.get("seen", "").split(","),
737741
existing_comment=existing_comment,
738742
review_session_repr=str(review_session),
739-
title=f'Proposal Review: {proposal.title.localize("en")}',
743+
title=f"Proposal Review: {proposal.title.localize('en')}",
740744
)
741745
return TemplateResponse(request, "proposal-review.html", context)
742746

backend/reviews/templates/grants-recap.html

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@
254254
updateBottomBarUI();
255255
});
256256

257-
waitinglistInput.addEventListener("change", () => {
257+
waitinglistmaybeInput.addEventListener("change", () => {
258258
grantData.status = "waiting_list_maybe";
259259
updateBottomBarUI();
260260
});
@@ -469,13 +469,13 @@ <h3>
469469
<script>
470470
grantsById[{{item.id}}] = {
471471
id: {{item.id}},
472-
status: "{{ item.pending_status }}",
473-
originalStatus: "{{ item.pending_status }}",
472+
status: "{{ item.current_or_pending_status }}",
473+
originalStatus: "{{ item.current_or_pending_status }}",
474474
numOfVotes: {{item.userreview_set.count}},
475475
};
476476
</script>
477477
<tr
478-
data-original-status="{{ item.pending_status }}"
478+
data-original-status="{{ item.current_or_pending_status }}"
479479
data-original-approved-type="{{ item.approved_type }}"
480480
class="grant-item"
481481
id="grant-{{ item.id }}"
@@ -612,7 +612,7 @@ <h3>
612612
{% for status in all_review_statuses %}
613613
<li>
614614
<label>
615-
<input {% if item.pending_status == status.0 %}checked{% endif %}
615+
<input {% if item.current_or_pending_status == status.0 %}checked{% endif %}
616616
type="radio"
617617
class="status-decision-radio"
618618
name="decision-{{item.id}}"
@@ -641,7 +641,7 @@ <h3>
641641
{% if perms.reviews.decision_reviewsession %}
642642
<ul
643643
data-item-id="{{ item.id }}"
644-
class="approved-type-choices {% if item.pending_status != 'approved' %}hidden{% endif %}"
644+
class="approved-type-choices {% if item.current_or_pending_status != 'approved' %}hidden{% endif %}"
645645
>
646646
{% for approved_type in all_approved_types %}
647647
<li>

0 commit comments

Comments
 (0)