Test payment flows for MENA region including COD, Stripe, and local gateways
Comprehensive testing methodology for payment flows in the MENA region. COD (Cash on Delivery) is the dominant payment method -- it must work flawlessly. Stripe and local gateways handle card payments with MENA-specific currencies and tax rates.
COD is the primary payment method across MENA. It must be tested as a first-class flow, not an afterthought.
paymentMethod: 'cod' and paymentStatus: 'pending'.PENDING -> CONFIRMED (merchant accepts)CONFIRMED -> (merchant prepares)PROCESSINGPROCESSING -> SHIPPED (merchant ships / out for delivery)SHIPPED -> DELIVERED (delivery confirmed, payment collected)pending to collected.Verify packages/contracts/src/recipes.ts defines correct profiles for each target country:
| Country | Currency | Tax Rate | Primary Gateway | COD Prevalence |
|---|---|---|---|---|
| Egypt | EGP (ج.م) | 14% VAT | Stripe / local | Very High |
| Saudi Arabia | SAR (ر.س) | 15% VAT | Stripe | High |
| UAE | AED (د.إ) | 5% VAT | Stripe | High |
| Kuwait | KWD (د.ك) | 0% | Stripe | Medium |
| Bahrain | BHD (د.ب) | 10% VAT | Stripe | Medium |
| Oman | OMR (ر.ع) | 5% VAT | Stripe | High |
For each country, verify:
formatMoney() from the appropriate formatter.inhouse_event_deliveries with atomic claim (INSERT ... ON CONFLICT DO NOTHING).Payment events must correctly flow through the event pipeline:
InhouseCommerceService (or equivalent) calls emitEvent() to write to inhouse_domain_events.DOMAIN_TO_BUSINESS_MAP (or the event bridge cron) translates payment domain events into business_events.Verify state transitions are enforced by the service layer using {DOMAIN}_TRANSITIONS records from contracts:
PENDING -> CONFIRMED -> PROCESSING -> SHIPPED -> DELIVERED
| |
v v
CANCELLED RETURNED
PENDING -> DELIVERED) must be rejected by the service, not silently accepted.refunded. Stripe refund API is called. Refund event is emitted.partially_refunded with remaining amount.For payment-related KPIs displayed in the Run Hub:
business_events (via event bridge), seeding data into inhouse_orders alone will not make it appear. Seed where the UI reads, not where the domain writes.## COD Flow
- [PASS/FAIL] COD is default payment method in checkout
- [PASS/FAIL] Order state machine transitions work correctly
- [PASS/FAIL] Payment collection on delivery updates status
- [FAIL] COD cancellation before delivery triggers erroneous refund event
## Country Profiles
- [FAIL] Egypt VAT rate is 14% in code but should be 14% -- PASS
- [FAIL] Kuwait country profile missing COD configuration
## Stripe Integration
- [PASS/FAIL] Webhook signature verification fails closed
- [PASS/FAIL] Idempotency prevents duplicate processing
- [FAIL] BHD amounts not converted correctly (3 decimal places)
## Event Bridge
- [FAIL] Payment events not appearing in business_events -- bridge cron not picking up event type "payment.completed"
- [PASS] Revenue KPI reads from correct source
## KPI Accuracy
- [FAIL] "Total Revenue" card displays order count, not revenue amount
- Label: "Total Revenue"
- Component prop: revenue
- API field: orderCount <-- MISMATCH
Every failure must include: what was expected, what was observed, and the specific file/table/field where the issue originates.