You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Followup to the event-registration transfer work (#1944 / PR #2044). Start as a new branch off main after #2044 merges — not part of #2044.
Context
A transferred-in registration's registrant-facing ticket/callout pages don't correctly surface or service the money/scholarship that live on the source reg. The read-side "amount due" already delegates to the source; the gaps are the payment ledger, scholarship servicing, and a pay-flow that misfiles a payment onto the transferred-in reg without clearing the delegated balance.
Scholarship decline flow with agreement status and history #2178 (scholarship decline flow) is now merged and reworked the scholarship agreement into a tri-state agreement_response_status (pending/accepted/declined) + ScholarshipAgreementResponse history. Part 2 (scholarship servicing) must be built against that new model, not the old agreement_signed_at boolean.
The governing rule
Delegation to the source is conditional on the source actually having allocations/payments.
Source has payments → the financial record is anchored on the source. Show the source's ledger + delegated balance on the new ticket; to pay a remaining balance, send the registrant to the source reg's ticket (pay there, allocations stay on source). Never let a payment land on the transferred-in reg in this case.
Source has no payments → the math should all be on the new reg. The new reg owns its own cost/balance/allocations; the registrant pays on the new reg normally (no delegation). This also removes the misfiling risk.
Implementation seam: gate the existing transferred_in? delegation in EventRegistration (remaining_cost, paid_in_full?, payment_received?, payment_access_granted?, invoice_available?, etc.) on transferred_from_registration.allocations.exists? (or payments_sum.positive?). Add a predicate like source_holds_financials? = transferred_in? && source.allocations.exists? and key the delegations + the pay routing off it. Verify the invoice/receipt from_registration swap (app/presenters/event_invoice.rb, event_receipt.rb) respects the same condition.
Keep this reg's own allocations rendering as-is (the existing @allocations list).
If transferred-in AND the source has allocations, add a separate section below — "Payments on your original registration" — rendering source.allocations. Reuse the figures the admin summary already computes in app/views/event_registrations/_transferred_in_financials.html.erb (source.event.cost_cents, source.allocations_sum/payments_sum, due).
"Amount due" already correct via delegated remaining_cost — leave it, but it now follows the conditional-delegation rule.
Part 2 — Scholarship servicing
Let the registrant view + respond to the source's scholarship from the new ticket, showing the old reg's scholarship record.
scholarship action gate + @scholarship: resolve via the chain — EventRegistration#effective_scholarship (scholarships.first || transferred_from_registration&.effective_scholarship) instead of raw @event_registration.scholarships.first. Relax the gate so a transferred-in reg whose source has a scholarship isn't redirected away.
scholarship_status_card builder (app/services/builtin_callout_cards.rb): use the effective scholarship for the card's gate + data.
Task completion stays admin-only (display only).
The scholarship view's admin "Edit scholarship" link should point at the source's scholarship record.
Part 3 — Pay-flow correctness
pay action + redirect_to_stripe_checkout (Events::RegistrationsController) and the webhook allocation (pay_charge_extensions.rb): when source_holds_financials?, route the checkout/allocation to the source reg (metadata event_registration_id = source), so paying clears the delegated balance. When the source holds no financials, the transferred-in reg pays itself (correct once remaining_cost no longer delegates in that case).
On the ticket/payment page, the pay button for a transferred-in reg with a source balance should link to the source's payment/ticket rather than posting to its own pay path.
Per-builtin (no change needed)
ce_hours — correct (hours ride on the new reg's own record).
certificate — correct (earned at the intended/new event).
Model specs for conditional delegation: transferred-in with source payments → delegates; with no source payments → own math.
Request specs: payment page shows the source-allocations section only when transferred-in + source has allocations; scholarship page renders + services the source's scholarship from the new slug; pay routing targets the correct reg.
ai/test_extra before opening the (draft) PR.
🤖 Filed by Claude for maebeale — followup to #1944.
Followup to the event-registration transfer work (#1944 / PR #2044). Start as a new branch off
mainafter #2044 merges — not part of #2044.Context
A transferred-in registration's registrant-facing ticket/callout pages don't correctly surface or service the money/scholarship that live on the source reg. The read-side "amount due" already delegates to the source; the gaps are the payment ledger, scholarship servicing, and a pay-flow that misfiles a payment onto the transferred-in reg without clearing the delegated balance.
The governing rule
Delegation to the source is conditional on the source actually having allocations/payments.
Implementation seam: gate the existing
transferred_in?delegation inEventRegistration(remaining_cost,paid_in_full?,payment_received?,payment_access_granted?,invoice_available?, etc.) ontransferred_from_registration.allocations.exists?(orpayments_sum.positive?). Add a predicate likesource_holds_financials?=transferred_in? && source.allocations.exists?and key the delegations + the pay routing off it. Verify the invoice/receiptfrom_registrationswap (app/presenters/event_invoice.rb,event_receipt.rb) respects the same condition.Part 1 — Payment ledger
app/views/events/callouts/payment.html.erb(+paymentaction,Events::CalloutsController):@allocationslist).source.allocations. Reuse the figures the admin summary already computes inapp/views/event_registrations/_transferred_in_financials.html.erb(source.event.cost_cents,source.allocations_sum/payments_sum, due).remaining_cost— leave it, but it now follows the conditional-delegation rule.Part 2 — Scholarship servicing
Let the registrant view + respond to the source's scholarship from the new ticket, showing the old reg's scholarship record.
scholarshipaction gate +@scholarship: resolve via the chain —EventRegistration#effective_scholarship(scholarships.first || transferred_from_registration&.effective_scholarship) instead of raw@event_registration.scholarships.first. Relax the gate so a transferred-in reg whose source has a scholarship isn't redirected away.sign_agreement(and the new accept/decline flow from Scholarship decline flow with agreement status and history #2178): operate on the source's Scholarship record (same person).scholarship_status_cardbuilder (app/services/builtin_callout_cards.rb): use the effective scholarship for the card's gate + data.Part 3 — Pay-flow correctness
payaction +redirect_to_stripe_checkout(Events::RegistrationsController) and the webhook allocation (pay_charge_extensions.rb): whensource_holds_financials?, route the checkout/allocation to the source reg (metadataevent_registration_id= source), so paying clears the delegated balance. When the source holds no financials, the transferred-in reg pays itself (correct onceremaining_costno longer delegates in that case).Per-builtin (no change needed)
Verification
ai/test_extrabefore opening the (draft) PR.🤖 Filed by Claude for maebeale — followup to #1944.