From a47eeeedcb53865cb41423840627ffaf376c89c0 Mon Sep 17 00:00:00 2001 From: yaosutu <770858045@qq.com> Date: Tue, 23 Jun 2026 16:05:51 +0800 Subject: [PATCH] =?UTF-8?q?docs(invoice):=20=E5=8F=91=E7=A5=A8=E7=94=B3?= =?UTF-8?q?=E8=AF=B7=E6=9C=80=E7=BB=88=E5=A5=91=E7=BA=A6=20-=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E2=E6=96=87=E4=BB=B6=20+=20=E5=8B=98=E8=AF=AF2=E6=96=87?= =?UTF-8?q?=E4=BB=B6=EF=BC=88#4290=20#4292=20#4302=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增: - changelogs-v2/2026-06/23_4290_发票申请入参票种修正-修改接口-管理后台.md - changelogs-v2-mp/2026-06/23_4290_发票申请票种修正-修改接口-小程序端.md 勘误: - 23_4258_发票详情接口:删除 mailAddress 出参字段、去掉 ELECTRONIC 枚举、email 改为始终有值 - 23_4265_发票列表:invoiceType 枚举去掉 ELECTRONIC(普票/专票两值) 契约定稿要点:invoiceType 只有 VAT_NORMAL/VAT_SPECIAL;email 始终必填+格式; 专票限 COMPANY 抬头(581523);专票五项全必填(581515);删 mailAddress(全电子交付) --- ...4290_发票申请票种修正-修改接口-小程序端.md | 334 ++++++++++++++++++ .../23_4258_发票详情接口-新增接口-管理后台.md | 13 +- ..._发票列表page结构调整-修改接口-管理后台.md | 3 +- ..._发票申请入参票种修正-修改接口-管理后台.md | 303 ++++++++++++++++ 4 files changed, 646 insertions(+), 7 deletions(-) create mode 100644 changelogs-v2-mp/2026-06/23_4290_发票申请票种修正-修改接口-小程序端.md create mode 100644 changelogs-v2/2026-06/23_4290_发票申请入参票种修正-修改接口-管理后台.md diff --git a/changelogs-v2-mp/2026-06/23_4290_发票申请票种修正-修改接口-小程序端.md b/changelogs-v2-mp/2026-06/23_4290_发票申请票种修正-修改接口-小程序端.md new file mode 100644 index 0000000..0c9a5f1 --- /dev/null +++ b/changelogs-v2-mp/2026-06/23_4290_发票申请票种修正-修改接口-小程序端.md @@ -0,0 +1,334 @@ +# 发票申请票种修正(最终契约)— 小程序端 + +> 变更类型:修改接口(破坏性) +> 端类型:小程序端 +> 日期:2026-06-23 | Issue:#4296 | PR:#4292 / #4302 | 服务:hl-order-service-v3 + +> ⚠️ **破坏性变更**:`invoiceType` 删除 `ELECTRONIC`、`email` 改为始终必填 + 格式校验、专票限公司抬头 + 必填五项、删除 `mailAddress` 字段。小程序开票页与详情页均需同步改动,上线时前后端须同步发布。 + +--- + +## 接口背景 + +发票模型经 PR #4292 + #4302 多轮修正后定稿:删除「电子发票」票种(业务决策统一走普票),专票收严字段校验(限公司抬头 + 必填银行注册信息),email 改为始终必填(全系统电子交付),删除纸质邮寄字段 `mailAddress`。 + +本次涉及小程序两个接口:初次申请 `POST /v3/internal/mp/order/{orderId}/invoice/apply` 和重新开票 `POST /v3/internal/mp/invoice/{id}/reissue`,入参字段矩阵相同,出参亦做同步修正(删 `mailAddress`,invoiceType 去 ELECTRONIC)。 + +--- + +## 变更清单 + +| # | 变更类型 | 说明 | +|---|---------|------| +| 1 | ⚠️ 申请入参删枚举值 | `invoiceType` 删除 `ELECTRONIC`,只保留 `VAT_NORMAL` / `VAT_SPECIAL` | +| 2 | ⚠️ 申请入参删字段 | 删除 `mailAddress`(纸质邮寄地址) | +| 3 | ⚠️ 申请入参校验收严 | `email` 改为始终必填 + 邮箱格式校验 | +| 4 | ⚠️ 申请入参校验新增 | `taxNo`:单位抬头或专票时必填 | +| 5 | ⚠️ 申请入参校验新增 | 专票:`bankName` / `bankAccount` / `registAddress` / `registPhone` 四项必填 | +| 6 | ⚠️ 申请入参新增错误码 | `581523` 专票只能开给单位 | +| 7 | ⚠️ 详情出参删字段 | `GET /v3/internal/mp/order/{orderId}/invoice/detail` 出参删除 `mailAddress` | +| 8 | ⚠️ 列表出参枚举收窄 | `GET /v3/internal/mp/order/{orderId}/invoice/list` 出参 invoiceType 不再出现 ELECTRONIC | +| 9 | 重开接口同步 | `POST /v3/internal/mp/invoice/{id}/reissue` 入参字段矩阵与申请接口保持一致 | + +--- + +## 接口详情 + +### 小程序申请接口 + +| 项 | 说明 | +|---|------| +| **方法 + 路径** | `POST /v3/internal/mp/order/{orderId}/invoice/apply` | +| **接口名** | 小程序客户自主申请发票 | +| **描述** | 客户在订单完成后自主提交开票申请,支持普票/专票,全电子交付 | +| **认证** | 小程序 JWT(Bearer Token,C 端用户) | +| **幂等性** | 非幂等,重复提交触发 581511(一单一票) | +| **限流** | 无特殊限流 | + +### 小程序重开接口 + +| 项 | 说明 | +|---|------| +| **方法 + 路径** | `POST /v3/internal/mp/invoice/{id}/reissue` | +| **接口名** | 小程序重新开票 | +| **描述** | 旧发票作废后,客户重新提交开票申请;入参字段矩阵与 apply 接口相同 | +| **认证** | 小程序 JWT(Bearer Token,C 端用户) | +| **幂等性** | 非幂等 | +| **限流** | 无特殊限流 | + +--- + +## 接口入参 + +### 路径参数 + +**apply 接口:** + +| 参数名 | 类型 | 必填 | 说明 | +|--------|------|------|------| +| `orderId` | string(Long 雪花 ID) | 是 | 订单 ID | + +**reissue 接口:** + +| 参数名 | 类型 | 必填 | 说明 | +|--------|------|------|------| +| `id` | string(Long 雪花 ID) | 是 | 被重开的旧发票 ID | + +### 请求体字段(两接口共用) + +| 字段名 | 类型 | 必填条件 | 说明 | +|--------|------|---------|------| +| `invoiceType` | string | 始终必填 | 发票类型:`VAT_NORMAL`(普票)/ `VAT_SPECIAL`(专票);**不含 ELECTRONIC** | +| `titleType` | string | 始终必填 | 抬头类型:`COMPANY`(单位)/ `PERSONAL`(个人);**VAT_SPECIAL 只能 COMPANY** | +| `titleName` | string | 始终必填 | 发票抬头 | +| `taxNo` | string | `titleType=COMPANY` 或 `invoiceType=VAT_SPECIAL` 时必填 | 纳税人识别号 | +| `bankName` | string | `invoiceType=VAT_SPECIAL` 时必填 | 开户银行 | +| `bankAccount` | string | `invoiceType=VAT_SPECIAL` 时必填 | 银行账号 | +| `registAddress` | string | `invoiceType=VAT_SPECIAL` 时必填 | 注册地址 | +| `registPhone` | string | `invoiceType=VAT_SPECIAL` 时必填 | 注册电话 | +| `amount` | integer | 始终必填 | 开票金额,单位**分**,须 > 0 且不超过订单总金额 | +| `email` | string | 始终必填 | 收件邮箱,须通过邮箱格式校验 | +| `remark` | string | 选填 | 备注 | + +> ⚠️ `mailAddress` 字段**已删除**,不再接收。 + +--- + +## 出参字段 + +### apply / reissue 接口出参 + +返回结构:`Result` + +| 字段名 | 类型 | 说明 | +|--------|------|------| +| `data` | string | 新建/重开发票 ID,字符串雪花 ID | + +### 发票详情出参变化(GET /v3/internal/mp/order/{orderId}/invoice/detail) + +| 字段名 | 变化 | 说明 | +|--------|------|------| +| `mailAddress` | **已删除** | 原出参中此字段已移除,前端不应再渲染邮寄地址 | +| `invoiceType` | 值范围收窄 | 只会出现 `VAT_NORMAL` / `VAT_SPECIAL`,不再出现 `ELECTRONIC` | +| `email` | 始终有值 | 原可能为 null,现始终有值 | + +--- + +## 枚举 / 数据字典 + +### 发票类型(invoiceType) + +| 枚举值 | 中文名 | 适用抬头 | 专票字段要求 | +|--------|--------|---------|------------| +| `VAT_NORMAL` | 增值税普通发票 | COMPANY / PERSONAL | 专票四项均不需要 | +| `VAT_SPECIAL` | 增值税专用发票 | **仅 COMPANY** | taxNo + bankName + bankAccount + registAddress + registPhone 全必填 | + +> ~~`ELECTRONIC`~~ 已删除,不得传入。 + +### 抬头类型(titleType) + +| 枚举值 | 中文名 | 可选票种 | +|--------|--------|---------| +| `COMPANY` | 单位 | VAT_NORMAL / VAT_SPECIAL | +| `PERSONAL` | 个人 | 只能 VAT_NORMAL,选 VAT_SPECIAL 返回 581523 | + +--- + +## 错误码 + +| 错误码 | 含义 | 触发场景 | +|--------|------|---------| +| `581510` | 订单未完成,不可开票 | 订单状态不是 COMPLETED | +| `581511` | 一单一票,已有有效发票 | 已有 REQUESTED / ISSUED / PUSHED 状态发票 | +| `581512` | 开票金额超订单总额 | `amount` > 订单 `orderAmount` | +| `581513` | 发票类型非法 | `invoiceType` 不是 VAT_NORMAL 或 VAT_SPECIAL | +| `581514` | 公司抬头或专票须填税号 | 单位抬头或专票时 `taxNo` 为空 | +| `581515` | 专票须填银行及注册信息 | 专票时任一四项为空 | +| `581516` | 收件邮箱不能为空 | HTTP 400,入参层 @NotBlank 校验;格式错误返回 400「邮箱格式不正确」 | +| `581523` | 专票只能开给单位 | `invoiceType=VAT_SPECIAL` 且 `titleType=PERSONAL` | +| `401` | 未授权 | 未携带有效 JWT | +| `403` | 无权限 / 越权 | 非订单归属用户操作 | + +--- + +## 示例 + +### 典型成功(增值税普通发票,个人抬头) + +请求: +``` +POST /v3/internal/mp/order/1920000000000000001/invoice/apply +Authorization: Bearer +Content-Type: application/json +``` +```json +{ + "invoiceType": "VAT_NORMAL", + "titleType": "PERSONAL", + "titleName": "张三", + "taxNo": null, + "amount": 98600, + "email": "zhangsan@qq.com", + "remark": "旅游报销" +} +``` + +响应: +```json +{ + "code": 200, + "msg": "success", + "data": "1934567890123456789" +} +``` + +### 典型成功(增值税专用发票,公司抬头,全字段) + +请求: +``` +POST /v3/internal/mp/order/1920000000000000002/invoice/apply +Authorization: Bearer +Content-Type: application/json +``` +```json +{ + "invoiceType": "VAT_SPECIAL", + "titleType": "COMPANY", + "titleName": "某某科技有限公司", + "taxNo": "91310000XXXXXXXXXX", + "bankName": "招商银行上海支行", + "bankAccount": "1234567890123456", + "registAddress": "上海市浦东新区XX路XX号", + "registPhone": "021-88888888", + "amount": 298000, + "email": "finance@company.com" +} +``` + +响应: +```json +{ + "code": 200, + "msg": "success", + "data": "1934567890123456790" +} +``` + +### 业务失败(专票个人抬头,错误码 581523) + +请求: +``` +POST /v3/internal/mp/order/1920000000000000003/invoice/apply +Authorization: Bearer +Content-Type: application/json +``` +```json +{ + "invoiceType": "VAT_SPECIAL", + "titleType": "PERSONAL", + "titleName": "李四", + "taxNo": null, + "amount": 50000, + "email": "lisi@example.com" +} +``` + +响应: +```json +{ + "code": 581523, + "msg": "增值税专用发票只能开给单位,个人抬头不可选专票", + "data": null +} +``` + +--- + +## 业务边界 + +**适用场景** +- 客户在小程序「我的订单 - 订单详情」中点「申请发票」,订单状态为 COMPLETED 时可用 +- 旧发票被作废后,客户在小程序发起重新申请(reissue 接口) + +**不适用场景** +- 订单未完成(非 COMPLETED 状态),返回 581510 +- 已有有效发票,须先由财务作废后才能 reissue,不能再次 apply +- 管理后台代客申请走 admin 专属接口 + +**特殊边界** +- 金额单位:`amount` 为整数**分**,前端显示元时需在提交前 ×100 +- 一单一票:同一订单至多一张有效发票 +- 专票抬头联动:选专票后,抬头类型需强制为单位,个人选项需禁用或隐藏 +- 详情回显:`mailAddress` 字段已不存在,前端不应渲染邮寄地址块 + +--- + +## 修改前后对比 + +### 发票类型枚举 + +| 旧值 | 新值 | +|------|------| +| VAT_NORMAL(保留) | VAT_NORMAL(保留) | +| VAT_SPECIAL(保留) | VAT_SPECIAL(保留) | +| ELECTRONIC(电子发票) | **已删除** | + +### email 字段校验 + +| 旧行为 | 新行为 | +|--------|--------| +| 条件必填(ELECTRONIC 时才必填) | **始终必填 + 邮箱格式校验** | + +### mailAddress 字段 + +| 旧行为 | 新行为 | +|--------|--------| +| 申请入参可选填;详情/列表出参包含此字段 | **申请入参已删除;详情出参已删除** | + +### 专票限制 + +| 旧行为 | 新行为 | +|--------|--------| +| titleType 无限制 | 专票只能 COMPANY(个人返回 581523) | +| bankName 等无强制要求 | 专票 taxNo + 银行四项全部必填(返回 581515) | + +--- + +## 影响评估 / 回滚 + +### 小程序开票页必须改动 + +| 模块 | 必须改动 | +|------|---------| +| 发票类型选择 | 去掉「电子发票」,只保留「增值税普通发票」/「增值税专用发票」 | +| 专票表单区块 | 新增开户行、银行账号、注册地址、注册电话 4 个必填项,仅选专票时显示 | +| 抬头类型联动 | 选专票时隐藏/禁用「个人」选项 | +| email 输入框 | 改为必填(加红星),增加邮箱格式校验 | +| mailAddress 输入框 | 移除,不再渲染邮寄地址块 | +| 详情页 | 移除邮寄地址展示区,invoiceType 显示只有普票/专票两种文案 | + +### 回滚方案 + +后端回滚至 PR #4292 前,ELECTRONIC 重新有效,email 恢复条件必填,mailAddress 重新可用。小程序需同步回滚开票页逻辑。 + +--- + +## 注意事项 + +1. `ELECTRONIC` 已从枚举删除,小程序开票选项只有两项,禁止出现「电子发票」 +2. 重开接口(reissue)入参字段矩阵与 apply 完全相同,改动同步适用 +3. 专票五项(taxNo + 开户行 + 账号 + 注册地址 + 注册电话)在专票场景下全必填,缺一返回 581515 +4. 详情页 `mailAddress` 字段已消失,老版本小程序读到 undefined 需做好空值守卫(不报错) +5. `amount` 单位为分,小程序展示/输入框以元为单位时,提交前须 ×100 + +--- + +## 关联 / 联系人 + +| 项 | 内容 | +|----|------| +| **Issue(功能)** | [#4290 发票申请票种修正](https://git.1814.love:8443/wx/HL/issues/4290) | +| **Issue(小程序)** | [#4296 小程序发票申请同步修正](https://git.1814.love:8443/wx/HL/issues/4296) | +| **PR(票种删 ELECTRONIC)** | [#4292](https://git.1814.love:8443/wx/HL/pulls/4292) | +| **PR(专票限公司/email 必填/删 mailAddress)** | [#4302](https://git.1814.love:8443/wx/HL/pulls/4302) | +| **后端负责人** | yst | diff --git a/changelogs-v2/2026-06/23_4258_发票详情接口-新增接口-管理后台.md b/changelogs-v2/2026-06/23_4258_发票详情接口-新增接口-管理后台.md index cb85cf4..3b52de2 100644 --- a/changelogs-v2/2026-06/23_4258_发票详情接口-新增接口-管理后台.md +++ b/changelogs-v2/2026-06/23_4258_发票详情接口-新增接口-管理后台.md @@ -6,6 +6,11 @@ --- +> **勘误(2026-06-23,#4292 #4302)**:本文件初版(#4262)包含 3 处与最终实现不符的内容,已在本次修正: +> 1. `invoiceType` 枚举已删除 `ELECTRONIC`(电子发票),只保留 `VAT_NORMAL`(增值税普通发票)和 `VAT_SPECIAL`(增值税专用发票) +> 2. 出参已删除 `mailAddress` 字段(无纸质邮寄,全电子交付) +> 3. `email` 字段始终有值(全电子交付),不再是"电子发票为 null" + ## 接口背景 财务在「上传发票 PDF」弹窗或发票详情页中,需要读取完整的开票申请明细:抬头信息、开票金额、专票四项(银行账号、注册地址、注册电话)、开票后的发票号 / PDF / 推送记录。本接口返回单张发票的全量字段,供弹窗回显和详情页展示使用。 @@ -73,8 +78,7 @@ | `registAddress` | string / null | 注册地址,**仅专票**有值,其余 null | | `registPhone` | string / null | 注册电话,**仅专票**有值,其余 null | | `amount` | string | 开票金额,单位**分**,字符串防精度丢失,如 `"98600"` | -| `email` | string / null | 电子发票接收邮箱 | -| `mailAddress` | string / null | 纸质发票邮寄地址,电子发票为 null | +| `email` | string | 收件邮箱(始终有值,全电子交付) | | `applyReason` | string / null | 备注(申请原因) | ### 状态字段 @@ -124,7 +128,6 @@ |--------|--------|------| | `VAT_NORMAL` | 增值税普通发票 | 普票,专票四项字段均为 null | | `VAT_SPECIAL` | 增值税专用发票 | 专票,bankName / bankAccount / registAddress / registPhone 有值 | -| `ELECTRONIC` | 电子发票 | 电子普票,mailAddress 为 null,仅 email 有值 | ### 抬头类型(titleType) @@ -184,7 +187,6 @@ Authorization: Bearer "registPhone": null, "amount": "98600", "email": "finance@hulalv.com", - "mailAddress": null, "applyReason": "报销使用", "status": "REQUESTED", "statusText": "待开票", @@ -235,7 +237,6 @@ Authorization: Bearer "registPhone": "021-12345678", "amount": "150000", "email": null, - "mailAddress": "上海市浦东新区财务部", "applyReason": null, "status": "ISSUED", "statusText": "已开票(待推送)", @@ -288,7 +289,7 @@ Authorization: Bearer - 小程序端查询发票(本接口仅管理后台) **特殊边界** -- 专票四项字段(`bankName` / `bankAccount` / `registAddress` / `registPhone`):仅 `invoiceType=VAT_SPECIAL` 时有值,前端按 invoiceType 决定是否展示这四项 +- 专票五项字段(`taxNo` / `bankName` / `bankAccount` / `registAddress` / `registPhone`):taxNo 普票公司抬头也需填,专票四项仅 `invoiceType=VAT_SPECIAL` 时有值,前端按 invoiceType 决定是否展示 - 开票痕迹字段(`invoiceNo` / `fileUrl` / `pdfName` / `pdfSize` / `issuedBy` / `issuedAt`):状态为 `ISSUED` 或 `PUSHED` 时有值,`REQUESTED` 和 `VOIDED` 时为 null - 推送痕迹字段(`pushedAt` / `pushedChannels`):仅 `PUSHED` 时有值 - `amount` 单位为**分**,前端展示时除以 100 转为元 diff --git a/changelogs-v2/2026-06/23_4265_发票列表page结构调整-修改接口-管理后台.md b/changelogs-v2/2026-06/23_4265_发票列表page结构调整-修改接口-管理后台.md index c8d7a85..5f07794 100644 --- a/changelogs-v2/2026-06/23_4265_发票列表page结构调整-修改接口-管理后台.md +++ b/changelogs-v2/2026-06/23_4265_发票列表page结构调整-修改接口-管理后台.md @@ -8,6 +8,8 @@ --- +> **勘误(2026-06-23,#4292 #4302)**:`invoiceType` 枚举已删除 `ELECTRONIC`(电子发票),当前系统只有 `VAT_NORMAL`(增值税普通发票)和 `VAT_SPECIAL`(增值税专用发票)两种类型。列表行 `invoiceType` 字段不会出现 `ELECTRONIC` 值,前端发票类型筛选下拉也只保留普票/专票两项。 + ## 接口背景 财务发票管理列表本轮进行了三项结构升级: @@ -159,7 +161,6 @@ |--------|--------| | `VAT_NORMAL` | 增值税普通发票 | | `VAT_SPECIAL` | 增值税专用发票 | -| `ELECTRONIC` | 电子发票 | --- diff --git a/changelogs-v2/2026-06/23_4290_发票申请入参票种修正-修改接口-管理后台.md b/changelogs-v2/2026-06/23_4290_发票申请入参票种修正-修改接口-管理后台.md new file mode 100644 index 0000000..16de519 --- /dev/null +++ b/changelogs-v2/2026-06/23_4290_发票申请入参票种修正-修改接口-管理后台.md @@ -0,0 +1,303 @@ +# 发票申请入参票种修正(最终契约) + +> 变更类型:修改接口(破坏性) +> 端类型:管理后台 +> 日期:2026-06-23 | Issue:#4290 | PR:#4292 / #4302 | 服务:hl-order-service-v3 + +> ⚠️ **破坏性变更**:`invoiceType` 删除 `ELECTRONIC`、`email` 改为始终必填 + 格式校验、新增 `taxNo`/银行/注册信息专票五项校验、删除 `mailAddress` 字段、专票限 `COMPANY` 抬头。前端申请表单需同步改动,上线时前后端须同步发布。 + +--- + +## 接口背景 + +发票模型经 PR #4292 + #4302 多轮修正后定稿:删除原设计中的「电子发票」票种(业务决策统一走 VAT_NORMAL 普票),对专票收严字段校验(专票限公司抬头 + 必填五项),email 改为始终必填(全系统电子交付),删除纸质邮寄字段 `mailAddress`。 + +本文档为最终契约,与本月早前 `23_4172_...` 系列文件中的历史设计存在差异,以本文档为准。 + +--- + +## 变更清单 + +| # | 变更类型 | 说明 | +|---|---------|------| +| 1 | ⚠️ 删枚举值 | `invoiceType` 删除 `ELECTRONIC`,只保留 `VAT_NORMAL` / `VAT_SPECIAL` | +| 2 | ⚠️ 删字段 | 申请入参 + 详情出参均删除 `mailAddress`(纸质邮寄地址) | +| 3 | ⚠️ 校验收严 | `email` 改为始终必填(原为条件必填),并加邮箱格式校验 | +| 4 | ⚠️ 新增校验 | `taxNo`:单位抬头或专票时必填(原仅"公司抬头"须填) | +| 5 | ⚠️ 新增校验 | `bankName` / `bankAccount` / `registAddress` / `registPhone`:专票必填(原无此四项限制) | +| 6 | ⚠️ 新增错误码 | `581523` 专票只能开给单位(`titleType` 须 `COMPANY`) | +| 7 | ✨ 行为明确 | `VAT_SPECIAL` 自动限 `COMPANY` 抬头,个人选专票被拒(581523) | + +--- + +## 接口详情 + +### 管理后台申请接口 + +| 项 | 说明 | +|---|------| +| **方法 + 路径** | `POST /v3/admin/order/{orderId}/invoice/apply` | +| **接口名** | 管理后台代客申请发票 | +| **描述** | 财务或定制师代客提交开票申请,支持普票/专票,全电子交付 | +| **认证** | 管理后台 JWT(Bearer Token) | +| **幂等性** | 非幂等,重复提交触发 581511(一单一票) | +| **限流** | 无特殊限流 | + +--- + +## 接口入参 + +### 路径参数 + +| 参数名 | 类型 | 必填 | 说明 | +|--------|------|------|------| +| `orderId` | string(Long 雪花 ID) | 是 | 订单 ID,字符串传输防精度丢失 | + +### 请求体字段 + +| 字段名 | 类型 | 必填条件 | 说明 | +|--------|------|---------|------| +| `invoiceType` | string | 始终必填 | 发票类型,只有 `VAT_NORMAL` / `VAT_SPECIAL` 两值,**不含 ELECTRONIC** | +| `titleType` | string | 始终必填 | 抬头类型:`COMPANY`(单位)/ `PERSONAL`(个人);**VAT_SPECIAL 只能 COMPANY** | +| `titleName` | string | 始终必填 | 发票抬头(企业全称或个人姓名) | +| `taxNo` | string | `titleType=COMPANY` 或 `invoiceType=VAT_SPECIAL` 时必填 | 纳税人识别号 | +| `bankName` | string | `invoiceType=VAT_SPECIAL` 时必填 | 开户银行名称 | +| `bankAccount` | string | `invoiceType=VAT_SPECIAL` 时必填 | 银行账号 | +| `registAddress` | string | `invoiceType=VAT_SPECIAL` 时必填 | 注册地址 | +| `registPhone` | string | `invoiceType=VAT_SPECIAL` 时必填 | 注册电话 | +| `amount` | integer | 始终必填 | 开票金额,单位**分**,须 > 0 且 ≤ 订单总金额 | +| `email` | string | 始终必填 | 收件邮箱,全电子交付,须通过邮箱格式校验 | +| `remark` | string | 选填 | 申请备注 | +| `applyReason` | string | 选填 | 申请原因(与 remark 二选一或并用) | + +> ⚠️ `mailAddress` 字段**已删除**,后端不接收,填了也忽略。 + +--- + +## 出参字段 + +返回结构:`Result` — 返回新建发票 ID(字符串,雪花 ID)。 + +| 字段名 | 类型 | 说明 | +|--------|------|------| +| `data` | string | 新建发票 ID,如 `"1934567890123456789"` | + +--- + +## 枚举 / 数据字典 + +### 发票类型(invoiceType) + +| 枚举值 | 中文名 | 校验规则 | +|--------|--------|---------| +| `VAT_NORMAL` | 增值税普通发票 | bankName / bankAccount / registAddress / registPhone 均不需要 | +| `VAT_SPECIAL` | 增值税专用发票 | taxNo + 银行四项均必填,且 titleType 必须 COMPANY | + +> ~~`ELECTRONIC`~~ 已删除,禁止传入(传入返回 581513)。 + +### 抬头类型(titleType) + +| 枚举值 | 中文名 | 限制 | +|--------|--------|------| +| `COMPANY` | 单位 | 普票/专票均可 | +| `PERSONAL` | 个人 | 只能选 `VAT_NORMAL`,选 `VAT_SPECIAL` 返回 581523 | + +--- + +## 错误码 + +| 错误码 | 含义 | 触发场景 | +|--------|------|---------| +| `581510` | 订单未完成,不可开票 | 订单状态不是 `COMPLETED` | +| `581511` | 一单一票,已有有效发票 | 该订单已存在 REQUESTED / ISSUED / PUSHED 状态发票 | +| `581512` | 开票金额超订单总额 | `amount` > 订单 `orderAmount` | +| `581513` | 发票类型非法 | `invoiceType` 不是 `VAT_NORMAL` 或 `VAT_SPECIAL` | +| `581514` | 公司抬头或专票须填税号 | `titleType=COMPANY` 或 `invoiceType=VAT_SPECIAL` 时 `taxNo` 为空 | +| `581515` | 专票须填银行及注册信息 | `invoiceType=VAT_SPECIAL` 时 taxNo / bankName / bankAccount / registAddress / registPhone 任一为空 | +| `581516` | 收件邮箱不能为空 | 入参层 `@NotBlank`,返回 HTTP 400「收件邮箱不能为空」;格式错误返回 400「邮箱格式不正确」 | +| `581523` | 专票只能开给单位 | `invoiceType=VAT_SPECIAL` 且 `titleType=PERSONAL` | +| `401` | 未授权 | 未携带有效 JWT | +| `403` | 无权限 | 当前账号无发票申请权限 | + +> 注意:581516 在入参校验层(`@NotBlank` / `@Email`)返回 HTTP 400,不走业务错误码;581513~581523 走 `BusinessException` 返回 200 包体。 + +--- + +## 示例 + +### 典型成功(增值税普通发票,个人抬头) + +请求: +``` +POST /v3/admin/order/1920000000000000001/invoice/apply +Authorization: Bearer +Content-Type: application/json +``` +```json +{ + "invoiceType": "VAT_NORMAL", + "titleType": "PERSONAL", + "titleName": "李四", + "taxNo": null, + "amount": 98600, + "email": "lisi@example.com", + "remark": "报销使用" +} +``` + +响应: +```json +{ + "code": 200, + "msg": "success", + "data": "1934567890123456789" +} +``` + +### 典型成功(增值税专用发票,公司抬头,全字段) + +请求: +``` +POST /v3/admin/order/1920000000000000002/invoice/apply +Authorization: Bearer +Content-Type: application/json +``` +```json +{ + "invoiceType": "VAT_SPECIAL", + "titleType": "COMPANY", + "titleName": "某某贸易有限公司", + "taxNo": "91310000YYYYYYYYYY", + "bankName": "工商银行上海支行", + "bankAccount": "6222000000000001", + "registAddress": "上海市浦东新区XX路XX号", + "registPhone": "021-12345678", + "amount": 150000, + "email": "finance@company.com", + "remark": null +} +``` + +响应: +```json +{ + "code": 200, + "msg": "success", + "data": "1934567890123456790" +} +``` + +### 业务失败(专票个人抬头被拒,错误码 581523) + +请求: +``` +POST /v3/admin/order/1920000000000000003/invoice/apply +Authorization: Bearer +Content-Type: application/json +``` +```json +{ + "invoiceType": "VAT_SPECIAL", + "titleType": "PERSONAL", + "titleName": "张三", + "taxNo": null, + "amount": 50000, + "email": "zhangsan@example.com" +} +``` + +响应: +```json +{ + "code": 581523, + "msg": "增值税专用发票只能开给单位,个人抬头不可选专票", + "data": null +} +``` + +--- + +## 业务边界 + +**适用场景** +- 财务在「发票管理 - 未申请 tab」找到已完成订单,代客提交开票申请 +- 定制师在订单详情页为客户发起申请 + +**不适用场景** +- 重新开票(走 `POST /v3/admin/order/invoice/{id}/reissue` 重开接口,入参相同) +- 小程序客户自主申请(走小程序端专属接口 `POST /v3/internal/mp/order/{orderId}/invoice/apply`) + +**特殊边界** +- 一单一票:同一订单只允许一张有效发票(REQUESTED / ISSUED / PUSHED 状态),若已有则返回 581511,须先作废旧发票再申请 +- 订单状态:仅 `COMPLETED`(已完成)状态订单可申请,其他状态返回 581510 +- 金额单位:`amount` 为整数**分**(不是元),前端输入元时需在提交前 ×100 + +--- + +## 修改前后对比 + +### 发票类型(invoiceType 枚举) + +| 旧值(历史设计) | 新值(最终实现) | +|--------|--------| +| `VAT_NORMAL` 增值税普通发票 | `VAT_NORMAL` 增值税普通发票(保留) | +| `VAT_SPECIAL` 增值税专用发票 | `VAT_SPECIAL` 增值税专用发票(保留) | +| `ELECTRONIC` 电子发票 | **已删除,禁止传入** | + +### email 字段 + +| 旧行为 | 新行为 | +|--------|--------| +| 条件必填(电子发票时必填,普票/专票选填) | **始终必填** + 邮箱格式校验(全电子交付) | + +### mailAddress 字段 + +| 旧行为 | 新行为 | +|--------|--------| +| 纸质发票邮寄地址(选填) | **已删除**(无纸质邮寄,全电子交付) | + +### 专票校验 + +| 旧行为 | 新行为 | +|--------|--------| +| 无 titleType 限制 | **专票只能 COMPANY**(个人返回 581523) | +| bankName 等四项无强制 | **专票 bankName / bankAccount / registAddress / registPhone 全部必填**(返回 581515) | + +--- + +## 影响评估 / 回滚 + +### 破坏兼容性评估(前端申请表单必须改动) + +| 模块 | 必须改动 | +|------|---------| +| 发票类型下拉 | 去掉「电子发票」选项,只保留「增值税普通发票」/「增值税专用发票」 | +| 专票表单区块 | 新增开户行、银行账号、注册地址、注册电话 4 个必填输入框,仅在选专票时显示 | +| 抬头类型联动 | 选专票时,抬头类型只能选「单位」,隐藏或禁用「个人」选项 | +| email 字段 | 改为始终必填,加邮箱格式校验(正则或 HTML input type=email) | +| mailAddress 字段 | 移除,不再向后端传此字段 | + +### 回滚方案 + +后端回滚至 #4292 前版本后,`ELECTRONIC` 枚举值重新有效,`email` 恢复条件必填,`mailAddress` 重新可用。前端需同步回滚或做前向兼容处理。 + +--- + +## 注意事项 + +1. `ELECTRONIC` 枚举值已删除,前端下拉不可出现此选项;老订单历史数据如有该枚举值,出参展示时可显示「未知类型」或联系后端处理 +2. `email` 无论票种均必填,前端不可根据票种做条件隐藏 +3. 专票表单区块(税号 + 开户行 + 账号 + 注册地址 + 注册电话)共 5 个字段,在选专票时全部必填,不可缺任何一项 +4. `amount` 单位为**分**,前端展示/输入框单位通常为元,提交前须乘以 100 + +--- + +## 关联 / 联系人 + +| 项 | 内容 | +|----|------| +| **Issue(功能)** | [#4290 发票申请票种修正](https://git.1814.love:8443/wx/HL/issues/4290) | +| **Issue(小程序)** | [#4296 小程序发票申请同步修正](https://git.1814.love:8443/wx/HL/issues/4296) | +| **PR(票种删 ELECTRONIC)** | [#4292](https://git.1814.love:8443/wx/HL/pulls/4292) | +| **PR(专票限公司/email 必填/删 mailAddress)** | [#4302](https://git.1814.love:8443/wx/HL/pulls/4302) | +| **后端负责人** | yst |