Files
vmall/openspec/changes/add-wallet-settlement/tasks.md
T

39 lines
6.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## 1. Persistence and shared contract
- [ ] 1.1 Add migration `0018_wallet.sql` adapting tigshop's `user_recharge_order` and `user_withdraw_apply`: `wallet_recharges` (user, currency, amount_minor BIGINT, status, timestamps) and `wallet_withdrawals` (user, currency, amount_minor BIGINT, account_details JSONB, status pending/approved/rejected with CHECK, reviewing admin, reviewed_at, review_note, timestamps) with foreign keys, non-negative amount CHECKs, and customer-facing indexes. (Migration numbers 0016/0017 are taken by parallel changes.)
- [ ] 1.2 Add migration `0019_settlement.sql` adapting tigshop's `vendor_settlement_order`: `settlement_statements` (shop, period_kind week/month, period_start, period_end, order_count, gross_minor, refund_minor, commission_rate_bps, commission_minor, payable_minor, status pending/confirmed with CHECK, generated_by, confirmed_by, confirmed_at, timestamps) with a unique index on (shop_id, period_kind, period_start), plus a platform-level settings row for `settlement.commission_rate_bps`.
- [ ] 1.3 Add `@vmall/shared` wallet types and customer-client methods: `getWallet` (available/frozen minor with currency), `listWalletEntries` (paged signed ledger entries), `rechargeWallet` (demo), `applyWithdrawal`, and `listMyWithdrawals`.
- [ ] 1.4 Add `@vmall/shared` settlement and review methods: admin client `listWithdrawalApplications`, `reviewWithdrawal`, `getCommissionRate`, `setCommissionRate`, `listSettlementStatements`, `getSettlementStatement`, `generateSettlementStatement`, `confirmSettlementStatement`; shop client `listShopSettlementStatements`, `getShopSettlementStatement`, `generateShopSettlementStatement`. All money fields are i64 minor units; no floating-point amounts cross the contract.
## 2. Wallet backend
- [ ] 2.1 Implement `apps/api/src/modules/wallet/` (repo, service returning `ApiResult<Dto>`, DTOs, handlers, module registration) with user-scoped `/wallet` routes and `/admin/wallet/withdrawals` review routes declaring the platform-admin role.
- [ ] 2.2 Implement demo recharge: one transaction records a `wallet_recharges` row and credits the available account through the existing `customer-accounts` primitives with a `wallet_recharge` ledger entry; the DTO carries an explicit demo marker.
- [ ] 2.3 Implement the withdrawal lifecycle: application freezes funds via guarded `UPDATE ... WHERE balance_minor >= $amount` moving available to frozen with paired ledger entries; admin approve deducts frozen balance with a ledger entry; admin reject returns frozen balance to available with a ledger entry; each review is guarded by `UPDATE ... WHERE status = 'pending'`, returns 409 on repeat, and records reviewer, timestamp, and note.
- [ ] 2.4 Implement paginated fund-entry listing mapped to `customer_account_entries` for the caller's monetary accounts (newest first; signed delta, resulting balance, reason, reference) with ownership filtering.
- [ ] 2.5 Add `apps/api/tests/wallet.rs` covering concurrent withdrawal overdraw, insufficient-balance no-op, double-review 409, reject unfreeze, approve frozen deduction, recharge ledger pairing, and entry pagination isolation, reusing the `tests/common/mod.rs` fixtures.
## 3. Settlement backend
- [ ] 3.1 Implement `apps/api/src/modules/settlement/` (repo, service returning `ApiResult<Dto>`, DTOs, handlers, module registration) with `/shop/settlement/*` routes scoped through `AuthUser::own_shop` and `/admin/settlement/*` routes declaring the platform-admin role.
- [ ] 3.2 Implement idempotent statement generation for a shop and closed week/month period: snapshot order count and gross totals of confirmed-received orders in the period, deduct completed refunds (`aftersales` rows with status `refunded`, per-order totals maintained by `add-aftersale-refunds` — if developed in parallel with P0, merge the P0 `aftersales` migration first), apply the platform commission rate in integer basis points with integer minor-unit arithmetic (payable = gross − refunds − commission), and return the existing statement untouched on repeat generation.
- [ ] 3.3 Implement statement listing and detail with per-order and refund breakdown, with merchant routes restricted to the own shop and platform-admin routes seeing every shop.
- [ ] 3.4 Implement `pending -> confirmed` payout confirmation: guarded `UPDATE ... WHERE status = 'pending'` (409 on repeat) crediting the payable amount to the shop owner's available account with exactly one ledger entry referencing the statement.
- [ ] 3.5 Implement platform commission-rate configuration (integer basis points), applied only to statements generated after a change; generated statements keep their snapshot.
- [ ] 3.6 Add `apps/api/tests/settlement.rs` covering generation idempotency and period uniqueness, refund deduction, commission snapshot immutability after a rate change, double-confirmation 409 with exactly one payout ledger entry, and cross-shop isolation, reusing the `tests/common/mod.rs` fixtures.
## 4. Frontend surfaces
- [ ] 4.1 Add the mall buyer-center wallet page (available/frozen balance, paginated fund entries, clearly labeled demo recharge, withdrawal request and history) through `@vmall/shared`, with bilingual strings in the existing Mall locale source.
- [ ] 4.2 Add the `wallet` domain to the Mall fixed-data adapter (`apps/mall/mock/api.ts`) with matching behavior, and wire `wallet` into the Mall API selection `LIVE_PICKS` and default live domains (`apps/mall/plugins/api.ts`).
- [ ] 4.3 Add admin pages for withdrawal review (approve/reject with outcome and 409 feedback), commission-rate configuration, and settlement statement list/detail with manual generation and one-time payout confirmation.
- [ ] 4.4 Add shop-admin pages for own-shop settlement statement list/detail with manual generation and shop-account summary plus withdrawal request/history.
- [ ] 4.5 Keep all three frontends on the `@vmall/shared` contract only (no page-level fetch of wallet/settlement endpoints) and render page chrome with `@vmall/ui` primitives.
## 5. Verification and tracker cleanup
- [ ] 5.1 Run the wallet and settlement integration tests in `apps/api/tests/wallet.rs` and `apps/api/tests/settlement.rs` (reusing the `tests/common/mod.rs` fixtures), then `cargo test -p vmall-api` to prove the suite stays green against the shared test database.
- [ ] 5.2 Build all three frontends because the shared API contract changes: `pnpm --filter @vmall/mall build`, `pnpm --filter @vmall/admin build`, and `pnpm --filter @vmall/shop-admin build`.
- [ ] 5.3 Browser-smoke the API plus frontends: demo recharge updates the wallet; withdrawal freeze, admin reject unfreeze, and admin approve deduction round trip; wallet entries pagination; commission-rate configuration; idempotent statement generation with refund deduction; one-time payout confirmation writing one ledger entry; and shop-admin own-shop statement isolation.
- [ ] 5.4 Check every OpenSpec task, then run `openspec change validate add-wallet-settlement --strict` and `openspec validate --all --strict`.