diff --git a/backend/visa/models.py b/backend/visa/models.py index 7a9b00fd81..4990d9ce57 100644 --- a/backend/visa/models.py +++ b/backend/visa/models.py @@ -122,6 +122,15 @@ def grant_approved_type(self) -> str | None: return "_".join(sorted(categories)) if len(categories) > 1 else categories[0] + @property + def total_grantee_reimbursement_amount(self): + grant = self.user_grant + + if not grant: + return None + + return grant.total_grantee_reimbursement_amount + @cached_property def user_grant(self): return Grant.objects.for_conference(self.conference).of_user(self.user).first() diff --git a/backend/visa/tasks.py b/backend/visa/tasks.py index dea8e1c765..5069ed5234 100644 --- a/backend/visa/tasks.py +++ b/backend/visa/tasks.py @@ -151,6 +151,7 @@ def _render_content(content, invitation_letter_request, config): "grant_approved_type": invitation_letter_request.grant_approved_type, "has_accommodation_via_grant": invitation_letter_request.has_accommodation_via_grant(), "has_travel_via_grant": invitation_letter_request.has_travel_via_grant(), + "total_grantee_reimbursement_amount": invitation_letter_request.total_grantee_reimbursement_amount, # conference "conference": invitation_letter_request.conference, } diff --git a/backend/visa/tests/test_models.py b/backend/visa/tests/test_models.py index 53cc436df1..2204ffd981 100644 --- a/backend/visa/tests/test_models.py +++ b/backend/visa/tests/test_models.py @@ -26,6 +26,7 @@ def test_request_on_behalf_of_other(): assert request.user is None assert request.role == "Attendee" assert request.has_grant is False + assert request.total_grantee_reimbursement_amount is None # With matching user, it is found user = UserFactory(email="example@example.org") @@ -87,6 +88,13 @@ def test_request_grant_info( assert request.has_travel_via_grant() == expected_has_travel # grant_approved_type returns sorted categories joined by underscore assert request.grant_approved_type == expected_type + # total_grantee_reimbursement_amount excludes ticket + expected_amount = Decimal(0) + if "travel" in categories: + expected_amount += Decimal("500") + if "accommodation" in categories: + expected_amount += Decimal("200") + assert request.total_grantee_reimbursement_amount == expected_amount def test_role_for_speakers(): diff --git a/backend/visa/tests/test_tasks.py b/backend/visa/tests/test_tasks.py index b71313cd0d..31891119fa 100644 --- a/backend/visa/tests/test_tasks.py +++ b/backend/visa/tests/test_tasks.py @@ -187,6 +187,66 @@ def test_process_invitation_letter_request_accomodation_doc_with_no_accommodatio assert output.pages[0].extract_text() == "Thisisasampleticket pdf" +@override_settings(PRETIX_API="https://pretix/api/") +def test_process_invitation_letter_request_renders_total_grantee_reimbursement_amount( + mock_ticket_present, +): + config = InvitationLetterConferenceConfigFactory() + InvitationLetterDocumentFactory( + invitation_letter_conference_config=config, + document=None, + dynamic_document={ + "header": {"content": "header", "margin": "0", "align": "top-left"}, + "footer": {"content": "footer", "margin": "0", "align": "bottom-left"}, + "page_layout": {"margin": "0"}, + "pages": [ + { + "content": "Reimbursement: {{total_grantee_reimbursement_amount}}" + }, + ], + }, + ) + + request = InvitationLetterRequestFactory( + conference=config.conference, nationality="Italian" + ) + mock_ticket_present(request) + + grant = GrantFactory( + conference=config.conference, + user=request.requester, + ) + GrantReimbursementFactory( + grant=grant, + category__conference=config.conference, + category__ticket=True, + granted_amount=Decimal("100"), + ) + GrantReimbursementFactory( + grant=grant, + category__conference=config.conference, + category__travel=True, + granted_amount=Decimal("500"), + ) + GrantReimbursementFactory( + grant=grant, + category__conference=config.conference, + category__accommodation=True, + granted_amount=Decimal("200"), + ) + + process_invitation_letter_request(invitation_letter_request_id=request.id) + + request.refresh_from_db() + + assert request.status == InvitationLetterRequestStatus.PROCESSED + + output = PdfReader(request.invitation_letter.open()) + assert output.get_num_pages() == 2 + assert output.pages[0].extract_text() == "Reimbursement: 700 \nheader\nfooter" + assert output.pages[1].extract_text() == "Thisisasampleticket pdf" + + @override_settings(PRETIX_API="https://pretix/api/") def test_process_invitation_letter_request_with_doc_only_for_accommodation( mock_ticket_present,