Epic: #151
Proposal: proposals/bookings_engine.md (local, git-excluded). Argument: https://github.com/Davidslv/notes/issues/178
Purpose
After the hold commits, the guest is redirected to Checkout. Billing creates the Stripe Customer first, then the session, on that same request. Bookings never names a Billing class.
Scope
In scope
bin/seams bookings now requires the billing release that contains Billing::Charge.
- Hold creation commits, releases the occurrence lock, then publishes
booking.held.bookings with amount_cents, currency, payable_ref, success_url, cancel_url, the guest email, and the offering name as the line-item description.
- Billing's subscriber, on that event, on the publisher's thread: create the Customer when the payload has no customer id, using idempotency key
customer- plus the identity id. Then create the session with that customer id, idempotency key session- plus payable_ref. Write Billing::Charge. Publish charge.opened.billing with the URL and the customer id.
- The Bookings subscriber writes the URL on the instalment and the customer id on the booking, then the controller redirects. Those writes are the same request. They are the second half of the inline exception.
- A second publish for the same
payable_ref returns the open Charge instead of creating a second session.
- If the gateway raises, the subscriber rescues Billing's own error and publishes
charge.open_failed.billing. It does not raise into the Bookings controller. The hold stays held. Log the failure through the existing observability adapter.
- Do not call Stripe inside the occurrence lock. Do not copy the lifetime service, which holds
FOR UPDATE across the Stripe call.
Out of scope
- Expiring the session and freeing the row.
- Confirming from
payment.succeeded.billing. The hold can be marked paid by hand until that issue.
- The balance page.
booking.balance_due.bookings stays registered and unwired.
How to deliver
Branch <issue-number>-open-checkout. PR title [#<issue-number>] Open Checkout after the hold commits.
Spec the listener with a fake gateway before wiring Stripe. The occurrence lock must be released before the gateway method is called. Assert that with the test, not a comment.
Acceptance Criteria
Epic: #151
Proposal:
proposals/bookings_engine.md(local, git-excluded). Argument: https://github.com/Davidslv/notes/issues/178Purpose
After the hold commits, the guest is redirected to Checkout. Billing creates the Stripe Customer first, then the session, on that same request. Bookings never names a Billing class.
Scope
In scope
bin/seams bookingsnow requires the billing release that containsBilling::Charge.booking.held.bookingswithamount_cents,currency,payable_ref,success_url,cancel_url, the guest email, and the offering name as the line-item description.customer-plus the identity id. Then create the session with that customer id, idempotency keysession-pluspayable_ref. WriteBilling::Charge. Publishcharge.opened.billingwith the URL and the customer id.payable_refreturns the open Charge instead of creating a second session.charge.open_failed.billing. It does not raise into the Bookings controller. The hold staysheld. Log the failure through the existing observability adapter.FOR UPDATEacross the Stripe call.Out of scope
payment.succeeded.billing. The hold can be marked paid by hand until that issue.booking.balance_due.bookingsstays registered and unwired.How to deliver
Branch
<issue-number>-open-checkout. PR title[#<issue-number>] Open Checkout after the hold commits.Spec the listener with a fake gateway before wiring Stripe. The occurrence lock must be released before the gateway method is called. Assert that with the test, not a comment.
Acceptance Criteria
charge.opened.billingfor a first-time guest includes a customer id and a URL.booking.held.bookingsfor the samepayable_refdoes not create a second session.charge.open_failed.billing, leaves the bookingheld, and does not raise a Billing exception into the controller.