# 半年付车票时长修复 API 固定处理规格 **772、774**。沿用后台登录凭证,要求 `validAccount:addTime` 权限。 修改已开通车票的到期时间,不修改规格默认月份、开始时间或订单金额。 ## 1. 预览 ```http GET /manage/group/relation/duration-repair/preview?afterId=0&limit=100 ``` 可以传可选参数 `userId`,先只查看一个用户的车票,例如: ```http GET /manage/group/relation/duration-repair/preview?userId=12345&afterId=0&limit=100 ``` 将 `12345` 替换为要核对的用户 ID。传入后只查询 `groups_relation.user_id` 为该用户、 当前规格为 772/774 的车票;不会扩展到关联账号。不传则保留按这两个规格预览所有用户的行为。 `userId` 必须大于 0。预览仅查询,不执行扣减。 沿用项目 `Result` 响应包装,业务数据含 `userId`、`items`、`hasMore`、`nextAfterId`。 `hasMore=true` 时,将 `nextAfterId` 作为下次 `afterId`,同时保留相同的 `userId`;每页最多 200 张。 每条记录包括: | 字段 | 含义 | | --- | --- | | relationId / groupsId / skuId / userId | 车票、车队、规格、当前用户 | | startTime / expiryTime / updateTime | 当前开始、到期、更新时间,均为毫秒时间戳 | | newExpiryTime | 候选车票预计的新到期时间,原到期减 6 个自然月 | | yearDifferenceMillis | 原到期与开始加 12 个月的毫秒差 | | orderCount | 当前车票用户关联的有效订单数,已按订单去重 | | decision / reason | 筛选结果与原因 | | expiredAfterRepair | 候选车票扣减后是否已到期 | `decision`: - `candidate`:起止完整、精确 12 个自然月,当前有用户且为有效/额外车位;普通购买、非 VIP、 无冻结、恢复、保留天数或补时,且只关联一笔同规格普通订单。可提交执行。 - `review`:有秒差、续费、多订单、补时、冻结等情况;不自动扣减。 - `skipped`:未设置时间、已经半年或其他不符合条件的时长。 月份运算使用项目原有 `DateUtil.offsetMonth`;不按 180 天、不用完整月份数取整判断。 例如开始为 `2024-02-29`、原到期 `2025-02-28`,扣减后为 `2024-08-28`。 候选筛查无法证明所有历史修改原因,提交前仍需核对预览是否属于本次误设范围。 ## 2. 执行 ```http POST /manage/group/relation/duration-repair/execute Content-Type: application/json ``` 将预览中需要处理的 `candidate` 行的以下快照字段原样回传,时间必须用预览返回值: ```json { "remark": "半年付套餐误设一年,扣回多发的半年时长", "items": [ { "relationId": 123, "groupsId": 456, "skuId": 772, "userId": 789, "startTime": 1767225600000, "expiryTime": 1798761600000, "updateTime": 1767225600000 } ] } ``` 上面的 ID 和时间只是请求格式示例。`updateTime` 若在预览中为 `null`,也传 `null`。 `remark` 是可选的自定义备注,有内容时原样写入本批每张车票的 `incr_expiry_time_record.remark`, 不会追加默认说明;不传、空字符串或纯空白时,使用默认修复说明(包含新旧到期时间)。 每批 1 至 200 张,不能包含重复车票;不接受任意规格、任意扣减月份或强制跳过校验。 执行时锁定车票、再次查询订单和补时历史,对比身份及起止/更新时间,整批验证后扣减。 任一车票已经变化、不满足条件、更新失败或审计记录保存失败,整批事务回滚。 成功返回每张车票的修改前后时间,`decision=updated`。 再次提交同一快照会因旧到期时间不一致被拒绝,避免重复扣减。 每张修复车票写入现有 `incr_expiry_time_record`:旧到期时间、实际扣减天数(负数)、 操作人及备注;未提供自定义备注时,备注记录扣减 6 个自然月的说明及新旧到期时间。 后台同时记录 API 操作日志。 如果扣减后已经到期,接口仍保存该到期时间,不在本次事务内清票或调用外部服务, 预览和执行响应中的 `expiredAfterRepair` 会标明这种情况。 ## 验证 ```powershell mvn -pl netflix-service -am '-Dtest=TicketDurationRepairServiceImplTest' '-Dsurefire.failIfNoSpecifiedTests=false' test mvn -pl netflix-web -am '-DskipTests' compile ``` 测试使用 Mockito,不连接业务数据库。部署后使用现有后台会话调用以上接口。