文件
hl-api-changelog/changelogs-v2/2026-09/18_7946_团期转订单收紧为只允许招募中团期之间转-修改接口-管理后台.md
T
2026-09-18 17:22:48 +08:00

14 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 7946 团期转订单收紧为只允许招募中(未成团)团期之间转 admin jw(GIT) 修改接口 deployed verified verified mmg e932c18a6bb68ea39c697416007fd8d8a7138620 2026-09-18 团期转订单 POST .../sub-order/{orderId}/transfer-in 与候选列表 GET .../transfer-candidates 的可转团期状态由「招募中 + 资源准备中」收紧为只允许招募中(未成团),源期与目标期都适用;同产品限制不变。入参、出参、路径均不变,589510 文案改为「须为招募中」。后端已合并 dev-v3(843e81712)并部署 TEST,网关实测 7/7 通过。前端待办(一行):团期详情「更多操作 → 转订单」入口白名单 canTransferOrder 由 ['RECRUITING','RESOURCE_PREPARING'] 改为 ['RECRUITING'],见第四节。[mmg 2026-09-18 交付] canTransferOrder 白名单已收紧为仅 RECRUITING,589510 透后端 message 不建字典;建详情页首个 spec(moreActionOptions:RECRUITING 含/RESOURCE_PREPARING 不含且调整满团名额仍在对照/MATERIAL_PREPARING 不含),定向 3/3+scoped checkpoint 全绿,ref 为业务仓 v2.1 commit。 2026-09-18 dev-v3

order-v3: 团期转订单收紧为只允许招募中(未成团)团期之间转

存放目录: changelogs-v2/{YYYY-MM}/(管理后台,二期 order-v3)

服务: hl-order-service-v3 (端口 8086) PR: #7948 Issue: #7946 日期: 2026-09-18 影响范围: 团期详情「更多操作 → 转订单」弹窗


⚠️ 关键变化

  1. 只有招募中(未成团)的团期之间才能转订单:订单所在的原团期、要转入的本团期,两个都必须是招募中。
  2. 已成团的团期(资源准备中及之后)既不能转出,也不能转入:候选列表里不再出现这些团期的订单;本团期已成团时候选列表直接为空。
  3. 同一产品的限制不变;入参、出参、路径都不变。
  4. 前端待办(一行):转订单入口的显示条件改为只在招募中显示,见第四节。

一、背景

转订单(#7095)原来允许在「招募中」和「资源准备中」两个状态之间转。资源准备中其实就是已成团(看板「已成团」这一栏 = 资源准备中 + 物料准备中),成团后该户已进入资源采购与配房,业务要求不再跨团期挪动。jw 2026-09-18 定案:只允许招募中。


二、变更接口清单

# 接口 方法 路径 变更类型 说明
1 转订单(子订单跨期转入) POST /v3/admin/order/group-batch/{groupBatchId}/sub-order/{orderId}/transfer-in 修改 源期、目标期都须为招募中,否则 589510
2 转订单候选子订单列表 GET /v3/admin/order/group-batch/{groupBatchId}/transfer-candidates 修改 本期非招募中返回 [];候选只来自同产品其他招募中团期

三、接口详情

1. 转订单(子订单跨期转入) POST /v3/admin/order/group-batch/{groupBatchId}/sub-order/{orderId}/transfer-in

VO: Result<TransferSubOrderRespVO>(不变)

使用场景

团期详情「更多操作 → 转订单」弹窗,选中候选订单后确认:把同一产品另一个团期的一户转到本团期。不退钱、订金跟人走、尾款按本团期价格重算。

入参

本次入参不变。

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ 转入期(本期)团期 ID 须为招募中
orderId Path Long ✅ 待转入的子订单 ID 订单状态须为待支付 / 待出行
fromGroupBatchId Body Long ✅ 源期团期 ID 须为招募中,且与本期同一产品
reason Body String 否 ≤512 字 不传记「管理员手动转期」
notify Body Boolean 否 缺省 true 是否通知客户

出参

本次出参不变。

字段 类型 说明
orderId String 子订单 ID
fromBatchNo String 源期期号
toBatchNo String 目标期期号
oldOrderAmount Number 转期前应收
newOrderAmount Number 转期后应收(按目标期价格重算)
paidAmount Number 已付(转期不动钱)
newBalanceDue Number 转期后待收尾款 = 新应收 − 已付
warnings List 非阻断提示

请求示例

POST /v3/admin/order/group-batch/2100866001561128962/sub-order/2100866000617414658/transfer-in
Authorization: Bearer <token>
Content-Type: application/json

{ "fromGroupBatchId": "2100866000667746306", "reason": "#7946 验收", "notify": false }

响应示例

(测试服真实响应,2026-09-18,两个团期都是招募中)

{
  "code": 200,
  "message": "成功",
  "data": {
    "orderId": "2100866000617414658",
    "fromBatchNo": "Q202705102100866000156069890",
    "toBatchNo": "Q202705172100866000994930690",
    "oldOrderAmount": 6000.0,
    "newOrderAmount": 6000.0,
    "paidAmount": 0.0,
    "newBalanceDue": 6000.0,
    "warnings": []
  },
  "success": true
}

空数据 / 降级响应

写接口,无空数据形态。被拒时整笔回滚:订单归属、两个团期的报名人数、产品库存、转期流水都不变。

{ "code": 589510, "message": "转订单时源期或目标期状态不满足条件(须为招募中)", "data": null, "success": false }

错误响应

(测试服真实响应:源期已成团)

{ "code": 589510, "message": "转订单时源期或目标期状态不满足条件(须为招募中)", "data": null, "success": false }
code 触发条件
589510 源期或目标期不是招募中(本次收紧:资源准备中也会触发;文案改为「须为招募中」)
589525 源期与目标期不是同一产品(不变)
589524 源期与目标期是同一团期(不变)
589512 子订单不属于源期(不变)
589501 订单状态不可转(不变)
589560 该户已在源期分到房(不变)

业务边界

  • 状态判断在读订单之前完成(事务里只先对两个团期各取一次行锁);被拒时整笔回滚,净写入为零。
  • 同产品、订单状态、容量、价格不低于已付等其余守卫全部不变。
  • 已分房守卫(589560)保留:用于「取消成团回到招募中」但源期仍残留分房行的情形。

2. 转订单候选子订单列表 GET /v3/admin/order/group-batch/{groupBatchId}/transfer-candidates

VO: Result<List<TransferCandidateVO>>(不变)

使用场景

转订单弹窗的搜索下拉:列出可以转入本团期的订单。

入参

本次入参不变。

字段 位置 类型 必填 约束 说明
groupBatchId Path Long ✅ 转入期(本期)团期 ID 非招募中时直接返回 []
keyword Query String 否 手机号须整串 订单号 / 客户名 / 期号 / 手机号

出参

本次出参不变。

字段 类型 说明
orderId String 子订单 ID
orderNo String 订单号
customerName String 客户名
peopleCount Integer 人数
paidAmount Number 已付
fromGroupBatchId String 所在源期团期 ID(只会是招募中的团期)
batchNo String 源期期号
batchName String 源期名称
departDate String 源期出发日

请求示例

GET /v3/admin/order/group-batch/2100866001561128962/transfer-candidates
Authorization: Bearer <token>

响应示例

(按测试服验收时的真实值整理,只列本单造数那一条;同产品已成团团期 C 的订单已不在列表中)

{
  "code": 200,
  "message": "成功",
  "data": [
    {
      "orderId": "2100866000617414658",
      "orderNo": "HL20260918163421351",
      "customerName": "测试七九四六A",
      "peopleCount": 2,
      "paidAmount": 0.0,
      "fromGroupBatchId": "2100866000667746306",
      "batchNo": "Q202705102100866000156069890",
      "batchName": "#7946-A",
      "departDate": "2027-05-10"
    }
  ],
  "success": true
}

空数据 / 降级响应

本团期已成团(资源准备中及之后)时,候选直接为空(测试服真实响应,改前同一团期返回 9 条):

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

错误响应

{ "code": 589500, "message": "团期不存在", "data": null, "success": false }
code 触发条件
589500 本期团期不存在(不变)
401 未登录(网关拦截)

业务边界

  • 本期非招募中 → [],不查订单。
  • 源期只取同产品、招募中、非本期的团期;已成团团期的订单不再出现。
  • 关键词匹配规则不变。

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

前端需要改的一行

hl-ui v2.1:src/views/order-v2/batch/detail/index.vue 约第 657 行

// 改前
const canTransferOrder = computed(() =>
  ['RECRUITING', 'RESOURCE_PREPARING'].includes(detail.value?.batchStatus))
// 改后
const canTransferOrder = computed(() => detail.value?.batchStatus === 'RECRUITING')

不改的后果:资源准备中的团期仍会显示「转订单」入口,点开后候选列表永远是空的,运营会以为「搜不到单」。不会转错数据(后端已拦)。

✅ 正确 / ❌ 错误 用法

场景 做法
✅ 决定是否显示转订单入口 只在 batchStatus === 'RECRUITING' 时显示
✅ 589510 的提示 直接展示后端 message「须为招募中」
❌ 在资源准备中团期显示转订单入口 候选恒为空,点了没用
❌ 前端自己拼「须为招募中/资源准备中」的提示文案 旧口径,已作废

五、数据库行为

  • 无表结构变更,无 Flyway。
  • 转入成功时的写入与改前完全相同:订单改归属到目标团期并刷新出发 / 返程日期,两个团期报名人数一增一减,记一条转期记录,两个团期时间线各记一条。
  • 本次只是把一部分请求提前拒掉:被拒时事务在状态守卫处整笔回滚,零写入(测试服已核对订单、两期报名人数、转期流水均未变化)。

六、边界行为

  • 源期、目标期都招募中且同产品 → 成功。
  • 源期资源准备中(已成团)→ 589510,零写入。
  • 目标期资源准备中(已成团)→ 589510,零写入。
  • 物料准备中及之后 → 589510(与改前相同)。
  • 跨产品 → 589525(与改前相同,先于状态判断)。
  • 候选列表:本期非招募中 → [];本期招募中 → 只含同产品其他招募中团期的订单。

六.6、修改前后对比

字段级对比

项 改前 改后
入参 / 出参 / 路径 — 不变
589510 文案 须为招募中/资源筹备中 须为招募中

行为级对比

行为 改前 改后
可转团期状态 招募中、资源准备中 只有招募中
本期资源准备中的候选列表 同产品这两种状态其他团期的订单 []
源期资源准备中的订单 出现在候选中,可转 不出现,转入被 589510 拒

六.7、影响评估

  • 是否破坏向后兼容: 结构上兼容(字段不变);行为上收紧,原来能在资源准备中团期之间转的现在会被拒。
  • 前端是否必须同步上线: 否,不改也不会出错;但需要前端改那一行,入口才不会出现在已成团的团期。
  • 回滚: 回滚 PR #7948 即可,无数据变更。

七、不影响范围

  • 仅影响: 上述两个接口的可转状态判断与 589510 文案。
  • 零影响: 退单户(GB-ADM-070)、成团 / 取消成团、调整满团名额、发起流团;转订单的金额计算、库存、配房联动、行程与用车重排;数据库结构。

八、测试环境已验证

被测版本:hl-order-service-v3 = dev-v3 843e81712(2026-09-18 17:09 部署,双实例滚动完成),网关实测 7/7 通过。

造数:同一产品建三个班期 A / B(招募中)、C(经成团接口推到资源准备中),各下一张真实订单。

改前(部署前,同一批数据)
  候选 本期=C(资源准备中) → 9 条(含 A、B 的单)
  候选 本期=B(招募中)     → 含 C(资源准备中) 的单
改后
  AC-4 候选 本期=C → [];候选 本期=B → 含 A 单、不含 C 单                                      ✓
  AC-2 C(资源准备中)→B      → 589510「须为招募中」,订单 / 两期报名人数 / 转期流水零变化          ✓
  AC-3 A→C(资源准备中)      → 589510,零变化                                                  ✓
  AC-5 跨产品源期→B          → 589525,零变化                                                  ✓
  AC-1 A→B(均招募中)       → 200;订单归属与出发日改到 B;报名人数 A 2→0、B 2→4;流水 1 条       ✓

本地:GroupBatchTransferServiceTest 50/0/0(新增 5 例)、GroupBatchTransferDayConfirmConcurrencyIT 3/0/0(真实 MySQL);全量 Half A 7955/0/0、Half B 3967/F1(MapperBoundaryArchTest dev-v3 既存,与本次无关)。

验收后已清理:三张订单取消,三个班期在产品侧取消(CANCELLED);订单侧团期行不随产品侧取消同步,停在原状态。


十、相关文档

  • 关联 Issue: wx/HL#7946
  • 关联 PR: wx/HL#7948
  • 接口文档:docs/group/团期模块接口文档-v2.0.html GB-ADM-071 小节与错误码表已同步

关联 / 联系人

链接

联系人

  • 后端负责人: @jw
  • 前端负责人: @mmg