# 支付流程文档 ## 1. 概述 本文档描述 Android 项目(Flutter)的完整支付流程,包括商品获取、支付方式选择、订单创建、Google Play 内购以及补单机制。 --- ## 2. 支付流程总览 ``` 用户点击 Buy │ ├─ enableThirdPartyPayment === true 且已登录 │ │ │ ├─ getPaymentMethods(activityId) 获取支付方式 │ ├─ 弹窗选择支付方式 │ ├─ createPayment 创建订单 │ │ │ ├─ 若选中的是 Google Pay │ │ ├─ 调起 Google Play 内购 │ │ ├─ 拿到 purchaseData + signature │ │ └─ googlepay 回调验证 │ │ │ └─ 否则(其他支付方式) │ └─ 打开 payUrl 在外部浏览器完成支付 │ └─ enableThirdPartyPayment !== true 或未登录 └─ 仅 Android:直接调起 Google Play 内购 ``` --- ## 3. 支付分支依据 | 条件 | 说明 | |------|------| | `UserState.enableThirdPartyPayment` | 登录后由 AuthService 从 `/v1/user/common_info` 响应写入 | | `UserState.userId` | 用户登录后存储的用户 ID | | **第三方支付** | `enableThirdPartyPayment == true` 且 `userId` 非空 | | **直接谷歌支付** | 其他情况(未开第三方支付或未登录)| --- ## 4. 商品展示与获取 ### 4.1 接口 ```dart // Android(app 默认 backendAppTypeAndroid,可传 client) final res = await PaymentApi.getGooglePayActivities( country: '国家', // 可选 ); // iOS(app 默认 backendAppTypeIOS) final res = await PaymentApi.getApplePayActivities( country: '国家', // 可选 ); ``` ### 4.2 返回实体 ```dart class PaymentProductsResponse { List? productList; } class PaymentProductItem { String? productId; // 商品 ID (对应 helm) String? activityId; // 活动 ID (对应 warrior) String? actualAmount; // 实际金额 (对应 guardian) String? originAmount; // 原价 (对应 curriculum) int? bonus; // 赠送积分 (对应 forge) String? title; // 标题 (对应 glossary) } ``` --- ## 5. 第三方支付流程 ### 5.1 获取支付方式 ```dart final res = await PaymentApi.getPaymentMethods( activityId: 12345, // int country: '国家', // 可选 ); if (res.isSuccess) { final methods = res.data!.paymentMethods; // methods 包含: // - paymentMethod: 支付方式 (如 GOOGLEPAY) // - subPaymentMethod: 子支付方式 // - name: 显示名称 // - icon: 图标 URL // - recommend: 是否推荐 } ``` ### 5.2 创建订单 ```dart final res = await PaymentApi.createPayment( app: 'HAndroid', // HIOS / HAndroid userId: '用户ID', activityId: '活动ID', paymentMethod: '支付方式', paymentType: '支付子类型', // 可选 ); if (res.isSuccess) { final order = res.data!; final orderId = order.orderId; // 订单 ID final payUrl = order.payUrl; // 支付链接 } ``` ### 5.3 支付分支 - **Google Pay**: 调起内购 → 获取 purchaseData/signature → 调用 `googlepay` 回调 - **其他方式**: 打开 `payUrl` 在外部浏览器 --- ## 6. 直接谷歌支付流程 仅 Android,且不经过 `getPaymentMethods` 和 `createPayment`(三方支付关闭时): ```dart // 1. 创建订单(直接走谷歌支付) final createRes = await PaymentApi.createPayment( app: 'HAndroid', userId: '用户ID', activityId: '活动ID', paymentMethod: 'GooglePay', paymentType: 'GooglePay', ); // 2. 调起 Google Play 内购 final purchaseResult = await GooglePlayPurchaseService.launchPurchaseAndReturnData( productId: '商品ID', ); // 3. 回调验证 if (purchaseResult != null) { final res = await PaymentApi.googlepay( signature: purchaseResult.payload.signature, purchaseData: purchaseResult.payload.purchaseData, orderId: orderId ?? purchaseResult.orderId, userId: userId, ); } ``` --- ## 7. Google Play 内购统一入口 ### 7.1 调起内购 ```dart final result = await GooglePlayPurchaseService.launchPurchaseAndReturnData( productId: '商品ID', ); if (result != null) { // result.orderId: Google 订单号 // result.payload.purchaseData: 用于 merchant // result.payload.signature: 用于 signature // result.purchaseDetails: PurchaseDetails 对象 } ``` ### 7.2 回调验证 ```dart final res = await PaymentApi.googlepay( signature: result.payload.signature, purchaseData: result.payload.purchaseData, orderId: orderId, userId: userId, ); if (res.isSuccess) { // 核销订单 await GooglePlayPurchaseService.completeAndConsumePurchase( result.purchaseDetails, ); } ``` ### 7.3 响应实体 ```dart class GooglePayCallbackResponse { String? orderId; String? status; // SUCCESS / FAILED bool? creditsAdded; // 是否已加积分 } ``` --- ## 8. 补单机制 ### 8.1 触发时机 - 进入充值页时调用 `GooglePlayPurchaseService.runOrderRecovery()` ### 8.2 补单流程 1. 获取未核销订单: `getUnacknowledgedPurchases()` - 合并 `queryPastPurchases` 和 `purchaseStream` 的待处理订单 2. 对每笔订单: - 查询本地存储的 `federation` 映射 - 若存在 federation: 调用 `googlepay` 回调 → 成功后 consume - 若无 federation: 仅执行 consume 解除「已拥有此内容」 3. 补单成功后刷新账户 --- ## 9. API 汇总 | 接口 | 方法 | 返回实体 | |------|------|----------| | `getGooglePayActivities` | GET | `PaymentProductsResponse` | | `getApplePayActivities` | GET | `PaymentProductsResponse` | | `getPaymentMethods` | POST | `PaymentMethodsResponse` | | `createPayment` | POST | `CreatePaymentResponse` | | `getPaymentDetailList` | GET | `PaymentOrderListResponse` | | `getOrderDetail` | GET | `OrderDetailResponse` | | `googlepay` | POST | `GooglePayCallbackResponse` | --- ## 10. 字段映射说明 框架自动完成字段映射,调用层使用原始字段名。 ### 请求 → 响应 字段对照 | 业务含义 | 请求字段 | 响应字段 | |----------|----------|----------| | 应用 ID | app | - | | 用户 ID | userId | - | | 活动 ID | activityId | - | | 支付方式 | paymentMethod | - | | 支付子类型 | paymentType | - | | 订单 / 支付 ID(详情 query) | `id`(Dart 仍用参数名 orderId) | orderId | | 购买签名 | signature | - | | 购买数据 | purchaseData | - | | 商品 ID | - | productId | | 实际金额 | - | actualAmount | | 原价 | - | originAmount | | 赠送积分 | - | bonus | | 支付链接 | - | payUrl | | 订单状态 | - | status | --- ## 11. 代码文件位置 | 功能 | 文件路径 | |------|----------| | 充值页面 | `lib/features/recharge/recharge_screen.dart` | | 支付 API | `lib/core/api/services/payment_api.dart` | | Google Play 内购服务 | `lib/features/recharge/google_play_purchase_service.dart` | | 支付方式模型 | `lib/features/recharge/models/payment_method_item.dart` | | 商品模型 | `lib/features/recharge/models/activity_item.dart` | | 购买结果模型 | `lib/features/recharge/models/google_pay_purchase_result.dart` | | WebView 支付页 | `lib/features/recharge/payment_webview_screen.dart` | --- ## 12. 常见问题 ### 12.1 商品未找到 - 原因: 客户端 `productId` 与 Google Play 后台「产品 ID」不一致 - 排查: 检查 Play 后台产品 ID 配置 ### 12.2 补单 - 未确认订单可能不会出现在 `queryPastPurchases` 中 - 应用启动时订阅 `purchaseStream` 接收重新下发 - 补单会合并两者的待处理订单 --- ## 13. 注意事项 - 所有 Google Play 内购统一使用 `launchPurchaseAndReturnData()` 方法 - 回调验证成功后必须调用 `completePurchase` + `consumePurchase` - 支付 URL 打开方式取决于 `createPayment` 返回的 `payUrl` 字段 - 订单状态轮询: 间隔 1/3/7/15/31/63 秒