微信支付分业务开发流程.md 11 KB

微信支付分整体业务开发流程

一、流程总览

商户创建支付分订单
    ↓
商户调用支付分创建接口  POST /v3/payscore/serviceorder
    ↓
创建支付分订单成功(state: CREATED)
    ↓
用户确认支付分订单(PAYSCORE.USER_CONFIRMED 回调 → state: DOING)
    ↓
商户拉起支付分小程序确认订单页面
    ↓
用户确认订单
    ↓
商户向用户提供服务
    ↓
┌─────────────────────┬─────────────────────┐
│ 服务开启异常         │ 服务开启成功         │
│ ↓                   │ ↓                   │
│ POST .../cancel     │ 服务结束             │
│ 取消支付分订单        │ ↓                   │
│                     │ POST .../complete    │
│                     │ 完结支付分订单        │
└─────────────────────┴─────────────────────┘
                          ↓
                      POST .../pay
                      商户发起扣款
                          ↓
                微信支付持续周期性扣款
                          ↓
        ┌───────────────┴───────────────┐
        │                               │
      扣款成功                      扣款失败
        │                               │
        ↓                               ↓
PAYSCORE.USER_PAID 回调        商户引导用户主动支付
        │                               │
        ↓                     ┌─────────┴─────────┐
支付分订单结束                │                   │
                             ↓                   ↓
                   跳转支付分订单详情页     其他方式完成支付
                             ↓                   ↓
                       收银台支付          POST .../sync
                             ↓           同步订单信息
                       支付成功回调           ↓
                             ↓           支付分订单结束
                       支付分订单结束

    ↓
   对账
    ├─ 商户平台下载交易账单
    └─ API接口下载交易账单

    ↓
   退款
    ├─ POST .../pay/refund  申请退款
    └─ GET  .../pay/refund/{id}  查询退款
            ↓
         退款成功

二、API 接口清单

步骤 方法 接口 说明
1. 创建订单 POST /v3/payscore/serviceorder 创建支付分服务订单
2. 查询订单 GET /v3/payscore/serviceorder/{out_order_no} 查询服务订单状态
3. 取消订单 POST /v3/payscore/serviceorder/{out_order_no}/cancel 服务开启异常时取消
4. 完结订单 POST /v3/payscore/serviceorder/{out_order_no}/complete 服务结束后完结订单
5. 修改订单 POST /v3/payscore/serviceorder/{out_order_no}/modify 修改订单金额(仅可下调)
6. 发起扣款 POST /v3/payscore/serviceorder/{out_order_no}/pay 发起支付扣款(创单结单)
7. 同步信息 POST /v3/payscore/serviceorder/{out_order_no}/sync 用户已通过其他方式支付时同步
8. 申请退款 POST /v3/payscore/serviceorder/{out_order_no}/pay/refund 对已支付订单申请退款
9. 查询退款 GET /v3/payscore/serviceorder/{out_order_no}/pay/refund/{out_refund_no} 查询退款状态

依赖

  • SDK: com.github.wechatpay-apiv3:wechatpay-java:0.2.17
  • Base URL: https://api.mch.weixin.qq.com/v3/payscore/serviceorder

三、关键回调事件

事件类型 说明 本地处理
PAYSCORE.USER_CONFIRMED 用户确认使用服务 订单状态 → DOING
PAYSCORE.USER_PAID 用户完成支付 订单状态 → COMPLETED,支付状态 → PAID
PAYSCORE.REFUND_PAID 退款到账通知 更新退款状态
PAYSCORE.USER_CANCEL 用户取消订单 订单状态 → CANCELLED

四、订单状态流转

微信侧状态

CREATED ──→ DOING ──→ DONE
                │
                └──→ USER_PAYING(等待用户支付)
                └──→ EXPIRED(过期)
                └──→ REVOKED(撤销)

本地订单状态

字段 说明
pay_score_state CREATED 已创建服务订单
DOING 用户已确认,服务进行中
DONE 已完结并扣款成功
USER_PAYING 已完结,等待用户支付
EXPIRED 已过期
REVOKED 已撤销
pay_status UNPAID 未支付
PAID 已支付
REFUND 已退款
status PENDING 待处理
COMPLETED 已完成
CANCELLED 已取消

五、代码实现层次

PayScoreService (接口)
    └── PayScoreServiceImpl (业务逻辑 + 订单状态管理)
            └── PayScoreStrategy (策略接口,支持多渠道)
                    └── WxPayScoreStrategy (微信支付分实现,HTTP 调用)

5.1 创建订单

接口: PayScoreService.createPayScoreOrder(orderId, openId)

// PayScoreServiceImpl.java
PayScoreCreateRequest request = new PayScoreCreateRequest();
request.setOutOrderNo(generateOutOrderNo(orderId));  // "PS" + timestamp + orderId
request.setServiceId(wxPayConfig.getServiceId());
request.setOpenId(openId);
request.setRiskFundAmount(riskFundAmount);
// ... 设置服务时间、位置、后付费项目等

PayScoreResult result = payScoreStrategy.createServiceOrder(request);
// 成功后将 outOrderNo 存入 order.payScoreOrderId

outOrderNo 生成规则: "PS" + 秒级时间戳(10位) + orderId,总长度 ≤ 32 字符。

5.2 完结订单

接口: PayScoreService.completePayScoreOrder(orderId, totalAmount, payments, discounts)

服务结束后调用,标记服务完成并触发扣款。

PayScoreCompleteRequest request = new PayScoreCompleteRequest();
request.setOutOrderNo(order.getPayScoreOrderId());
request.setTotalAmount(totalAmount);
request.setPostPayments(payments);   // 后付费项目列表
request.setPostDiscounts(discounts); // 后付费优惠
request.setEndTime(formatDateTime(LocalDateTime.now()));

PayScoreResult result = payScoreStrategy.completeServiceOrder(request);

5.3 发起扣款

接口: PayScoreService.payPayScoreOrder(orderId)

重要: 必须先调用此接口,退款接口 /pay/refund 才会可用。/pay/pay/refund 的父资源,不调 /pay 直接退款会返回 404

// 请求体
{
  "appid": "wx...",
  "service_id": "0000400000..."
}
// 响应
{
  "out_order_no": "PS..."
}

5.4 取消订单

接口: PayScoreService.cancelPayScoreOrder(orderId, reason)

服务开启异常时调用,取消支付分订单并释放授权。

PayScoreCancelRequest request = new PayScoreCancelRequest();
request.setOutOrderNo(order.getPayScoreOrderId());
request.setReason(reason);
PayScoreResult result = payScoreStrategy.cancelServiceOrder(request);

5.5 修改金额

接口: PayScoreService.modifyPayScoreOrder(orderId, totalAmount, payments, reason)

仅在 USER_PAYING 状态可调用,金额只能下调。

5.6 同步订单

接口: PayScoreService.syncOrderPaidInfo(orderId, detail)

用户通过其他方式(如收银台)完成支付后,调用此接口同步信息给微信,停止周期性扣款。

// 请求体
{
  "appid": "wx...",
  "service_id": "0000400000...",
  "type": "ORDER_PAID",
  "detail": { "paid_time": "2026-06-25T12:40:00+08:00", "amount": 265 }
}

5.7 申请退款

接口: PayScoreService.refundPayScoreOrder(orderId, refundAmount, reason)

前置条件:

  • 订单 payStatus = PAID(已支付)
  • 距支付时间不超过 7 天
  • 已调用 /pay 接口发起扣款(否则返回 404)

    // 先确保 /pay 资源存在
    payScoreStrategy.payServiceOrder(order.getPayScoreOrderId());
    
    // 再调用退款
    PayScoreRefundRequest request = new PayScoreRefundRequest();
    request.setOutOrderNo(order.getPayScoreOrderId());
    request.setRefundAmount(actualRefundAmount);
    request.setReason(reason);
    
    PayScoreResult result = payScoreStrategy.refundServiceOrder(request);
    

5.8 查询退款

接口: PayScoreService.queryPayScoreRefund(orderId, outRefundNo)

payScoreStrategy.queryRefund(order.getPayScoreOrderId(), outRefundNo);

六、Redis 预授权机制

为了优化用户体验,项目支持预创建支付分订单

用户扫码 → 预创建支付分订单 → 存入 Redis(TTL 10分钟)
     ↓
用户选择商品 → 从 Redis 取出预授权信息 → 关联到实际订单
Redis Key 说明 TTL
payscore:preauth:{deviceId} 预授权信息(outOrderNo, state) 10 分钟
payscore:preauth:tracking:{userId} 用户预授权跟踪(Set) 24 小时

预授权流程

  1. 用户扫码 → preCreatePayScoreOrder(userId, deviceId, openId)
  2. 创建支付分订单 → 存 Redis
  3. 自动取消该用户/设备下的旧未使用预授权
  4. 用户下单 → applyPreAuthPayScore(order) 取出关联

七、常见错误码

错误码 说明 处理建议
404 NOT_FOUND 服务订单不存在或未支付 确认 outOrderNo 正确,确认已调 /pay 接口
ORDER_PAID 订单已支付 不需要重复操作
ORDER_DONE 订单已完结 不需要重复操作
PARAM_ERROR 参数错误 检查请求参数格式
SIGN_ERROR 签名验证失败 检查证书配置
FREQUENCY_LIMITED 频率超限 降低调用频率

八、注意事项

  1. /pay 必须在退款前调用:退款接口 URL 为 /pay/refund,是 /pay 资源的子资源。不调 /pay 直接退款会返回 404。
  2. 退款期限:支付完成后 7 天内可退款,超期需走其他流程。
  3. 金额单位:微信 API 金额单位为,代码中使用 yuanToFen() 转换。
  4. outOrderNo 限制:≤ 32 字符,项目使用 PS + 时间戳 + orderId 格式(31 字符)。
  5. 回调验签:收到微信回调时必须验证签名,防止伪造通知。
  6. 幂等性:创建订单的 out_order_no 需保证唯一,重复使用会返回已有订单信息。