Skip to content

Conversation

@estyxx
Copy link
Member

@estyxx estyxx commented Jun 7, 2025

  • Add flexible grant reimbursement categories
  • Add django model and migration for grant reimbursement
  • Add Django command to backfill grant reimbursements
  • Display reimbursement amounts in grants admin

What

ToDo

@estyxx estyxx self-assigned this Jun 7, 2025
@vercel
Copy link

vercel bot commented Jun 7, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Updated (UTC)
pycon Ready Ready Preview Nov 22, 2025 5:08pm

@codecov
Copy link

codecov bot commented Jun 7, 2025

Codecov Report

❌ Patch coverage is 68.51852% with 17 lines in your changes missing coverage. Please review.
✅ Project coverage is 92.71%. Comparing base (6686fae) to head (7c8820c).
⚠️ Report is 8 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4420      +/-   ##
==========================================
- Coverage   94.53%   92.71%   -1.82%     
==========================================
  Files         352      352              
  Lines       10131    10123       -8     
  Branches      733      725       -8     
==========================================
- Hits         9577     9386     -191     
- Misses        461      645     +184     
+ Partials       93       92       -1     
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Remove hardcoded default grant amounts for ticket, accommodation, and travel
from `Conference` in favor of using `GrantReimbursementCategory`. Update
all relevant admin forms, models, and templates to reference flexible
categories instead of fixed fields.

- Remove legacy fields: `grants_default_ticket_amount`,
  `grants_default_accommodation_amount`, `grants_default_travel_from_italy_amount`,
  and `grants_default_travel_from_europe_amount` from `Conference`
- Update `Grant` and `GrantReimbursement` logic to work exclusively with
  `GrantReimbursementCategory`
- Refactor grant review admin and summary logic to support multiple,
  configurable reimbursement categories per grant
- Migrate existing grants to new reimbursement category scheme
- Add and update tests and migrations to cover flexible grant categories

This change allows flexible reimbursement types (and amounts) to be
configured per conference, supports granular grant allocation, and
paves the way for internationalization and more complex business rules.
@estyxx
Copy link
Member Author

estyxx commented Nov 24, 2025

@copilot

Copy link

Copilot AI commented Nov 24, 2025

@estyxx I've opened a new pull request, #4498, to work on those changes. Once the pull request is ready, I'll request review from you.

@estyxx estyxx requested a review from Copilot November 24, 2025 12:07
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors the grant reimbursement system from a fixed set of approved types to a flexible category-based approach. The changes enable conference organizers to define custom reimbursement categories (e.g., Travel, Ticket, Accommodation) with individual maximum amounts, replacing the previous hardcoded approved_type field.

Key changes:

  • Introduced GrantReimbursementCategory and GrantReimbursement models for flexible grant management
  • Migrated existing grant data from the old approved_type system to the new category-based system
  • Updated admin interfaces to display and manage reimbursements through the new models

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
backend/grants/models.py Added new models for reimbursement categories and reimbursements; removed deprecated fields and calculation logic
backend/grants/admin.py Added admin interfaces for new models and updated grant display to show reimbursement details
backend/reviews/admin.py Updated grant review workflow to handle multiple reimbursement categories instead of single approved type
backend/reviews/templates/grants-recap.html Changed UI from radio buttons to checkboxes for selecting multiple reimbursement categories
backend/grants/summary.py Refactored financial aggregation to sum from reimbursements instead of grant amounts
backend/grants/migrations/0030_remove_grant_accommodation_amount_and_more.py Migration to create new models and backfill existing data
backend/conferences/migrations/0055_remove_conference_grants_default_accommodation_amount_and_more.py Migration to remove deprecated conference-level grant amount fields
backend/conferences/models/conference.py Removed deprecated grant default amount fields
backend/conferences/admin/conference.py Removed deprecated grant configuration fieldset from admin
backend/grants/tests/test_models.py Updated tests to use new reimbursement system
backend/grants/tests/test_migration_backfill_grant_reimbursements.py Added comprehensive migration tests
backend/reviews/tests/test_admin.py Added tests for grant review workflow with new reimbursement system

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 156 to 172
"""
Aggregates financial data (total amounts) by grant status.
"""
financial_data = filtered_grants.values("pending_status").annotate(
total_amount_sum=Sum("total_amount")
)
financial_summary = {status[0]: 0 for status in statuses}
overall_total = 0

for data in financial_data:
pending_status = data["pending_status"]
total_amount = data["total_amount_sum"] or 0
financial_summary[pending_status] += total_amount
if pending_status in self.BUDGET_STATUSES:
overall_total += total_amount
for status in statuses:
grants_for_status = filtered_grants.filter(pending_status=status[0])
reimbursements = GrantReimbursement.objects.filter(
grant__in=grants_for_status
)
total = reimbursements.aggregate(total=Sum("granted_amount"))["total"] or 0
financial_summary[status[0]] = total
if status[0] in self.BUDGET_STATUSES:
overall_total += total

return financial_summary, overall_total
Copy link

Copilot AI Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This unused function should be removed since it has been replaced by _aggregate_financial_data_by_status_new (which should be renamed to take its place). Having both functions could cause confusion about which one is actually being used.

Copilot uses AI. Check for mistakes.

@admin.display(description="Status")
def current_or_pending_status(self, obj):
return obj.current_or_pending_status
Copy link

Copilot AI Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Missing blank line after the method definition. There should be a blank line before the next method definition for consistency with Python style guidelines.

Copilot uses AI. Check for mistakes.
return ""
@admin.display(description="Total")
def total_amount_display(self, obj):
return f"{obj.total_allocated:.2f}"
Copy link

Copilot AI Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The property name is total_allocated_amount (line 271 in models.py) but this code references obj.total_allocated which is the annotation added in the queryset. This should reference obj.total_allocated_amount to be consistent with the model property, or the comment should clarify this relies on the queryset annotation.

Copilot uses AI. Check for mistakes.
"name": "Ticket",
"description": "Conference ticket",
"max_amount": conference.grants_default_ticket_amount
or Decimal("0.00"),
Copy link

Copilot AI Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing import for Decimal. The migration uses Decimal on lines 20, 31, and 42 but doesn't import it from the decimal module.

Copilot uses AI. Check for mistakes.
},
),
# Backfill existing grants
migrations.RunPython(
Copy link

Copilot AI Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The migrate_grants function should be called before ensure_categories_exist to ensure categories exist before attempting to create reimbursements. Add a RunPython operation for ensure_categories_exist before this one.

Suggested change
migrations.RunPython(
migrations.RunPython(
code=ensure_categories_exist,
),
migrations.RunPython(

Copilot uses AI. Check for mistakes.
# TODO: move the amount calculation in a separate function maybe?
grant.save(update_fields=["pending_status", "approved_type"])
grant.save(update_fields=["pending_status",])
approved_reimbursement_categories = approved_reimbursement_categories_decisions.get(grant.id, "")
Copy link

Copilot AI Nov 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Default value should be an empty list [] instead of an empty string "" to match the expected type. This is used in a for loop on line 318, and iterating over a string would produce unexpected behavior.

Suggested change
approved_reimbursement_categories = approved_reimbursement_categories_decisions.get(grant.id, "")
approved_reimbursement_categories = approved_reimbursement_categories_decisions.get(grant.id, [])

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants