- 新增成对迁移 000222:tb_exchange_order 增加非空 migration_status 与 migration_failure_reason,按既有 migrate_data/migration_completed 回填历史, 并加四值 CHECK 约束,不新增索引 - 模型与常量定义四种迁移状态及中文名称,保留既有布尔字段兼容语义 - 物流换货创建恒 not_migrated,发货按请求落 pending/not_migrated, 完成成功写 migrated/not_migrated 并清空失败原因、同步兼容字段 - 直接换货创建即完成,任一步失败整体回滚,不持久化换货单、不产生 failed - 迁移失败回滚全部业务修改后,在独立短事务内条件更新 failed 与安全失败原因 并写失败审计,RowsAffected 为 0 时跳过状态写入但仍写审计 - failed 物流单重试仅限超级管理员或平台用户,授权以锁内 FOR UPDATE 判定为准, 重试从钱包余额起整表重跑;非 failed 单沿用既有完成门禁 - 列表与详情返回迁移状态与中文名称,仅 failed 返回失败原因;既有三字段保持兼容 - 换货导出在「状态」列后新增中文「迁移状态」列,不导出失败原因 - 同步 order-refund-exchange 主 spec 与验证证据,归档本 Change - 登记 KNOWN-ISSUE-001:既有标签复制 OnConflict 未声明部分索引谓词(42P10), 旧资产带标签时迁移最后一步失败,待另立变更修复
29 KiB
订单、退款与换货当前行为
Purpose
描述订单、退款、换货及订单套餐失效的当前可观察行为。
Requirements
Requirement: 订单、退款与换货状态门禁
系统 SHALL 仅允许待支付订单取消;退款申请按待审批、已通过、已拒绝、已退回、原路退款处理中、原路退款失败流转,仅已拒绝、已退回和原路退款失败申请可修改并重新提交;换货按待填写信息、待发货、已发货、已完成或已取消流转,并拒绝与当前状态或流程类型不匹配的操作。处于待审批、原路退款处理中或原路退款失败的退款申请 MUST 阻止同一订单创建新的退款申请,且 MUST NOT 被再次推进为新的审批实例或第二次渠道退款。
Scenario: 重复推进终态
- GIVEN 退款或换货已进入不允许当前操作的状态
- WHEN 再次审批、发货、完成、取消或重新提交
- THEN 系统返回状态冲突且不重复改变资产、余额或业务状态
Scenario: 原路退款失败后重提
- WHEN 退款申请处于原路退款失败状态且调用方在其数据范围内修改材料后重新提交
- THEN 系统新增一条审批尝试记录与一个新的企业微信审批实例并使申请回到待审批,历史尝试与已提交的渠道退款不被覆盖
Scenario: 企业微信通过后撤销的申请被再次推进
- GIVEN 退款申请已记录企业微信通过后撤销的审批异常
- WHEN 调用者再次提交或重提该申请
- THEN 系统返回状态冲突,不恢复套餐权益、不取消已提交的渠道退款且不自动重提
Requirement: 代理退款查询按所属店铺隔离
系统 SHALL 允许代理账号通过 GET /api/admin/refunds 查询其当前所属店铺的全部退款申请,并通过 GET /api/admin/refunds/{id} 查询其中任一申请详情,不以申请创建账号作为查询条件。该范围 SHALL 不包含下级代理店铺、其他店铺或未关联店铺的退款申请;代理账号未关联店铺时,列表 SHALL 为空且详情 SHALL 返回不存在。平台和超级管理员的既有退款查询范围 SHALL 保持不变。
Scenario: 查看同店铺其他账号提交的退款
- GIVEN 当前代理所属店铺存在由另一账号创建的退款申请
- WHEN 该代理查询退款列表或该申请详情
- THEN 系统返回该退款申请
Scenario: 查询下级代理店铺的退款
- GIVEN 当前代理的下级代理店铺存在退款申请
- WHEN 当前代理查询退款列表或该申请详情
- THEN 系统不返回该退款申请,详情查询返回不存在
Scenario: 未绑定店铺的代理查询退款
- GIVEN 当前代理账号未关联店铺
- WHEN 该代理查询退款列表或退款申请详情
- THEN 系统返回空列表或不存在,且不泄露任何退款申请
Requirement: 历史待审批退款可主动接入企业微信审批
系统 SHALL 提供 POST /api/admin/refunds/{id}/trigger-approval,使具有既有退款管理访问权限的后台账号可为历史退款申请主动创建企业微信审批。系统 MUST 仅在退款申请状态为待审批且 approval_instance_id 为空时创建审批;审批发起人 MUST 使用该退款申请的原创建账号。创建成功后,系统 MUST 原子保存唯一审批实例、审批提交请求及退款申请的审批实例关联,并返回更新后的退款申请审批摘要。
Scenario: 主动发起历史退款审批成功
- GIVEN 退款申请处于待审批状态、未关联审批实例,且其原创建账号和企业微信退款审批场景均可用
- WHEN 有既有退款管理访问权限的后台账号请求
POST /api/admin/refunds/{id}/trigger-approval - THEN 系统创建以原创建账号为发起人的唯一企业微信审批并返回审批摘要,后续由既有可靠提交流程提交至企业微信
Scenario: 非待审批或已发起记录被拒绝
- WHEN 请求主动发起的退款申请不是待审批状态或已关联审批实例
- THEN 系统返回状态冲突且不创建新的审批实例或提交请求
Scenario: 并发主动发起同一退款审批
- WHEN 两个请求同时为同一符合条件的退款申请主动发起审批
- THEN 系统至多创建一个审批实例和一个审批提交请求,未成功创建关联的请求返回冲突
Scenario: 原创建人或审批渠道不可用
- WHEN 退款申请原创建账号不可用,或企业微信退款审批场景不可用
- THEN 系统返回相应错误,退款申请保持未关联审批实例,修复条件后可再次发起
Requirement: 退款实收金额与方式矩阵
系统 SHALL 从来源订单或原成功支付记录派生并冻结权威实收金额,提交人不得填写或修改;无法确定权威实收金额或该金额非正时拒绝创建申请。冻结来源为:线上支付取该订单原成功支付记录金额;资产钱包、代理主钱包和后台线下套餐订单取订单实际收款或实际扣款金额。退款金额 MUST 为正分且不得超过冻结实收金额,系统 MUST 在申请创建、审批提交和企业微信通过后的执行前重复校验该上限。一笔订单最多一张最终成功退款申请,成功后该订单不得再申请退款。代理充值预存款业务单不在本期退款范围。
可选方式按来源订单的实际支付方式确定,不匹配的方式返回「该订单不支持此退款方式」:线上微信、支付宝或富友支付仅可选原路退款或客户收款信息退款;资产钱包支付仅退回原资产钱包;代理预存款或主钱包支付仅退回原代理钱包;后台线下和员工代收套餐订单仅可选客户收款信息退款。系统 MUST NOT 为本能力新增人工退款方式开关。客户收款信息退款必须同时提供客户收款信息自由文本和至少一个客户凭证附件,且不得复用公司收款方式字典。
线上订单原路可退条件按渠道契约在创建、提交和执行前重复预检:冻结实际商户的退款必需凭证不完整、服务商类型不具备退款能力、或原交易超出渠道可退时限时禁用原路并说明原因,只允许客户收款信息退款。富友原交易的原始日期必须回传渠道;未回传时仅支持 30 天内原交易,回传后可退 360 天内原交易,超出该范围的申请不得选择原路。
Scenario: 无权威实收金额
- WHEN 来源订单无法取得权威实收金额,或取得的金额非正
- THEN 系统拒绝创建退款申请,不允许提交人以自填金额替代
Scenario: 提交人试图修改冻结实收金额
- WHEN 创建或重提请求携带与派生值不同的实收金额
- THEN 系统仍使用派生值作为冻结实收金额,不接受请求值
Scenario: 钱包订单申请退款
- WHEN 已支付套餐订单的实际支付方式为资产钱包或代理主钱包
- THEN 系统只提供退回对应原钱包方式,不展示原路或客户收款信息退款
Scenario: 原路凭证不完整
- GIVEN 订单为线上支付且其冻结实际商户缺少该服务商类型退款必需凭证
- WHEN 调用者申请退款
- THEN 系统禁用原路退款并返回原因,只允许客户收款信息退款
Scenario: 富友原交易超出可退时限
- WHEN 富友原交易的原始支付时间早于可退时限
- THEN 系统禁用原路退款并说明原因,只允许客户收款信息退款
Requirement: 企业微信唯一终审与审批尝试重提
退款申请 SHALL 保存退款原因、冻结实收金额、唯一关联套餐及其使用情况、方式、金额和当次材料快照。超级管理员、平台用户和代理可在各自订单数据范围内创建、修改并重提未成功申请;企业微信是唯一终审,本地 MUST NOT 人工通过、拒绝或退回已关联审批实例的申请。每次创建或重提 MUST 新增一条不可变的审批尝试记录,并以该尝试记录作为通用审批业务标识;同一申请每次提交各自持有独立审批实例,历史尝试材料与审批结果不被覆盖。退款单 SHALL 仅保存最新尝试与最新审批实例引用用于展示。
同一订单同时至多存在一张待审批、原路退款处理中或原路退款失败的退款申请。企业微信驳回、企业微信关闭、或原路退款明确失败后可修改未成功申请的金额、原因、方式、收款信息和附件并重提;每次重提必须新建审批实例及快照。企业微信提交失败或审批结果未知时申请保持在途,使用既有查询与恢复闭环,不得另建或重提。企业微信通过后撤销时不回滚套餐失效或已启动退款,标记审批异常并禁止自动重提。
审批终态 MUST 以审批实例标识判别业务归属:先按审批尝试记录标识与审批实例匹配,未命中时按退款申请标识与审批实例匹配以兼容尚未切换到尝试模式的存量申请,两者均不匹配时返回稳定冲突错误,不得回落到任一候选业务单。
Scenario: 审批通过前结果未知
- WHEN 企业微信提交成功性或最终结果暂时未知
- THEN 申请保持在途且订单不得创建第二张活动申请,系统通过既有恢复机制确认结果
Scenario: 未成功申请重提新建实例
- GIVEN 退款申请处于已拒绝、已退回或原路退款失败状态且无审批异常
- WHEN 调用者修改材料后重新提交
- THEN 系统在同一事务新增审批尝试记录并创建新的企业微信审批实例,原尝试记录与历史审批结果保持不变
Scenario: 存量申请审批终态仍被消费
- GIVEN 退款申请由本能力上线前创建,其审批实例的业务标识指向退款申请本身
- WHEN 该审批实例到达通过或关闭终态
- THEN 系统按审批实例标识匹配到该退款申请并幂等推进,不按尝试模式误判为不存在
Scenario: 已关联实例的本地人工终审
- GIVEN 退款申请已关联审批实例
- WHEN 后台账号调用本地通过、拒绝或退回入口
- THEN 系统拒绝该操作且不改变退款申请与订单状态
Scenario: 存量无实例待审批申请仍可终结
- GIVEN 退款申请未关联任何审批实例且处于待审批状态
- WHEN 后台账号在既有开关开放时调用本地通过、拒绝或退回入口
- THEN 系统按既有语义终结该申请,不要求该申请先接入企业微信审批
Requirement: 原路退款渠道能力与执行
对线上订单,系统 SHALL 在创建、提交及企业微信通过后的执行前校验原支付单、实际收款商户、原渠道交易流水、可退金额和该商户退款必需凭证;商户停用不得阻断历史单校验。新支付按冻结实际商户标识加载该商户当前有效凭证,历史支付按原支付配置标识读取,不得按当前启用商户池推断历史商户。退款能力判定 MUST 只依据服务商类型与该服务商类型退款必需凭证的完整性,不提供人工退款能力开关:微信直连、富友和支付宝商户具备原路退款能力;微信 v2 商户的退款接口为双向证书接口,故其退款必需凭证含 API 客户端证书,缺少该证书时按其凭证完整性判定为不可用并只允许客户收款信息退款,补录证书后即可用。系统 MUST NOT 提供渠道降级开关。不可用时返回的错误说明 MUST 指明缺少哪一类凭证,避免被误判为功能未实现。
微信 v2 退款申请接口的返回仅代表渠道受理情况,MUST NOT 据此判定退款成功:受理成功时退款申请 MUST 保持原路退款处理中并等待退款查询确认,退款查询返回明确成功时才可标记已通过并保存渠道退款流水。
原路退款 MUST 使用冻结金额并调用原实际收款商户,实际收款商户不得改选。每次审批尝试 MUST 持久化一个稳定的记录级渠道退款请求号,提交时按冻结服务商类型的契约规则生成,同一尝试重试复用该值、重提生成新值;系统 MUST 以该请求号作为渠道幂等标识,至多提交一次可确认的退款请求。
仅渠道明确成功留存渠道退款流水后退款单才标记已通过;超时、结果未知、渠道明确拒绝、凭证失效、渠道余额不足或本地原支付事实不可用时不标记成功,写入结构化失败分类并保持原路退款处理中或失败状态。重申资金动作至多提交一次:系统 MUST 在提交前持久化认领该次渠道提交,只有认领成功的执行才可调用渠道退款接口;同一次尝试的重复投递或人工重放 MUST 只查询渠道结果并回填,MUST NOT 再次提交资金动作。
恢复任务 MUST 只查询渠道并回填结果,不得重复发起资金动作。本地查询窗口超期且结果仍未知时,系统 MUST 终止本次渠道执行并转人工核对:退款申请 SHALL 转为原路退款失败、渠道退款状态 SHALL 转为已失败、失败分类 SHALL 写为超时或结果未知,且此后 MUST NOT 再查询该渠道。超期 MUST NOT 标记为渠道明确成功。窗口超期后系统 MUST NOT 自动重提该申请(本次渠道请求可能已被受理,重提会以新请求号再次提交资金动作),也 MUST NOT 解除同一订单的活动退款互斥。超期边界为:富友因其契约只支持 3 日内查询而在 72 小时后超期;微信 v2 的受理响应不含退款状态且渠道无查询时限,其本地确认上限为 7 天。需改为客户收款信息退款时必须修改申请材料并重新走企业微信审批。
Scenario: 原路渠道调用未知
- WHEN 企业微信已通过的原路退款调用超时且无法确认渠道结果
- THEN 退款保持原路退款处理中,套餐权益不恢复,系统不得再次提交退款,仅由查询恢复回填结果
Scenario: 渠道明确成功
- WHEN 渠道返回明确退款成功
- THEN 系统保存渠道退款流水号与渠道退款金额快照并把退款申请标记为已通过,同时按方式置订单已退款
Scenario: 富友退款查询窗口已过且结果未知
- GIVEN 富友原路退款已提交但结果未确认,且已超出其退款查询窗口
- WHEN 恢复任务再次处理该退款
- THEN 系统不再发起退款调用,保留办理中并记录审批异常供人工核对
Scenario: 商户已停用的历史原路退款
- GIVEN 原支付单命中的实际商户已被停用
- WHEN 该订单执行原路退款
- THEN 系统仍按该商户当前凭证调用渠道,商户停用本身不阻断调用
Scenario: 微信 v2 补录证书后原路可用
- GIVEN 订单原支付单命中的商户服务商类型为微信 v2,且其凭证补录了 API 客户端证书与私钥
- WHEN 调用者申请原路退款
- THEN 系统判定该商户原路退款可用,并以商户退款单号作为渠道路径的幂等标识发起退款
Scenario: 微信 v2 退款申请仅代表渠道受理
- GIVEN 微信 v2 商户凭证完整且企业微信已通过原路退款
- WHEN 渠道退款申请接口返回受理成功但未返回退款状态
- THEN 系统保持退款申请为原路退款处理中且订单保持已支付,只由退款查询确认最终结果
Scenario: 微信 v2 商户缺少客户端证书
- GIVEN 订单原支付单命中的商户服务商类型为微信 v2,且其凭证只有 APIv2 密钥
- WHEN 调用者申请退款
- THEN 系统禁用原路退款并说明缺少 API 客户端证书,只允许客户收款信息退款,且不阻断该商户的支付与查单
Scenario: 渠道退款结果不经通知接收
- WHEN 系统发起原路退款请求
- THEN 系统不传递任何渠道退款结果通知地址、不新增退款通知路由,退款终态只由渠道同步响应、主动查询与恢复任务确认
Requirement: 退款权益与订单状态时点
企业微信最终通过时,系统 SHALL 在同一事务内写退款申请终态、按方式确定的订单支付状态、原钱包退款回款、员工代收账单冲销和可靠套餐失效事实;企业微信通过后的撤销不回滚上述任何已成立事实。套餐失效、接续下一套餐和停机评估 MUST 由既有可靠机制最终一致执行,不得在资金事务内执行运营商停机等不可回滚的外部调用。
订单支付状态时点按退款方式确定:客户收款信息退款与退回原钱包在企微通过时置为已退款;原路退款仅在渠道明确成功时置为已退款,此前订单保持已支付。原路退款在企微通过后、渠道结果确认前的期间内,同一订单 MUST 由活动退款唯一约束阻止产生第二张活动退款申请。重复或乱序的企业微信终态不得再次失效套餐、再次回款或启动第二次渠道退款。
Scenario: 企微通过后的权益时点
- WHEN 退款申请到达企业微信最终通过
- THEN 系统在同一事务写退款终态与可靠失效事实,套餐失效、接续与停机由既有可靠机制随后完成
Scenario: 原路退款在渠道确认前置订单状态
- GIVEN 退款方式为原路退款且企业微信已通过
- WHEN 渠道结果尚未确认
- THEN 订单保持已支付、套餐权益已按企微通过失效,且该订单不得创建新的退款申请
Scenario: 渠道最终失败不回滚权益
- WHEN 原路退款渠道明确失败
- THEN 退款申请标记原路退款失败且不标记已通过,已失效套餐权益不恢复,订单保持已支付
Requirement: 退款终态事实与失败分类
退款申请 SHALL 保存结构化失败分类、渠道退款状态、渠道退款流水与渠道退款请求号,并在列表、详情和导出中返回冻结实收金额、方式、申请状态、渠道退款状态、失败安全摘要、审批尝试历史和渠道流水,按既有订单数据范围过滤。失败分类 MUST 为稳定枚举,至少覆盖:渠道明确拒绝、渠道凭证失效、渠道余额不足、超时或结果未知、企业微信驳回或关闭、企业微信通过后撤销,以及本地原支付事实不可用。渠道凭证失效与本地原支付事实不可用 MUST 为两个并列分类、语义不得合并:前者指该商户退款必需凭证缺失或失效,后者指本地原支付单、实际收款商户、原渠道流水或可退金额校验不通过。每个分类 MUST 显式标记其是否属于「明确失败」:明确失败表示该次退款尝试已终结且不可自动恢复,非明确失败表示仍在途、可自动恢复或需人工处理。该标记 MUST 仅用于判定尝试终结性与人工处置,MUST NOT 作为佣金回溯的准入条件。审计 SHALL 记录申请、重提、审批终态、权益处理、渠道调用与恢复,且不得记录凭证内容、完整收款文本或商户密钥。
为后续佣金回溯能力提供稳定事实,退款终态 SHALL 可按退款单与订单定位,并提供:成功退款金额、冻结实收金额与终态时点。佣金回溯准入 MUST 由退款申请状态、审批异常标记与退款方式得出,MUST NOT 依据失败分类标记、退款原因文本或新增的独立完成事件键:仅退款申请已通过且不存在审批异常标记时可进入回溯判定,原路退款还须渠道明确成功;待审批、原路处理中、渠道明确失败(可修改材料后重提)与企业微信通过后撤销均不得回溯。系统 MUST 保留既有退款佣金回扣事件键的兼容语义;佣金回溯的幂等键为一次退款一次回溯,不依赖退款单上的佣金回扣标记。
Scenario: 渠道失败分类可查询
- WHEN 原路退款因渠道余额不足失败
- THEN 退款详情返回该失败分类与安全摘要,且不返回任何凭证内容或完整收款文本
Scenario: 审计不含敏感内容
- WHEN 渠道退款调用或恢复完成后写入审计
- THEN 审计只记录业务标识、金额、状态与脱敏摘要,不记录商户密钥或凭证原文
Scenario: 回溯准入仅取决于退款申请状态
- WHEN 退款申请处于待审批、原路处理中、渠道明确失败或企业微信通过后撤销
- THEN 系统不生成任何佣金回溯事实;仅当退款申请已通过(原路退款还须渠道明确成功)时才生成
Scenario: 失败分类不决定回溯准入
- WHEN 一次退款尝试带有明确失败分类,但该退款申请尚未处于已通过状态
- THEN 系统不生成佣金回溯事实,该分类只用于判定尝试终结性与人工处置
Requirement: 退款展示当前退款套餐用量
退款管理列表、详情与导出 SHALL 返回「当前退款套餐已用量」与「当前退款套餐总量」两个字段,取值为该套餐使用记录当前可取得的真实已用量与真实总量(单位 MB)。两个字段 MUST 仅用于展示、查询与导出,MUST NOT 参与或改变退款金额校验、冻结实收金额、套餐失效、接续下一套餐、停机评估、佣金回溯或渠道退款任何规则。
「当前退款套餐」MUST 按与退款套餐失效一致的口径解析,且 MUST 按下列优先级取唯一一条:退款申请冻结的套餐使用记录(其 package_usage_id);该退款关联订单下 master_usage_id 为空的主套餐使用记录;该退款关联订单下任一套餐使用记录。同一优先级内按使用记录标识升序取第一条,保证同一退款每次返回相同结果。解析 MUST NOT 按当前生效套餐或当前世代推断,也 MUST NOT 跨订单取套餐。
套餐使用记录不存在、已被物理删除或字段为空时,两个字段 SHALL 返回 0,且 MUST NOT 因此阻断列表、详情或导出。列表返回 MUST NOT 因逐条查询套餐使用记录而放大查询次数。
Scenario: 退款申请已冻结套餐使用记录
- GIVEN 退款申请记录了套餐使用记录标识,且该记录属于其关联订单
- WHEN 查询退款列表、详情或导出
- THEN 两个字段返回该套餐使用记录的真实已用量与真实总量
Scenario: 退款申请未冻结套餐使用记录
- GIVEN 退款申请的套餐使用记录为空,且其关联订单存在主套餐使用记录
- WHEN 查询退款列表、详情或导出
- THEN 两个字段返回该订单主套餐使用记录的已用量与总量,不返回零值
Scenario: 套餐使用记录已不存在
- GIVEN 退款申请冻结的套餐使用记录已被物理删除,且解析结果为空
- WHEN 查询退款列表、详情或导出
- THEN 两个字段返回 0,且列表、详情与导出仍正常返回该退款申请
Scenario: 列表不因套餐字段放大查询
- GIVEN 退款列表一页返回多条退款申请
- WHEN 查询该页列表
- THEN 系统以批量方式读取套餐使用记录,查询次数不随该页退款申请条数线性增长
Scenario: 展示字段不影响资金与权益规则
- GIVEN 任一退款申请
- WHEN 系统解析并返回这两个展示字段
- THEN 退款金额校验、冻结实收金额、套餐失效、接续下一套餐、停机评估与佣金回溯行为均不发生变化
Requirement: 换货业务数据迁移状态与失败恢复
系统 SHALL 为每张已持久化的物流换货单返回业务数据迁移状态 not_migrated(不迁移)、pending(待迁移)、migrated(已迁移)或 failed(迁移失败),以及对应的中文状态名称。未选择业务数据迁移的换货单状态 MUST 为 not_migrated;选择迁移但尚未成功完成的换货单状态 MUST 为 pending;完整迁移成功后状态 MUST 为 migrated;迁移执行失败后状态 MUST 为 failed,并保存最近一次可安全展示的失败原因。
换货列表和详情 SHALL 返回迁移状态及中文名称;仅当状态为 failed 时返回最近一次失败原因。既有 migrate_data、migration_completed 和迁移余额字段 SHALL 保持兼容,但客户端不得再通过它们推断迁移结果。直接换货创建失败继续按既有原子性整体回滚,不产生可查询的失败换货单。
Scenario: 不迁移的换货单
- WHEN 创建或发货时未选择业务数据迁移
- THEN 换货列表和详情返回
not_migrated及“不迁移”,且不返回迁移失败原因
Scenario: 待迁移的换货单
- WHEN 换货单已选择业务数据迁移但尚未成功完成换货
- THEN 换货列表和详情返回
pending及“待迁移”
Scenario: 成功完成业务数据迁移
- WHEN 换货完成时全部业务数据迁移成功
- THEN 系统原子完成换货及业务数据迁移,列表和详情返回
migrated及“已迁移”,并清除最近一次失败原因
Scenario: 迁移失败后保留可恢复事实
- WHEN 换货完成时任一业务数据迁移步骤失败
- THEN 系统不得提交本次换货完成及任何部分迁移结果,换货单保持可确认完成状态,返回迁移失败,并在独立持久化事实中将迁移状态更新为
failed和最近一次失败原因
Scenario: 管理员重试失败迁移
- WHEN 超级管理员或平台用户对处于可确认完成状态且迁移状态为
failed的换货单再次确认完成 - THEN 系统重新原子执行完整业务数据迁移;成功后将状态更新为
migrated,再次失败则保留failed并覆盖为最近一次失败原因
Scenario: 非平台账号重试失败迁移
- WHEN 非超级管理员且非平台用户尝试再次确认迁移状态为
failed的换货单 - THEN 系统拒绝该操作,换货单及迁移状态不变
Requirement: 换货业务数据迁移范围
系统 SHALL 仅在选择业务数据迁移的换货完成中迁移旧资产的钱包余额、有效套餐使用记录、累计充值字段和资产标签。资产归属与个人客户—资产绑定 SHALL 继续作为换货完成固有动作,不受业务数据迁移选项控制;手机号—资产关联 MUST NOT 随换货或业务数据迁移转移,新资产首次访问时按其适用的手机号绑定规则处理。
Scenario: 选择业务数据迁移完成换货
- WHEN 换货单选择业务数据迁移并成功确认完成
- THEN 系统迁移钱包余额、有效套餐使用记录、累计充值字段和资产标签,且不迁移手机号—资产关联
Scenario: 不选择业务数据迁移完成换货
- WHEN 换货单未选择业务数据迁移并确认完成
- THEN 系统仍完成资产归属与个人客户—资产绑定的固有换货动作,但不迁移钱包余额、套餐使用记录、累计充值字段或资产标签
Requirement: 换货导出业务数据迁移状态
换货导出 SHALL 包含业务数据迁移状态,取值使用中文状态名称(不迁移、待迁移、已迁移、迁移失败),并 MUST NOT 导出迁移失败原因。该列 MUST 仅用于展示与追溯,MUST NOT 改变换货完成、业务数据迁移、失败恢复或数据访问范围任何规则。
Scenario: 导出包含迁移状态
- WHEN 调用方导出换货记录
- THEN 每行在「状态」之后返回该记录对应的中文迁移状态
Scenario: 迁移失败的记录被导出
- WHEN 换货记录的迁移状态为
failed,且该记录保存了最近一次失败原因 - THEN 导出行的迁移状态为“迁移失败”,且导出不输出该失败原因
可达操作索引
本节只用于入口导航,不是行为 Requirement;业务义务以上述 Requirements 为准。
订单管理
GET /api/admin/orders(获取订单列表);POST /api/admin/orders(创建订单);GET /api/admin/orders/{id}(获取订单详情);POST /api/admin/orders/{id}/cancel(取消订单);POST /api/admin/orders/purchase-check(套餐购买预检)。
退款管理
GET /api/admin/refunds(退款申请列表);POST /api/admin/refunds(创建退款申请);GET /api/admin/refunds/{id}(退款申请详情);POST /api/admin/refunds/{id}/trigger-approval(补发历史退款审批);POST /api/admin/refunds/{id}/approve(审批通过退款申请);POST /api/admin/refunds/{id}/reject(审批拒绝退款申请);POST /api/admin/refunds/{id}/resubmit(重新提交退款申请);POST /api/admin/refunds/{id}/return(退回退款申请)。
换货管理
GET /api/admin/exchanges(获取换货单列表);POST /api/admin/exchanges(创建换货单);GET /api/admin/exchanges/{id}(获取换货单详情);POST /api/admin/exchanges/{id}/cancel(取消换货);POST /api/admin/exchanges/{id}/complete(确认换货完成);POST /api/admin/exchanges/{id}/renew(旧资产转新);POST /api/admin/exchanges/{id}/ship(换货发货)。
订单套餐失效
GET /api/admin/order-package-invalidate-tasks(查询订单套餐失效任务列表);POST /api/admin/order-package-invalidate-tasks(创建订单套餐批量失效任务);GET /api/admin/order-package-invalidate-tasks/{id}(查询订单套餐失效任务详情)。