# 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.
