feat: wave 2 migration (P3, P5, P7 openspec changes)

Implements, verifies, and archives the three remaining Wave 2 changes from
openspec/MIGRATION-PLAN.md.

- add-wallet-settlement (P3): demo recharge, guarded withdrawal freeze and
  one-time admin review, paginated own fund entries, idempotent per-shop
  weekly/monthly settlement statements with commission rate and one-time
  payout confirmation.
- add-merchant-onboarding (P5): personal/enterprise applications with one live
  application per user, guarded review with mandatory rejection reason, and
  transactional shop + owner provisioning returning one-time credentials;
  mall onboarding/status pages and an admin review console.
- add-membership-messaging (P7): platform member levels, append-only growth
  accrual on order completion with guarded one-way leveling, order/shipment/
  refund system messages with unread/read state and soft deletion, plus the
  mall header unread badge.

Backend: migrations 0019-0023, new wallet, settlement, merchant_onboarding,
membership and messaging modules, event hooks in order/fulfillment/aftersale,
and integration suites for each. Shared contract extended and all three
frontends updated; code indexes, domain docs, backend guidelines and the
migration tracker synced.

Verification: cargo test -p vmall-api green twice consecutively; mall, admin
and shop-admin builds pass; browser smoke on every new surface; openspec
validate --all --strict green (33 passed).

The three changes share the @vmall/shared contract, the mall mock adapter and
per-app locale/nav files, so they are committed together to keep every commit
buildable.
This commit is contained in:
2026-09-25 15:25:29 +00:00
parent 772aafa3fb
commit 9904696e76
120 changed files with 14097 additions and 125 deletions
+163
View File
@@ -12,6 +12,8 @@ export const enExtra = {
aftersales: "After-sales",
freightTemplates: "Freight templates",
reviews: "Reviews",
settlements: "Settlements",
shopAccount: "Shop account",
},
shop: {
profileSaved: "Shop profile saved.",
@@ -170,6 +172,87 @@ export const enExtra = {
groupMembersInvalid: "At least two paid members are required.",
groupLifetimeInvalid: "Group lifetime must be a positive number of hours.",
groupWindowInvalid: "End must not precede start.",
settlement: {
generate: "Generate statement",
generateHint:
"Pick any date inside the target week or month. An existing statement for the same period is returned unchanged.",
periodKind: "Period",
periodWeek: "Week",
periodMonth: "Month",
periodDate: "Date inside the period",
period: "Period",
orderCount: "Orders",
gross: "Gross",
refund: "Refunds",
commissionRate: "Commission rate",
commission: "Commission",
payable: "Payable",
confirmedAt: "Confirmed at",
generatedNew: "Statement generated.",
generatedExisting:
"A statement for this period already exists; the existing statement is shown.",
newStatement: "New",
existingStatement: "Existing",
notClosed:
"That period has not closed yet, so it cannot be settled. Only completed periods can be settled.",
dateRequired: "Pick a date inside the period.",
detail: "Statement detail",
orders: "Contributing orders",
noOrders: "No orders in this period.",
orderNo: "Order no.",
orderCurrency: "Order currency",
hideDetail: "Hide detail",
status: {
pending: "Pending",
confirmed: "Confirmed",
},
},
account: {
available: "Available balance",
frozen: "Frozen balance",
frozenHint: "Frozen while a withdrawal request awaits platform review.",
withdraw: "Request a withdrawal",
amount: "Amount",
method: "Payout method",
methodBank: "Bank transfer",
methodDemo: "Demo channel",
account: "Payout account",
holder: "Account holder (optional)",
withdrawHint:
"The amount is frozen immediately and stays pending until the platform reviews the request.",
submitWithdrawal: "Submit request",
withdrawalRequested: "Withdrawal request submitted; the amount is now frozen pending review.",
withdrawalHistory: "Withdrawal history",
noWithdrawals: "No withdrawal requests yet.",
reviewNote: "Review note",
reviewedAt: "Reviewed at",
entries: "Recent fund entries",
noEntries: "No fund entries yet.",
accountKind: "Account",
entryReason: "Reason",
delta: "Change",
balanceAfter: "Balance after",
amountInvalid: "Enter a positive amount valid for this currency.",
methodRequired: "Choose a payout method.",
accountRequired: "Enter the payout account.",
insufficient: "The amount exceeds your available balance.",
kind: {
available: "Available",
frozen: "Frozen",
},
status: {
pending: "Pending",
approved: "Approved",
rejected: "Rejected",
},
reason: {
wallet_recharge: "Demo recharge",
wallet_withdrawal_freeze: "Withdrawal frozen",
wallet_withdrawal_approved: "Withdrawal paid out",
wallet_withdrawal_rejected: "Withdrawal unfrozen",
settlement_payout: "Settlement payout",
},
},
},
freight: {
title: "Freight templates",
@@ -291,6 +374,8 @@ export const zhExtra = {
shopProfile: "店铺资料",
aftersales: "售后",
freightTemplates: "运费模板",
settlements: "结算对账",
shopAccount: "店铺账户",
},
shop: {
profileSaved: "店铺资料已保存。",
@@ -349,6 +434,7 @@ export const zhExtra = {
status: "状态",
invoiceNo: "发票号",
noInvoice: "—",
orderNo: "订单号",
items: "商品数",
total: "合计",
details: "详情",
@@ -448,6 +534,83 @@ export const zhExtra = {
groupMembersInvalid: "成团人数至少为 2。",
groupLifetimeInvalid: "团有效期必须为正数小时。",
groupWindowInvalid: "结束时间不能早于开始时间。",
settlement: {
generate: "生成结算单",
generateHint: "可选择目标周/月内的任意一天;同一周期已存在的结算单会原样返回。",
periodKind: "周期类型",
periodWeek: "周",
periodMonth: "月",
periodDate: "周期内日期",
period: "周期",
orderCount: "订单数",
gross: "销售总额",
refund: "退款额",
commissionRate: "佣金比例",
commission: "佣金",
payable: "应结金额",
confirmedAt: "确认时间",
generatedNew: "结算单已生成。",
generatedExisting: "该周期已存在结算单,下方展示的是已有结算单。",
newStatement: "新建",
existingStatement: "已存在",
notClosed: "该周期尚未结束,无法结算,只有已结束的周期可以结算。",
dateRequired: "请选择周期内的日期。",
detail: "结算单详情",
orders: "关联订单",
noOrders: "该周期内没有订单。",
orderNo: "订单号",
orderCurrency: "订单币种",
hideDetail: "收起详情",
status: {
pending: "待确认",
confirmed: "已确认",
},
},
account: {
available: "可用余额",
frozen: "冻结余额",
frozenHint: "提现申请待平台审核期间该金额会被冻结。",
withdraw: "申请提现",
amount: "金额",
method: "提现方式",
methodBank: "银行转账",
methodDemo: "演示渠道",
account: "收款账户",
holder: "开户人(可选)",
withdrawHint: "提交后金额立即冻结,在平台审核前保持待审核状态。",
submitWithdrawal: "提交申请",
withdrawalRequested: "提现申请已提交,金额已冻结待审核。",
withdrawalHistory: "提现记录",
noWithdrawals: "暂无提现申请。",
reviewNote: "审核备注",
reviewedAt: "审核时间",
entries: "最近资金流水",
noEntries: "暂无资金流水。",
accountKind: "账户",
entryReason: "原因",
delta: "变动",
balanceAfter: "变动后余额",
amountInvalid: "请输入该币种下的有效正数金额。",
methodRequired: "请选择提现方式。",
accountRequired: "请填写收款账户。",
insufficient: "金额超过可用余额。",
kind: {
available: "可用",
frozen: "冻结",
},
status: {
pending: "待审核",
approved: "已通过",
rejected: "已拒绝",
},
reason: {
wallet_recharge: "演示充值",
wallet_withdrawal_freeze: "提现冻结",
wallet_withdrawal_approved: "提现已打款",
wallet_withdrawal_rejected: "提现解冻",
settlement_payout: "结算打款",
},
},
},
freight: {
title: "运费模板",