文件
hl-api-changelog/changelogs-v2/2026-09/07_7105_团期合同保险面板与逐户出具-新增接口-管理后台.md
T
2026-09-08 14:48:31 +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 7105 团期合同保险面板与逐户出具 admin jw(GIT) 新增接口 deployed verified verified mmg 838e77da 2026-09-08 新增团期合同保险面板与逐户手动开/作废重开/批量催签四端点,后端已部署 TEST 并实测。注意:出具门依赖房车导摄四项 ready,而 hotel_ready 线上无写入方(#4132 未完成),故面板 issuable 恒 false、手动开/作废重开恒 589548;面板读与批量催签不受影响现在就能用。前端待接:团期详情新增合同保险 Tab(汇总计数+逐户表格+三态徽标用后端 contractStateText/insuranceStateText 不自映射),手动开/作废重开弹窗(target+可选户+逐户结果),批量催签,出具类按钮按 issuable 置灰;权限读 group-batch:view、写 group-batch:contract:issue(需先部署用户服务)。决策:整个 Tab 入 backlog 排在 #7067 U3-U7 闭环后统一汇总审派发,接入时按 issuable 置灰即可、不因 #4132 单独挂起。本条保持 pending。 2026-09-07 dev-v3

团期「合同保险」面板:逐户出具、作废重开、批量催签

影响范围:管理后台「团期详情 → 合同保险」Tab。 当前状态:后端已部署 TEST 并实测;前端待接入。 请先读下面的「当前不可用的部分」再排期。

⚠️ 当前不可用的部分(重要)

出具的开闸条件是房 / 车 / 导 / 摄四项资源全部就绪。这四项里:

项 线上有没有写入方
导游 ready ✅ 成团时若该团不需要导游即自动置位,需要时由人员配置置位
摄影 ready ✅ 同上
车辆 ready ✅ 车队服务整团配车完成后回填
酒店 ready ❌ 没有。回填它的那条链路挂在一个从未被发出的事件上,见 HL#4132

结果:现网任何团期的四项都集不齐,所以

  • 面板的 issuable 恒为 false
  • 手动开 / 作废重开 恒返 589548
  • 团期单的合同与保险不会自动出具

前端可以照本文档接入,但在 HL#4132 落地前,出具相关的按钮点下去只会拿到 589548。 面板读取与批量催签不受此限制,现在就能用。

这一条是产品链路的既有缺口,不是本次交付的缺陷,但它决定了本功能何时真正可用,故写在最前面。

一、背景

此前团期没有合同保险的集中视图,管理员要逐户点进订单才能看到谁的合同出了、谁签了、谁的保险还没投; 开错了也只能逐户处理,催签只有单张接口。本次补齐面板与三个批量动作。

二、变更接口清单

# 接口 方法 路径 变更类型 说明
1 合同保险面板 GET /v3/admin/order/group-batch/{groupBatchId}/contracts 新增接口 汇总计数 + 逐户三态明细;权限码 group-batch:view
2 手动开合同/保险 POST /v3/admin/order/group-batch/{groupBatchId}/contracts/issue 新增接口 逐户补开;权限码 group-batch:contract:issue
3 作废重开 POST /v3/admin/order/group-batch/{groupBatchId}/contracts/reissue 新增接口 先作废后重开;权限码 group-batch:contract:issue
4 批量催签合同 POST /v3/admin/order/group-batch/{groupBatchId}/contracts/remind-sign 新增接口 只对已出未签的户发短信;权限码 group-batch:contract:issue

三、接口详情

1. 合同保险面板 GET /v3/admin/order/group-batch/{groupBatchId}/contracts

VO: GroupBatchContractBoardVO

使用场景

进入团期详情的「合同保险」Tab 时调用,一次拿到整团的汇总计数与逐户明细。 整页只发 3 次底层查询,不随户数放大。

入参

字段 位置 类型 必填 约束 说明
groupBatchId path Long 是 正整数 团期 ID

出参

字段 类型 说明
issuable Boolean 当前是否允许出具(四项已配齐)。现网恒为 false,见文首说明
batchStatus String 团期状态
totalCount Integer 活跃子订单户数(已取消的户不计)
contractIssuedCount Integer 合同已出户数
contractSignedCount Integer 合同已签户数
insuranceIssuedCount Integer 保险已出户数
contractWrongCount Integer 合同开错户数
insuranceWrongCount Integer 保险开错户数
items[].contractState String 三态:NOT_ISSUED / ISSUED / WRONG
items[].contractStateText String 三态中文名,服务端给出,前端直接显示
items[].awaitingSign Boolean 已出未签,即催签的目标
items[].contractUrl String 合同文件地址,未出为 null
items[].policyNo String 保单号,未出为 null

请求示例

GET /v3/admin/order/group-batch/2096412454643802114/contracts
Authorization: Bearer <token>

响应示例

{
  "code": 200,
  "message": "成功",
  "data": {
    "batchId": "2096412454643802114",
    "issuable": false,
    "batchStatus": "RESOURCE_PREPARING",
    "totalCount": 55,
    "contractIssuedCount": 0,
    "contractSignedCount": 0,
    "insuranceIssuedCount": 0,
    "contractWrongCount": 0,
    "insuranceWrongCount": 0,
    "items": [
      {
        "orderId": "2096633951715033089",
        "orderNo": "HL20260907001741975",
        "contactName": "蒋岚妍",
        "contractState": "NOT_ISSUED",
        "contractStateText": "未出",
        "contractStatus": null,
        "contractPlanName": null,
        "contractSignedAt": null,
        "contractUrl": null,
        "awaitingSign": false,
        "insuranceState": "NOT_ISSUED",
        "insuranceStateText": "未出",
        "insuranceStatus": null,
        "insuranceProductName": null,
        "policyNo": null
      }
    ]
  },
  "success": true
}

空数据 / 降级响应

团期尚无子订单时 totalCount 为 0、items 为空数组,各计数器均为 0,页面展示空态。

错误响应

{
  "code": 589507,
  "message": "无操作权限(非团期管理员 / 非本定制师名下)",
  "data": null,
  "success": false
}

业务边界

  • 已取消的户不出现在面板里,也不计入任何计数器。
  • 三态不落库,全部由既有的合同状态与保险状态派生;后端给出中文名,前端不要自行映射。
  • 读面板走只读权限,不需要出具权限。

2. 手动开合同/保险 POST /v3/admin/order/group-batch/{groupBatchId}/contracts/issue

VO: GroupBatchContractIssueReqVO

使用场景

四项资源配齐后,为漏开的户补开合同与旅行意外险。正常情况下系统会自动出具, 本接口是补救通路。

入参

字段 位置 类型 必填 约束 说明
groupBatchId path Long 是 正整数 团期 ID
target body String 是 CONTRACT / INSURANCE / BOTH 本次要开什么
orderIds body String[] 否 子订单 ID 列表 不传表示整团所有活跃户

出参

字段 类型 说明
totalCount Integer 本次处理户数
successCount Integer 成功户数
failCount Integer 失败户数
skipCount Integer 跳过户数(已出具无需重复开)
results[].outcome String SUCCESS / FAILED / SKIPPED
results[].message String 失败或跳过的原因,成功为 null

请求示例

{
  "target": "BOTH",
  "orderIds": ["2096633951715033089", "2096633958908264449"]
}

响应示例

{
  "code": 200,
  "message": "成功",
  "data": {
    "totalCount": 2,
    "successCount": 1,
    "failCount": 1,
    "skipCount": 0,
    "results": [
      { "orderId": "2096633951715033089", "target": "CONTRACT", "outcome": "SUCCESS", "message": null },
      { "orderId": "2096633958908264449", "target": "INSURANCE", "outcome": "FAILED", "message": "保险下单失败,请稍后重试" }
    ]
  },
  "success": true
}

空数据 / 降级响应

指定的户都已出具时全部记 SKIPPED,successCount 为 0,属正常情况不是错误。

错误响应

{
  "code": 589548,
  "message": "房/车/导/摄四项配齐后才能出具合同与保险",
  "data": null,
  "success": false
}

业务边界

  • 逐户独立事务:单户失败不回滚已成功的户,也不中断后续户,前端按 results 逐行展示。
  • 四项未配齐整单拒绝,返回 589548 且零写入——不是部分成功。
  • 五秒内重复提交会被幂等窗口拦下,返回「出具处理中,请勿重复提交」。
  • 同一团期的出具动作串行执行,并发点击不会重复开。

3. 作废重开 POST /v3/admin/order/group-batch/{groupBatchId}/contracts/reissue

VO: GroupBatchContractIssueReqVO

使用场景

合同方案选错、保险投保信息有误等「开错」情形:先作废原件,再按同一条链路重新开具。

入参

字段 位置 类型 必填 约束 说明
groupBatchId path Long 是 正整数 团期 ID
target body String 是 CONTRACT / INSURANCE / BOTH 本次要重开什么
orderIds body String[] 否 子订单 ID 列表 不传表示整团所有活跃户
reason body String 否 最长 512 字 作废原因,写入操作记录

出参

字段 类型 说明
totalCount Integer 本次处理户数
successCount Integer 作废并重开成功的户数
failCount Integer 失败户数(含作废失败与重开失败,message 区分)
skipCount Integer 跳过户数(该户没有可作废的单据)
results[].orderId String 子订单 ID
results[].target String CONTRACT / INSURANCE
results[].outcome String SUCCESS / FAILED / SKIPPED
results[].message String 失败或跳过的原因,成功为 null

请求示例

{
  "target": "CONTRACT",
  "orderIds": ["2096633951715033089"],
  "reason": "合同方案选错"
}

响应示例

{
  "code": 200,
  "message": "成功",
  "data": {
    "totalCount": 1,
    "successCount": 1,
    "failCount": 0,
    "skipCount": 0,
    "results": [
      { "orderId": "2096633951715033089", "target": "CONTRACT", "outcome": "SUCCESS", "message": null }
    ]
  },
  "success": true
}

空数据 / 降级响应

指定的户没有可作废的单据时记 SKIPPED,不产生任何写入。

错误响应

{
  "code": 589550,
  "message": "无可用合同方案,无法出具合同",
  "data": null,
  "success": false
}

业务边界

  • 作废失败不进重开:该户直接记 FAILED,绝不会出现「原件作废了但新件没开出来」的空档。
  • 与「手动开」共用同一道四项配齐门,未配齐同样返 589548。
  • 幂等窗口与串行锁同「手动开」。

4. 批量催签合同 POST /v3/admin/order/group-batch/{groupBatchId}/contracts/remind-sign

VO: GroupBatchContractRemindReqVO

使用场景

合同已出但客户迟迟不签,管理员一次性给这些户重发签署短信。 本接口不受四项配齐门限制,现在就能用。

入参

字段 位置 类型 必填 约束 说明
groupBatchId path Long 是 正整数 团期 ID
orderIds body String[] 否 子订单 ID 列表 不传表示整团所有活跃户

出参

字段 类型 说明
totalCount Integer 本次处理户数
successCount Integer 实际发出短信的户数
skipCount Integer 跳过户数
results[].message String 跳过原因

请求示例

{
  "orderIds": ["2096633951715033089", "2096633958908264449"]
}

响应示例

{
  "code": 200,
  "message": "成功",
  "data": {
    "totalCount": 2,
    "successCount": 0,
    "failCount": 0,
    "skipCount": 2,
    "results": [
      { "orderId": "2096633951715033089", "target": "CONTRACT", "outcome": "SKIPPED", "message": "该户合同未出具或已签署,无需催签" },
      { "orderId": "2096633958908264449", "target": "CONTRACT", "outcome": "SKIPPED", "message": "该户合同未出具或已签署,无需催签" }
    ]
  },
  "success": true
}

空数据 / 降级响应

无「已出未签」的户时全部 SKIPPED,successCount 为 0,不发任何短信。这是正常结果。

错误响应

{
  "code": 589507,
  "message": "无操作权限(非团期管理员 / 非本定制师名下)",
  "data": null,
  "success": false
}

业务边界

  • 只对「已出未签」的户发:未出具的、已签署的一律跳过并说明原因。
  • 单户发送失败不影响其他户,逐户记 FAILED。
  • 只要真发出了至少一条,就写一条团期操作记录。

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

  • 出具按钮的可用性以面板返回的 issuable 为准,不要前端自行按团期状态推断。
  • 三个写动作共用一个权限码 group-batch:contract:issue,读面板走 group-batch:view。
  • orderIds 不传即整团,传了就只处理这几户;两种用法都返回逐户结果。
  • 逐户结果必须逐行展示:这三个接口都可能部分成功,只看 code=200 会误导操作者。
  • 三态文案用后端返回的 contractStateText / insuranceStateText,不要前端自己映射枚举。
  • 出具与重开有五秒幂等窗口,前端做防抖即可。

五、数据库行为

  • 面板读取零写入。
  • 手动开 / 重开逐户独立事务:每户单独提交,失败的户不回滚成功的户。
  • 四项未配齐时在任何写操作之前拒绝,零写入。
  • 重开时先作废后开具,作废失败即停在该户,不会留下「已作废未重开」的中间态。
  • 出具、重开、催签各写一条团期操作记录;催签仅在真发出短信时才写。
  • 无权限、幂等拦截、参数非法一律零写入。

六、边界行为

  • 已取消的户不参与任何动作,也不出现在面板。
  • 指定的户不属于本团期时按跳过处理,不整单失败。
  • 同团期的出具动作串行,避免并发重复开具。

六.7、影响评估

  • 自动出具链路新增了同一道门:团期单在四项配齐前不再自动出具合同与保险, 未配齐时静默跳过(不建待办、不发失败通知)。散客单不受影响。
  • 上线依赖部署顺序:group-batch:contract:issue 权限码由用户服务的迁移注册并授予 管理员与超级管理员,必须先部署用户服务再部署订单服务,否则三个写动作除超级管理员外全返 589507。
  • 本功能当前实际不可用,原因见文首:酒店就绪标志线上无写入方(HL#4132)。
  • 面板读与批量催签不受上述限制。

七、不影响范围

  • 散客单(非团期单)的合同保险出具完全不变。
  • 单张合同的出具、签署、作废接口不变,本次只加团期级的批量入口。
  • 小程序端不受影响。
  • 团期成团、名额调整、流团审批等其他动作不受影响。

八、测试环境已验证

TEST 环境已部署用户服务与订单服务并实测:

  • 面板读取:55 户的团期返回 55 行逐户明细,计数器与 issuable 齐全。
  • 空团期读面板:户数 0、明细空数组,不报错。
  • 四项未配齐时手动开 → 589548,零写入。
  • 四项未配齐时作废重开 → 589548,与手动开同一道门。
  • 出具目标非法时同样先被四项配齐门拦下(门先于目标校验)。
  • 批量催签指定两户 → 均跳过并给出「该户合同未出具或已签署,无需催签」,零副作用。
  • 权限码已生效:读面板通过、三个写动作走到业务校验而非 589507, 说明权限已注册并授予管理员。

尚未验证

  • 出具成功的正向路径未在网关侧实测:需要四项配齐的团期,而酒店就绪标志线上无写入方(HL#4132), 该状态在测试环境造不出来。出具成功、逐户独立事务、作废失败不进重开等行为由单元测试覆盖(60 例全绿), 但未经真实环境验证,前端联调时请以实际返回为准。
  • 出具目标非法的错误码 589549 因被四项配齐门先拦,同样未在真实环境命中。

十、相关文档

  • 工单:HL#7105
  • 合并:HL PR#7243
  • 后续修正:HL#7248 / PR#7249——出具门原先按团期状态判定,与「合同全签才能进入物资准备」 这道既有门形成死锁,已改为直接判四项就绪标志。本文档描述的是修正后的口径。
  • 阻塞项:HL#4132——团期基准变更事件未发出,导致酒店就绪标志无写入方

关联 / 联系人

  • 后端:jw
  • 前端待接:合同保险 Tab(汇总计数 + 逐户表格 + 三态徽标)、 手动开与作废重开弹窗(目标选择、可选择户、逐户结果展示)、批量催签、 出具类按钮按 issuable 置灰并提示原因