文件
hl-api-changelog/changelogs-v2/2026-10/04_8755_发票推送接短信推送日志新增SKIP-修改接口-管理后台.md
T
Mimingguang b4f2e3da14
changelog-filename-gate / validate (push) Failing after 1s
docs(changelog): #8755 回写前端 implemented(mmg,ref bfe3c4537)
2026-10-04 16:07:12 +08:00

17 KiB
原始文件 Blame 文件历史

schema, ticket, title, consumer, author, change_type, backend_status, gateway_status, frontend_status, frontend_owner, frontend_ref, target_release, verified_at, status_note, updated_at, base
schema ticket title consumer author change_type backend_status gateway_status frontend_status frontend_owner frontend_ref target_release verified_at status_note updated_at base
hl-changelog/v2 8755 发票推送接短信(按下单手机号直发):推送日志按真实结果落库,pushStatus 新增 SKIP「未发送」,邮件 / 微信不再假写成功 admin jw(GIT) 修改接口 deployed verified implemented mmg bfe3c4537a718769af4f8f99dbe0fa24e0f763f0 v2.1 2026-10-04 PUT /v3/admin/order/invoice/{id}/push 入参 / 出参 / 错误码不变,行为变:选 sms 时经通知中心按订单下单手机号直发「发票已开具」短信(带 8 位下载短码),推送日志按通知中心真实结果写 SUCCESS / FAILED / SKIP / PENDING;email / wechat 未接入,一律写 SKIP。GET /{id}/push-logs 与 GET /{id} 的 pushLogs[].pushStatus 新增取值 SKIP(statusText「未发送」),failReason 如实写原因。短信模板尚在申请(#8790,wx),模板到位前短信渠道写 SKIP「短信模板未配置,未发送」。已合并 dev-v3(9cd23903a)并部署 TEST,经网关实测,工单 #8755 已关。前端待做两处:推送弹窗 PushModal.vue:15 文案「本期仅记录推送状态,客户暂不会实际收到通知」改为如实说明(短信按下单手机号发送、邮件 / 微信暂不发送);推送日志抽屉 SKIP 行的原因前缀「失败原因:」改为「原因:」,可选给 SKIP 配一个标签色。statusText 已能自动显示「未发送」。前端已交付(2026-10-04):PushModal 文案改如实说明(短信按下单手机号发送/模板生效后,邮件微信暂不发送);PushLogsDrawer 前缀改「原因:」且仅 FAILED 染红(SKIP 走灰 tag+次级色原因行);invoice.js JSDoc 补 SKIP 口径,提交 bfe3c4537。 2026-10-04 dev-v3

发票推送接短信:推送日志按真实结果落库、新增 SKIP(管理后台)

服务: hl-order-service-v3(端口 8086/8186)+ hl-user-service(通知事件配置迁移) PR: #8776 Issue: #8755 日期: 2026-10-03 影响范围: 管理后台财务「发票管理」页的推送弹窗、推送记录抽屉、发票详情抽屉;接口签名零变化


⚠️ 关键变化

  1. 推送不再是假推送:选「短信」时经通知中心按订单下单手机号直发(不依赖小程序 userId,团期子订单也能收到),短信里带 8 位下载短码,客户免登录下载发票(配套新增接口见同单另一份 changelog)。
  2. 推送日志如实落库:pushStatus 新增 SKIP(statusText「未发送」),failReason 写清原因;原先三个渠道一律写 SUCCESS 的口径作废。
  3. 邮件 / 微信未接入:选了照样能推(状态机不变),但日志写 SKIP「邮件渠道未接入,未发送」/「微信渠道未接入,未发送」。
  4. 短信模板未到位(#8790):模板过审填入前,短信渠道日志写 SKIP「短信模板未配置,未发送」,客户收不到短信。
  5. 短信结果是异步回写的:推送接口返回时短信那行先是 PENDING,通常 1 秒内回写为终态;推送记录抽屉打开时再拉一次即可。

一、背景

#4230 曾定「本期不真发」:三个推送渠道监听器只登记一条 SUCCESS,前端弹窗也提示「客户暂不会实际收到通知」。jw 2026-10-03 定客户触达一律短信、按下单手机号直发、模板后补,于是本单接通短信并把推送日志改为如实落库。


二、变更接口清单

# 接口 方法 路径 变更类型 说明
1 推送发票给客户 PUT /v3/admin/order/invoice/{id}/push 修改接口 入参出参不变;sms 真发短信,各渠道日志按真实结果落库
2 发票推送明细日志 GET /v3/admin/order/invoice/{id}/push-logs 修改接口 pushStatus 新增 SKIP,failReason 如实写原因
3 发票详情 GET /v3/admin/order/invoice/{id} 修改接口 仅 pushLogs[] 同上变化,其余字段不变

网关:本组接口无改动(在既有 /v3/admin/** 通配下)。


三、接口详情

1. 推送发票给客户 PUT /v3/admin/order/invoice/{id}/push

VO: InvoicePushReqVO(入参)/ Result<Void>(出参)

使用场景

财务在「发票管理 · 待推送 / 已推送」点「推送」,勾选渠道后提交。发票状态 ISSUED → PUSHED(PUSHED 可再次推送);事务提交后各渠道异步发送并写推送日志。

入参

字段 位置 类型 必填 约束 说明
id path string(Long) 是 发票 ID 发票主键,字符串透传
channels body string[] 是 非空;元素 ∈ 字典 invoice_push_channel(email / wechat / sms) 推送渠道,可多选

出参

字段 类型 说明
code int 200 成功
message string 「成功」
data null 无数据;各渠道发送结果看推送日志

请求示例

{
  "channels": ["sms", "email"]
}

响应示例

{
  "code": 200,
  "message": "成功",
  "data": null,
  "traceId": null,
  "success": true
}

空数据 / 降级响应

接口本身无空数据形态。通知中心不可用、短信发送失败都不影响推送接口返回成功(发送在事务提交后异步进行),失败结果体现在推送日志 FAILED / PENDING:

{
  "channel": "sms",
  "pushStatus": "FAILED",
  "statusText": "失败",
  "pushedBy": "王会计",
  "pushedAt": "2026-10-03 21:05:45",
  "failReason": "通知中心调用失败"
}

错误响应

错误码与改前完全一致:

业务码 场景
581500 发票不存在
581520 发票当前状态不允许推送(须 ISSUED / PUSHED)
581521 推送渠道为空
581522 推送渠道非法
{
  "code": 581520,
  "message": "发票当前状态不允许推送(须已开票)",
  "data": null,
  "traceId": null,
  "success": false
}

业务边界

  • 状态机不变:ISSUED / PUSHED → PUSHED,pushedAt / pushedChannels 每次推送覆盖。
  • 每个勾选渠道每次推送写一条日志;sms 先写 PENDING,发完回写终态。
  • 短信收件人 = 订单 customer_phone(下单手机号);为空时写 SKIP「下单手机号为空,未发送短信」,不生成下载码。
  • 短信只在 sms 渠道发;email / wechat 不发、写 SKIP。
  • 同一发票连推两次会发两条短信(每次推送各自生成下载码)。

2. 发票推送明细日志 GET /v3/admin/order/invoice/{id}/push-logs

VO: InvoicePushLogRespVO

使用场景

推送记录抽屉按推送时间倒序展示每次、每个渠道的推送结果。

入参

字段 位置 类型 必填 约束 说明
id path string(Long) 是 发票 ID 发票主键

出参

字段 类型 说明
channel string email / wechat / sms
pushStatus string SUCCESS / FAILED / PENDING / SKIP(新增)
statusText string 成功 / 失败 / 待发 / 未发送(新增)
pushedBy string 操作人真实姓名
pushedAt string 推送时间 yyyy-MM-dd HH:mm:ss
failReason string | null 原因:FAILED / SKIP / PENDING 时有值,SUCCESS 为 null(原注释「预留」,现已启用)

请求示例

GET /v3/admin/order/invoice/2106369928091283458/push-logs
Authorization: Bearer <admin token>

响应示例

{
  "code": 200,
  "message": "成功",
  "data": [
    {
      "channel": "email",
      "pushStatus": "SKIP",
      "statusText": "未发送",
      "pushedBy": "admin",
      "pushedAt": "2026-10-03 21:11:53",
      "failReason": "邮件渠道未接入,未发送"
    },
    {
      "channel": "sms",
      "pushStatus": "SKIP",
      "statusText": "未发送",
      "pushedBy": "admin",
      "pushedAt": "2026-10-03 21:05:45",
      "failReason": "短信模板未配置,未发送"
    }
  ],
  "traceId": null,
  "success": true
}

空数据 / 降级响应

从未推送过:

{
  "code": 200,
  "message": "成功",
  "data": [],
  "traceId": null,
  "success": true
}

错误响应

{
  "code": 581500,
  "message": "发票不存在",
  "data": null,
  "traceId": null,
  "success": false
}

业务边界

  • 存量日志不订正:本单上线前的历史行仍是 SUCCESS(当时并未真发)。
  • pushStatus 未知值时 statusText 回落为原始值(既有口径)。
  • 短信行在推送后约 1 秒内由 PENDING 回写为终态;结果不确定时保留 PENDING 并写「以通知中心发送日志为准」。

3. 发票详情 GET /v3/admin/order/invoice/{id}

VO: AdminInvoiceDetailRespVO

使用场景

发票详情 / 上传抽屉。本单只影响其中的 pushLogs[](与接口 2 同源同 VO),其余字段零变化。

入参

字段 位置 类型 必填 约束 说明
id path string(Long) 是 发票 ID 发票主键

出参

字段 类型 说明
pushLogs InvoicePushLogRespVO[] 字段与接口 2 完全一致:pushStatus 新增 SKIP、statusText 新增「未发送」、failReason 如实写原因
其余字段 - 不变

请求示例

GET /v3/admin/order/invoice/2106369928091283458
Authorization: Bearer <admin token>

响应示例

{
  "code": 200,
  "message": "成功",
  "data": {
    "id": "2106369928091283458",
    "orderNo": "HL20260930170915373",
    "status": "PUSHED",
    "statusText": "已推送",
    "invoiceNo": "26152000000087551236",
    "pushedChannels": "email",
    "pushLogs": [
      {
        "channel": "email",
        "pushStatus": "SKIP",
        "statusText": "未发送",
        "pushedBy": "admin",
        "pushedAt": "2026-10-03 21:11:53",
        "failReason": "邮件渠道未接入,未发送"
      },
      {
        "channel": "sms",
        "pushStatus": "SKIP",
        "statusText": "未发送",
        "pushedBy": "admin",
        "pushedAt": "2026-10-03 21:05:45",
        "failReason": "短信模板未配置,未发送"
      }
    ]
  },
  "traceId": null,
  "success": true
}

空数据 / 降级响应

未推送过的发票 pushLogs 为空数组:

{
  "pushLogs": []
}

错误响应

{
  "code": 581500,
  "message": "发票不存在",
  "data": null,
  "traceId": null,
  "success": false
}

业务边界

  • 判权、其余字段、status / statusText 口径均不变。

四、契约约束与正确调用方式

✅ 正确 / ❌ 错误调用顺序

  • ✅ 推送记录展示用 statusText;failReason 非空时都展示(SKIP、PENDING 也有原因),前缀建议用「原因:」而不是「失败原因:」。
  • ✅ 推送成功后若立刻打开推送记录,短信行可能还是 PENDING,可在抽屉打开时重新拉取。
  • ❌ 不要把 SKIP 渲染成失败(红色),它表示「没发」而不是「发失败」。
  • ❌ 不要继续展示「本期仅记录推送状态,客户暂不会实际收到通知」。

五、数据库行为

  • order-v3:零 DDL。invoice_push_log.push_status(VARCHAR(16)、无 CHECK)新增写入值 SKIP;fail_reason 由「预留」改为如实写原因。短信推送每次写一条 invoice_download_code(建表见同单新增接口 changelog)。
  • user-service:Flyway V20261003_8755__invoice_pushed_notification.sql 往 notification_event_config 插(或按 uk_event_code 收敛)INVOICE_PUSHED:只开短信、模板哨兵 TODO_PLACEHOLDER、sms_field_mapping 为 orderNo / invoiceNo / amount / code;重放不覆盖运营已填的模板编码。通知中心每次发送写一行 notification_send_log(biz_type=INVOICE_PUSH、biz_id=推送日志 ID,收件人脱敏)。

六、边界行为

场景 推送日志
选 sms,模板未配置(当前) SKIP「短信模板未配置,未发送」
选 sms,下单手机号为空 SKIP「下单手机号为空,未发送短信」
选 sms,阿里云受理(带回执号) SUCCESS
选 sms,短信通道为模拟档(无回执号) SKIP「短信通道为模拟档(未配置短信网关),未真实发送」
选 sms,阿里云拒发 FAILED「短信发送失败:<原因>」
选 sms,通知中心不可用 FAILED「通知中心调用失败」
选 sms,投递结果不确定 / 查不到发送记录 PENDING(写明以通知中心发送日志为准)
选 email / wechat SKIP「邮件 / 微信渠道未接入,未发送」
发票状态非 ISSUED / PUSHED 581520,不写日志(同改前)

六.6、修改前后对比

项 改前 改后
选 sms 不发,日志写 SUCCESS 经通知中心按下单手机号直发,日志按真实结果写
选 email / wechat 不发,日志写 SUCCESS 不发,日志写 SKIP + 原因
pushStatus 取值 SUCCESS(实际恒定)/ FAILED / PENDING(预留) SUCCESS / FAILED / PENDING / SKIP
statusText 取值 成功 / 失败 / 待发 成功 / 失败 / 待发 / 未发送
failReason 恒 null FAILED / SKIP / PENDING 时写原因
短信行写入时机 推送后异步一次写入 推送后异步先写 PENDING,发完回写终态
入参 / 出参 / 错误码 / 状态机 — 不变

六.7、影响评估

  • 前端(hl-ui v2.1 实查):
    • src/views/order/invoice/components/PushLogsDrawer.vue:30 显示 log.statusText || log.pushStatus,「未发送」自动生效;:27 标签色 STATUS_TYPE[s] || 'default',SKIP 落灰色,可选补一个色。
    • PushLogsDrawer.vue:41把 failReason 冠以「失败原因:」前缀展示——SKIP 行也会显示,前缀建议改「原因:」。
    • src/views/order/invoice/components/PushModal.vue:15「本期仅记录推送状态,客户暂不会实际收到通知。」需改为如实说明:短信按订单下单手机号发送(模板生效后),邮件、微信暂不发送。
    • src/api/invoice.js:191 注释中的取值说明可同步补 SKIP。
  • 历史数据:上线前的推送日志仍是 SUCCESS(当时未真发),不订正。
  • 其他调用方:无。小程序端、通知中心其他事件、团期 / 订单流程零影响。

七、不影响范围

  • 仅影响: 推送接口的发送行为与推送日志取值(3 个管理端接口的 pushLogs 相关字段)。
  • 零影响:
    • 发票申请、开票、重传、重开、列表、统计接口
    • 小程序发票查询 / 下载 / 重开
    • 通知中心其他事件
  • 零权限种子变更、零网关变更(本组接口)。

八、测试环境已验证

部署:hl-user-service、hl-order-service-v3、hl-gateway = dev-v3 @ 9cd23903a(2026-10-03 20:56 / 20:59 / 21:00);TEST flyway_schema_history user 20261003.8755 success=1,INVOICE_PUSHED 配置行读回只开短信、模板 TODO_PLACEHOLDER;构建身份探针 6/6 命中新代码。经网关 https://api.test.1814.love 真实鉴权实测(2026-10-03 21:05–21:11),工单 #8755 已验收关单。

# 场景 结果
1 团期子订单(user_id 为空)发票 ISSUED,推 ["sms"] 200;发票 → PUSHED;推送日志 SKIP「短信模板未配置,未发送」;通知中心发送日志一行 INVOICE_PUSHED / SMS / status=3,收件人 138****2356,params_json 无手机号;生成下载码 1 枚(7 天)
2 另一张 ISSUED 发票推 ["email","wechat"] 200;发票 → PUSHED;两行 SKIP,原因分别为微信 / 邮件渠道未接入;不生成下载码
3 已 PUSHED 发票再推 ["email"] 200;仍 PUSHED,pushedAt / pushedChannels 已更新
4 GET /{id}/push-logs、GET /{id} pushStatus=SKIP、statusText=未发送、failReason 如实
5 日志脱敏 TEST order-v3 日志 11 位手机号出现 0 次
6 TEST 短信网关形态 aliyun.sms.access-key-id 为真实 AK(非模拟档);哨兵期在模板检查处跳过,未触达阿里云、未发出短信

九、相关历史 PR

PR Issue 说明 是否仍有效
— #4230 发票推送「本期不真发」 ⚠️ 被本单取代
— #3713 通知中心 directPhone 收件通道 ✅
— #8754 成团通知客户短信(同样按下单手机号直发) ✅
本 PR #8776 #8755 发票推送接短信 + 凭短码免登录下载 ✅ 最新

十、相关文档

  • 关联 Issue: wx/HL#8755
  • 关联 PR: wx/HL#8776
  • 短信模板申请跟进: wx/HL#8790
  • 同单配套新增接口: changelogs-v2/2026-10/04_8755_发票短信短码免登录下载-新增接口-管理后台.md

关联 / 联系人

链接

联系人

  • 后端负责人: @jw
  • 前端负责人: @mmg
  • 短信模板: @wx(#8790)