Deposit — Test Cases
Feature version: v1.0
Reference doc: Finance System · Deposit Technical Reference
Result notation: ✅ Pass | ❌ Fail | ⏭ Skip | 🐛 Fail + bug report
Changelog
| Date | Version | Change | Author |
|---|---|---|---|
| 2026-05-10 | v1.0 | Initial creation | — |
TC-DEP-001 — Flow 1: Player online deposit (Wallet-only) 🆕 NEW
Precondition: Player is a free player (not shop-linked), account is
active, no game selected.
| # | Description | Steps | Expected Result | Actual Result |
|---|---|---|---|---|
| 1 | Transaction created successfully | Player selects amount + method → POST /api/payment/deposit | Returns { transactionId, paymentUrl, status: 'pending', expiresAt } | |
| 2 | transactionId format at creation | Check the transactionId in the response | Format is TEMP_{timestamp}_{userId} | |
| 3 | Initial status is pending | Check DB after creation | status = 'pending' | |
| 4 | Status transitions after IPN received | Simulate a successful IPN from the gateway | Status: pending → processing → completed | |
| 5 | Credits land in master wallet after completion | Complete a $10 deposit → Check wallet | balance += 10 credits | |
| 6 | Inactive player cannot deposit | Set player status = 'inactive' → Attempt deposit | HTTP 403 "Account is not active" | |
| 7 | Negative amount is rejected | POST deposit with amount = -5 | HTTP 400 "Invalid amount" | |
| 8 | Zero amount is rejected | POST deposit with amount = 0 | HTTP 400 "Invalid amount" |
TC-DEP-002 — Flow 1 (variant): Direct-to-game deposit 🆕 NEW
Precondition: Player is active. Game provider exists and
depositType ≠ 'manual'.
| # | Description | Steps | Expected Result | Actual Result |
|---|---|---|---|---|
| 1 | walletFlow is set correctly | POST deposit with a valid gameProviderId → Check transaction | walletFlow = 'master_to_game' | |
| 2 | Credits go to inGameBalance | Complete a $10 direct-to-game deposit → Check user_game_wallets | inGameBalance += 10 | |
| 3 | syncStatus = 'pending' after payment completes | Check after gateway callback | syncStatus = 'pending' | |
| 4 | After game sync completes | Wait for async sync job to finish | syncStatus = 'completed'; walletBalance and inGameBalance match | |
| 5 | Unknown game provider is rejected | POST deposit with a gameProviderId not in DB | HTTP 400 "Provider not found" |
TC-DEP-003 — Flow 2: Shop Player Deposit (CDN Flow) 🆕 NEW
Precondition: Player is linked to a Shop. Prepare two scenarios: shop with sufficient credit and shop with zero credit.
| # | Description | Steps | Expected Result | Actual Result |
|---|---|---|---|---|
| 1 | Shop has credit — shop wallet is debited | Shop has 50 credits; player deposits $10 → Complete | Shop master wallet: −10 credits; Player master wallet: +10 credits | |
| 2 | Shop has credit — shop receives USD (fee=0) | Check Shop USD wallet after player deposits $10 with feeRate=0% | Shop USD wallet: +$10 | |
| 3 | Shop has credit — shop receives USD minus fee | feeRate=10%, player deposits $10 | Shop USD wallet: +$9 (fee $1 deducted) | |
| 4 | Shop lacks credit — online deposit blocked at API | Shop = 0 credits; player attempts POST /api/payment/deposit or GET /deposit-precheck | HTTP 400; message: The shop currently cannot process online deposit transactions. Please visit the shop in person to complete this action.; no payment URL created | |
| 5 | Shop lacks credit — no credits after gateway (defense in depth) | Shop had credit at deposit creation but insufficient at IPN settlement | Settlement fails (strictShopPayer); player does not receive credits; manual ops follow-up | |
| 6 | Free player unaffected when shop has zero credit | Player has no shop_id; shop unrelated | Deposit proceeds; system payer credits player as Flow 1 |
TC-DEP-004 — Flow 3: Shop Counter Deposit (Cashier) 🆕 NEW
Precondition: Shop is active, player belongs to the shop, shop master wallet has sufficient credits.
| # | Description | Steps | Expected Result | Actual Result |
|---|---|---|---|---|
| 1 | Staff transfers credits successfully | Shop portal → "Transfer to Player" → Enter player + amount → Confirm | Shop wallet: −amount; Player wallet: +amount | |
| 2 | CashierTransaction is created with the correct type | Check DB after transfer | cashier_transactions.type = 'deposit_credits' | |
| 3 | paymentMethod = 'cash' is saved correctly | Transfer with paymentMethod = 'cash' | cashier_transactions.paymentMethod = 'cash' | |
| 4 | paymentMethod = 'bank_transfer' is saved correctly | Transfer with paymentMethod = 'bank_transfer' | cashier_transactions.paymentMethod = 'bank_transfer' | |
| 5 | Player not belonging to the shop is rejected | Attempt to transfer credits to a player from a different shop | Error — player does not belong to this shop | |
| 6 | Inactive shop cannot perform transfer | Set shop status = 'inactive' → Attempt cashier deposit | HTTP 4xx — shop is not active |
TC-DEP-005 — Flow 4: Multi-Game Deposit 🆕 NEW
Precondition: Player is active. At least 2 game providers exist. One should have
depositType = 'manual'to test the manual_pending branch.
| # | Description | Steps | Expected Result | Actual Result |
|---|---|---|---|---|
| 1 | $50 allocated across 3 games (all auto) | Create deposit with allocations: [{game1: $20}, {game2: $20}, {game3: $10}] → Complete | Each game wallet credited with the correct amount | |
| 2 | multiGameProcessedAt is set after processing | Check syncMetadata after completion | syncMetadata.multiGameProcessedAt contains an ISO timestamp | |
| 3 | Total allocation equals deposited amount | Check syncMetadata.totalAmountDeposited | totalAmountDeposited = 50 | |
| 4 | Game with depositType = 'manual' → manual_pending | Include an allocation for a manual-type game | allocationResults[i].status = 'manual_pending'; manual deposit request created | |
| 5 | Idempotency — processing the same transaction twice | Trigger processMultiGameDeposit() a second time for the same transaction | No double-credit (skipped because multiGameProcessedAt already exists) |
TC-DEP-006 — Flow 5: CDN Credit Purchase (Agent / Shop buying credits via gateway) 🆕 NEW
Precondition: Shop or Agent account exists. Payment gateway is operational.
| # | Description | Steps | Expected Result | Actual Result |
|---|---|---|---|---|
| 1 | Shop buys credits successfully | Shop pays $80 via gateway, costRate=0.80 | Shop credit wallet: +100 credits | |
| 2 | Credit amount calculated correctly from costRate | costRate=0.80; grossUsd=$80 | creditComputed = 80 / 0.80 = 100 | |
| 3 | Shop USD wallet is credited after purchase | Check shop USD wallet after CDN purchase completes | balanceGross += 80; balanceNet += 80 − fee | |
| 4 | 0x insufficient status above threshold → completed | 0x webhook returns status='insufficient' but receivedUsd ≥ expected × (1 − feeRate) | Transaction marked completed; syncMetadata.receivedNetUsd stores the actual received amount | |
| 5 | 0x insufficient status below threshold → not settled | receivedUsd < expected × (1 − feeRate) | Transaction is not settled |