Wire tournament checkout URLs into blast query for per-player payment links #463
Labels
No labels
domain:backend
domain:devops
domain:frontend
status:approved
status:in-progress
status:needs-fix
status:qa
type:bug
type:devops
type:feature
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
forgejo_admin/basketball-api#463
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Type
Feature
Lineage
Discovered during Utah Invitational blast prep (2026-04-12). #456 (blast system) and #457 (tournament checkout) were built as independent features. The blast query returns
checkout_url: ""because it has no access to Stripe session data. This ticket is the integration glue.Repo
forgejo_admin/basketball-apiUser Story
As an admin
I want tournament fee emails to include each player's unique Stripe payment link
So that parents can pay directly from the email without any manual URL distribution
Context
The blast endpoint (
POST /admin/email/blast) resolves{{checkout_url}}per recipient, but thetournament_committedquery inemail_queries.pyreturnscheckout_url: ""with a comment "populated by body.data override." Problem:body.datais shared across ALL recipients — it can't provide per-player URLs. The Stripe checkout sessions were created (21 sessions for Utah Invitational) and Order records exist withstatus=pending, but the Stripe session URL is not stored on the Order. The query needs to join through Tournament → TournamentProduct → Product → Order to resolve checkout URLs per player.File Targets
Files the agent should modify or create:
src/basketball_api/models.py— Addstripe_checkout_urlcolumn (VARCHAR 500, nullable) to Order model.alembic/versions/NNN_add_stripe_checkout_url_to_orders.py— NEW. Determine next migration slot from remote main HEAD (currently 046). Add column.src/basketball_api/services/email_queries.py— Updatequery_tournament_committed(): accepttournament_idinquery_params, join Order table to find pending tournament orders per player, populatecheckout_urlfromOrder.stripe_checkout_url. Fall back to empty string if no order exists.src/basketball_api/routes/admin.py— Update tournament checkout-links endpoint (POST /admin/tournaments/{id}/checkout-links): savesession.urltoOrder.stripe_checkout_urlwhen creating the Stripe session.src/basketball_api/routes/checkout.py— Updatecreate_player_checkout_session()helper: savesession.urlto the Order record.Files the agent should NOT touch:
build_action_email()— email builder is fineAcceptance Criteria
Order.stripe_checkout_urlis populated when checkout links are generated viaPOST /admin/tournaments/{id}/checkout-linkstournament_committedquery acceptstournament_idinquery_paramsand returns per-playercheckout_urlfrom Order recordstest_email→ email contains unique Stripe URL for the test playercheckout_url: ""(graceful fallback, not error)Test Expectations
pytest tests/ -k "tournament"Constraints
Checklist
Related
project-westside-basketball— parent projectstory:WS-S33— user story (tournament billing)sop-email-send— blast gate for actual sendsScope Review: READY
Review note:
review-998-2026-04-12All template sections present, all 5 file targets verified against live codebase, upstream dependencies (#456, #457) both merged. Story WS-S33 confirmed in project-westside-basketball user-stories section.
[SCOPE] recommendations (non-blocking):
arch-emailfor the email subsystemarch-checkoutfor the checkout/payment subsystemThese are documentation debts already tracked by board items #990 and #991. The ticket itself is well-scoped and ready for dispatch.