Skip to content

Commit 2af1983

Browse files
committed
Avoid logging pending_status change when is not changed
1 parent ae42d15 commit 2af1983

2 files changed

Lines changed: 90 additions & 17 deletions

File tree

backend/reviews/admin.py

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -296,16 +296,23 @@ def _review_grants_recap_view(self, request, review_session):
296296
review_session.conference.grants.filter(id__in=decisions.keys()).all()
297297
)
298298

299+
grants_with_pending_status_changes = {}
299300
for grant in grants:
300301
decision = decisions[grant.id]
301302
if decision not in Grant.REVIEW_SESSION_STATUSES_OPTIONS:
302303
continue
303304

305+
original_pending_status = grant.pending_status
304306
if decision != grant.status:
305307
grant.pending_status = decision
306308
elif decision == grant.status:
307309
grant.pending_status = None
308310

311+
if grant.pending_status != original_pending_status:
312+
grants_with_pending_status_changes[grant.id] = (
313+
original_pending_status
314+
)
315+
309316
# if there are grant reimbursements and the decision is not approved, delete them all
310317
if grant.reimbursements.exists():
311318
approved_reimbursement_categories = (
@@ -343,11 +350,15 @@ def _review_grants_recap_view(self, request, review_session):
343350
"pending_status",
344351
]
345352
)
346-
create_change_admin_log_entry(
347-
request.user,
348-
grant,
349-
change_message=f"[Review Session] Grant status updated: pending_status changed from '{grant.status}' to '{grant.pending_status}'.",
350-
)
353+
if grant.id in grants_with_pending_status_changes:
354+
original_pending_status = grants_with_pending_status_changes[
355+
grant.id
356+
]
357+
create_change_admin_log_entry(
358+
request.user,
359+
grant,
360+
change_message=f"[Review Session] Grant status updated: pending_status changed from '{original_pending_status}' to '{grant.pending_status}'.",
361+
)
351362

352363
# The frontend may send reimbursement categories as checked by default,
353364
# so they're always passed to the backend. However, if the grant is not approved,
@@ -381,12 +392,6 @@ def _review_grants_recap_view(self, request, review_session):
381392
grant,
382393
change_message=f"[Review Session] Reimbursement {reimbursement.category.name} added.",
383394
)
384-
else:
385-
create_change_admin_log_entry(
386-
request.user,
387-
grant,
388-
change_message=f"[Review Session] Reimbursement {reimbursement.category.name} updated.",
389-
)
390395

391396
messages.success(
392397
request, "Decisions saved. Check the Grants Summary for more info."

backend/reviews/tests/test_admin.py

Lines changed: 74 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ def test_save_review_grants_updates_grant_and_creates_reimbursements(rf, mocker)
375375
assert LogEntry.objects.filter(
376376
user=user,
377377
object_id__in=[str(grant_1.id), str(grant_2.id)],
378-
change_message=f"[Review Session] Grant status updated: pending_status changed from '{Grant.Status.pending}' to '{Grant.Status.approved}'.",
378+
change_message="[Review Session] Grant status updated: pending_status changed from 'None' to 'approved'.",
379379
).exists()
380380
assert LogEntry.objects.filter(
381381
user=user,
@@ -557,21 +557,24 @@ def test_save_review_grants_modify_reimbursements(rf, mocker):
557557
reimbursement.category for reimbursement in grant_1.reimbursements.all()
558558
} == {ticket_category}
559559

560-
assert LogEntry.objects.count() == 3
560+
# Verify log entries were created
561+
assert LogEntry.objects.count() == 2
561562
assert LogEntry.objects.filter(
562563
user=user,
563564
object_id=grant_1.id,
564-
change_message="[Review Session] Grant status updated: pending_status changed from 'approved' to 'None'.",
565+
change_message=f"[Review Session] Reimbursement removed: {travel_category.name}",
565566
).exists()
566567
assert LogEntry.objects.filter(
567568
user=user,
568569
object_id=grant_1.id,
569-
change_message=f"[Review Session] Reimbursement removed: {travel_category.name}",
570+
change_message=f"[Review Session] Reimbursement removed: {accommodation_category.name}",
570571
).exists()
571-
assert LogEntry.objects.filter(
572+
573+
# pending_status change should not be logged because the grant status is not changed
574+
assert not LogEntry.objects.filter(
572575
user=user,
573576
object_id=grant_1.id,
574-
change_message=f"[Review Session] Reimbursement removed: {accommodation_category.name}",
577+
change_message="[Review Session] Grant status updated: pending_status changed from 'approved' to 'None'.",
575578
).exists()
576579

577580

@@ -657,3 +660,68 @@ def test_save_review_grants_waiting_list_does_not_create_reimbursments(rf, mocke
657660
LogEntry.objects.filter(object_id=grant_2.id).count() == 1
658661
) # 1 pending_status change, 3 reimbursement additions
659662
mock_messages.success.assert_called_once()
663+
664+
665+
def test_save_review_grants_two_times_does_not_create_duplicate_log_entries(rf, mocker):
666+
mocker.patch("reviews.admin.messages")
667+
668+
user = UserFactory(is_staff=True, is_superuser=True)
669+
conference = ConferenceFactory()
670+
671+
# Create reimbursement categories
672+
travel_category = GrantReimbursementCategoryFactory(
673+
conference=conference,
674+
travel=True,
675+
max_amount=Decimal("500"),
676+
)
677+
ticket_category = GrantReimbursementCategoryFactory(
678+
conference=conference,
679+
ticket=True,
680+
max_amount=Decimal("100"),
681+
)
682+
accommodation_category = GrantReimbursementCategoryFactory(
683+
conference=conference,
684+
accommodation=True,
685+
max_amount=Decimal("200"),
686+
)
687+
688+
# Create review session for grants
689+
review_session = ReviewSessionFactory(
690+
conference=conference,
691+
session_type=ReviewSession.SessionType.GRANTS,
692+
status=ReviewSession.Status.COMPLETED,
693+
)
694+
AvailableScoreOptionFactory(review_session=review_session, numeric_value=0)
695+
AvailableScoreOptionFactory(review_session=review_session, numeric_value=1)
696+
697+
grant_1 = GrantFactory(conference=conference, status=Grant.Status.pending)
698+
post_data = {
699+
f"decision-{grant_1.id}": Grant.Status.approved,
700+
f"reimbursementcategory-{grant_1.id}": [
701+
str(ticket_category.id),
702+
str(travel_category.id),
703+
str(accommodation_category.id),
704+
],
705+
}
706+
request = rf.post("/", data=post_data)
707+
request.user = user
708+
709+
admin = ReviewSessionAdmin(ReviewSession, AdminSite())
710+
admin._review_grants_recap_view(request, review_session) # First save
711+
admin._review_grants_recap_view(request, review_session) # Second save
712+
713+
grant_1.refresh_from_db()
714+
715+
assert grant_1.reimbursements.count() == 3
716+
assert {
717+
reimbursement.category for reimbursement in grant_1.reimbursements.all()
718+
} == {ticket_category, travel_category, accommodation_category}
719+
720+
for e in LogEntry.objects.all():
721+
print(e.change_message)
722+
assert LogEntry.objects.count() == 4
723+
assert LogEntry.objects.filter(
724+
user=user,
725+
object_id=grant_1.id,
726+
change_message="[Review Session] Grant status updated: pending_status changed from 'None' to 'approved'.",
727+
).exists()

0 commit comments

Comments
 (0)