Appearance
03 · 充值系统
0. 文档说明
| 项 | 内容 |
|---|---|
| 版本 | V1.0 |
资金入口。成功入账走 02 的
DEPOSIT_CREDIT(入账恒本位币baseCurrency),并发DepositSucceeded事件驱动 06 成长值 / 09 充值类活动 / 11 佣金。本篇是 02 §3.2「充值边界锁价」的落地。
一、定位与职责
- 定义支付通道抽象(法币通道 / 加密链上)与通道币种路由;
- 定义充值订单的生命周期(状态机)、回调验签与幂等入账;
- 落地充值边界换算:通道币种可 ≠ 本位币,下单时点锁价
lockedRate折入本位币入账(02 §3.2); - 定义充值与优惠活动的联动(下单选活动、首充标记);
- 提供订单查询、超时关闭、后台补单能力。
术语(照 02):baseCurrency 本位币(站的唯一记账/展示币种)、channelCurrency 通道币种(通道对外收付币种,可 ≠ 本位币)、lockedRate 锁价(下单时点快照汇率)。
边界:余额记账归 02(账户恒本位币,站内单账户);充值类活动的资格与发放规则归 09;通道商(PSP)对接细节属技术实现,本文只定义抽象与状态。
二、核心概念与数据模型
2.1 支付通道 PaymentChannel(平台目录)
| 字段 | 说明 |
|---|---|
channelId / provider | 通道标识、所属通道商 |
kind | FIAT(银行卡/云闪付/支付宝/微信/VIPPAY/GOPAY)/ CRYPTO(链上) |
supportedCurrencies | 支持币种(加密含网络维度,如 USDT@TRC-20) |
capLimits | 通道级单笔/日累计上限(平台风控线) |
status | 可用 / 维护中 |
平台维护目录;子平台在 deposit.channels 内选用与排序(§五)。
2.2 充值订单 DepositOrder(状态机)
| 字段 | 说明 |
|---|---|
orderId / tenantId / userId | 订单号(幂等键)、归属 |
currency / amount / fee | 本位币 baseCurrency(入账币种)、入账金额、手续费(通常 0) |
channelCurrency / paidAmount / lockedRate | 通道币种(可 ≠ 本位币)、实付金额、下单锁价快照(同币种=1,→ §三.2bis)。06 成长值折入引用此 lockedRate 快照 |
channelId | 所走通道 |
promoId | 下单时选择参与的充值活动(可空,→ 09) |
network / address / txHash | 加密专属:网络、收款地址、链上哈希 |
externalRef | 通道方订单号(回调对账键) |
state / expiredAt / paidAt / creditedAt | 状态与时间戳 |
创建订单 支付完成/链上见块 确认数达标(加密)
● ──────► PENDING(待支付) ──────► CONFIRMING(确认中) ──────► SUCCESS(已入账)
│ │ │ ▲
超时未付│ │用户取消 │通道失败 │法币回调验签通过直达
▼ ▼ ▼ │(法币无 CONFIRMING)
EXPIRED CANCELLED FAILED ──后台补单工单────┘| 流转 | 触发 | 动作 |
|---|---|---|
| → SUCCESS | 回调验签通过(法币)/ 确认数达标(加密) | DEPOSIT_CREDIT(02,幂等键=orderId)→ 发 DepositSucceeded |
| → EXPIRED | expiredAt 到期未支付 | 释放收款地址占用(加密) |
| FAILED → SUCCESS | 后台补单(实付未回调,双人复核工单) | 同上,幂等键仍为 orderId |
2.3 加密收款地址
每用户 × 币种 × 网络分配专属收款地址(地址池 / HD 派生,选型归开放问题);地址与用户绑定后长期复用,凭地址归集识别付款人。
三、业务规则
- 通道与本位币解耦:充值通道币种
channelCurrency与账户本位币baseCurrency相互独立——CNY 站可收 USDT/ETH/BTC 通道,USDT 站可收 CNY 等通道;站内单账户,通道展示不随站型收窄,该站wallet.depositChannelCurrencies(→ 02 §四)内的全部已配置通道恒展示。展示层按「充值类型 → 充值渠道 → 金额」三级组织(→ design/modules/wallet.md):- 类型 = 支付大类(6):
数字钱包 / 虚拟货币 / 支付宝 / 微信 / 银行卡 / 云闪付; - 渠道 = 大类下的具体通道(各带限额/标签/形态):数字钱包 → VIPPAY/GOPAY/OKPAY/波币/NO钱包/TOPAY/万币/UPAY/K豆/JJPAY/808钱包/365钱包/HD钱包/C币钱包/SPAY钱包/TGPAY钱包…;虚拟货币 → USDT(官方)置顶(唯一自有渠道,页内生单)/USDT扫码/USDT转账/USDT大额/USDT小额/ETH扫码/ETH大额/BTC扫码/BTC大额(除官方外全部三方,跳外部收银台;ETH/BTC 为渠道级币种覆盖)…;支付宝 → 小额支付宝1/小额支付宝2/支付宝扫码/大额支付宝/支付宝金条;微信 → 小额微信1/小额微信2/微信扫码/大额微信…;银行卡 → 银行卡转账;云闪付 → 云闪付扫码/转卡。 1bis. 通道形态(三种,决定下单后的支付要素):① 收银台跳转(数字钱包/支付宝/微信/云闪付主流通道);② 平台收款账户转账(银行卡:下单后动态分配收款卡,展示 收款银行/户名/卡号/转账附言码,并生成含唯一识别尾数的转账金额(如 ¥500.38,双保险自动核销),要求按该金额足额转账 + 附言必填);③ 链上地址(虚拟货币:地址/网络/确认数,按实收入账)。
- 类型 = 支付大类(6):
- 金额校验:限额以当前通道为准(min/max);快捷金额 presets 按通道币种取配置并落在通道区间内。 2bis. 充值边界锁价(下单锁价,落地 02 §3.2):通道币种 ≠ 本位币时,
credited = paid × lockedRate(入账 = 实付 × 锁价);lockedRate于下单时点取自平台汇率源并锁定入订单,订单有效期内以此结算,订单超时/取消关闭后即失效,重新下单重新询价;该快照仅作本单记账/统计,不构成站内可复用汇率(→ 02 §3.1 无汇率铁律);展示层「获得金额」按当前参考价预估、下单即锁定。同币种(通道币种 = 本位币)lockedRate = 1,无换算行。 - 回调幂等:回调必验签;以
(tenantId, channelId, externalRef)唯一约束防重放;入账以orderId为幂等键,重复回调不重复入账。 - 金额一致性(含跨币种取价,闭环 §三.2bis):实付金额 ≠ 订单金额时(常见于链上任意额转账):加密按实收金额入账并修正订单;法币金额不符 → FAILED 转人工。跨币种链上充值的折算口径:订单有效期内到账,
credited = 实收金额(通道币种)× 下单 lockedRate——即超额/少额部分一律沿用下单锁价(不因实收额变动重新询价),lockedRate自下单锁定、订单存续期内恒定;06 成长值折入同引用该单lockedRate,与入账口径一致。超期到账(expiredAt后 EXPIRED 单收到链上付款):不沿用已失效锁价,转入后台补单工单按到账时点重新询价锁价后入账(双人复核,→ §五manualCredit)。同币种通道lockedRate = 1,无此歧义。 - 首充标记:
DepositSucceeded载荷带isFirstOverall(该租户首笔成功充值)与isFirstOfKind(法币/加密各自首笔),供 09 的「首存 / 钱包首次入款 / 虚拟币首次入款」判定(细则归 09)。 - 活动联动(可叠加):渠道加赠(通道属性,直接计入
credited入账)与充值类活动奖励(09,按活动rewardTarget入彩金/可用)可叠加、互不冲抵;展示层「获得金额」仅含渠道加赠,活动奖励在奖励中心领取。下单可选promoId;SUCCESS 后由 09 校验发放。 6bis. 渠道加赠bonusPct语义与成本护栏(平台侧充值加赠):bonusPct一律是平台侧加赠——无论官方自有渠道还是三方托管渠道,平台只以实际到账口径(官方链上=实收金额;三方=回调确认金额)为基数,在入账时由平台补入credited(credited = 到账基数 × lockedRate ×(1 + bonusPct)),即平台自贴成本、非三方多给;三方渠道回调金额本身不含加赠。故加赠是可控成本项,受平台风控护栏约束:bonusPct ≤ deposit平台风控上限(Schema 校验),并受deposit.bonusBudget(加赠总额/单笔上限,达上限该渠道加赠自动置 0,→ §四、17 成本域实时对照)兜底,bonusPct=0的渠道无加赠、展示不出「+x%」角标。与 09 充值活动奖励的边界:二者均为平台成本、可叠加互不冲抵(§三.6),加赠在入账即时补入、活动奖励在奖励中心领取。 - 风控:大额/高频充值触发 14 异步画像;充值本身不设同步门(资金流入),但可疑来源标记账户。
四、★ 租户可配置项(deposit 命名空间;原型 WXTYPES/WXPRE/CONFIG.fx 即其配置化形状)
jsonc
"deposit": {
"types": [ // 充值类型(6 大类:数字钱包/虚拟货币/支付宝/微信/银行卡/云闪付)
{ "key": "ewallet", "name": "数字钱包", "sub": "笔笔加赠", "tag": "推荐", "currency": "CNY",
"channels": [ // 渠道 = 大类下具体通道;icon 短标/色随素材配置
{ "name": "VIPPAY", "min": 100, "max": 50000, "bonusPct": 2, "form": "cashier" },
{ "name": "OKPAY", "min": 100, "max": 100000, "bonusPct": 2, "form": "cashier" },
{ "name": "K豆", "min": 50, "max": 20000, "bonusPct": 0, "form": "cashier" }
/* …Global 现行 16 渠道 */ ] },
{ "key": "crypto", "name": "虚拟货币", "sub": "链上直充", "tag": "安全", "currency": "USDT",
"channels": [
{ "name": "USDT(官方)", "official": true, "min": 1, "max": 500000, "bonusPct": 2, "form": "chain", "net": "TRC-20", "confirms": 19 },
{ "name": "USDT扫码", "min": 10, "max": 50000, "bonusPct": 1.5, "form": "chain", "net": "TRC-20", "confirms": 19 },
{ "name": "USDT大额", "min": 1000, "max": 500000, "bonusPct": 2, "form": "chain", "net": "ERC-20", "confirms": 12 },
{ "name": "ETH扫码", "currency": "ETH", "min": 0.01, "max": 20, "bonusPct": 1.5, "form": "chain", "net": "Ethereum(ERC-20)", "confirms": 12 },
{ "name": "BTC大额", "currency": "BTC", "min": 0.5, "max": 50, "bonusPct": 2, "form": "chain", "net": "Bitcoin 主网", "confirms": 2 }
/* …渠道级 currency 覆盖类型 currency(缺省继承);金额输入/区间/快捷额均按渠道币种。
official=true 仅 USDT(官方):页内生成链上收款要素(形态③);其余链上渠道皆三方,走形态①跳外部收银台 */ ] },
{ "key": "alipay", "name": "支付宝", "sub": "一键支付", "tag": "极速", "currency": "CNY", "channels": [ /* 小额1/小额2/扫码/大额/金条 */ ] },
{ "key": "wechat", "name": "微信", "sub": "方便快捷", "tag": "稳定", "currency": "CNY", "channels": [ /* 小额1/小额2/扫码/大额 */ ] },
{ "key": "bank", "name": "银行卡", "sub": "大额转账", "currency": "CNY",
"channels": [ { "name": "银行卡转账", "min": 500, "max": 200000, "form": "bankTransfer" } ] },
{ "key": "unionpay", "name": "云闪付", "sub": "银联扫码", "currency": "CNY", "channels": [ /* 扫码/转卡 */ ] }
],
"typeTags": ["推荐", "极速", "安全", "稳定"], // 类型标签四词制;渠道角标只标 bonusPct
"presets": { "CNY": [30, 50, 100, 200, 500, 1000, 3000, 5000], "USDT": [50, 100, 500, 1000, 3000, 5000], "ETH": [0.05, 0.1, 0.5, 1, 3, 5, 10, 20], "BTC": [0.005, 0.01, 0.05, 0.1, 0.5, 1, 2, 5] }, // 快捷额按渠道币种取表,再按渠道区间过滤;默认选中 500 优先(无 500 取首项)
"orderExpireMinutes": 30,
"amountFingerprint": true, // bankTransfer:生成含唯一识别尾数的转账金额(+附言双保险核销)
"bonusBudget": { "perOrderCap": { "CNY": "500", "USDT": "80" }, "totalCap": { "CNY": "0", "USDT": "0" } }, // 渠道加赠成本护栏(本位币):单笔封顶 + 周期总额(0=不限);达总额上限该渠道 bonusPct 自动置 0(§三.6bis,17 成本域对照)
"marquee": true // 跑马灯(权威活动摘要,点击跳优惠中心)
},
"fx": { "source": "platform-rate-svc", "usdtCny": 7.16, "rates": { "USDT": { "CNY": 7.16 }, "ETH": { "USDT": 2600 }, "BTC": { "USDT": 65000 } } } // 平台汇率源(非直连币对经 USDT 中转);仅边界询价用,**lockedRate 下单锁定**(§三.2bis);非站内牌价、站内不复用(→ 02 §3.1)Schema 校验:types[].key ∈ 六大类枚举;tag ∈ typeTags;渠道 min < max;form ∈ cashier | bankTransfer | chain(chain 必带 net/confirms);bonusPct ≤ 平台风控上限;presets 币种 ⊆ 引擎币种目录。
五、与其他系统的关系 / 接口
| 接口 | 调用方 | 幂等键 | 说明 |
|---|---|---|---|
createOrder(userId, channelId, paidAmount, promoId?) | 展示层 | 客户端单号 | 通道币种由 channelId 决定,入账币种恒本位币;返回订单 + 支付要素(跳转参数 / 地址二维码)+ lockedRate(跨币种) |
channelCallback(payload, sign) | 通道商 | externalRef | 验签 → 推进状态机 → 入账 |
queryOrder(orderId) / listOrders(userId, filter) | 展示层 / 13 | — | 状态查询、充值记录 |
manualCredit(orderId, ticketId) | 15 后台 | orderId | 补单(双人复核工单后执行) |
事件:产 DepositSucceeded(→ 02/06/09/11/16/17)。
六、运营后台能力(→ 15)
| 侧 | 能力 |
|---|---|
| 平台控制台 | 通道目录与 PSP 接入、通道费率与风控线、通道健康监控 |
| 商户控制台 | 本站通道开关/排序/限额/快捷金额;订单查询(按状态/用户/单号);补单工单(实付未到账,双人复核);充值汇总(→ 17) |
七、展示契约(→ 原型映射)
| UI 元素 | 数据 | 原型载体 | 系统契约 |
|---|---|---|---|
| 头部两态 | WX_FROM 来源栈 | body.wallet-head / wallet-pushed:底导进入(根)=平台 logo + 居中「充值中心」+ 🎧 客服;页内/游戏/活动 CTA 进入 = ‹ 返回(各回来源) | CTA 进入为推入页形态(隐藏底导);来源栈决定返回落点 |
| 余额卡 | 本位币余额 | #wal-bal:行1「我的余额 …🧾充值记录」;行2「本位币符号 + 金额 + 👁 + [提现]」 | 单币种站只显示本位币,符号与提现模块一致(恒本位币,→ 02 §七) |
| 跑马灯 | 活动摘要 | .wx2-marquee[data-tab=promo] | 权威活动摘要,点击跳优惠中心 |
| 类型九宫格 | deposit.types | WXTYPES ← deposit.types:3 列大卡 + 四词标签,默认选中首类型 | 6 大类恒全量(与站型解耦,通道币种可 ≠ 本位币) |
| 渠道行 | bonusPct | 5 列图标豆腐块 + 加赠角标(+x%);默认选中首渠道 | 切换联动区间/预设/校验;角标仅标 bonusPct>0(平台侧加赠,§三.6bis) |
| 金额区 | presets + 通道区间 | 大字输入 + 通道区间 + 预设(区间内过滤,默认 500 优先)+ 越界即时红字 | 快捷额按渠道币种取表再按区间过滤(§三.2) |
| 获得金额 | lockedRate + bonusPct | 一行式「获得金额(含渠道加赠 +x%) 本位币符号」;跨币种附「参考汇率 · 下单后锁定本单汇率」行 | = 到账基数 ×(lockedRate)×(1+加赠),round2 防浮点(500×1.5%=507.5);汇率行明示本单锁价、非站内牌价 |
| CTA | 通道形态 | fixCtaBar():固定置底(按 tabbar 实高自适应,推入态贴底);文案随形态 | 立即充值 / 获取收款账户 / 生成充值订单(对应形态①②③) |
| 订单卡(下单即锁) | 订单快照 + lockedRate | wxOrderShow + wxOpenCashier()(原型外部页=cashier.html),骨架 WX_ORDER_TPL:单号 + 支付金额(+到账约,含加赠)+ 类型·渠道 +(跨币种)本单汇率(已锁定)+ 30 分倒计时,订单存续期表单收起 | 三形态要素:①三方收银台=下单即新窗口跳外部支付页(页内:支付方式行+我已完成支付+重开链接+取消)②银行卡=收款银行/户名/卡号/转账金额(含识别尾数)/附言码(均可复制)③官方链上=网络/地址/确认数;①=三方托管页(数字钱包/支付宝/微信/云闪付 + 非官方链上),②③=平台自有页内生成(银行卡转账 + USDT官方) |
| 支付成功闭环 | 入账金额(本位币) | wxPaySuccess():去支付/我已完成转账 → 等待回调 → 成功卡(✓ 已到账/单号/入账金额本位币) | = DEPOSIT_CREDIT + DepositSucceeded 语义;余额卡/顶部胶囊/我的/充值记录四处联动+「活动奖励另计」提示 |
| 失败挽留 | 同通道币种渠道 | wxShowRetry():超时/取消 → 横幅推荐高成功率渠道一键重下(带原金额)+ 联系客服 | 推荐同通道币种渠道(关单后 lockedRate 失效需重下重询价) |
| 充值记录页 | WXREC.dep | #sub-txn:独立页标题居中;三下拉(类型 × 状态[已到账/待入账/已超时/已撤销] × 时间[今日默认/昨日/近7日]);详情页超时态带联系客服 | 金额恒本位币入账值(跨币种单据可展开原通道币种实付 + 锁价快照);mock 含跨币种锁价/加赠/附言样本 |
演示/调试钩子:?kyc=1(后台对该账户要求实名)&kycst=…(KYC 预置态)&go=withdraw(直达提现);支付回调以 2.6s 定时器模拟(生产 = channelCallback)。
八、数据库设计(全表含 tenant_id;金额 DECIMAL(32,8))
| 表 | 关键字段 | 约束/索引 |
|---|---|---|
payment_channels(平台级) | channel_id PK, provider, kind, supported_currencies JSON, cap_limits JSON, status | — |
deposit_orders | order_id PK, tenant_id, user_id, currency(本位币,入账币种), amount(本位币入账额), fee, channel_currency(通道币种,可 ≠ 本位币), paid_amount(通道币种实付), locked_rate(下单锁价快照,同币种=1), channel_id, promo_id, network, address, tx_hash, external_ref, state, expired_at, paid_at, credited_at, created_at | UK(tenant_id,order_id);IDX(tenant_id,user_id,created_at);IDX(tenant_id,state) |
deposit_callbacks | id PK, tenant_id, channel_id, external_ref, payload JSON, verify_result, created_at | UK(tenant_id,channel_id,external_ref) |
crypto_addresses | id PK, tenant_id, user_id, currency, network, address, status | UK(address);UK(tenant_id,user_id,currency,network) |
九、扩展点与开放问题
- 地址方案:HD 派生 vs 地址池租用 vs 通道商代收,涉及归集成本与安全,基建选型定。
- 确认数:各币种/网络确认阈值属平台参数(如 TRC-20 USDT=19 块),是否开放租户收紧,待定。
- 边界锁价 vs 站内无汇率:通道币种 = 本位币时按原额入账、无折算;通道币种 ≠ 本位币时按下单
lockedRate折入本位币(边界锁价,02 §3.2)——快照仅记本单,站内不复用为牌价、不做站内币币兑换(02 §3.3,明确不做)。 - 通道熔断:通道成功率监控与自动切换,归平台侧运维。
十、验收要点
- [ ] 同一回调重放 100 次只入账一次;
orderId与账变biz_key一一对应;入账币种恒本位币; - [ ] 订单超时自动 EXPIRED,支付要素失效;
- [ ] 链上实付 ≠ 订单额时按实收入账且订单金额被修正;
- [ ] 补单必经双人复核工单,且与自然回调互斥幂等;
- [ ]
isFirstOverall/isFirstOfKind各只为 true 一次(并发充值下仍唯一); - [ ] CNY 站 / USDT 站类型九宫格完全一致(通道与站型解耦);通道币种 ≠ 本位币时「获得金额」按
lockedRate+ 加赠折入本位币(507.5 精度案例); - [ ] 订单卡锁价行仅跨币种出现且明示为本单锁价(非站内牌价);关单(超时/取消)后
lockedRate失效并出现同通道币种推荐渠道一键重下; - [ ] bankTransfer 订单生成唯一识别尾数金额 + 附言,双保险核销提示;
- [ ] 支付成功后 余额卡/顶部胶囊/我的/充值记录 四处联动一致(DepositSucceeded 演示);
- [ ] 渠道加赠计入入账且与充值活动奖励可叠加(提示到位)。