# Billing Cooldown Runtime Checklist (Staging) ## Scope Validate these behaviors end-to-end: 1. `pending_cooldown` lock on new checkout (120s) 2. Continue pending payment via `Pay` button 3. PayPal/Pakasir webhook delay handling 4. Auto-status transition from `pending` to `paid` ## Preconditions 1. Staging is deployed with latest billing changes. 2. Config is refreshed: - `php artisan optimize:clear` - `php artisan config:cache` 3. Env includes: - `DEWEMOJI_CHECKOUT_PENDING_COOLDOWN=120` 4. Webhooks are configured and reachable: - PayPal webhook endpoint - Pakasir webhook endpoint 5. Test account available (verified email, logged in). ## Quick Observability 1. Browser devtools open (`Network` tab). 2. Keep Billing page open in another tab for status checks. 3. Optional server logs tail: - `tail -f storage/logs/laravel.log` ## Test Matrix ### A. Cooldown Lock (PayPal) 1. Start Personal checkout in USD. 2. Before webhook settles, try starting another checkout from Pricing. 3. Expected: - API returns `409` with `error: pending_cooldown`. - UI shows wait message with countdown (`retry_after` seconds). - Checkout CTA stays disabled until countdown reaches 0. ### B. Cooldown Lock (Pakasir) 1. Start Personal checkout in IDR (QRIS modal opens). 2. Close/cancel modal only if needed for this test case. 3. Immediately try another new checkout from Pricing. 4. Expected: - API returns `409 pending_cooldown`. - UI countdown appears and blocks new checkout. ### C. Continue Pending (PayPal) 1. Create a PayPal pending payment. 2. Go to `/dashboard/billing`. 3. Click `Pay` on pending row. 4. Expected: - Redirect to PayPal approve URL. - No new payment row created just for resume action. ### D. Continue Pending (Pakasir) 1. Create a Pakasir pending payment. 2. Go to `/dashboard/billing`. 3. Click `Pay` on pending row. 4. Expected: - QR modal opens with amount + expiry. - Polling runs and closes modal when status becomes paid. ### E. Webhook Delay UX 1. Complete payment at provider. 2. Observe app while webhook is delayed. 3. Expected: - Status may remain `pending` briefly. - User can continue pending (`Pay` button). - After webhook/poll settles: status updates to `paid`. ### F. Pending Timeout to New Checkout 1. Keep a payment pending beyond cooldown (`>=120s`). 2. Try new checkout from Pricing. 3. Expected: - New checkout is allowed again. - Existing behavior for replacing/canceling pending remains intact. ### G. Edge Responses 1. Try `Pay` on a row that is no longer pending (race condition). 2. Expected: - UI handles response (`payment_not_pending`) and refreshes state safely. 3. If pending QR is expired: - Expected `payment_expired`, prompt to start new checkout. ## API Assertions (Network) Check response payloads: 1. Cooldown block: ```json { "error": "pending_cooldown", "retry_after": 87, "pending_payment_id": 123, "provider": "paypal" } ``` 2. Resume PayPal: ```json { "ok": true, "mode": "redirect", "approve_url": "https://..." } ``` 3. Resume Pakasir: ```json { "ok": true, "mode": "qris", "payment_number": "...", "order_id": "DW-...", "expired_at": "..." } ``` ## Pass/Fail Sheet | Check | Result | Notes | |---|---|---| | A. PayPal cooldown lock | | | | B. Pakasir cooldown lock | | | | C. Resume pending PayPal | | | | D. Resume pending Pakasir | | | | E. Webhook delay UX | | | | F. New checkout after cooldown | | | | G. Edge response handling | | | ## Exit Criteria Release-ready when: 1. All rows above are `PASS`. 2. No uncaught JS errors in console. 3. No unexpected 5xx in network log during flow.