Tasks — Player → Shop/Cashier (Phase 3)
Spec: player-to-shop-cashier · Mockup: Redemptions tab
Phụ thuộc: Phase 2 deposit (schema + shop cash-transactions API nền); Cashier redeem + approval (Cashier spec).
Tóm tắt nghiệp vụ
Khi Shop redeem credit của Player, Shop trả lại Player một khoản tiền mặt tương ứng tại quầy.
Player yêu cầu rút credit
→ Shop/Cashier xác nhận
→ Trừ credit Player, cộng credit Shop (CDN wallet)
→ Shop trả tiền mặt cho Player
→ Ghi sổ cash (Cash Out) + báo cáo
Hai số liệu bắt buộc khi thao tác:
| Trường | Ý nghĩa | Ví dụ |
|---|
| Số credit redeem | Credit trừ khỏi ví Player | 30 credits |
| Số tiền mặt trả Player | Cash Shop đưa trực tiếp cho Player | $30.00 |
V1: thường 1:1 (30 credits → $30.00), nhưng Shop nhập cả hai để hệ thống ghi nhận rõ ràng credit đã thu hồi và cash đã chi. Ledger và báo cáo dùng số tiền mặt trả Player cho Cash Out — không suy diễn từ credit.
Phạm vi V1: Chỉ redemption. Auto-settled khi completed; pending approval không tạo cash tx.
Ai làm gì
| Vai trò | Hành động |
|---|
| Player | Yêu cầu rút; có mặt tại quầy |
| Shop Manager | Nhập credit redeem + tiền mặt trả Player; xác nhận redeem từ Shop portal |
| Cashier | Nhập credit redeem + tiền mặt trả Player; trả cash sau completed (hoặc sau Manager approve) |
| Hệ thống | Debit player wallet, credit shop wallet, ghi cash_transactions, cập nhật shift Cash Out |
Hai kênh thực hiện
| Kênh | API | Ghi chú |
|---|
| Shop portal | POST /shop/players/:id/credits (action: deduct) | Không bắt buộc shift |
| Cashier portal | POST /cashier/players/:id/redeem | Active shift; cash only |
Cả hai kênh đều phải thu credit redeem và cash paid; sau khi wallet transfer thành công → tạo cash_transactions flow shop_player_redemption.
Phase 1 — Schema
| # | Task | Ghi chú |
|---|
| 1.1 | Flow shop_player_redemption | Nếu chưa ship cùng Phase 2 migration |
| 1.2 | metadata.approvalId optional | Link approval record (Cashier path) |
| 1.3 | Doc schema-cash-transactions | credit_amount ≠ cash_received khi cần |
Phase 2 — Backend biz (redemption only)
| # | Task | Ghi chú |
|---|
| 2.1 | createCounterRedemptionCashTransaction | seller=player, buyer=shop |
| 2.2 | Payload: credit_amount + cash_paid (cash_received) | Cả hai bắt buộc, > 0 |
| 2.3 | expected_cash = cash_paid | Số tiền mặt Shop chi |
| 2.4 | Hook sau _adjustCreditsDeduct | Chỉ khi wallet transfer completed |
| 2.5 | Không hook từ pending_approval | Chỉ sau approve + transfer |
| 2.6 | Shop portal action: deduct | Validate + truyền cash_paid vào ledger |
| 2.7 | Cashier redeemCredits | Body thêm cash_paid; cashDelta = −cash_paid |
| 2.8 | Wire sau cashierRedemptionApprovalBizService approve | Approval dùng cùng cash_paid đã lưu |
| 2.9 | Idempotency theo reqId | Tránh duplicate cash tx |
| 2.10 | Unit tests | Happy path; insufficient balance; pending→approve; cash ≠ credit (nếu cho phép) |
File chính: cashTransactionBizService.js, shopPlayerBizService.js, cashierTransactionBizService.js, cashierRedemptionApprovalBizService.js
Ledger (cash_transactions):
| Field | Value |
|---|
| flow | shop_player_redemption |
| seller | player / player uuid |
| buyer | shop / shop uuid |
| credit_amount | Số credit redeem |
| expected_cash / cash_received | Số tiền mặt trả Player |
| status | paid_full (auto khi completed) |
Links: payment_transaction_id, wallet txs, cashier_transaction_id, shift_id, metadata.approvalId.
Phase 3 — Shop portal API (redemption filter)
| # | Task | Ghi chú |
|---|
| 3.1 | GET /api/shop/cash-transactions?flow=shop_player_redemption | List redemptions |
| 3.2 | Detail hiện credit + cash paid + approval context | |
| 3.3 | Summary: Cash Out (SUM cash_received), pending approval count | Aggregate toàn bộ filter, không chỉ page |
| 3.4 | Export CSV | Cột credit redeem + cash paid |
Mở rộng shopCashSettlementController — hiện chỉ filter shop_player_deposit.
Phase 4 — Shop portal UI
| # | Task | Ghi chú |
|---|
| 4.1 | Tab Payable — Redemptions | Mockup phase2 redeem tab |
| 4.2 | Modal redeem Player: 2 ô nhập — credit redeem + cash trả Player | Pre-fill cash = credit (1:1); Shop sửa nếu cần |
| 4.3 | Review step hiện cả credit và cash trước confirm | |
| 4.4 | Summary card Cash Out (today / filter) | Từ ledger cash_received |
| 4.5 | Bảng: player, credits redeemed, cash paid, cashier/actor, status | Settled / Pending approval |
| 4.6 | Badge Pending approval vs Settled | |
| 4.7 | Combined dashboard: Cash In (P2) + Cash Out (P3) = Net | Optional sau cả hai tab |
Phase 5 — Cashier / Shift
| # | Task | Ghi chú |
|---|
| 5.1 | Cashier redeem form: credit + cash paid | Giống Shop portal |
| 5.2 | Redemption completed → shift Cash Out = cash_paid | Không dùng credit amount cho cashDelta |
| 5.3 | Pending approval: cashDelta = 0 | Chưa trả tiền |
| 5.4 | Cashier tx list hiện CTX-* sau settle | Read-only; hiện cash paid |
| 5.5 | Integration test Expected Closing Cash | Cash Out khớp tổng redemption |
Phase 6 — Báo cáo
| # | Task | Ghi chú |
|---|
| 6.1 | Shop portal Redemptions tab summary | Cash Out aggregate |
| 6.2 | Export CSV redemption | credit_amount, cash_received, player, date |
| 6.3 | Shift reconciliation report | Cash Out từ redemption dùng cash_paid |
| 6.4 | Admin / Shop cash-transaction detail | View-only; link payment + wallet txs |
Phase 7 — QA (redemption)
| # | Scenario | Expected |
|---|
| 7.1 | Shop redeem 30 credits, trả $30 cash | cash tx: credit=30, cash_received=30; wallet −30/+30 |
| 7.2 | Shop redeem 30 credits, trả $28 cash (nếu cho phép) | cash tx cash_received=28; shift cashDelta −28 |
| 7.3 | Cashier redeem pending approval | No cash tx; cashDelta = 0 |
| 7.4 | Approve → complete | cash tx created once với cash_paid đã lưu |
| 7.5 | Insufficient player balance | 400; no cash tx |
| 7.6 | Shop manual deduct thiếu cash_paid | 400 validation |
| 7.7 | Idempotent retry cùng reqId | Một cash tx duy nhất |
Thứ tự triển khai
Phase 2 deposit done
→ Schema redemption (1)
→ Biz hook + cash_paid payload (2)
→ Shop API redemption filter (3)
→ UI: modal 2 ô + tab Redemptions (4)
→ Cashier cash_paid + shift (5)
→ Báo cáo (6)
→ QA (7)
Hiện trạng (baseline)
| Thành phần | Trạng thái |
|---|
| Wallet transfer player → shop | ✅ |
Cashier redeem + approval + cashDelta (1 field) | ✅ — cần thêm cash_paid |
| Shop portal manual deduct (1 field) | ✅ — cần thêm cash_paid |
cash_transactions flow shop_player_redemption | ❌ |
| Shop portal redemption ledger + báo cáo Cash Out | ❌ |