# 发票推送渠道改走数据字典 invoice_push_channel（管理后台）

- **接口**：PUT /v3/admin/order/invoice/{id}/push
- **变更类型**：修改接口（推送渠道合法值由后端硬编码改为数据字典 `invoice_push_channel` 驱动）
- **端类型**：管理后台
- **日期**：2026-06-25
- **Issue**：[#4379](https://git.1814.love:8443/wx/HL/issues/4379)
- **PR**：[#4379](https://git.1814.love:8443/wx/HL/pulls/4379)

发票「推送客户」的渠道合法值（email/wechat/sms）原为后端硬编码，本次改为读取数据字典 `invoice_push_channel`，便于后续在字典中增删渠道而无需改代码。当前可选值与含义不变。

---

## 1 接口背景

发票详情页「推送客户」操作（PUT push），入参为渠道列表 `channels`。原后端在代码里硬编码合法渠道集合 `{email, wechat, sms}` 做校验；本次改为运行时读取数据字典 `invoice_push_channel` 的全部 ACTIVE 字典值作为合法集合。

- 字典为空或字典服务不可用时，**降级回硬编码 `{email, wechat, sms}`**，保证可用性。
- 本期渠道值与含义**未变**，仍为 email/wechat/sms 三项。
- 前端渠道下拉/多选项建议改为从字典接口拉取（见第 6 节），不再前端写死，后续字典增删渠道前端可自动同步。

---

## 2 变更清单

| # | 变更项 | 变更前 | 变更后 |
|---|--------|--------|--------|
| 1 | push 渠道合法值来源 | 后端硬编码 `{email, wechat, sms}` | 数据字典 `invoice_push_channel` 的 ACTIVE 字典值 |
| 2 | 字典缺失/异常时行为 | 不适用 | 降级回硬编码 `{email, wechat, sms}` |
| 3 | 入参字段 / 渠道值 | channels: string[]，值 email/wechat/sms | 不变（同前） |
| 4 | 错误码 581521/581522 | 已存在 | 不变（语义同前，仅合法集合来源变化） |

> 接口路径、入参结构、出参、错误码均无变化；仅「合法渠道值的来源」从硬编码改为字典。

---

## 3 接口详情

| 属性 | 值 |
|------|----|
| 方法 | PUT |
| 路径 | /v3/admin/order/invoice/{id}/push |
| 描述 | 将已开具发票推送给客户（多渠道多选）；本期仅落状态与渠道记录，不真发通知 |
| 认证 | Bearer JWT（管理员） |
| 幂等性 | 状态守卫，非幂等 |
| 限流 | 无特殊限制 |

---

## 4 接口入参

### 4.1 路径参数

| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| id | string（Long 雪花） | 是 | 发票记录 ID |

### 4.2 请求体字段（InvoicePushReqVO）

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| channels | string[] | 是 | 推送渠道，多选；每个值须为字典 `invoice_push_channel` 中的 ACTIVE 字典值（当前 email/wechat/sms）。空数组报 581521，含非法值报 581522 |

---

## 5 出参字段

操作成功返回 HTTP 200，data 为 null。

---

## 6 枚举 / 数据字典

### 6.1 推送渠道字典（invoice_push_channel）

合法渠道值来源由本次改为该字典。前端可调用字典接口 `GET /admin/dict/data/invoice_push_channel` 动态获取下拉项（dictValue 作为提交值，dictLabel 作为展示文案）。

| dictValue | dictLabel | sortOrder | status |
|-----------|-----------|-----------|--------|
| email | 邮件 | 10 | ACTIVE |
| wechat | 微信 | 20 | ACTIVE |
| sms | 短信 | 30 | ACTIVE |

> 提交 push 时 channels 传 dictValue（如 `email`），非 dictLabel。

---

## 7 错误码

| 错误码 | 常量 | 触发场景 |
|--------|------|----------|
| 581521 | INVOICE_PUSH_CHANNEL_REQUIRED | channels 为空（至少选一个渠道） |
| 581522 | INVOICE_PUSH_CHANNEL_INVALID | channels 含非法值（不在字典 invoice_push_channel 的 ACTIVE 字典值内） |

---

## 8 示例

### 8.1 典型成功——推送邮件 + 微信

请求
```
PUT /v3/admin/order/invoice/2069957731908784129/push
Authorization: Bearer <token>
Content-Type: application/json
```
```json
{
  "channels": ["email", "wechat"]
}
```

响应
```json
{"code": 200, "msg": "success", "data": null}
```

### 8.2 边界——单渠道短信

```json
{"channels": ["sms"]}
```
响应
```json
{"code": 200, "msg": "success", "data": null}
```

### 8.3 业务失败——非法渠道值

请求
```json
{"channels": ["fax"]}
```
响应
```json
{"code": 581522, "msg": "推送渠道非法（须为 email/wechat/sms）", "data": null}
```

---

## 9 业务边界

适用：
- channels 非空，且每个值均为字典 `invoice_push_channel` 中的 ACTIVE 字典值。

不适用：
- channels 为空数组 → 581521
- channels 含任意非字典值 → 581522（即便其余值合法，整体拒绝）

特殊边界：
- 字典 `invoice_push_channel` 不可用或为空时，后端降级回硬编码 `{email, wechat, sms}`，校验行为与改前一致。

---

## 10 修改前后对比

| 维度 | 变更前 | 变更后 |
|------|--------|--------|
| 合法渠道来源 | 代码硬编码 `{email, wechat, sms}` | 数据字典 `invoice_push_channel`（ACTIVE 字典值） |
| 增删渠道 | 改代码 + 发版 | 维护字典即可（前端从字典接口取项可自动同步） |
| 入参 / 出参 / 错误码 | — | 无变化 |
| 当前可选渠道 | email/wechat/sms | email/wechat/sms（不变） |

---

## 11 影响评估 / 回滚

破坏兼容性：否

- 当前渠道值与含义未变，已写死 email/wechat/sms 的前端仍可正常提交，不会立即报错。
- 建议前端将渠道选项改为从 `GET /admin/dict/data/invoice_push_channel` 拉取，以便后续字典增删渠道时自动同步。

回滚方案：回滚后端至 #4379 前版本，合法渠道恢复为硬编码 `{email, wechat, sms}`；字典 `invoice_push_channel` 保留不影响其他功能。

---

## 12 注意事项

1. 提交 channels 传 dictValue（`email`/`wechat`/`sms`），不是中文 dictLabel。
2. 字典维护需保持 status=ACTIVE 才生效；置为非 ACTIVE 的渠道值将被视为非法（581522）。
3. 本期 push 仅落状态与渠道记录，不真实发送通知。

---

## 13 关联 / 联系人

- **Issue**：[#4379](https://git.1814.love:8443/wx/HL/issues/4379)
- **PR**：[#4379 发票推送渠道改走数据字典 invoice_push_channel](https://git.1814.love:8443/wx/HL/pulls/4379)
- **后端负责人**：腰苏图（yaosutu）
