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

6.9 KiB
Raw Blame History

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.