阅读主题
订单与演示支付
v0.2.0 已跑通本地订单、优惠券、钱包扣款与模拟资产到账。demo 不连接微信、支付宝或银行卡;wallet 消耗本地演示余额。界面显示支付成功,仅代表本地事务完成,不能作为真实收款或外部游戏发货凭据。
一次完整购买
先完成 服务端登录兑换,再使用已经持有玩家会话的 SDK 实例。商品与角色必须从当前玩家中心获取,不能在前端任意填写金额。
ts
const center = await sdk.center();
const product = center.products.find(item => item.kind === 'game_item');
if (!product) throw new Error('当前游戏暂无可购买商品');
// 一次购买意图只生成一次 requestId;网络重试保留它。
const requestId = crypto.randomUUID();
const order = await sdk.createOrder({
productId: product.id,
roleId: center.role.id,
paymentMethod: 'demo',
requestId,
});
const result = await sdk.payOrder(order.id);
if (result.status === 'fulfilled') {
const refreshed = await sdk.center();
// 使用 refreshed.role / wallet 刷新界面,不在客户端自行加钻石。
}示例中的 sdk 指已初始化并完成登录的当前实例。选择 wallet 时,先显示服务端返回的可用余额与订单实付金额;余额以整数最小单位计算,详见 钱包与平台币。
已实现接口
以下玩家接口使用 Authorization: Bearer <玩家会话>。它们是当前实现说明,尚未收录在本版仅覆盖登录核心的 OpenAPI 中。
| 操作 | HTTP 请求 | 请求与响应 |
|---|---|---|
| 玩家中心 | GET /api/center | 包含商品、角色、钱包、订单、流水 |
| 创建订单 | POST /api/orders | {productId, roleId, paymentMethod, couponId?, requestId};201 返回 Order |
| 确认演示支付 | POST /api/orders/{id}/pay | {requestId};返回 Order |
| 当前游戏订单列表 | GET /api/orders | 返回 {items: Order[]} |
| 查询订单 | GET /api/orders/{id} | 返回 Order |
| 关闭待支付订单 | POST /api/orders/{id}/close | SDK 发送 {};返回 Order |
| 演示退款 | POST /api/orders/{id}/refund | {requestId};返回 Order |
requestId 为 8~100 位字母、数字、下划线或连字符。服务端有操作幂等记录与订单状态校验。createOrder 可显式传入它;当前 SDK 的 payOrder、refundOrder 每次调用都会生成新值,重复操作还依赖订单状态防止重复扣款或退款。
创建订单只锁定价格快照与优惠券,不扣款。服务端验证商品启用状态、游戏归属、角色归属和优惠券可用性。priceCents、discountCents、amountCents 分别是原价、优惠与实付金额,单位均为分。
状态与网络异常
| 状态 | 含义 | 后续操作 |
|---|---|---|
pending | 待支付,优惠券可能已锁定 | 支付、关闭或超时关闭 |
paid | 内部已确认支付阶段 | 当前本地事务通常立即继续履约 |
fulfilled | 本地商品效果已生效 | 查询结果或按规则退款 |
closed | 未支付订单已关闭 | 重新下单 |
refunded | 本地退款与资产回退完成 | 不得再次支付 |
待支付有效期 30 分钟。过期关闭由玩家中心、订单查询、下单与支付等访问触发,当前没有独立超时调度器。不能据此承诺在第 30 分钟准时推送关单事件。
支付响应丢失时,先按订单 ID 查询。已 fulfilled 则刷新资产;仍 pending 才继续原订单支付;已 closed 则重新下单。不要因超时立刻创建多笔替代订单。下单超时应以同一请求内容和 requestId 重试。
优惠与退款规则
优惠券必须已领取、属于当前游戏、未过期且达到门槛。下单锁券,支付用券,关闭释放券。平台币充值不支持优惠券,也不能用平台币为自己充值。
退款是本地可逆操作:游戏商品须仍有足够可回收钻石;平台币充值须仍有足够的原付费币与赠币;钱包购买按原扣款桶退回。月卡已领取每日权益不能退款,存在后续续费时须先处理最新订单。退回的优惠券若已过期,仍按过期规则展示。
| 错误码 | 处理方式 |
|---|---|
PRODUCT_UNAVAILABLE | 刷新商品列表,提示商品已下架 |
COUPON_UNAVAILABLE / COUPON_EXPIRED | 重新选择可用券,不静默更改用户实付金额 |
COUPON_THRESHOLD | 提示未达到门槛 |
INSUFFICIENT_BALANCE | 刷新钱包并让用户重新选择支付方式 |
ORDER_NOT_PAYABLE / ORDER_EXPIRED | 查询订单最终状态,必要时重新下单 |
ASSET_CONSUMED / BENEFIT_CONSUMED | 提示资产或权益已使用,不能按演示规则退款 |
MEMBERSHIP_CHANGED | 先核查后续续费订单 |
验收步骤
- 购买一笔游戏商品,检查订单仅一条、钻石仅增加一次,重复支付不重复到账。
- 使用钱包支付,核对订单实付与两类余额扣减之和一致。
- 下单锁券后关闭,确认优惠券恢复可用;退款后再次核对券状态。
- 在可回收资产充足时退款,再次退款不重复返还;消耗资产后退款应被拒绝。
- 切换另一逻辑游戏,确认不能读取或支付原游戏订单。H5、Android、iOS 与 Windows 属于同一逻辑游戏时共享该游戏身份。
真实支付需要独立的签名回调、查单、对账、异步履约与退款流程,见 生产接入边界。
实现依据
packages/server/src/app.ts:玩家订单路由、请求校验、过期订单清理。packages/server/src/platform.ts:createOrder、payOrder、closeOrder、refundOrder,本地事务与资产变更。packages/contracts/src/index.ts:Order、Product、PaymentMethod、OrderStatus。packages/sdk/src/index.ts:订单 SDK 方法及请求 ID 生成。