hl-api-changelog/changelogs-v2-mp/2026-06/21_4174_发票小程序端申请+可见性+签名下载-新增接口-小程序端.md

10 KiB

发票补齐 - 小程序端申请 + 可见性过滤 + 签名下载(小程序端)

Issue: #4174 / #4182 PR: #4181mp 端申请+可见性)/ #4184(签名下载) 日期: 2026-06-21 服务: hl-order-service-v3invoice 域) 端类型: 小程序端


1. 接口背景

小程序发票模块本次补齐三项改动:

  • 申请门槛收紧PR4 / Issue #4174原 collab 域 POST /v3/internal/mp/order/{orderId}/invoice/apply 路径不变,但实现从 collab 迁入 invoice 域,门槛由宽松(可叠加多张)改为严格(一单一票 + 订单必须 COMPLETED + 金额不超订单总价)。
  • 出参可见性过滤PR4GET /v3/internal/mp/order/{orderId}/invoice/list 和 GET /v3/internal/mp/order/invoice/{invoiceId}/detail 出参中,fileUrl 字段现在仅在 ISSUED / PUSHED 状态时返回;REQUESTED 状态返回 null处理中,前端勿展示 PDF 链接)。
  • 新增签名下载端点#4184 / Issue #4182GET /v3/internal/mp/order/invoice/{invoiceId}/download,返回 1 小时有效期 OSS 签名 URL,供前端调 wx.openDocument 预览或下载发票 PDF。

2. 变更清单

# 接口 变更类型 说明
1 POST /v3/internal/mp/order/{orderId}/invoice/apply 修改接口(行为收紧) 申请门槛由宽松改严格:一单一票 + 订单 COMPLETED + 金额不超总价;resp status 字段值从 APPLIED 改为 REQUESTED
2 GET /v3/internal/mp/order/{orderId}/invoice/list 修改接口(字段行为变化) fileUrl 字段REQUESTED 状态由有值改为 null;ISSUED / PUSHED 保持有值
3 GET /v3/internal/mp/order/invoice/{invoiceId}/detail 修改接口(字段行为变化) fileUrl 字段同上REQUESTED 返 null,ISSUED / PUSHED 有值
4 GET /v3/internal/mp/order/invoice/{invoiceId}/download 新增接口 返回发票 PDF 的 OSS 签名下载 URL1 小时有效期),含 IDOR 鉴权

3. 接口详情

认证:所有接口走小程序 JWT 认证,Header 携带 Authorization: Bearer token小程序 openId → userId。 幂等性apply 非幂等(一单一票,重复提交报 581511;download 幂等(每次生成新签名 URL。 限流:网关全局限流。


4. 接口入参

4.1 路径参数 / Query 参数

接口 参数名 类型 必填 说明
POST /{orderId}/apply orderId Long 路径参数,订单 ID
GET /{orderId}/invoice/list orderId Long 路径参数,订单 ID
GET /invoice/{invoiceId}/detail invoiceId Long 路径参数,发票 ID
GET /invoice/{invoiceId}/download invoiceId Long 路径参数,发票 ID

4.2 请求体字段

POST /v3/internal/mp/order/{orderId}/invoice/apply

字段 类型 必填 说明
amount String 开票金额(字符串,单位元),不超过订单总价
invoiceType String 发票类型,枚举见 6 节
titleType String 抬头类型PERSONAL / COMPANY
title String 发票抬头(姓名或公司名)
taxNo String 条件必填 税号titleType=COMPANY 时必填)
bankName String 条件必填 开户行invoiceType=VAT_SPECIAL 时必填)
bankAccount String 条件必填 银行账号invoiceType=VAT_SPECIAL 时必填)
registAddress String 条件必填 注册地址invoiceType=VAT_SPECIAL 时必填)
registPhone String 条件必填 注册电话invoiceType=VAT_SPECIAL 时必填)
email String 条件必填 收票邮箱invoiceType=ELECTRONIC 时必填)
remark String 备注

GET 接口无请求体。


5. 出参字段

POST /v3/internal/mp/order/{orderId}/invoice/apply

字段 类型 说明
id String 新建发票 IDLong 序列化)
status String 固定为 REQUESTED

注意status 值此前旧实现返回 APPLIEDcollab 域),新实现返回 REQUESTEDinvoice 域)。请前端对齐新值。

GET /v3/internal/mp/order/{orderId}/invoice/list单条字段,变化部分

字段 原来行为 现在行为
fileUrl REQUESTED / ISSUED / PUSHED 均有值 REQUESTED 返 null;ISSUED / PUSHED 有值

其余字段不变id / orderId / status / statusName / amount / invoiceType / title / taxNo / createTime 等)。

GET /v3/internal/mp/order/invoice/{invoiceId}/detail变化部分

字段 原来行为 现在行为
fileUrl 同上,恒有值 REQUESTED 返 null;ISSUED / PUSHED 有值

GET /v3/internal/mp/order/invoice/{invoiceId}/download新增接口

字段 类型 说明
fileUrl String OSS 签名下载 URL1 小时有效期,格式为 HTTPS 带签名参数的 URL
pdfName String PDF 文件名(可选,用于 wx.openDocument 的 name 参数)

6. 枚举 / 数据字典

InvoiceStatus - 发票状态(影响 fileUrl 可见性)

枚举值 中文名 fileUrl 是否可见
REQUESTED 待开票 null处理中,前端勿展示 PDF 链接)
ISSUED 已开票 有值
PUSHED 已推送 有值
VOIDED 已作废 null

InvoiceType - 发票类型

枚举值 中文名
VAT_NORMAL 增值税普通发票
VAT_SPECIAL 增值税专用发票
ELECTRONIC 电子发票

TitleType - 抬头类型

枚举值 中文名
PERSONAL 个人
COMPANY 公司

7. 错误码

错误码 常量 触发场景
581510 INVOICE_ORDER_NOT_COMPLETED 订单状态非 COMPLETED,不可申请开票
581511 INVOICE_ALREADY_EXISTS 该订单已有有效发票,不可重复申请(一单一票)
581512 INVOICE_AMOUNT_EXCEED 开票金额超过订单总价
581513 INVOICE_TYPE_INVALID 发票类型枚举值非法
581514 INVOICE_TAX_NO_REQUIRED 公司抬头 / 专票时税号为必填
581515 INVOICE_VAT_SPECIAL_FIELDS_REQUIRED 专票时开户行 / 银行账号 / 注册地址 / 注册电话为必填
581516 INVOICE_EMAIL_REQUIRED 电子发票时邮箱为必填
581517 INVOICE_NOT_DOWNLOADABLE 发票尚未开具REQUESTED / VOIDED 状态),暂时无法下载
581518 INVOICE_FORBIDDEN 无权访问该发票IDOR 防护,含发票不存在场景)
581519 INVOICE_SIGNED_URL_FAILED 获取签名下载 URL 失败,请稍后重试hl-user-service 暂时不可用)

8. 示例

8.1 典型成功:申请开票

POST /v3/internal/mp/order/1234567890123456789/invoice/apply

请求体:

响应:

8.2 边界情况:列表中 REQUESTED 状态 fileUrl 为 null

GET /v3/internal/mp/order/1234567890123456789/invoice/list 响应示例(某张待开票发票):

8.3 业务失败REQUESTED 状态发票不可下载

GET /v3/internal/mp/order/invoice/111/download

响应:


9. 业务边界

适用:

  • 申请:订单状态必须为 COMPLETED;无有效发票一单一票;金额不超订单总价
  • 下载:发票状态为 ISSUED 或 PUSHED;且该发票属于当前登录用户的订单

不适用:

  • 订单 COMPLETED 之前不可申请
  • 已有有效发票,不可重复申请
  • REQUESTED / VOIDED 状态发票不可下载(报 581517
  • 访问他人订单的发票报 581518IDOR 防护,不返回 404 以避免泄露存在性)

特殊边界:

  • 签名 URL 有效期 1 小时。前端如果缓存了 fileUrl,每次打开下载前须重新调 download 接口获取最新签名 URL,不可长期复用。
  • wx.openDocument 下载后端直接返回签名 URL,前端无需中转。

10. 修改前后对比

POST apply 申请门槛变化

项目 变更前(旧 collab 实现) 变更后invoice 域)
一单一票限制 无(可叠加多张) existsActiveByOrderId 拦截)
金额校验 已开+本次 <= 总价 本次金额 <= 总价(一单一票前提下等价)
响应 status 值 APPLIED REQUESTED

GET list / detail fileUrl 可见性变化

发票状态 变更前 fileUrl 变更后 fileUrl
REQUESTED 有值OSS 公链) null前端显示处理中
ISSUED 有值 有值(不变)
PUSHED 有值 有值(不变)
VOIDED 有值 null

11. 影响评估 / 回滚

  • 破坏兼容性重要fileUrl 字段在 REQUESTED 状态下由有值变为 null。前端如果之前有展示 REQUESTED 状态下 PDF 链接的逻辑(点击打开 OSS 文件),现在会读到 null,需要做 null 判断,展示「处理中」状态文案。
  • apply status 值变化:从 APPLIED 改为 REQUESTED。前端如果有对 status 值做 hardcode 判断if status == APPLIED,需要更新。
  • 前端同步上线建议fileUrl null 判断 + apply 响应 status 对齐必须在本次版本同步更新。
  • 回滚方案回滚旧版本,fileUrl 可见性恢复,download 端点返回 404。apply 的 status 回退为 APPLIED如旧版本有此值

12. 注意事项

  1. fileUrl null 判断list / detail 接口读到 fileUrl 为 null 时,前端应显示「处理中」或「待开票」而不是空链接。
  2. 签名 URL 勿缓存超过 1 小时download 返回的签名 URL 有效期 1 小时,前端每次用前须重新调接口,不可全局缓存复用。
  3. apply 响应 status 值变更:旧值 APPLIED 已废弃,现在返回 REQUESTED。如前端有 switch/if 判断该值,须对齐。
  4. download IDOR 防护:发票不存在或不属于当前用户均返回 581518INVOICE_FORBIDDEN,不返回 404,避免存在性枚举攻击。

13. 关联 / 联系人