Introduced in #11955.
On the checkout confirmation screen, the invite panel computes available seats as checkout.seats - 1, assuming the backend auto-claimed exactly one seat for the buyer. It breaks for a buyer who purchases the same one-time seat-based product more than once: each purchase mints a fresh order (a separate seat container), and the backend skips the buyer auto-claim on the repeat order (has_claimed_seat_for_product_via_orders returns true from the earlier order). That repeat order therefore has all seats unclaimed, but the UI still shows checkout.seats - 1 available.
Given the very edge case nature of this (repeat one-time seat-based buyers), decided not to solve it in the original PR.
The proper fix would be to drive the panel's available-seat count from the portal's authoritative GET /v1/customer-portal/seats endpoint and use available_seats instead of checkout.seats - 1.
That's not feasible today because CheckoutPublic exposes neither subscription_id nor order_id, so the client can't query that endpoint.
Introduced in #11955.
On the checkout confirmation screen, the invite panel computes available seats as
checkout.seats - 1, assuming the backend auto-claimed exactly one seat for the buyer. It breaks for a buyer who purchases the same one-time seat-based product more than once: each purchase mints a fresh order (a separate seat container), and the backend skips the buyer auto-claim on the repeat order (has_claimed_seat_for_product_via_ordersreturnstruefrom the earlier order). That repeat order therefore has all seats unclaimed, but the UI still showscheckout.seats - 1available.Given the very edge case nature of this (repeat one-time seat-based buyers), decided not to solve it in the original PR.
The proper fix would be to drive the panel's available-seat count from the portal's authoritative
GET /v1/customer-portal/seatsendpoint and useavailable_seatsinstead ofcheckout.seats - 1.That's not feasible today because
CheckoutPublicexposes neithersubscription_idnororder_id, so the client can't query that endpoint.