Skip to content

Open-order supersede skips the buyer's own already-lapsed hold on the same window; the stale PENDING row and its tentative slot wait for the abandoned-payments sweep #1478

Description

@teetangh

findReusablePendingOrderPayment (lib/payments/operations/checkout.ts, the candidate query) gates on expiresAt > now, by design ("never resume a stale hold"). A buyer who returns to the exact same slot after their 30-minute window lapsed therefore gets a fresh order (correct), but the lapsed row is never a candidate, so it is neither resumed nor superseded, and releaseSupersededHolds (#1465) does not run for it. The old Payment stays PENDING and its tentative slot rows stay SCHEDULED until the abandoned-payments sweep (the Netlify ticker runs it every 5 minutes in production).

Nothing is blocked or double-charged in the interim: buildDeadHoldFilter already treats the lapsed hold as dead for availability, which is why the new order mints. The cost is a stale tentative row on the consultant's calendar and an unresolved PENDING payment for up to one sweep cycle.

Suggested fix: when the self-hold lookup (findSelfHoldAppointmentIds) finds the buyer's own hold on the exact window whose payment has lapsed, release it through releaseSupersededHolds in the same request (same CAS, same transition helpers) before minting the new order. Keep the freshness gate for resume.

Evidence: wave 3 on deploy-preview-1422 (union ff7cf5d), Payment 5d4dd778-4eef-44e0-b9bc-be9ea81fcfde backdated by SQL, second POST minted order_TYIKJ3UB3LCva1 while the old row stayed PENDING with slot 84e49b8e-072b-4658-b955-0cffc16d4ddc SCHEDULED. The wave's report also claimed the supersede block only flips the payment status; that is wrong on dev — releaseSupersededHolds releases slots and parent requests for fresh-but-mismatched candidates.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bookingBooking, scheduling, slots, reschedule, cancellationfinancePayments, refunds, earnings, payouts, invoicing, ledgerlaunch: post-mvpFirst 90 days after launch — coverage, polish, operational maturitytech-debtRefactors, structure, dependency upgrades, cleanup

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions