# 微信集成 API 文档

本文档详细说明微信 OAuth 登录和微信支付相关的 API 接口。

## 目录

- [认证说明](#认证说明)
- [错误码](#错误码)
- [API 接口](#api-接口)
  - [1. 微信 OAuth 登录](#1-微信-oauth-登录)
  - [2. 绑定微信账号](#2-绑定微信账号)
  - [3. 微信 JSAPI 支付](#3-微信-jsapi-支付)
  - [4. 微信 H5 支付](#4-微信-h5-支付)
  - [5. 微信支付回调](#5-微信支付回调)

---

## 认证说明

### 公开接口

以下接口无需认证，可直接调用：

- `POST /api/c/v1/wechat/auth` - 微信 OAuth 登录
- `POST /api/callback/wechat-pay` - 微信支付回调

### 需要认证的接口

以下接口需要在请求头中携带 JWT Token：

```
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
```

- `POST /api/c/v1/bind-wechat` - 绑定微信账号（个人客户）
- `POST /api/h5/orders/:id/wechat-pay/jsapi` - 微信 JSAPI 支付（H5认证）
- `POST /api/h5/orders/:id/wechat-pay/h5` - 微信 H5 支付（H5认证）

---

## 错误码

微信集成相关的错误码：

| 错误码 | 说明 | HTTP 状态码 |
|--------|------|-------------|
| 1044 | 微信 OAuth 授权失败 | 400 |
| 1045 | 获取微信用户信息失败 | 400 |
| 1046 | 微信支付失败 | 400 |
| 1047 | 微信支付回调数据无效 | 400 |
| 1003 | 参数无效 | 400 |
| 1020 | 手机号已被使用 | 400 |
| 1021 | 个人客户不存在 | 404 |
| 1035 | 订单不存在 | 404 |

---

## API 接口

### 1. 微信 OAuth 登录

通过微信授权码登录或创建账号。如果用户首次登录，系统会自动创建账号。

**接口地址**

```
POST /api/c/v1/wechat/auth
```

**请求参数**

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| code | string | ✅ | 微信授权码（5分钟有效期，一次性使用） |

**请求示例**

```json
{
  "code": "071abc123456789def"
}
```

**响应参数**

| 参数 | 类型 | 说明 |
|------|------|------|
| code | integer | 响应码（0表示成功） |
| msg | string | 响应消息 |
| data | object | 响应数据 |
| data.token | string | JWT Token（用于后续请求认证） |
| data.customer_id | integer | 个人客户ID |
| data.phone | string | 手机号（未绑定时为空） |
| data.nickname | string | 昵称（微信昵称） |
| data.is_new_user | boolean | 是否新用户 |
| timestamp | string | 响应时间戳（RFC3339格式） |

**响应示例**

```json
{
  "code": 0,
  "msg": "登录成功",
  "data": {
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjdXN0b21lcl9pZCI6MTIzLCJleHAiOjE3MDY2OTI4MDB9.abc123def456",
    "customer_id": 123,
    "phone": "138****8888",
    "nickname": "微信用户",
    "is_new_user": false
  },
  "timestamp": "2025-01-30T12:00:00+08:00"
}
```

**错误响应**

```json
{
  "code": 1044,
  "msg": "微信 OAuth 授权失败",
  "timestamp": "2025-01-30T12:00:00+08:00"
}
```

**业务逻辑**

1. 验证授权码是否有效
2. 调用微信API获取用户 OpenID 和 UnionID
3. 查找数据库是否存在该微信用户：
   - **存在**：返回已有账号的 Token
   - **不存在**：创建新账号，返回新账号的 Token
4. 新用户状态为"未绑定手机号"，后续需要绑定手机号才能使用完整功能

**注意事项**

- 授权码（code）只能使用一次，重复使用会失败
- 授权码有效期为5分钟
- Token 有效期为7天
- 新用户首次登录时 `phone` 字段为空，需要引导绑定手机号

---

### 2. 绑定微信账号

将当前登录的个人客户账号绑定到微信。

**接口地址**

```
POST /api/c/v1/bind-wechat
```

**认证方式**

需要携带 JWT Token（个人客户）。

**请求参数**

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| code | string | ✅ | 微信授权码 |

**请求示例**

```json
{
  "code": "071abc123456789def"
}
```

**响应参数**

| 参数 | 类型 | 说明 |
|------|------|------|
| code | integer | 响应码（0表示成功） |
| msg | string | 响应消息 |
| timestamp | string | 响应时间戳 |

**响应示例**

```json
{
  "code": 0,
  "msg": "绑定成功",
  "timestamp": "2025-01-30T12:00:00+08:00"
}
```

**错误响应**

```json
{
  "code": 1020,
  "msg": "该微信号已被其他账号绑定",
  "timestamp": "2025-01-30T12:00:00+08:00"
}
```

**业务逻辑**

1. 验证授权码是否有效
2. 获取微信 OpenID 和 UnionID
3. 检查该微信号是否已被其他账号绑定
4. 更新当前账号的微信绑定信息

**注意事项**

- 一个微信号只能绑定一个账号
- 绑定后无法解绑（需联系管理员）
- 绑定成功后，可以使用微信登录

---

### 3. 微信 JSAPI 支付

创建微信 JSAPI 支付订单（微信内网页支付）。

**接口地址**

```
POST /api/h5/orders/:id/wechat-pay/jsapi
```

**认证方式**

需要携带 H5 Token。

**路径参数**

| 参数 | 类型 | 说明 |
|------|------|------|
| id | integer | 订单ID |

**请求参数**

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| open_id | string | ✅ | 用户的微信 OpenID（在公众号内获取） |

**请求示例**

```json
{
  "open_id": "o6_bmjrPTlm6_2sgVt7hMZOPfL2M"
}
```

**响应参数**

| 参数 | 类型 | 说明 |
|------|------|------|
| code | integer | 响应码（0表示成功） |
| msg | string | 响应消息 |
| data | object | 响应数据 |
| data.prepay_id | string | 预支付交易会话标识 |
| data.pay_config | object | 支付配置（直接传给微信JSAPI） |
| data.pay_config.appId | string | 公众号AppID |
| data.pay_config.timeStamp | string | 时间戳 |
| data.pay_config.nonceStr | string | 随机字符串 |
| data.pay_config.package | string | 订单详情扩展字符串 |
| data.pay_config.signType | string | 签名方式（RSA） |
| data.pay_config.paySign | string | 签名 |
| timestamp | string | 响应时间戳 |

**响应示例**

```json
{
  "code": 0,
  "msg": "支付订单创建成功",
  "data": {
    "prepay_id": "wx30123456789012345678901234567890",
    "pay_config": {
      "appId": "wxabcdef1234567890",
      "timeStamp": "1706606400",
      "nonceStr": "5K8264ILTKCH16CQ2502SI8ZNMTM67VS",
      "package": "prepay_id=wx30123456789012345678901234567890",
      "signType": "RSA",
      "paySign": "oR9d8PuhnIc+YZ8cBHFCwfgpaK9gd7JS..."
    }
  },
  "timestamp": "2025-01-30T12:00:00+08:00"
}
```

**错误响应**

```json
{
  "code": 1035,
  "msg": "订单不存在",
  "timestamp": "2025-01-30T12:00:00+08:00"
}
```

**业务逻辑**

1. 验证订单是否存在且状态为"待支付"
2. 验证订单归属（只能支付自己的订单）
3. 调用微信支付API创建预支付订单
4. 生成支付配置（包含签名）
5. 返回支付配置给前端

**前端调用示例**

```javascript
// 获取支付配置
const res = await fetch(`/api/h5/orders/${orderId}/wechat-pay/jsapi`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${h5Token}`
  },
  body: JSON.stringify({ open_id: openId })
});

const result = await res.json();

// 调用微信JSAPI支付
wx.chooseWXPay({
  ...result.data.pay_config,
  success: function(res) {
    console.log('支付成功', res);
  },
  fail: function(res) {
    console.log('支付失败', res);
  }
});
```

**注意事项**

- 只能在微信内网页中使用
- OpenID 需要通过公众号 OAuth 获取
- 支付有效期为2小时
- 订单只能支付一次

---

### 4. 微信 H5 支付

创建微信 H5 支付订单（微信外浏览器支付）。

**接口地址**

```
POST /api/h5/orders/:id/wechat-pay/h5
```

**认证方式**

需要携带 H5 Token。

**路径参数**

| 参数 | 类型 | 说明 |
|------|------|------|
| id | integer | 订单ID |

**请求参数**

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| scene_info | object | ❌ | 场景信息 |
| scene_info.payer_client_ip | string | ❌ | 用户客户端IP |
| scene_info.h5_type | string | ❌ | H5类型（Wap/IOS/Android） |

**请求示例**

```json
{
  "scene_info": {
    "payer_client_ip": "123.12.12.123",
    "h5_type": "Wap"
  }
}
```

**响应参数**

| 参数 | 类型 | 说明 |
|------|------|------|
| code | integer | 响应码（0表示成功） |
| msg | string | 响应消息 |
| data | object | 响应数据 |
| data.h5_url | string | H5 支付跳转链接 |
| timestamp | string | 响应时间戳 |

**响应示例**

```json
{
  "code": 0,
  "msg": "H5 支付订单创建成功",
  "data": {
    "h5_url": "https://wx.tenpay.com/cgi-bin/mmpayweb-bin/checkmweb?prepay_id=wx30123456789012345678901234567890&package=3583359058"
  },
  "timestamp": "2025-01-30T12:00:00+08:00"
}
```

**前端调用示例**

```javascript
// 创建 H5 支付订单
const res = await fetch(`/api/h5/orders/${orderId}/wechat-pay/h5`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${h5Token}`
  },
  body: JSON.stringify({
    scene_info: {
      payer_client_ip: clientIp,
      h5_type: 'Wap'
    }
  })
});

const result = await res.json();

// 跳转到微信 H5 支付页面
if (result.code === 0) {
  const returnUrl = encodeURIComponent(`https://your-domain.com/orders/${orderId}`);
  window.location.href = `${result.data.h5_url}&redirect_url=${returnUrl}`;
}
```

**注意事项**

- 适用于微信外浏览器
- 支付完成后会跳转到 `redirect_url`（需URL编码）
- 支付有效期为5分钟
- 需要在微信商户平台配置 H5 支付域名

---

### 5. 微信支付回调

接收微信支付的异步通知。

**接口地址**

```
POST /api/callback/wechat-pay
```

**认证方式**

无需认证（由微信签名验证）。

**请求说明**

该接口由微信支付系统调用，开发者无需主动调用。

**请求头**

| 参数 | 说明 |
|------|------|
| Wechatpay-Serial | 微信支付平台证书序列号 |
| Wechatpay-Signature | 微信签名 |
| Wechatpay-Timestamp | 微信时间戳 |
| Wechatpay-Nonce | 微信随机串 |

**请求体**

微信发送的加密数据（JSON格式）。

**响应**

成功处理返回 HTTP 200：

```json
{
  "code": "SUCCESS",
  "message": "成功"
}
```

失败返回 HTTP 500：

```json
{
  "code": "FAIL",
  "message": "失败原因"
}
```

**处理流程**

1. 验证微信签名（PowerWeChat 自动处理）
2. 解密通知数据
3. 提取支付结果（交易状态、金额、订单号等）
4. 更新订单状态为"已支付"
5. 触发异步任务：
   - 分佣计算
   - 套餐分配
   - 钱包充值
6. 返回成功响应给微信

**幂等性保证**

系统会检查订单状态，避免重复处理：

- 如果订单已支付，直接返回成功
- 如果订单不存在，返回失败
- 使用数据库事务确保原子性

**重试机制**

微信会在以下情况重试：

- 商户系统未返回响应
- 返回 HTTP 状态码不是 200
- 返回结果为 FAIL

重试规则：
- 15秒后第1次重试
- 30秒后第2次重试
- 3分钟后第3次重试
- 最多重试3次

**注意事项**

- 接口必须在 **10秒内** 返回响应
- 必须返回正确的 JSON 格式
- 签名验证失败会记录日志但不影响服务
- 处理失败会自动重试，无需手动干预

---

## 测试建议

### 开发环境测试

1. **OAuth 登录测试**
   - 使用微信测试号（公众号测试账号）
   - 在本地配置内网穿透（ngrok、frp等）
   - 测试授权流程和账号创建

2. **支付功能测试**
   - 使用 0.01 元小额订单测试
   - 验证支付流程和回调处理
   - 测试完成后可通过退款功能退回

3. **回调测试**
   - 使用微信支付沙箱环境（需申请）
   - 或者使用 Postman 模拟回调请求
   - 验证幂等性和重试机制

### 生产环境测试

1. 使用真实商户号和公众号
2. 配置正确的 HTTPS 域名
3. 小额订单测试（建议 0.01 元）
4. 监控日志确认回调正常

---

## 相关文档

- [使用指南](./使用指南.md) - 详细的配置和部署说明
- [环境变量配置](../environment-variables.md) - 所有环境变量说明
- [README](../../README.md) - 项目整体说明
