## ADDED Requirements

### Requirement: 微信参数配置 CRUD 管理

系统 SHALL 支持平台用户对微信支付参数配置的完整生命周期管理，包括创建、列表查询、详情查询、更新、删除。每个配置包含完整的支付身份信息（渠道凭证 + 公众号 OAuth 信息 + 小程序 OAuth 信息）。

---

#### Scenario: 创建微信直连支付配置

**WHEN** 平台用户调用 `POST /api/admin/wechat-configs`，`provider_type` 为 `wechat`，提供名称、公众号信息、小程序信息、商户号、API V3 密钥、证书内容（Base64）、私钥内容（Base64）、证书序列号、回调地址

**THEN** 系统创建配置记录，`is_active` 默认为 `false`，返回完整配置信息（敏感字段脱敏）

##### 请求

```
POST /api/admin/wechat-configs
Authorization: Bearer {token}
Content-Type: application/json
```

```json
{
  "name": "微信直连主配置",
  "description": "生产环境微信直连支付配置",
  "provider_type": "wechat",
  "oa_app_id": "wx1234567890abcdef",
  "oa_app_secret": "abcdef1234567890abcdef1234567890",
  "oa_token": "mytoken123",
  "oa_aes_key": "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFG",
  "oa_oauth_redirect_url": "https://example.com/oauth/callback",
  "miniapp_app_id": "wx9876543210fedcba",
  "miniapp_app_secret": "fedcba0987654321fedcba0987654321",
  "wx_mch_id": "1234567890",
  "wx_api_v3_key": "your32charv3keyhere1234567890abc",
  "wx_api_v2_key": "your32charv2keyhere1234567890abc",
  "wx_cert_content": "BASE64_ENCODED_CERT_CONTENT_HERE",
  "wx_key_content": "BASE64_ENCODED_KEY_CONTENT_HERE",
  "wx_serial_no": "ABCDEF1234567890ABCDEF1234567890ABCDEF12",
  "wx_notify_url": "https://example.com/api/payment/wechat/notify"
}
```

##### 请求字段说明

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| name | string | 是 | 配置名称，最长 100 字符 |
| description | string | 否 | 配置描述，最长 500 字符 |
| provider_type | string | 是 | 渠道类型，枚举值：`wechat`（微信直连）、`fuiou`（富友） |
| oa_app_id | string | 否 | 公众号 AppID |
| oa_app_secret | string | 否 | 公众号 AppSecret |
| oa_token | string | 否 | 公众号消息校验 Token |
| oa_aes_key | string | 否 | 公众号消息加解密 Key |
| oa_oauth_redirect_url | string | 否 | 公众号 OAuth 回调地址 |
| miniapp_app_id | string | 否 | 小程序 AppID |
| miniapp_app_secret | string | 否 | 小程序 AppSecret |
| wx_mch_id | string | provider_type=wechat 时必填 | 微信商户号 |
| wx_api_v3_key | string | provider_type=wechat 时必填 | API V3 密钥（32字符） |
| wx_api_v2_key | string | 否 | API V2 密钥（32字符） |
| wx_cert_content | string | provider_type=wechat 时必填 | 商户证书内容（Base64 编码） |
| wx_key_content | string | provider_type=wechat 时必填 | 商户私钥内容（Base64 编码） |
| wx_serial_no | string | provider_type=wechat 时必填 | 商户证书序列号 |
| wx_notify_url | string | provider_type=wechat 时必填 | 微信支付回调地址 |

##### 成功响应

```json
{
  "code": 0,
  "data": {
    "id": 1,
    "name": "微信直连主配置",
    "description": "生产环境微信直连支付配置",
    "provider_type": "wechat",
    "is_active": false,
    "oa_app_id": "wx1234567890abcdef",
    "oa_app_secret": "abcd***7890",
    "oa_token": "myto***n123",
    "oa_aes_key": "[已配置]",
    "oa_oauth_redirect_url": "https://example.com/oauth/callback",
    "miniapp_app_id": "wx9876543210fedcba",
    "miniapp_app_secret": "fedc***4321",
    "wx_mch_id": "1234567890",
    "wx_api_v3_key": "your***0abc",
    "wx_api_v2_key": "your***0abc",
    "wx_cert_content": "[已配置]",
    "wx_key_content": "[已配置]",
    "wx_serial_no": "ABCD***EF12",
    "wx_notify_url": "https://example.com/api/payment/wechat/notify",
    "fy_ins_cd": "",
    "fy_mchnt_cd": "",
    "fy_term_id": "",
    "fy_private_key": "[未配置]",
    "fy_public_key": "[未配置]",
    "fy_api_url": "",
    "fy_notify_url": "",
    "created_at": "2026-03-16T10:00:00+08:00",
    "updated_at": "2026-03-16T10:00:00+08:00"
  },
  "msg": "success",
  "timestamp": "2026-03-16T10:00:00+08:00"
}
```

##### 敏感字段脱敏规则

| 字段 | 脱敏规则 | 示例原值 | 脱敏后 |
|------|---------|---------|--------|
| oa_app_secret | 前4位 + `***` + 后4位 | `abcdef1234567890abcdef1234567890` | `abcd***7890` |
| oa_token | 前4位 + `***` + 后4位 | `mytoken123` | `myto***n123` |
| oa_aes_key | `[已配置]` / `[未配置]` | 任意值 | `[已配置]` |
| miniapp_app_secret | 前4位 + `***` + 后4位 | `fedcba0987654321fedcba0987654321` | `fedc***4321` |
| wx_api_v3_key | 前4位 + `***` + 后4位 | `your32charv3keyhere1234567890abc` | `your***0abc` |
| wx_api_v2_key | 前4位 + `***` + 后4位 | `your32charv2keyhere1234567890abc` | `your***0abc` |
| wx_cert_content | `[已配置]` / `[未配置]` | Base64 内容 | `[已配置]` |
| wx_key_content | `[已配置]` / `[未配置]` | Base64 内容 | `[已配置]` |
| wx_serial_no | 前4位 + `***` + 后4位 | `ABCDEF1234567890ABCDEF1234567890ABCDEF12` | `ABCD***EF12` |
| fy_private_key | `[已配置]` / `[未配置]` | Base64 内容 | `[已配置]` |
| fy_public_key | `[已配置]` / `[未配置]` | Base64 内容 | `[已配置]` |

---

#### Scenario: 创建富友支付配置

**WHEN** 平台用户调用 `POST /api/admin/wechat-configs`，`provider_type` 为 `fuiou`，提供名称、公众号信息、小程序信息、机构号、商户号、终端号、商户私钥（Base64）、富友公钥（Base64）、API 地址、回调地址

**THEN** 系统创建配置记录，`is_active` 默认为 `false`

##### 请求

```
POST /api/admin/wechat-configs
Authorization: Bearer {token}
Content-Type: application/json
```

```json
{
  "name": "富友支付配置",
  "description": "富友聚合支付渠道配置",
  "provider_type": "fuiou",
  "oa_app_id": "wx1234567890abcdef",
  "oa_app_secret": "abcdef1234567890abcdef1234567890",
  "oa_oauth_redirect_url": "https://example.com/oauth/callback",
  "miniapp_app_id": "wx9876543210fedcba",
  "miniapp_app_secret": "fedcba0987654321fedcba0987654321",
  "fy_ins_cd": "0000100",
  "fy_mchnt_cd": "0000100002000001",
  "fy_term_id": "00000001",
  "fy_private_key": "BASE64_ENCODED_MERCHANT_PRIVATE_KEY",
  "fy_public_key": "BASE64_ENCODED_FUIOU_PUBLIC_KEY",
  "fy_api_url": "https://spay.fuiou.com",
  "fy_notify_url": "https://example.com/api/payment/fuiou/notify"
}
```

##### 请求字段说明

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| name | string | 是 | 配置名称，最长 100 字符 |
| description | string | 否 | 配置描述，最长 500 字符 |
| provider_type | string | 是 | 渠道类型，此处为 `fuiou` |
| oa_app_id | string | 否 | 公众号 AppID |
| oa_app_secret | string | 否 | 公众号 AppSecret |
| oa_token | string | 否 | 公众号消息校验 Token |
| oa_aes_key | string | 否 | 公众号消息加解密 Key |
| oa_oauth_redirect_url | string | 否 | 公众号 OAuth 回调地址 |
| miniapp_app_id | string | 否 | 小程序 AppID |
| miniapp_app_secret | string | 否 | 小程序 AppSecret |
| fy_ins_cd | string | provider_type=fuiou 时必填 | 富友机构号 |
| fy_mchnt_cd | string | provider_type=fuiou 时必填 | 富友商户号 |
| fy_term_id | string | provider_type=fuiou 时必填 | 富友终端号 |
| fy_private_key | string | provider_type=fuiou 时必填 | 商户私钥（Base64 编码） |
| fy_public_key | string | provider_type=fuiou 时必填 | 富友公钥（Base64 编码） |
| fy_api_url | string | provider_type=fuiou 时必填 | 富友 API 地址 |
| fy_notify_url | string | provider_type=fuiou 时必填 | 富友支付回调地址 |

##### 成功响应

```json
{
  "code": 0,
  "data": {
    "id": 2,
    "name": "富友支付配置",
    "description": "富友聚合支付渠道配置",
    "provider_type": "fuiou",
    "is_active": false,
    "oa_app_id": "wx1234567890abcdef",
    "oa_app_secret": "abcd***7890",
    "oa_token": "",
    "oa_aes_key": "[未配置]",
    "oa_oauth_redirect_url": "https://example.com/oauth/callback",
    "miniapp_app_id": "wx9876543210fedcba",
    "miniapp_app_secret": "fedc***4321",
    "wx_mch_id": "",
    "wx_api_v3_key": "",
    "wx_api_v2_key": "",
    "wx_cert_content": "[未配置]",
    "wx_key_content": "[未配置]",
    "wx_serial_no": "",
    "wx_notify_url": "",
    "fy_ins_cd": "0000100",
    "fy_mchnt_cd": "0000100002000001",
    "fy_term_id": "00000001",
    "fy_private_key": "[已配置]",
    "fy_public_key": "[已配置]",
    "fy_api_url": "https://spay.fuiou.com",
    "fy_notify_url": "https://example.com/api/payment/fuiou/notify",
    "created_at": "2026-03-16T10:00:00+08:00",
    "updated_at": "2026-03-16T10:00:00+08:00"
  },
  "msg": "success",
  "timestamp": "2026-03-16T10:00:00+08:00"
}
```

---

#### Scenario: 创建配置参数校验失败

**WHEN** 平台用户创建配置时缺少必填字段（如 `provider_type` 为 `wechat` 但未提供 `wx_mch_id`）

**THEN** 系统返回错误码 `1001`，拒绝创建

##### 请求示例（缺少 wx_mch_id）

```
POST /api/admin/wechat-configs
Authorization: Bearer {token}
Content-Type: application/json
```

```json
{
  "name": "微信直连配置",
  "provider_type": "wechat",
  "wx_api_v3_key": "your32charv3keyhere1234567890abc"
}
```

##### 错误响应

```json
{
  "code": 1001,
  "data": null,
  "msg": "参数错误",
  "timestamp": "2026-03-16T10:00:00+08:00"
}
```

---

#### Scenario: 查询配置列表

**WHEN** 平台用户调用 `GET /api/admin/wechat-configs`，支持按 `provider_type` 和 `is_active` 筛选，支持分页

**THEN** 系统返回配置列表，敏感字段脱敏

##### 请求

```
GET /api/admin/wechat-configs?provider_type=wechat&is_active=false&page=1&page_size=20
Authorization: Bearer {token}
```

##### 查询参数说明

| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| provider_type | string | 否 | 按渠道类型筛选，枚举值：`wechat`、`fuiou` |
| is_active | boolean | 否 | 按激活状态筛选，`true` 或 `false` |
| page | integer | 否 | 页码，默认 1 |
| page_size | integer | 否 | 每页条数，默认 20，最大 100 |

##### 成功响应

```json
{
  "code": 0,
  "data": {
    "list": [
      {
        "id": 1,
        "name": "微信直连主配置",
        "description": "生产环境微信直连支付配置",
        "provider_type": "wechat",
        "is_active": false,
        "oa_app_id": "wx1234567890abcdef",
        "oa_app_secret": "abcd***7890",
        "oa_token": "myto***n123",
        "oa_aes_key": "[已配置]",
        "oa_oauth_redirect_url": "https://example.com/oauth/callback",
        "miniapp_app_id": "wx9876543210fedcba",
        "miniapp_app_secret": "fedc***4321",
        "wx_mch_id": "1234567890",
        "wx_api_v3_key": "your***0abc",
        "wx_api_v2_key": "your***0abc",
        "wx_cert_content": "[已配置]",
        "wx_key_content": "[已配置]",
        "wx_serial_no": "ABCD***EF12",
        "wx_notify_url": "https://example.com/api/payment/wechat/notify",
        "fy_ins_cd": "",
        "fy_mchnt_cd": "",
        "fy_term_id": "",
        "fy_private_key": "[未配置]",
        "fy_public_key": "[未配置]",
        "fy_api_url": "",
        "fy_notify_url": "",
        "created_at": "2026-03-16T10:00:00+08:00",
        "updated_at": "2026-03-16T10:00:00+08:00"
      }
    ],
    "total": 1,
    "page": 1,
    "page_size": 20
  },
  "msg": "success",
  "timestamp": "2026-03-16T10:00:00+08:00"
}
```

---

#### Scenario: 查询配置详情

**WHEN** 平台用户调用 `GET /api/admin/wechat-configs/:id`

**THEN** 系统返回配置详情，敏感字段脱敏

##### 请求

```
GET /api/admin/wechat-configs/1
Authorization: Bearer {token}
```

##### 成功响应

```json
{
  "code": 0,
  "data": {
    "id": 1,
    "name": "微信直连主配置",
    "description": "生产环境微信直连支付配置",
    "provider_type": "wechat",
    "is_active": false,
    "oa_app_id": "wx1234567890abcdef",
    "oa_app_secret": "abcd***7890",
    "oa_token": "myto***n123",
    "oa_aes_key": "[已配置]",
    "oa_oauth_redirect_url": "https://example.com/oauth/callback",
    "miniapp_app_id": "wx9876543210fedcba",
    "miniapp_app_secret": "fedc***4321",
    "wx_mch_id": "1234567890",
    "wx_api_v3_key": "your***0abc",
    "wx_api_v2_key": "your***0abc",
    "wx_cert_content": "[已配置]",
    "wx_key_content": "[已配置]",
    "wx_serial_no": "ABCD***EF12",
    "wx_notify_url": "https://example.com/api/payment/wechat/notify",
    "fy_ins_cd": "",
    "fy_mchnt_cd": "",
    "fy_term_id": "",
    "fy_private_key": "[未配置]",
    "fy_public_key": "[未配置]",
    "fy_api_url": "",
    "fy_notify_url": "",
    "created_at": "2026-03-16T10:00:00+08:00",
    "updated_at": "2026-03-16T10:00:00+08:00"
  },
  "msg": "success",
  "timestamp": "2026-03-16T10:00:00+08:00"
}
```

##### 配置不存在时的错误响应

```json
{
  "code": 1170,
  "data": null,
  "msg": "微信支付配置不存在",
  "timestamp": "2026-03-16T10:00:00+08:00"
}
```

---

#### Scenario: 更新配置（非敏感字段）

**WHEN** 平台用户调用 `PUT /api/admin/wechat-configs/:id`，仅更新名称、描述、回调地址等非敏感字段

**THEN** 系统更新对应字段，敏感字段保持不变

##### 请求

```
PUT /api/admin/wechat-configs/1
Authorization: Bearer {token}
Content-Type: application/json
```

```json
{
  "name": "微信直连主配置（已更新）",
  "description": "更新后的描述",
  "wx_notify_url": "https://new.example.com/api/payment/wechat/notify"
}
```

##### 请求字段说明

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| name | string | 否 | 配置名称 |
| description | string | 否 | 配置描述 |
| oa_app_id | string | 否 | 公众号 AppID |
| oa_app_secret | string | 否 | 公众号 AppSecret；空字符串或不传 = 保留原值；传新值 = 替换 |
| oa_token | string | 否 | 公众号消息校验 Token；空字符串或不传 = 保留原值；传新值 = 替换 |
| oa_aes_key | string | 否 | 公众号消息加解密 Key；空字符串或不传 = 保留原值；传新值 = 替换 |
| oa_oauth_redirect_url | string | 否 | 公众号 OAuth 回调地址 |
| miniapp_app_id | string | 否 | 小程序 AppID |
| miniapp_app_secret | string | 否 | 小程序 AppSecret；空字符串或不传 = 保留原值；传新值 = 替换 |
| wx_mch_id | string | 否 | 微信商户号 |
| wx_api_v3_key | string | 否 | API V3 密钥；空字符串或不传 = 保留原值；传新值 = 替换 |
| wx_api_v2_key | string | 否 | API V2 密钥；空字符串或不传 = 保留原值；传新值 = 替换 |
| wx_cert_content | string | 否 | 商户证书内容（Base64）；空字符串或不传 = 保留原值；传新值 = 替换 |
| wx_key_content | string | 否 | 商户私钥内容（Base64）；空字符串或不传 = 保留原值；传新值 = 替换 |
| wx_serial_no | string | 否 | 商户证书序列号；空字符串或不传 = 保留原值；传新值 = 替换 |
| wx_notify_url | string | 否 | 微信支付回调地址 |
| fy_ins_cd | string | 否 | 富友机构号 |
| fy_mchnt_cd | string | 否 | 富友商户号 |
| fy_term_id | string | 否 | 富友终端号 |
| fy_private_key | string | 否 | 商户私钥（Base64）；空字符串或不传 = 保留原值；传新值 = 替换 |
| fy_public_key | string | 否 | 富友公钥（Base64）；空字符串或不传 = 保留原值；传新值 = 替换 |
| fy_api_url | string | 否 | 富友 API 地址 |
| fy_notify_url | string | 否 | 富友支付回调地址 |

##### 成功响应

```json
{
  "code": 0,
  "data": {
    "id": 1,
    "name": "微信直连主配置（已更新）",
    "description": "更新后的描述",
    "provider_type": "wechat",
    "is_active": false,
    "oa_app_id": "wx1234567890abcdef",
    "oa_app_secret": "abcd***7890",
    "oa_token": "myto***n123",
    "oa_aes_key": "[已配置]",
    "oa_oauth_redirect_url": "https://example.com/oauth/callback",
    "miniapp_app_id": "wx9876543210fedcba",
    "miniapp_app_secret": "fedc***4321",
    "wx_mch_id": "1234567890",
    "wx_api_v3_key": "your***0abc",
    "wx_api_v2_key": "your***0abc",
    "wx_cert_content": "[已配置]",
    "wx_key_content": "[已配置]",
    "wx_serial_no": "ABCD***EF12",
    "wx_notify_url": "https://new.example.com/api/payment/wechat/notify",
    "fy_ins_cd": "",
    "fy_mchnt_cd": "",
    "fy_term_id": "",
    "fy_private_key": "[未配置]",
    "fy_public_key": "[未配置]",
    "fy_api_url": "",
    "fy_notify_url": "",
    "created_at": "2026-03-16T10:00:00+08:00",
    "updated_at": "2026-03-16T10:30:00+08:00"
  },
  "msg": "success",
  "timestamp": "2026-03-16T10:30:00+08:00"
}
```

---

#### Scenario: 更新当前生效配置时清除 Redis 缓存

**WHEN** 平台用户更新的配置 `is_active=true`（当前生效配置）

**THEN** 系统更新字段后，主动清除 Redis 缓存 `wechat:config:active`，使变更即时生效

**THEN** 响应格式与普通更新相同

---

#### Scenario: 更新配置时替换敏感字段

**WHEN** 平台用户更新配置时，对脱敏字段传入新的明文值（非空字符串、非脱敏格式）

**THEN** 系统将该字段替换为新值

##### 请求示例（替换 API V3 密钥）

```json
{
  "wx_api_v3_key": "newkey32charsnewkey32charsnewkey"
}
```

**THEN** 系统将 `wx_api_v3_key` 更新为新值，响应中该字段显示脱敏后的新值 `newk***ekey`

---

#### Scenario: 删除未激活的配置

**WHEN** 平台用户调用 `DELETE /api/admin/wechat-configs/:id`，且该配置 `is_active=false`

**THEN** 系统软删除该配置记录，返回成功

##### 请求

```
DELETE /api/admin/wechat-configs/1
Authorization: Bearer {token}
```

##### 成功响应

```json
{
  "code": 0,
  "data": null,
  "msg": "success",
  "timestamp": "2026-03-16T10:00:00+08:00"
}
```

---

#### Scenario: 禁止删除激活中的配置

**WHEN** 平台用户尝试删除 `is_active=true` 的配置

**THEN** 系统返回错误码 `1171`，拒绝删除

##### 错误响应

```json
{
  "code": 1171,
  "data": null,
  "msg": "不能删除当前生效的支付配置，请先停用",
  "timestamp": "2026-03-16T10:00:00+08:00"
}
```

---

#### Scenario: 禁止删除有在途订单的配置

**WHEN** 平台用户尝试删除某配置，且存在 `payment_config_id` 指向该配置的待支付订单

**THEN** 系统返回错误码 `1172`，拒绝删除

##### 错误响应

```json
{
  "code": 1172,
  "data": null,
  "msg": "该配置存在未完成的支付订单，暂时无法删除",
  "timestamp": "2026-03-16T10:00:00+08:00"
}
```

---

### Requirement: 全局唯一激活约束

系统 SHALL 保证任意时刻最多一个支付配置处于激活状态。激活新配置时 MUST 自动停用旧配置。

---

#### Scenario: 激活配置

**WHEN** 平台用户调用 `POST /api/admin/wechat-configs/:id/activate`

**THEN** 系统在事务中执行：将所有 `is_active=true` 的配置设为 `false`，再将目标配置设为 `true`

**THEN** 系统清除 Redis 缓存 `wechat:config:active`

**THEN** 系统返回成功，新配置即时生效

##### 请求

```
POST /api/admin/wechat-configs/1/activate
Authorization: Bearer {token}
```

##### 成功响应

```json
{
  "code": 0,
  "data": {
    "id": 1,
    "name": "微信直连主配置",
    "description": "生产环境微信直连支付配置",
    "provider_type": "wechat",
    "is_active": true,
    "oa_app_id": "wx1234567890abcdef",
    "oa_app_secret": "abcd***7890",
    "oa_token": "myto***n123",
    "oa_aes_key": "[已配置]",
    "oa_oauth_redirect_url": "https://example.com/oauth/callback",
    "miniapp_app_id": "wx9876543210fedcba",
    "miniapp_app_secret": "fedc***4321",
    "wx_mch_id": "1234567890",
    "wx_api_v3_key": "your***0abc",
    "wx_api_v2_key": "your***0abc",
    "wx_cert_content": "[已配置]",
    "wx_key_content": "[已配置]",
    "wx_serial_no": "ABCD***EF12",
    "wx_notify_url": "https://example.com/api/payment/wechat/notify",
    "fy_ins_cd": "",
    "fy_mchnt_cd": "",
    "fy_term_id": "",
    "fy_private_key": "[未配置]",
    "fy_public_key": "[未配置]",
    "fy_api_url": "",
    "fy_notify_url": "",
    "created_at": "2026-03-16T10:00:00+08:00",
    "updated_at": "2026-03-16T10:05:00+08:00"
  },
  "msg": "success",
  "timestamp": "2026-03-16T10:05:00+08:00"
}
```

##### 配置不存在时的错误响应

```json
{
  "code": 1170,
  "data": null,
  "msg": "微信支付配置不存在",
  "timestamp": "2026-03-16T10:05:00+08:00"
}
```

---

#### Scenario: 停用配置

**WHEN** 平台用户调用 `POST /api/admin/wechat-configs/:id/deactivate`

**THEN** 系统将该配置 `is_active` 设为 `false`

**THEN** 系统清除 Redis 缓存 `wechat:config:active`

**THEN** 此后创建订单时仅支持钱包支付或线下支付

##### 请求

```
POST /api/admin/wechat-configs/1/deactivate
Authorization: Bearer {token}
```

##### 成功响应

```json
{
  "code": 0,
  "data": {
    "id": 1,
    "name": "微信直连主配置",
    "description": "生产环境微信直连支付配置",
    "provider_type": "wechat",
    "is_active": false,
    "oa_app_id": "wx1234567890abcdef",
    "oa_app_secret": "abcd***7890",
    "oa_token": "myto***n123",
    "oa_aes_key": "[已配置]",
    "oa_oauth_redirect_url": "https://example.com/oauth/callback",
    "miniapp_app_id": "wx9876543210fedcba",
    "miniapp_app_secret": "fedc***4321",
    "wx_mch_id": "1234567890",
    "wx_api_v3_key": "your***0abc",
    "wx_api_v2_key": "your***0abc",
    "wx_cert_content": "[已配置]",
    "wx_key_content": "[已配置]",
    "wx_serial_no": "ABCD***EF12",
    "wx_notify_url": "https://example.com/api/payment/wechat/notify",
    "fy_ins_cd": "",
    "fy_mchnt_cd": "",
    "fy_term_id": "",
    "fy_private_key": "[未配置]",
    "fy_public_key": "[未配置]",
    "fy_api_url": "",
    "fy_notify_url": "",
    "created_at": "2026-03-16T10:00:00+08:00",
    "updated_at": "2026-03-16T10:10:00+08:00"
  },
  "msg": "success",
  "timestamp": "2026-03-16T10:10:00+08:00"
}
```

##### 配置不存在时的错误响应

```json
{
  "code": 1170,
  "data": null,
  "msg": "微信支付配置不存在",
  "timestamp": "2026-03-16T10:10:00+08:00"
}
```

---

#### Scenario: 查询当前生效配置

**WHEN** 平台用户调用 `GET /api/admin/wechat-configs/active`

**THEN** 若有生效配置，返回该配置详情（脱敏）

**THEN** 若无生效配置，`data` 返回 `null`

##### 请求

```
GET /api/admin/wechat-configs/active
Authorization: Bearer {token}
```

##### 有生效配置时的成功响应

```json
{
  "code": 0,
  "data": {
    "id": 1,
    "name": "微信直连主配置",
    "description": "生产环境微信直连支付配置",
    "provider_type": "wechat",
    "is_active": true,
    "oa_app_id": "wx1234567890abcdef",
    "oa_app_secret": "abcd***7890",
    "oa_token": "myto***n123",
    "oa_aes_key": "[已配置]",
    "oa_oauth_redirect_url": "https://example.com/oauth/callback",
    "miniapp_app_id": "wx9876543210fedcba",
    "miniapp_app_secret": "fedc***4321",
    "wx_mch_id": "1234567890",
    "wx_api_v3_key": "your***0abc",
    "wx_api_v2_key": "your***0abc",
    "wx_cert_content": "[已配置]",
    "wx_key_content": "[已配置]",
    "wx_serial_no": "ABCD***EF12",
    "wx_notify_url": "https://example.com/api/payment/wechat/notify",
    "fy_ins_cd": "",
    "fy_mchnt_cd": "",
    "fy_term_id": "",
    "fy_private_key": "[未配置]",
    "fy_public_key": "[未配置]",
    "fy_api_url": "",
    "fy_notify_url": "",
    "created_at": "2026-03-16T10:00:00+08:00",
    "updated_at": "2026-03-16T10:05:00+08:00"
  },
  "msg": "success",
  "timestamp": "2026-03-16T10:15:00+08:00"
}
```

##### 无生效配置时的响应

```json
{
  "code": 0,
  "data": null,
  "msg": "当前无生效的支付配置，仅支持钱包支付",
  "timestamp": "2026-03-16T10:15:00+08:00"
}
```

---

#### Scenario: 配置切换不取消在途订单

**WHEN** 管理员激活新配置时，系统中存在使用旧配置创建的待支付订单

**THEN** 系统不取消这些订单

**THEN** 旧订单若支付成功，回调按订单关联的 `payment_config_id` 加载旧配置验签处理

**THEN** 旧订单若未支付，由现有 30 分钟超时机制自动取消

此场景无独立 API 接口，为激活接口的业务约束。

---

### Requirement: 生效配置 Redis 缓存

系统 SHALL 将当前生效的支付配置缓存在 Redis 中，减少数据库查询。

---

#### Scenario: 缓存命中

**WHEN** 支付流程查询生效配置，Redis 缓存 `wechat:config:active` 存在

**THEN** 直接返回缓存数据，不查询数据库

此场景为内部实现约束，无独立 API 接口。

---

#### Scenario: 缓存未命中

**WHEN** 支付流程查询生效配置，Redis 缓存 `wechat:config:active` 不存在

**THEN** 查询数据库获取 `is_active=true` 的配置

**THEN** 将结果写入 Redis，TTL 为 5 分钟

**THEN** 返回配置数据

此场景为内部实现约束，无独立 API 接口。

---

#### Scenario: 无生效配置时缓存空标记

**WHEN** 数据库中无 `is_active=true` 的配置

**THEN** 在 Redis 写入空标记（值为 `"none"`），TTL 为 1 分钟

**THEN** 后续请求命中空标记后直接返回无配置，不穿透数据库

此场景为内部实现约束，无独立 API 接口。

---

#### Scenario: 配置变更主动清除缓存

**WHEN** 执行激活、停用、更新生效配置、删除配置操作

**THEN** 系统主动 DEL Redis 缓存 `wechat:config:active`

此场景为内部实现约束，体现在激活、停用、更新、删除接口的副作用中。

---

### Requirement: 仅平台用户可操作

系统 SHALL 限制微信参数配置管理接口仅平台用户（`user_type=1` 超级管理员和 `user_type=2` 平台用户）可访问。路由层中间件统一拦截，无需在 Service 层重复校验。

---

#### Scenario: 平台用户访问成功

**WHEN** 超级管理员（`user_type=1`）或平台用户（`user_type=2`）请求微信参数配置管理接口

**THEN** 系统正常处理请求

---

#### Scenario: 非平台用户拒绝访问

**WHEN** 代理账号（`user_type=3`）或企业账号（`user_type=4`）请求微信参数配置管理接口

**THEN** 系统返回错误码 `1005`，消息"无权限访问支付配置管理功能"

##### 错误响应

```json
{
  "code": 1005,
  "data": null,
  "msg": "无权限访问支付配置管理功能",
  "timestamp": "2026-03-16T10:00:00+08:00"
}
```

---

#### Scenario: 未登录用户拒绝访问

**WHEN** 请求未携带有效 Token 或 Token 已过期

**THEN** 系统返回 HTTP 401，错误码 `1002`

##### 错误响应

```json
{
  "code": 1002,
  "data": null,
  "msg": "无效或已过期的认证令牌",
  "timestamp": "2026-03-16T10:00:00+08:00"
}
```

---

### Requirement: 审计日志

系统 SHALL 对所有微信参数配置的写操作（创建、更新、删除、激活、停用）记录操作审计日志，便于追溯配置变更历史。

---

#### Scenario: 创建配置时记录审计日志

**WHEN** 平台用户成功创建微信参数配置

**THEN** 系统异步写入审计日志，记录以下信息：

| 字段 | 值 |
|------|-----|
| operator_id | 当前操作人 ID |
| operator_type | 操作人用户类型 |
| operation_type | `create` |
| operation_desc | `创建微信支付配置：{配置名称}` |
| after_data | 新建配置的完整数据（敏感字段脱敏后存储） |
| request_id | 当前请求 ID |
| ip_address | 操作人 IP |
| user_agent | 操作人 User-Agent |

**THEN** 审计日志写入失败不影响业务操作，失败时记录 Error 日志

---

#### Scenario: 更新配置时记录审计日志

**WHEN** 平台用户成功更新微信参数配置

**THEN** 系统异步写入审计日志，记录以下信息：

| 字段 | 值 |
|------|-----|
| operator_id | 当前操作人 ID |
| operation_type | `update` |
| operation_desc | `更新微信支付配置：{配置名称}` |
| before_data | 更新前的配置数据（敏感字段脱敏后存储） |
| after_data | 更新后的配置数据（敏感字段脱敏后存储） |

---

#### Scenario: 删除配置时记录审计日志

**WHEN** 平台用户成功删除微信参数配置

**THEN** 系统异步写入审计日志，记录以下信息：

| 字段 | 值 |
|------|-----|
| operator_id | 当前操作人 ID |
| operation_type | `delete` |
| operation_desc | `删除微信支付配置：{配置名称}` |
| before_data | 删除前的配置数据（敏感字段脱敏后存储） |

---

#### Scenario: 激活配置时记录审计日志

**WHEN** 平台用户成功激活微信参数配置

**THEN** 系统异步写入审计日志，记录以下信息：

| 字段 | 值 |
|------|-----|
| operator_id | 当前操作人 ID |
| operation_type | `activate` |
| operation_desc | `激活微信支付配置：{配置名称}，原生效配置：{旧配置名称或"无"}` |
| before_data | 激活前的状态（旧生效配置 ID 和名称） |
| after_data | 激活后的状态（新生效配置 ID 和名称） |

---

#### Scenario: 停用配置时记录审计日志

**WHEN** 平台用户成功停用微信参数配置

**THEN** 系统异步写入审计日志，记录以下信息：

| 字段 | 值 |
|------|-----|
| operator_id | 当前操作人 ID |
| operation_type | `deactivate` |
| operation_desc | `停用微信支付配置：{配置名称}` |
| before_data | 停用前的配置状态 |
| after_data | 停用后的配置状态 |
