# Refashion 注册邮件发送接口文档

## 接口地址

**POST** `/fr_epr_reg/api/epr/send-refashion-mail`

服务器地址：`http://automation.usaeu.com:8888/`

完整地址：`http://automation.usaeu.com:8888/fr_epr_reg/api/epr/send-refashion-mail`

## 功能说明

将法国纺织法（Refashion / ECO TLC）的 POA ZIP 包通过邮件发送给 Refashion，同时更新源数据库中对应记录的推送状态为"推送成功"（PushTaxBureauStatus=3）。

与 `send-registration-mail`（Léko）的区别：无 `xlsx_url` 参数（Refashion 仅发送 POA ZIP，无合并 XLSX）；发送前校验 ZIP 内 PDF 数量与提交 ID 数量一致，且所有 ID 必须为 ECO TLC 纺织法记录，不一致则拒绝发送。

## 访问控制

接口受 `internal.network` 中间件保护，仅允许内网（172.16.x.x 子网）请求访问，非内网请求返回 401。

> **注意**：IP 限制默认开启（生产环境，由 `INTERNAL_NETWORK_ENFORCE` 控制，默认 `true`）。本地开发机不在 172.16 子网时，可在 `.env` 设置 `INTERNAL_NETWORK_ENFORCE=false` 临时关闭。

同时受 `parse.large.json` 中间件处理，支持大体积 JSON 请求体（含 Base64 编码的 POA ZIP），自动处理 JSON 中 Base64 换行符导致的解析失败。

## 请求

### Content-Type

`application/json`

### 请求参数

| 参数名 | 类型 | 必填 | 说明 |
|--------|------|------|------|
| pdf_zip_base64 | string | 是 | 包含所有 POA PDF 的 ZIP 文件的 Base64 编码字符串，最大 67MB |
| epr_reg_info_ids | string[] | 是 | `EPRRegInfo.Id` 数组，1~100 个 UUID 字符串（最长36位），须为 ECO TLC 纺织法记录 |

> 与 `send-registration-mail` 相比，仅缺少 `xlsx_url` 参数。

### 请求示例

```json
{
    "pdf_zip_base64": "UEsDBBQAAAAIAA...",
    "epr_reg_info_ids": [
        "EPR-REG-INFO-ID-001",
        "EPR-REG-INFO-ID-002",
        "EPR-REG-INFO-ID-003"
    ]
}
```

## 响应

### 成功响应（200）

```json
{
    "code": 200,
    "msg": "Refashion registration mail sent successfully",
    "data": {
        "sent_to": "hotline@refashion.fr",
        "client_count": 3
    }
}
```

| 字段 | 类型 | 说明 |
|------|------|------|
| code | int | 状态码，200 表示成功 |
| msg | string | 响应消息 |
| data.sent_to | string | 邮件收件人地址（来自 `services.refashion_smtp.to_email`，即 `REFASHION_REG_MAIL_TO`） |
| data.client_count | int | 发送的客户数量（即 `epr_reg_info_ids` 数组长度，等于 ZIP 内 POA 数） |

### 参数校验失败（400）

```json
{
    "code": 400,
    "msg": "pdf_zip_base64 is required",
    "data": null
}
```

其他可能的校验错误消息：

| 触发条件 | msg 内容 |
|----------|----------|
| pdf_zip_base64 为空 | `pdf_zip_base64 is required` |
| epr_reg_info_ids 为空 | `epr_reg_info_ids is required` |
| epr_reg_info_ids 不是数组 | `epr_reg_info_ids must be an array` |
| epr_reg_info_ids 为空数组 | `epr_reg_info_ids must contain at least 1 ID` |
| epr_reg_info_ids 超过100个 | `epr_reg_info_ids must not exceed 100 IDs` |
| epr_reg_info_ids 有重复 | `epr_reg_info_ids must contain unique IDs (no duplicates)` |
| 单个 ID 为空 | `EPRRegInfo ID cannot be empty` |

### 业务校验失败（400）

```json
{
    "code": 400,
    "msg": "PDF count(3) and ID count(5) mismatch",
    "data": null
}
```

其他可能的业务错误消息：

| 触发条件 | msg 内容 |
|----------|----------|
| ID 数超过 100 | `Count exceeds limit, max 100, got N` |
| 存在非 ECO TLC 记录 | `Non-ECO TLC EPRRegInfo IDs rejected (only ECO TLC records allowed): {ids}` |
| PDF 数 ≠ ID 数 | `PDF count(N) and ID count(M) mismatch` |
| Base64 解码失败 | `POA ZIP base64 decode failed` |
| ZIP 临时文件写入失败 | `POA ZIP temp file write failed` |
| ZIP 打开失败 | `ZIP file open failed (error code: N)` |
| 邮件发送失败 | `Mail send failed` |

### 非内网访问（401）

```json
{
    "code": 401,
    "msg": "Unauthorized: internal network only",
    "data": null
}
```

## 参数校验规则

| 规则 | 说明 |
|------|------|
| pdf_zip_base64 必填 | 请求体中必须包含此字段 |
| pdf_zip_base64 字符串类型 | 必须为字符串 |
| pdf_zip_base64 最大67MB | 最大长度 67000000 字符 |
| epr_reg_info_ids 必填 | 请求体中必须包含此字段 |
| epr_reg_info_ids 数组类型 | 必须为 JSON 数组 |
| epr_reg_info_ids 1~100个 | 数组长度 1~100 |
| epr_reg_info_ids 去重 | 数组内元素不可重复 |
| epr_reg_info_ids.* 必填 | 数组中每个元素不能为空 |
| epr_reg_info_ids.* 字符串类型 | 每个元素必须是字符串 |
| epr_reg_info_ids.* 最大36位 | 每个元素最长 36 个字符（UUID 长度） |

## 处理流程

1. **数量上限校验**：`epr_reg_info_ids` 数量超过 100 则拒绝
2. **ECO TLC 校验**：校验所有 `epr_reg_info_ids` 均属于 ECO TLC 纺织法记录（`SupplierName='ECO TLC'`），存在非 ECO TLC 记录则拒绝并列出非法 ID
3. **解码 ZIP**：将 `pdf_zip_base64` 解码为二进制数据，保存为本地 ZIP 临时文件，释放 base64 字符串内存
4. **统计 POA 数量**：打开 ZIP，统计 `.pdf` 文件数量（排除目录项）
5. **数量校验**：PDF 数量 = `epr_reg_info_ids` 数量，不一致则报错
6. **发送邮件**：
   - 邮件主题：`Demande de l'enregistrement avec Refashion {年份} pour {POA数} clients--Sea&Mew Consulting GmbH--{日期}`
   - 邮件正文（HTML 格式，保留段落换行）：
     ```
     Bonjour,
     Nous avons soumis {POA数} nouveaux enregistrements de la part de nos clients.
     Veuillez trouver ci-joint les POA.
     Pourriez-vous aider ces clients à compléter leur enregistrement ?
     Merci pour votre travail et votre patience. Bonne journée !

     Cordialement,
     Lena
     Sea&Mew Consulting GmbH
     Mittenhuber Str.4, 92318 Neumarkt
     Email : info@seamew.de
     ```
   - 附件：POA ZIP 包，文件名 `POA.zip`（无 XLSX 附件）
   - SMTP 配置：阿里云企业邮箱 `fr-epr@seamew.de`（`REFASHION_SMTP_*`），SSL 加密，收件人来自 `services.refashion_smtp.to_email`
7. **更新状态**：将所有 `epr_reg_info_ids` 对应的源记录 `PushTaxBureauStatus` 更新为 3（推送成功）
8. **清理临时文件**：删除本地 ZIP 临时文件

## 邮件发送配置

| 配置项 | 来源 | 说明 |
|--------|------|------|
| SMTP 主机 | `services.refashion_smtp.host` | 阿里云企业邮箱服务器 |
| SMTP 端口 | `services.refashion_smtp.port` | SSL 端口 |
| 发件人 | `services.refashion_smtp.from_email` / `from_name` | `fr-epr@seamew.de` / Sea&Mew Consulting GmbH |
| 收件人 | `services.refashion_smtp.to_email` | Refashion 接收邮箱（`REFASHION_REG_MAIL_TO`，默认 `hotline@refashion.fr`） |
| 加密方式 | SMTPS (SSL) | PHPMailer `ENCRYPTION_SMTPS` |
| 字符编码 | UTF-8 | |

## 邮件主题格式

`Demande de l'enregistrement avec Refashion {year} pour {count} clients--Sea&Mew Consulting GmbH--{Y.m.d}`

- `{year}`：当前年份（`date('Y')`）
- `{count}`：POA 文件数（ZIP 内 PDF 数）
- `{Y.m.d}`：发送邮件日期

示例：`Demande de l'enregistrement avec Refashion 2026 pour 3 clients--Sea&Mew Consulting GmbH--2026.07.29`

## 数量校验说明

- **PDF 文件数量**：ZIP 内所有 `.pdf` 扩展名的文件（排除目录项）
- **提交 ID 数量**：`epr_reg_info_ids` 数组长度

两者不一致意味着数据不完整或存在遗漏，拒绝发送并返回具体不一致的数值。

## ECO TLC 校验说明

所有 `epr_reg_info_ids` 必须属于 `SupplierName='ECO TLC'` 的纺织法记录（与 `generate-refashion-poa` 共用的识别口径）。存在 LEKO/CITEO 等包装法记录则拒绝发送，防止误发邮件 / 误置 `PushTaxBureauStatus=3`。

## 注意事项

- 请求体可能因 Base64 编码含换行符而体积较大，`parse.large.json` 中间件会自动处理 JSON 解析问题
- Windows 环境下阿里云企业邮箱 SSL 证书可能不匹配，代码已跳过 SSL 证书验证
- 邮件正文以 HTML 格式发送（`isHTML(true)`），换行通过 `nl2br()` 转为 `<br>` 标签，AltBody 保留纯文本格式
- 邮件主题与正文为法文，硬编码在 `RefashionMailService` 类常量中（业务固定，无需配置）；仅收件人地址可配置
- 处理完成后所有临时文件（ZIP 解码）都会被清理
- 错误信息记录在 `api_refashion_mail` 日志通道，路径为 `storage/logs/api/refashion-mail-YYYY-MM-DD.log`（30 天保留，`LOG_API_DAYS` 环境变量）
- 发送成功后源记录状态更新为推送成功（PushTaxBureauStatus=3），不可重复发送

## cURL 调用示例

```bash
curl -X POST \
  http://automation.usaeu.com:8888/fr_epr_reg/api/epr/send-refashion-mail \
  -H 'Content-Type: application/json' \
  -d '{
    "pdf_zip_base64": "UEsDBBQAAAAIAA...",
    "epr_reg_info_ids": [
      "EPR-REG-INFO-ID-001",
      "EPR-REG-INFO-ID-002",
      "EPR-REG-INFO-ID-003"
    ]
  }'
```
