from __future__ import annotations

import json
from pathlib import Path


def numbered(items: list[str]) -> str:
    return "\n".join(f"{index}. {item}" for index, item in enumerate(items, 1))


def case(
    case_id: str,
    module: str,
    title: str,
    precondition: str,
    steps: list[str],
    expected: list[str],
    asserts: list[str],
    note: str = "",
) -> dict[str, str]:
    return {
        "用例编号": case_id,
        "用例层级": "订单状态流转用例",
        "来源/组合依据": f"whiteboard_exported_image.png + 状态机对应关系梳理.html：【{module}】",
        "所属模块": module,
        "用例标题": title,
        "登录平台/角色账号": "丸掌柜：企业主账号或客服账号；丸友集：工作室主账号或客服账号；打手：打手子账号。",
        "前置条件": precondition,
        "测试数据": "来源单号、订单标题、丸掌柜主单号、丸掌柜子单号、丸友集父单号、打手子单号、操作原因、操作凭证、金额信息。",
        "执行步骤": numbered(steps),
        "预期结果": numbered(expected),
        "跨端/状态断言": numbered(asserts),
        "可组合/被引用关系": "订单状态流转分支库；可被订单、履约、撤销、售后、申诉、结算前置大流程引用。",
        "自动化状态": "待自动化",
        "备注": note,
    }


def wzg_detail_steps() -> list[str]:
    return [
        "在丸掌柜订单管理页面，按来源单号或订单标题查询目标订单。",
        "点击主单号进入订单详情。",
        "记录丸掌柜主单订单状态。",
        "记录丸掌柜子单状态。",
    ]


def wyj_detail_steps(location: str = "工作室履约应用-订单列表") -> list[str]:
    return [
        f"登录丸友集账号，进入{location}。",
        "按来源单号或订单标题查询目标订单。",
        "如查询到订单，点击订单详情并记录丸友集父单状态和打手子单状态。",
        "如查询不到订单，记录查询条件、当前页签和空结果。",
    ]


def player_detail_steps() -> list[str]:
    return [
        "登录打手账号，进入打手应用-我的订单。",
        "按订单标题或子单信息查询目标打手订单。",
        "打开订单详情并记录打手订单状态、子状态和操作按钮。",
    ]


CASES: list[dict[str, str]] = []


def add(
    module: str,
    title: str,
    precondition: str,
    steps: list[str],
    expected: list[str],
    asserts: list[str],
) -> None:
    case_id = f"S-FLOW-{len(CASES) + 1:03d}"
    CASES.append(case(case_id, module, title, precondition, steps, expected, asserts))


NORMALIZED_FLOW_TITLES = [
    "【丸掌柜视角】主单待接单 / 子单待接单 - 创建主单未推单",
    "【丸掌柜视角】主单待接单 / 子单待接单-已推单 - 推单到丸友集",
    "【丸掌柜视角】主单待接单 / 子单待接单-待推单或已推单 - 发起售后",
    "【丸掌柜视角】主单待接单 / 子单待接单-待推单或已推单 - 处理售后",
    "【丸掌柜视角】主单待接单 / 子单待接单-待推单或已推单 - 取消售后",
    "【丸掌柜视角】主单待接单 / 子单待接单-待推单或已推单 - 发起撤销",
    "【丸掌柜视角】主单待接单 / 子单取消订单 - 继续发子单",
    "【丸友集视角】丸友集待接单 / 丸掌柜主单待接单 / 子单待接单-已推单 - 拒绝接单",
    "【丸友集视角】丸友集待接单 / 丸掌柜主单待接单 / 子单待接单-已推单 - 确认接单",
    "【丸友集视角】丸友集已接单未发单 / 丸掌柜主单服务中 / 子单代练中 - 申请撤销",
    "【丸掌柜视角】丸友集已接单未发单 / 丸掌柜主单异常中 / 子单代练中异常 - 同意撤销",
    "【丸掌柜视角】丸友集已接单未发单 / 丸掌柜主单异常中 / 子单代练中异常 - 拒绝撤销",
    "【丸掌柜视角】丸友集已接单未发单 / 丸掌柜主单服务中 / 子单代练中 - 发起售后",
    "【丸掌柜视角】丸友集已接单未发单 / 丸掌柜主单售后中 / 子单售后中 - 处理售后",
    "【丸掌柜视角】丸友集已接单未发单 / 丸掌柜主单售后中 / 子单售后中 - 取消售后",
    "【丸友集视角】丸友集已接单未发单 / 丸掌柜主单服务中 / 子单代练中 - 发单到打手",
    "【丸友集视角】打手未接单 / 丸友集已发单 / 丸掌柜主单服务中 / 子单代练中 - 撤回发单",
    "【丸掌柜视角】打手未接单 / 丸友集已发单 / 丸掌柜主单服务中 / 子单代练中 - 发起售后",
    "【丸掌柜视角】打手未接单 / 丸友集已发单 / 丸掌柜主单售后中 / 子单售后中 - 处理售后",
    "【丸掌柜视角】打手未接单 / 丸友集已发单 / 丸掌柜主单售后中 / 子单售后中 - 取消售后",
    "【打手视角】打手待接单 / 丸友集已发单 / 丸掌柜主单服务中 / 子单代练中 - 立即抢单",
    "【打手视角】打手代练中 / 丸友集子单代练中 / 丸掌柜主单服务中 / 子单代练中 - 发起撤销",
    "【打手视角】打手撤销中 / 丸友集子单撤销中 / 丸掌柜主单服务中 / 子单代练中 - 取消撤销",
    "【丸友集视角】打手撤销中 / 丸友集子单撤销中 / 丸掌柜主单服务中 / 子单代练中 - 拒绝撤销",
    "【丸友集视角】打手撤销中 / 丸友集子单撤销中 / 丸掌柜主单服务中 / 子单代练中 - 同意撤销",
    "【丸友集视角】打手子单已撤销 / 丸掌柜主单服务中 / 子单代练中 - 二发新子单",
    "【丸友集视角】前一子单已撤销或已取消 / 丸掌柜主单服务中 / 子单代练中 - 续发下一子单",
    "【丸友集视角】丸友集申请上游撤销 / 丸掌柜主单异常中 / 子单代练中异常 - 等待丸掌柜处理",
    "【丸掌柜视角】主单异常中 / 子单代练中异常 - 发起售后",
    "【丸掌柜视角】主单售后中 / 子单售后中 - 处理售后",
    "【丸掌柜视角】主单售后中 / 子单售后中 - 取消售后",
    "【打手视角】打手代练中 / 丸友集子单代练中 / 丸掌柜主单服务中 / 子单代练中 - 发起取消订单",
    "【丸友集视角】打手取消中 / 丸友集子单取消中 / 丸掌柜主单服务中 / 子单代练中 - 拒绝取消",
    "【丸友集视角】打手取消中 / 丸友集子单取消中 / 丸掌柜主单服务中 / 子单代练中 - 同意取消",
    "【打手视角】打手代练中 / 丸友集子单代练中 / 丸掌柜主单服务中 / 子单代练中 - 申请验收",
    "【打手视角】打手待验收 / 丸友集子单待验收 / 丸掌柜主单服务中 / 子单代练中 - 取消验收",
    "【丸友集视角】打手待验收 / 丸友集子单待验收 / 丸掌柜主单服务中 / 子单代练中 - 拒绝验收子单",
    "【丸友集视角】打手待验收 / 丸友集子单待验收 / 丸掌柜主单服务中 / 子单代练中 - 同意验收子单",
    "【丸友集视角】前一子单已完成 / 丸掌柜主单服务中 / 子单代练中 - 续发下一子单",
    "【丸友集视角】丸友集父单代练中 / 丸掌柜主单服务中 / 子单代练中 - 申请上游验收",
    "【丸掌柜视角】主单待验收 / 子单待验收 - 发起售后",
    "【丸掌柜视角】主单售后中 / 子单售后中 - 处理售后",
    "【丸掌柜视角】主单售后中 / 子单售后中 - 取消售后",
    "【丸掌柜视角】主单待验收 / 子单待验收 - 同意验收",
    "【丸掌柜视角】主单已完成 / 子单已完成 - 发起申诉",
    "【丸掌柜视角】主单已售后 / 子单已售后 - 发起申诉",
    "【丸友集视角】申诉待处理 / 丸掌柜主单已完成或已售后 / 子单申诉中 - 确认赔偿",
    "【丸友集视角】申诉待处理 / 丸掌柜主单已完成或已售后 / 子单申诉中 - 驳回申诉",
]


# ===================== 上游发单 =====================
add(
    "上游发单",
    "丸掌柜视角-主单待接单状态/子单待接单状态-创建主单未推单",
    "丸掌柜账号可创建外来订单；订单已创建但尚未推送到丸友集。",
    [
        "登录丸掌柜账号。",
        "进入丸掌柜-商家管理-订单管理。",
        "创建外来订单或先执行用例A-ORDER-001（丸掌柜手工录单创建外来订单并发布到丸友集）中的录单前半段。",
        "保存主单但不执行推单。",
        *wzg_detail_steps(),
        *wyj_detail_steps("工作室履约应用-抢单大厅"),
    ],
    [
        "丸掌柜主单订单状态为待接单。",
        "丸掌柜子单状态为待接单。",
        "丸友集抢单大厅查询不到此单。",
        "打手侧查询不到此单。",
    ],
    [
        "未推单前，福通和丸友集不应出现可接单记录。",
        "主单号、来源单号、订单标题在丸掌柜详情中一致。",
    ],
)

add(
    "上游发单",
    "丸掌柜视角-主单待接单状态/子单待接单-已推单状态-推单到丸友集",
    "丸掌柜主单为待接单，子单为待接单，且存在可用丸友集推单策略。",
    [
        "登录丸掌柜账号。",
        "进入丸掌柜-商家管理-订单管理。",
        "查询目标待接单订单。",
        "点击推单或发布到丸友集。",
        *wzg_detail_steps(),
        *wyj_detail_steps("工作室履约应用-抢单大厅"),
    ],
    [
        "丸掌柜主单订单状态仍为待接单。",
        "丸掌柜子单状态为待接单-已推单。",
        "丸友集抢单大厅可以查询到该订单，丸友集父单状态为待接单。",
        "打手侧查询不到此单。",
    ],
    [
        "丸掌柜待接单-已推单对应福通主单已推送、福通子单已发布、丸友集父单待接单。",
        "福通只知道工作室，不知道打手。",
    ],
)

add(
    "上游发单",
    "丸友集抢单大厅待接单阶段-丸友集确认接单",
    "丸掌柜订单已推送到丸友集抢单大厅，丸友集尚未确认接单。",
    [
        "登录丸友集主账号。",
        "进入工作室履约应用-抢单大厅。",
        "按来源单号或订单标题查询目标订单。",
        "点击确认接单。",
        *wyj_detail_steps("工作室履约应用-订单列表"),
        *wzg_detail_steps(),
    ],
    [
        "丸友集父单从抢单大厅进入订单列表，状态为已接单或页面展示的承接状态。",
        "丸掌柜主单订单状态仍为待接单或页面同步后的待下游处理状态。",
        "丸掌柜子单状态仍不应被误改为已完成。",
        "打手侧仍查询不到此单。",
    ],
    [
        "丸友集确认接单是工作室承接，不是打手接单。",
        "该动作不应直接让打手产生订单。",
    ],
)

add(
    "上游发单",
    "丸友集已接单/未发单到打手阶段-指派打手发单",
    "丸友集已确认接收上游订单，订单在丸友集工作室履约应用-订单列表中；如工作室下没有已启用打手，需先在企业管理-成员管理邀请并确认打手成员。",
    [
        "登录丸友集主账号。",
        "检查当前工作室下是否存在已启用打手成员。",
        "如不存在可用打手，进入企业管理-成员管理，邀请成员并选择丸友集产品、打手角色，完成注册/确认后返回丸友集。",
        "进入工作室履约应用-订单列表。",
        "按来源单号或订单标题查询目标订单。",
        "确认订单为丸友集已接单但未发给打手状态，操作区展示立即发单。",
        "点击立即发单。",
        "在发单弹框中选择分配方式为指派打手。",
        "点击选择打手，按成员名称或手机号查询目标打手。",
        "勾选目标打手并点击确认选择。",
        "选择或确认价格模式为百分比发单价，填写收单价百分比90，并确认订单内容、时间要求、联系电话等必填字段。",
        "点击确认发单。",
        *wyj_detail_steps("工作室履约应用-订单列表"),
        "登录被指派打手账号，进入打手应用-我的订单或待接订单列表。",
        "查询该打手子单并记录打手订单状态。",
        *wzg_detail_steps(),
    ],
    [
        "丸友集成功将已接单订单以指派打手方式发给目标打手。",
        "发单弹框回填的打手姓名/手机号与目标打手一致。",
        "被指派打手侧可见该订单，订单处于待接单或页面对应可处理状态。",
        "丸掌柜主单为服务中/代练中等继续履约状态，子单列表展示已发布、已接单、服务中或页面对应发单后状态。",
    ],
    [
        "指派打手前必须存在该丸友集工作室下的已启用打手；没有则先邀请并确认打手成员。",
        "只有被指派打手可见或处理该订单，非目标打手不应误接该单。",
        "丸友集订单列表、打手我的订单、丸掌柜订单详情中的来源单号、订单标题、打手信息一致。",
    ],
)

add(
    "丸友集撤销",
    "丸友集已接单/未发单到打手抢单大厅阶段-丸友集申请撤销",
    "丸友集已在抢单大厅确认接单，订单进入丸友集订单列表，尚未点击立即发单给打手。",
    [
        "登录丸友集主账号或客服账号。",
        "进入工作室履约应用-订单列表。",
        "按来源单号或订单标题查询目标订单。",
        "记录丸友集父单状态为已接单，确认尚未生成打手子单。",
        "点击申请撤销或向上撤销。",
        "填写撤销原因和凭证。",
        "提交撤销申请。",
        *wyj_detail_steps("工作室履约应用-订单列表"),
        *wzg_detail_steps(),
    ],
    [
        "丸友集父单进入撤销中、异常中或页面对应待上游处理状态。",
        "丸掌柜订单进入异常中或页面对应待处理状态。",
        "丸掌柜子单展示撤销申请或异常原因。",
        "打手侧查询不到此单。",
    ],
    [
        "丸友集已接单但未发给打手时，撤销只涉及工作室和上游，不涉及打手。",
        "撤销原因需要在丸友集和丸掌柜侧一致。",
    ],
)

add(
    "丸友集撤销",
    "丸友集已接单/未发单到打手抢单大厅阶段-丸友集申请撤销-丸掌柜同意撤销",
    "丸友集已提交撤销申请，丸掌柜侧可处理该撤销申请。",
    [
        "登录丸掌柜账号。",
        "进入丸掌柜-商家管理-订单管理。",
        "查询目标异常中或待撤销处理订单。",
        "点击主单号进入订单详情。",
        "在子单列表中查看撤销申请和撤销原因。",
        "点击同意撤销。",
        "填写处理备注并确认。",
        *wzg_detail_steps(),
        *wyj_detail_steps("工作室履约应用-订单列表"),
    ],
    [
        "丸掌柜子单列表中目标子单的订单状态变为取消订单。",
        "丸友集父单或订单进入已撤销、已取消或撤销完成状态。",
        "丸友集订单不可继续发给打手。",
        "打手侧查询不到此单。",
    ],
    [
        "同意撤销后当前子单终结，主单如需继续履约，应走继续发子单流程。",
        "撤销处理备注和处理结果两端一致。",
    ],
)

add(
    "丸友集撤销",
    "丸友集已接单/未发单到打手抢单大厅阶段-丸友集申请撤销-丸掌柜拒绝撤销",
    "丸友集已提交撤销申请，丸掌柜侧可处理该撤销申请。",
    [
        "登录丸掌柜账号。",
        "进入丸掌柜-商家管理-订单管理。",
        "查询目标异常中或待撤销处理订单。",
        "点击主单号进入订单详情。",
        "在子单列表中查看撤销申请和撤销原因。",
        "点击拒绝撤销。",
        "填写拒绝原因并确认。",
        *wzg_detail_steps(),
        *wyj_detail_steps("工作室履约应用-订单列表"),
    ],
    [
        "丸掌柜订单恢复到撤销前的待接单或页面对应继续履约状态。",
        "丸掌柜子单不进入取消订单终态。",
        "丸友集父单恢复已接单或可继续处理状态。",
        "丸友集可继续立即发单给打手。",
    ],
    [
        "拒绝撤销后，不能残留撤销中作为当前状态。",
        "拒绝原因在丸掌柜和丸友集侧一致。",
    ],
)

add(
    "上游发起售后",
    "丸友集已接单/未发单到打手抢单大厅阶段&&丸掌柜主单服务中状态/子单代练中状态-丸掌柜发起售后",
    "丸友集已在抢单大厅确认接单，订单进入丸友集订单列表，尚未点击立即发单给打手。",
    [
        "登录丸掌柜账号。",
        "进入丸掌柜-商家管理-订单管理。",
        "按来源单号或订单标题查询目标主单。",
        "点击主单号进入订单详情。",
        "记录丸掌柜主单订单状态和子单列表中目标子单订单状态。",
        "点击发起售后。",
        "填写售后原因、售后金额和凭证。",
        "提交售后申请。",
        *wzg_detail_steps(),
        *wyj_detail_steps("工作室履约应用-订单列表"),
    ],
    [
        "丸掌柜订单状态为售后中。",
        "丸掌柜子单列表中目标子单订单状态为售后中或页面对应售后状态。",
        "丸友集父单进入售后中，不能继续立即发单给打手。",
        "打手侧查询不到此单。",
    ],
    [
        "该阶段丸友集已承接但未生成打手订单，因此售后不涉及打手状态。",
        "售后原因、金额、凭证在丸掌柜和丸友集侧一致。",
    ],
)

add(
    "上游处理售后",
    "丸友集已接单/未发单到打手抢单大厅阶段&&丸掌柜主单服务中状态/子单代练中状态-丸掌柜处理售后",
    "丸掌柜已在丸友集已接单但未发单给打手阶段发起售后，当前订单为售后中。",
    [
        "登录丸掌柜账号或具备售后处理权限的账号。",
        "进入订单管理或售后处理页面。",
        "查询目标售后订单。",
        "打开售后详情并记录原主单状态、原子单订单状态。",
        "点击处理售后。",
        "填写处理结果、退款金额和处理备注。",
        "提交售后处理。",
        *wzg_detail_steps(),
        *wyj_detail_steps("工作室履约应用-订单列表"),
    ],
    [
        "丸掌柜订单状态为已售后。",
        "丸掌柜子单列表中目标子单订单状态为已售后或取消订单，以页面实际展示为准。",
        "丸友集父单为售后完成或页面对应终态。",
        "打手侧查询不到此单。",
    ],
    [
        "处理售后后该丸友集承接链路终结。",
        "处理金额、结果、备注两端一致。",
    ],
)

add(
    "上游取消售后",
    "丸友集已接单/未发单到打手抢单大厅阶段&&丸掌柜主单服务中状态/子单代练中状态-丸掌柜取消售后",
    "丸掌柜已在丸友集已接单但未发单给打手阶段发起售后，当前订单为售后中且未处理完成。",
    [
        "登录丸掌柜账号。",
        "进入售后详情。",
        "记录取消前丸掌柜订单状态为售后中、子单列表目标子单订单状态为售后中或页面对应状态。",
        "点击取消售后。",
        "填写取消原因并确认。",
        *wzg_detail_steps(),
        *wyj_detail_steps("工作室履约应用-订单列表"),
    ],
    [
        "丸掌柜订单恢复到售后前状态。",
        "丸掌柜子单列表中目标子单恢复到售后前订单状态。",
        "丸友集父单恢复已接单或页面对应可继续处理状态。",
        "丸友集可继续立即发单给打手。",
    ],
    [
        "取消售后后不能残留售后中作为当前状态。",
        "取消原因可追溯。",
    ],
)

add(
    "丸友集撤销",
    "丸友集已发单到打手抢单大厅/打手未接单阶段-丸友集撤回发单",
    "丸友集已点击立即发单，打手抢单大厅可见订单，但打手尚未接单。",
    [
        "登录丸友集主账号或客服账号。",
        "进入工作室履约应用-订单列表。",
        "查询目标订单并记录丸友集父单状态和打手子单状态。",
        "确认打手子单状态为待接单，打手尚未接单。",
        "点击撤回发单、取消子单或页面展示的取消入口。",
        "填写撤回原因并确认。",
        *wyj_detail_steps("工作室履约应用-订单列表"),
        "登录打手账号，进入打手应用-抢单大厅查询目标订单。",
        *wzg_detail_steps(),
    ],
    [
        "打手抢单大厅查询不到该打手子单，或该子单不可继续抢单。",
        "丸友集打手子单状态为已取消、已撤回或页面对应终态。",
        "丸友集父单仍可继续发单给其他打手或按页面规则处理。",
        "丸掌柜不因打手未接单阶段撤回发单而直接已完成。",
    ],
    [
        "撤回的是工作室向下发给打手的子单，不是上游主单完结。",
        "如页面没有撤回/取消入口，应记录为缺口而不是通过脚本强行操作。",
    ],
)

add(
    "上游发起售后",
    "丸友集已发单到打手抢单大厅/打手未接单阶段&&丸掌柜主单服务中状态/子单代练中状态-丸掌柜发起售后",
    "丸友集已发单到打手抢单大厅，打手尚未接单。",
    [
        "登录丸掌柜账号。",
        "进入订单管理查询目标主单。",
        "点击主单号进入订单详情。",
        "记录丸掌柜主单订单状态和子单列表目标子单订单状态。",
        "点击发起售后。",
        "填写售后原因、售后金额和凭证。",
        "提交售后申请。",
        *wzg_detail_steps(),
        *wyj_detail_steps("工作室履约应用-订单列表"),
        "登录打手账号，进入打手应用-抢单大厅查询该订单。",
    ],
    [
        "丸掌柜订单状态为售后中。",
        "丸友集父单进入售后中或不可继续普通发单/撤回/验收。",
        "打手抢单大厅查询不到此单，或该订单不可继续抢单。",
    ],
    [
        "打手未接单时发起售后，不应生成打手代练中状态。",
        "丸友集和打手侧可见性应与售后状态一致。",
    ],
)

add(
    "上游处理售后",
    "丸友集已发单到打手抢单大厅/打手未接单阶段&&丸掌柜主单服务中状态/子单代练中状态-丸掌柜处理售后",
    "丸掌柜已在打手未接单阶段发起售后，当前订单为售后中。",
    [
        "登录丸掌柜账号或具备售后处理权限的账号。",
        "进入订单管理或售后处理页面。",
        "查询目标售后订单。",
        "点击处理售后。",
        "填写处理结果、退款金额和处理备注。",
        "提交售后处理。",
        *wzg_detail_steps(),
        *wyj_detail_steps("工作室履约应用-订单列表"),
        "登录打手账号，进入打手应用-抢单大厅查询该订单。",
    ],
    [
        "丸掌柜订单状态为已售后。",
        "丸友集父单售后完成或进入页面对应终态。",
        "打手抢单大厅查询不到此单。",
    ],
    [
        "处理售后后打手未接单链路终结。",
        "不应产生打手收入或履约记录。",
    ],
)

add(
    "上游取消售后",
    "丸友集已发单到打手抢单大厅/打手未接单阶段&&丸掌柜主单服务中状态/子单代练中状态-丸掌柜取消售后",
    "丸掌柜已在打手未接单阶段发起售后，当前订单为售后中且未处理完成。",
    [
        "登录丸掌柜账号。",
        "进入售后详情。",
        "点击取消售后。",
        "填写取消原因并确认。",
        *wzg_detail_steps(),
        *wyj_detail_steps("工作室履约应用-订单列表"),
        "登录打手账号，进入打手应用-抢单大厅查询该订单。",
    ],
    [
        "丸掌柜订单恢复售后前状态。",
        "丸友集父单恢复售后前状态。",
        "打手抢单大厅重新可见该订单，或页面恢复到售后前可接单状态。",
    ],
    [
        "取消售后后不能残留售后中。",
        "取消原因可追溯。",
    ],
)

add(
    "上游发单",
    "丸友集已发单到打手抢单大厅/打手未接单阶段-立即抢单",
    "丸友集已将订单发给打手，打手侧订单为待接单。",
    [
        "登录打手账号。",
        "进入打手应用-抢单大厅或待接订单列表。",
        "查询目标订单。",
        "点击接单或抢单。",
        *player_detail_steps(),
        *wyj_detail_steps("工作室履约应用-订单列表"),
        *wzg_detail_steps(),
    ],
    [
        "打手订单状态为代练中。",
        "丸友集打手子单状态为代练中。",
        "丸友集父单状态按工作室整体履约状态展示。",
        "丸掌柜订单状态和子单状态不因打手单独接单而额外穿透变更。",
    ],
    [
        "打手操作只影响打手和Orbit子单可见状态。",
        "向上同步由工作室层级动作触发。",
    ],
)


# ===================== 上游发起售后 / 处理售后 / 取消售后 =====================
AFTERSALE_BRANCHES = [
    {
        "main": "待接单",
        "sub": "待接单-待推单/已推单",
        "wyj_location": "工作室履约应用-抢单大厅",
        "wyj_after_apply": "丸友集抢单大厅查询不到此单，或该订单不可继续接单。",
        "pre": "丸掌柜主单订单状态为待接单，丸掌柜子单处于待接单-待推单或待接单-已推单阶段。",
        "child_cancel_after_aftersale": True,
    },
    {
        "main": "待验收",
        "sub": "待验收",
        "wyj_location": "工作室履约应用-订单列表",
        "wyj_after_apply": "丸友集订单进入售后中，不能继续普通验收流程。",
        "pre": "丸友集已申请上游验收，丸掌柜主单订单状态为待验收，丸掌柜子单状态为待验收。",
        "child_cancel_after_aftersale": False,
    },
    {
        "main": "异常中",
        "sub": "代练中异常",
        "wyj_location": "工作室履约应用-订单列表",
        "wyj_after_apply": "丸友集订单进入售后中或售后处理入口可见。",
        "pre": "丸友集已申请上游撤销或异常，丸掌柜主单订单状态为异常中，丸掌柜子单状态为代练中异常。",
        "child_cancel_after_aftersale": False,
    },
]

for branch in AFTERSALE_BRANCHES:
    add(
        "上游发起售后",
        f"丸掌柜视角-主单{branch['main']}状态/子单{branch['sub']}状态阶段发起售后",
        branch["pre"],
        [
            "登录丸掌柜账号。",
            "进入订单管理查询目标订单。",
            "打开订单详情并确认发起前的主单订单状态和子单状态。",
            "在子单列表中记录目标子单的订单状态。",
            "点击发起售后。",
            "填写售后原因、售后金额和凭证。",
            "提交售后申请。",
            *wzg_detail_steps(),
            *wyj_detail_steps(branch["wyj_location"]),
        ],
        [
            "丸掌柜订单状态为售后中。",
            (
                "丸掌柜子单列表中目标子单的订单状态为取消订单；该子单进入终结状态，后续需要由丸掌柜主单继续发子单。"
                if branch["child_cancel_after_aftersale"]
                else "丸掌柜子单状态为售后中。"
            ),
            branch["wyj_after_apply"],
            "售后原因、售后金额和凭证在丸掌柜售后记录中保存成功。",
        ],
        [
            f"发起售后前状态必须为主单{branch['main']}、子单{branch['sub']}。",
            "丸掌柜售后中对应福通售后中/仲裁中和丸友集售后中链路。",
            "售后中不能继续普通接单、发单、验收或完单动作。",
        ],
    )

for branch in AFTERSALE_BRANCHES:
    add(
        "上游处理售后",
        f"丸掌柜视角-主单{branch['main']}状态/子单{branch['sub']}状态阶段处理售后",
        f"已从主单{branch['main']}状态/子单{branch['sub']}状态发起售后，当前丸掌柜订单为售后中。",
        [
            "登录丸掌柜账号或具备售后处理权限的账号。",
            "进入订单管理或售后处理页面。",
            "查询目标售后订单。",
            "打开售后详情并记录售后前原主单状态和原子单状态。",
            "进入丸掌柜主单详情，在子单列表中记录目标子单的订单状态。",
            "点击处理售后。",
            "填写处理结果、退款金额和处理备注。",
            "提交售后处理。",
            *wzg_detail_steps(),
            *wyj_detail_steps(branch["wyj_location"]),
        ],
        [
            "丸掌柜订单状态为已售后。",
            (
                "丸掌柜子单列表中目标子单的订单状态保持为取消订单；该子单已终结，主单可继续发子单。"
                if branch["child_cancel_after_aftersale"]
                else "丸掌柜子单状态为已售后。"
            ),
            "丸友集订单为售后完成，或待接单阶段订单仍不可继续接单。",
            "售后退款或资金处理记录生成并与处理金额一致。",
        ],
        [
            "已售后为终态，不能再回到普通履约流程。",
            "售后处理结果、金额、备注在丸掌柜和丸友集侧一致。",
        ],
    )

for branch in AFTERSALE_BRANCHES:
    add(
        "上游取消售后",
        f"丸掌柜视角-主单{branch['main']}状态/子单{branch['sub']}状态阶段取消售后",
        f"已从主单{branch['main']}状态/子单{branch['sub']}状态发起售后，当前丸掌柜订单为售后中且未处理完成。",
        [
            "登录丸掌柜账号。",
            "进入售后详情。",
            "记录取消前丸掌柜订单状态为售后中、子单状态为售后中。",
            "进入丸掌柜主单详情，在子单列表中记录目标子单的订单状态。",
            "点击取消售后。",
            "填写取消原因并确认。",
            *wzg_detail_steps(),
            *wyj_detail_steps(branch["wyj_location"]),
        ],
        [
            f"丸掌柜订单状态恢复为{branch['main']}。",
            (
                "丸掌柜子单列表中目标子单的订单状态为取消订单；该子单不再继续履约，主单可继续发子单。"
                if branch["child_cancel_after_aftersale"]
                else f"丸掌柜子单状态恢复为{branch['sub']}。"
            ),
            "丸友集侧恢复到售后发起前的可见性和业务状态。",
            "售后取消原因被记录，当前状态不再展示为售后中。",
        ],
        [
            "取消售后必须恢复到发起售后前的主单状态和子单状态，不能统一恢复为代练中。",
            "售后取消后，后续可继续原阶段允许的动作。",
        ],
    )


# ===================== 上游发起撤销 =====================
add(
    "上游发起撤销",
    "丸掌柜视角-主单待接单状态/子单待接单-待推单/已推单状态阶段发起撤销",
    "丸掌柜主单订单状态为待接单，子单处于待接单-待推单或待接单-已推单阶段。",
    [
        "登录丸掌柜账号。",
        "进入丸掌柜-商家管理-订单管理。",
        "按来源单号或订单标题查询目标主单。",
        "点击主单号进入订单详情。",
        "在子单列表中记录目标子单的订单状态。",
        "在子单列表中对目标子单点击发起撤销。",
        "填写撤销原因和凭证。",
        "提交撤销申请。",
        *wzg_detail_steps(),
        *wyj_detail_steps("工作室履约应用-抢单大厅"),
    ],
    [
        "丸掌柜主单订单状态仍为待接单或页面展示的可继续处理状态。",
        "丸掌柜子单列表中目标子单的订单状态变为取消订单。",
        "该子单状态终结，不能继续履约。",
        "丸友集侧查询不到此单，或该订单不可继续接单。",
    ],
    [
        "上游对子单发起撤销只终结当前子单，不等于主单完结。",
        "当前子单取消订单后，需要由丸掌柜主单继续发子单。",
    ],
)

add(
    "上游发单",
    "丸掌柜视角-主单待接单状态/子单取消订单状态-继续发子单",
    "丸掌柜主单下已有目标子单订单状态为取消订单，主单仍需继续履约。",
    [
        "登录丸掌柜账号。",
        "进入丸掌柜-商家管理-订单管理。",
        "按来源单号或订单标题查询目标主单。",
        "点击主单号进入订单详情。",
        "确认原子单列表中的订单状态为取消订单。",
        "点击继续发子单或页面展示的继续发单入口。",
        "填写新子单信息并选择丸友集推单策略。",
        "提交并推送新子单。",
        *wzg_detail_steps(),
        *wyj_detail_steps("工作室履约应用-抢单大厅"),
    ],
    [
        "原子单订单状态保持取消订单。",
        "新子单创建成功，状态为待接单或待接单-已推单。",
        "丸友集抢单大厅可查询到新子单对应的订单。",
        "主单仍按整体履约继续流转。",
    ],
    [
        "继续发子单不能覆盖原取消订单子单。",
        "新旧子单状态、子单号和推单记录相互独立。",
    ],
)


# ===================== 下游发起撤销 =====================
add(
    "下游发起撤销",
    "打手代练中状态发起撤销-不穿透丸掌柜",
    "打手订单状态为代练中，丸掌柜主单为服务中，丸掌柜子单为代练中。",
    [
        "登录打手账号。",
        "进入打手应用-我的订单。",
        "打开目标订单详情并记录打手订单状态为代练中。",
        "点击申请撤销。",
        "填写撤销原因和凭证并提交。",
        *player_detail_steps(),
        *wyj_detail_steps("工作室履约应用-订单列表"),
        *wzg_detail_steps(),
    ],
    [
        "打手订单状态为撤销中。",
        "丸友集打手子单可见撤销申请或撤销中状态。",
        "丸掌柜订单状态仍为服务中。",
        "丸掌柜子单状态仍为代练中，不因打手单独申请撤销变为异常中。",
    ],
    [
        "打手申请撤销只影响打手和Orbit子单可见状态。",
        "若要丸掌柜异常中，必须由工作室申请上游撤销。",
    ],
)

add(
    "下游发起撤销",
    "打手撤销中状态取消撤销-恢复代练中",
    "打手已发起撤销，丸友集尚未审核。",
    [
        "登录打手账号。",
        "进入打手应用-我的订单。",
        "打开撤销中的订单详情。",
        "点击取消撤销。",
        "填写取消原因并确认。",
        *player_detail_steps(),
        *wyj_detail_steps("工作室履约应用-订单列表"),
        *wzg_detail_steps(),
    ],
    [
        "打手订单状态恢复为代练中。",
        "丸友集打手子单撤销申请关闭或恢复代练中。",
        "丸掌柜订单状态仍为服务中。",
        "丸掌柜子单状态仍为代练中。",
    ],
    [
        "取消撤销不应产生福通取消异常回调。",
        "取消原因可追溯。",
    ],
)

add(
    "下游发起撤销",
    "打手撤销中状态-丸友集同意撤销",
    "打手已发起撤销，丸友集可审核该撤销申请。",
    [
        "登录丸友集主账号或客服账号。",
        "进入工作室履约应用-订单列表。",
        "查询目标订单并打开撤销申请。",
        "记录丸友集父单状态和目标打手子单状态。",
        "点击同意撤销。",
        "填写审核备注并提交。",
        *wyj_detail_steps("工作室履约应用-订单列表"),
        *player_detail_steps(),
        *wzg_detail_steps(),
    ],
    [
        "打手订单状态为撤销完成。",
        "丸友集目标打手子单状态为已撤销或撤销完成。",
        "丸友集父单不应因单个打手子单撤销直接已完成。",
        "丸掌柜订单状态和子单状态不应被误置为已完成。",
    ],
    [
        "工作室同意的是打手子单撤销，不等于上游主单撤销完成。",
        "是否二发或申请上游撤销由工作室后续动作决定。",
    ],
)

add(
    "下游发起撤销",
    "打手撤销中状态-丸友集拒绝撤销",
    "打手已发起撤销，丸友集可审核该撤销申请。",
    [
        "登录丸友集主账号或客服账号。",
        "进入工作室履约应用-订单列表。",
        "打开撤销申请详情。",
        "记录拒绝前丸友集父单状态和目标打手子单状态。",
        "点击拒绝撤销。",
        "填写拒绝原因并提交。",
        *wyj_detail_steps("工作室履约应用-订单列表"),
        *player_detail_steps(),
        *wzg_detail_steps(),
    ],
    [
        "打手订单状态恢复为代练中。",
        "丸友集目标打手子单恢复为代练中。",
        "丸掌柜订单状态为服务中。",
        "丸掌柜子单状态为代练中。",
        "打手侧可见拒绝原因。",
    ],
    [
        "拒绝撤销后不能残留撤销中作为当前状态。",
        "拒绝原因在丸友集和打手侧一致。",
    ],
)

add(
    "下游发起撤销",
    "丸友集子单已撤销状态-二发新子单",
    "原打手子单已撤销或撤销完成，丸友集需要继续履约该上游订单。",
    [
        "登录丸友集主账号或客服账号。",
        "进入工作室履约应用-订单列表。",
        "查询目标订单并确认原打手子单为已撤销或撤销完成。",
        "点击继续发单、再次发单或页面展示的发单入口。",
        "填写新子单发单价、服务要求和服务时限。",
        "提交发单。",
        "登录新打手账号接单。",
        *wyj_detail_steps("工作室履约应用-订单列表"),
        *wzg_detail_steps(),
    ],
    [
        "原打手子单保持已撤销或撤销完成。",
        "新打手子单进入待接单或代练中。",
        "丸掌柜主单仍按工作室整体履约展示，不因旧子单撤销直接完结。",
        "丸掌柜子单状态不得被新子单覆盖为旧子单状态。",
    ],
    [
        "新旧子单状态独立。",
        "福通只知道工作室，不知道具体换了哪个打手。",
    ],
)

add(
    "下游发起撤销",
    "丸友集申请上游撤销-丸掌柜进入异常中",
    "丸友集父单处于代练中，工作室决定向上申请撤销。",
    [
        "登录丸友集主账号或客服账号。",
        "进入工作室履约应用-订单列表。",
        "查询目标订单并记录丸友集父单状态和子单状态。",
        "点击申请撤销或向上撤销。",
        "填写撤销原因和凭证。",
        "提交撤销申请。",
        *wyj_detail_steps("工作室履约应用-订单列表"),
        *wzg_detail_steps(),
    ],
    [
        "丸友集父单状态为异常中或撤销相关状态。",
        "丸掌柜订单状态为异常中。",
        "丸掌柜子单状态为代练中异常或页面对应异常子状态。",
        "丸掌柜详情可见异常原因或撤销原因。",
    ],
    [
        "工作室申请上游撤销才会向上通知福通。",
        "异常中的订单可衔接上游发起售后流程。",
    ],
)


# ===================== 下游拒绝接单 / 指派取消 =====================
add(
    "下游拒绝接单",
    "丸友集待接单状态拒绝上游订单-供应链拒绝结束",
    "订单在丸友集抢单大厅待接单，工作室尚未确认接单。",
    [
        "登录丸友集主账号。",
        "进入工作室履约应用-抢单大厅。",
        "查询目标订单并记录丸友集父单状态为待接单。",
        "点击拒绝接单或拒绝订单。",
        "填写拒绝原因并提交。",
        *wyj_detail_steps("工作室履约应用-抢单大厅"),
        *wzg_detail_steps(),
    ],
    [
        "丸友集父单状态为已拒绝或抢单大厅不再展示该订单。",
        "丸掌柜订单进入待继续处理、异常中或页面展示的拒绝相关状态。",
        "丸掌柜子单展示拒绝原因或拒绝结果。",
        "打手侧查询不到此单。",
    ],
    [
        "工作室拒绝接单才会向上通知福通。",
        "该场景不同于打手拒绝指派。",
    ],
)

add(
    "指派单 下游取消订单",
    "打手代练中状态发起取消订单",
    "已执行 S-FLOW-021，丸友集已按指派打手方式发单给目标打手；已执行 S-FLOW-026，被指派打手已接单并进入代练中。没有完成丸友集指派发单和打手接单时，打手侧不会出现可取消订单。",
    [
        "登录打手账号。",
        "进入打手应用-我的订单。",
        "打开指派单详情并记录订单状态为代练中。",
        "点击取消订单。",
        "填写取消原因并提交。",
        *player_detail_steps(),
        *wyj_detail_steps("工作室履约应用-订单列表"),
        *wzg_detail_steps(),
    ],
    [
        "打手订单状态为取消中。",
        "丸友集可见取消申请。",
        "丸掌柜订单状态和子单状态不因打手单独取消而进入已取消终态。",
    ],
    [
        "打手取消订单需要工作室审核。",
        "打手取消订单不同于丸掌柜向下取消订单。",
        "S-FLOW-037 不能单独作为 FLOW-021 起点，必须承接 S-FLOW-021 和 S-FLOW-026。",
    ],
)

add(
    "指派单 下游取消订单",
    "打手取消中状态-丸友集同意取消",
    "打手已提交取消订单申请，丸友集待审核。",
    [
        "登录丸友集主账号或客服账号。",
        "进入工作室履约应用-订单列表。",
        "打开取消申请详情。",
        "点击同意取消。",
        "填写处理备注并提交。",
        *wyj_detail_steps("工作室履约应用-订单列表"),
        *player_detail_steps(),
        *wzg_detail_steps(),
    ],
    [
        "打手订单状态为已取消。",
        "丸友集目标子单状态为已取消。",
        "丸友集父单根据是否需要继续履约展示为待继续发单、异常或页面对应状态。",
        "丸掌柜主单不因单个打手子单取消直接已完成。",
    ],
    [
        "取消审批记录、取消原因、子单终态可追踪。",
        "如需继续履约，应进入二发或续建子单流程。",
    ],
)

add(
    "指派单 下游取消订单",
    "打手取消中状态-丸友集拒绝取消",
    "打手已提交取消订单申请，丸友集待审核。",
    [
        "登录丸友集主账号或客服账号。",
        "进入工作室履约应用-订单列表。",
        "打开取消申请详情。",
        "点击拒绝取消。",
        "填写拒绝原因并提交。",
        *wyj_detail_steps("工作室履约应用-订单列表"),
        *player_detail_steps(),
        *wzg_detail_steps(),
    ],
    [
        "打手订单状态恢复为代练中。",
        "丸友集目标子单恢复为代练中。",
        "丸掌柜订单状态为服务中。",
        "丸掌柜子单状态为代练中。",
        "打手侧可见拒绝原因。",
    ],
    [
        "拒绝取消后不能残留取消中作为当前状态。",
        "拒绝原因在丸友集和打手侧一致。",
    ],
)


# ===================== 多子单履约 =====================
add(
    "多子单履约",
    "前一子单已完成状态-续发下一子单",
    "第一子单已完成，丸友集订单列表可查看同一主单，页面允许继续发单或再次发单。",
    [
        "先执行用例B-MULTI-002（前一子单完成后续建下一子单）。",
        "登录丸友集主账号。",
        "进入丸友集-工作室履约应用-订单列表。",
        "按来源单号搜索主单。",
        "点击订单详情并记录第一子单状态为已完成。",
        "查看订单行是否出现立即发单或再次发单入口。",
        "点击入口进入发单弹框。",
        "填写第二子单的分配方式、发单价、服务时限和订单要求。",
        "提交发单。",
        "登录打手账号，确认第二子单可见并接单。",
        *wyj_detail_steps("工作室履约应用-订单列表"),
        *wzg_detail_steps(),
    ],
    [
        "第一子单保持已完成。",
        "第二子单进入待接单或代练中。",
        "两个子单状态、金额、打手信息相互独立。",
        "丸掌柜主单子单计数或子单列表更新。",
    ],
    [
        "不会把第二子单覆盖到第一子单。",
        "丸掌柜仍按工作室整体履约状态聚合展示。",
    ],
)

add(
    "多子单履约",
    "前一子单已撤销/已取消状态-续发下一子单",
    "第一子单已发起撤销或取消并审批通过，状态进入已取消、已撤销或页面展示的终态。",
    [
        "先执行用例B-MULTI-003（前一子单撤销或取消后续建下一子单）。",
        "登录丸友集主账号，进入丸友集-工作室履约应用-订单列表。",
        "搜索目标订单。",
        "确认第一子单状态为已取消、已撤销或页面展示的终态。",
        "查看是否出现立即发单或再次发单入口。",
        "如入口出现，创建第二子单并提交发单。",
        "登录新打手账号接单。",
        *wyj_detail_steps("工作室履约应用-订单列表"),
        *wzg_detail_steps(),
    ],
    [
        "第一子单保持已取消、已撤销或页面终态。",
        "第二子单进入待接单或代练中。",
        "撤销申请、审批记录、子单终态、再次发单入口、主单状态在丸友集和丸掌柜侧一致。",
    ],
    [
        "子单撤销或取消必须经过审批。",
        "审批通过并进入终态后，才允许按页面规则续建下一子单。",
    ],
)


# ===================== 订单验收 =====================
add(
    "订单验收",
    "打手代练中状态申请验收-只到丸友集子单待验收",
    "打手订单处于代练中，已上号并已上传首图。",
    [
        "登录打手账号。",
        "进入打手应用-我的订单。",
        "打开目标订单详情并记录打手订单状态为代练中。",
        "点击申请验收。",
        "填写验收说明并提交。",
        *player_detail_steps(),
        *wyj_detail_steps("工作室履约应用-订单列表"),
        *wzg_detail_steps(),
    ],
    [
        "打手订单状态为待验收。",
        "丸友集打手子单状态为待验收。",
        "丸友集父单仍为代练中或页面整体履约状态。",
        "丸掌柜订单状态仍为服务中。",
        "丸掌柜子单状态仍为代练中。",
    ],
    [
        "打手申请验收不穿透到福通和丸掌柜。",
        "工作室需要单独申请上游验收。",
    ],
)

add(
    "订单验收",
    "打手待验收状态取消验收-恢复代练中",
    "打手已提交验收，丸友集尚未验收子单。",
    [
        "登录打手账号。",
        "进入打手应用-我的订单。",
        "打开待验收订单详情。",
        "点击取消验收。",
        "填写取消原因并确认。",
        *player_detail_steps(),
        *wyj_detail_steps("工作室履约应用-订单列表"),
        *wzg_detail_steps(),
    ],
    [
        "打手订单状态恢复为代练中。",
        "丸友集打手子单恢复为代练中或页面对应继续履约状态。",
        "丸掌柜订单状态仍为服务中。",
        "丸掌柜子单状态仍为代练中。",
    ],
    [
        "取消验收不影响福通。",
        "取消原因可追溯。",
    ],
)

add(
    "订单验收",
    "丸友集子单待验收状态-同意验收子单",
    "打手已提交验收，丸友集打手子单处于待验收。",
    [
        "登录丸友集主账号或客服账号。",
        "进入工作室履约应用-订单列表。",
        "查询目标订单并打开子单验收详情。",
        "记录丸友集父单状态和目标打手子单状态。",
        "点击同意验收子单。",
        "确认验收材料并提交。",
        *wyj_detail_steps("工作室履约应用-订单列表"),
        *player_detail_steps(),
        *wzg_detail_steps(),
    ],
    [
        "打手订单状态为已完成。",
        "丸友集目标打手子单状态为已完成。",
        "丸友集父单不因验收单个子单自动变为上游待验收，除非页面另行执行申请上游验收。",
        "丸掌柜订单状态仍为服务中。",
        "丸掌柜子单状态仍为代练中。",
    ],
    [
        "验收子单是工作室向下管理打手，不等于申请上游验收。",
        "打手收入或可结算记录可按结算用例继续校验。",
    ],
)

add(
    "订单验收",
    "丸友集子单待验收状态-拒绝验收子单",
    "打手已提交验收，丸友集打手子单处于待验收。",
    [
        "登录丸友集主账号或客服账号。",
        "进入工作室履约应用-订单列表。",
        "打开子单验收详情。",
        "点击拒绝验收。",
        "填写拒绝原因并提交。",
        *wyj_detail_steps("工作室履约应用-订单列表"),
        *player_detail_steps(),
        *wzg_detail_steps(),
    ],
    [
        "打手订单状态恢复为代练中或需重新提交验收。",
        "丸友集目标打手子单恢复为代练中或页面对应状态。",
        "丸掌柜订单状态仍为服务中。",
        "丸掌柜子单状态仍为代练中。",
        "打手侧可见拒绝原因。",
    ],
    [
        "拒绝子单验收不应生成已完成收入。",
        "拒绝子单验收不应让丸掌柜进入待验收。",
    ],
)

add(
    "订单验收",
    "丸友集父单代练中状态-申请上游验收",
    "丸友集已完成必要的打手子单验收，父单仍为代练中。",
    [
        "登录丸友集主账号或客服账号。",
        "进入工作室履约应用-订单列表。",
        "查询目标订单。",
        "点击申请上游验收或申请验收。",
        "确认提交验收申请。",
        *wyj_detail_steps("工作室履约应用-订单列表"),
        *wzg_detail_steps(),
    ],
    [
        "丸友集父单状态为待验收。",
        "丸掌柜订单状态为待验收。",
        "丸掌柜子单状态为待验收。",
        "打手已完成子单状态保持已完成或页面对应完成态。",
    ],
    [
        "工作室申请上游验收才向上通知福通。",
        "该动作是丸掌柜待验收的前置。",
    ],
)

add(
    "订单验收",
    "丸掌柜视角-主单待验收状态/子单待验收状态-同意验收完结主单",
    "丸友集已申请上游验收，丸掌柜主单和子单均为待验收。",
    [
        "登录丸掌柜账号。",
        "进入订单管理查询目标订单。",
        "打开订单详情并记录主单订单状态为待验收、子单状态为待验收。",
        "点击同意验收或确认验收。",
        "确认弹窗。",
        *wzg_detail_steps(),
        *wyj_detail_steps("工作室履约应用-订单列表"),
        *player_detail_steps(),
    ],
    [
        "丸掌柜订单状态为已完成。",
        "丸掌柜子单状态为已完成。",
        "丸友集父单状态为已完成。",
        "打手订单状态为已完成。",
    ],
    [
        "丸掌柜同意验收是上游完成的关键动作。",
        "完成后普通履约动作不可继续。",
    ],
)


# ===================== 申诉 =====================
add(
    "订单已完结 申诉-上游发起",
    "丸掌柜视角-已完成状态发起申诉",
    "丸掌柜订单状态为已完成，且存在申诉入口。",
    [
        "登录丸掌柜账号。",
        "进入已完成订单详情。",
        "记录主单订单状态为已完成、子单状态为已完成。",
        "点击发起申诉。",
        "填写申诉原因、申诉金额和凭证。",
        "提交申诉。",
        *wzg_detail_steps(),
        *wyj_detail_steps("申诉处理入口"),
    ],
    [
        "丸掌柜主状态保持已完成。",
        "丸掌柜子状态为已完成-申诉中或页面对应申诉中。",
        "丸友集出现待处理申诉。",
        "订单不回退到普通履约状态。",
    ],
    [
        "申诉单号、金额、原因两端一致。",
        "申诉不应改变已完成主状态。",
    ],
)

add(
    "订单已完结 申诉-上游发起",
    "丸掌柜视角-已售后状态发起申诉",
    "丸掌柜订单状态为已售后，且允许发起售后后申诉。",
    [
        "登录丸掌柜账号。",
        "进入已售后订单详情。",
        "记录主单订单状态为已售后、子单状态为已售后。",
        "点击发起申诉。",
        "填写申诉原因、申诉金额和凭证。",
        "提交申诉。",
        *wzg_detail_steps(),
        *wyj_detail_steps("申诉处理入口"),
    ],
    [
        "丸掌柜主状态保持已售后。",
        "丸掌柜子状态为已售后-申诉中或页面对应申诉中。",
        "丸友集出现待处理申诉。",
        "订单不回退到售后中或普通履约状态。",
    ],
    [
        "已售后申诉不同于普通售后中。",
        "申诉单号、金额、原因两端一致。",
    ],
)

add(
    "订单已完结 申诉-上游发起",
    "丸友集确认赔偿后申诉完成",
    "丸掌柜已发起申诉，丸友集侧申诉待处理。",
    [
        "登录丸友集主账号或客服账号。",
        "进入申诉处理入口。",
        "查询目标申诉单。",
        "点击确认赔偿。",
        "填写赔偿金额和备注。",
        "提交处理结果。",
        *wyj_detail_steps("申诉处理入口"),
        *wzg_detail_steps(),
    ],
    [
        "丸友集申诉处理结果为确认赔偿或申诉完成。",
        "丸掌柜子状态为申诉完成或页面对应完成状态。",
        "生成对应金额记录。",
    ],
    [
        "赔偿金额、处理备注、申诉结果两端一致。",
        "订单主状态保持已完成或已售后终态。",
    ],
)

add(
    "订单已完结 申诉-上游发起",
    "丸友集驳回申诉",
    "丸掌柜已发起申诉，丸友集侧申诉待处理。",
    [
        "登录丸友集主账号或客服账号。",
        "进入申诉处理入口。",
        "查询目标申诉单。",
        "点击驳回申诉。",
        "填写驳回原因并提交。",
        *wyj_detail_steps("申诉处理入口"),
        *wzg_detail_steps(),
    ],
    [
        "丸友集申诉处理结果为已驳回。",
        "丸掌柜可见驳回原因。",
        "不生成赔偿金额。",
        "订单主状态保持已完成或已售后终态。",
    ],
    [
        "驳回原因两端一致。",
        "无错误资金流水。",
    ],
)


def main() -> None:
    flow_titles = [
        # 丸掌柜视角：发单前后，以及该阶段可立即发生的上游动作。
        "丸掌柜视角-主单待接单状态/子单待接单状态-创建主单未推单",
        "丸掌柜视角-主单待接单状态/子单待接单-已推单状态-推单到丸友集",
        "丸掌柜视角-主单待接单状态/子单待接单-待推单/已推单状态阶段发起售后",
        "丸掌柜视角-主单待接单状态/子单待接单-待推单/已推单状态阶段处理售后",
        "丸掌柜视角-主单待接单状态/子单待接单-待推单/已推单状态阶段取消售后",
        "丸掌柜视角-主单待接单状态/子单待接单-待推单/已推单状态阶段发起撤销",
        "丸掌柜视角-主单待接单状态/子单取消订单状态-继续发子单",
        # 丸友集视角：抢单大厅接单或拒绝。
        "丸友集待接单状态拒绝上游订单-供应链拒绝结束",
        "丸友集抢单大厅待接单阶段-丸友集确认接单",
        "丸友集已接单/未发单到打手抢单大厅阶段-丸友集申请撤销",
        "丸友集已接单/未发单到打手抢单大厅阶段-丸友集申请撤销-丸掌柜同意撤销",
        "丸友集已接单/未发单到打手抢单大厅阶段-丸友集申请撤销-丸掌柜拒绝撤销",
        "丸友集已接单/未发单到打手抢单大厅阶段&&丸掌柜主单服务中状态/子单代练中状态-丸掌柜发起售后",
        "丸友集已接单/未发单到打手抢单大厅阶段&&丸掌柜主单服务中状态/子单代练中状态-丸掌柜处理售后",
        "丸友集已接单/未发单到打手抢单大厅阶段&&丸掌柜主单服务中状态/子单代练中状态-丸掌柜取消售后",
        # 丸友集向下派单，打手接单或拒绝。
        "丸友集已接单/未发单到打手抢单大厅阶段-立即发单",
        "丸友集已发单到打手抢单大厅/打手未接单阶段-丸友集撤回发单",
        "丸友集已发单到打手抢单大厅/打手未接单阶段&&丸掌柜主单服务中状态/子单代练中状态-丸掌柜发起售后",
        "丸友集已发单到打手抢单大厅/打手未接单阶段&&丸掌柜主单服务中状态/子单代练中状态-丸掌柜处理售后",
        "丸友集已发单到打手抢单大厅/打手未接单阶段&&丸掌柜主单服务中状态/子单代练中状态-丸掌柜取消售后",
        "丸友集已发单到打手抢单大厅/打手未接单阶段-立即抢单",
        # 打手/丸友集撤销与取消分支。
        "打手代练中状态发起撤销-不穿透丸掌柜",
        "打手撤销中状态取消撤销-恢复代练中",
        "打手撤销中状态-丸友集拒绝撤销",
        "打手撤销中状态-丸友集同意撤销",
        "丸友集子单已撤销状态-二发新子单",
        "前一子单已撤销/已取消状态-续发下一子单",
        "丸友集申请上游撤销-丸掌柜进入异常中",
        "丸掌柜视角-主单异常中状态/子单代练中异常状态阶段发起售后",
        "丸掌柜视角-主单异常中状态/子单代练中异常状态阶段处理售后",
        "丸掌柜视角-主单异常中状态/子单代练中异常状态阶段取消售后",
        "打手代练中状态发起取消订单",
        "打手取消中状态-丸友集拒绝取消",
        "打手取消中状态-丸友集同意取消",
        # 验收主线：打手申请验收 -> 丸友集验收子单 -> 丸友集申请上游验收 -> 丸掌柜验收。
        "打手代练中状态申请验收-只到丸友集子单待验收",
        "打手待验收状态取消验收-恢复代练中",
        "丸友集子单待验收状态-拒绝验收子单",
        "丸友集子单待验收状态-同意验收子单",
        "前一子单已完成状态-续发下一子单",
        "丸友集父单代练中状态-申请上游验收",
        "丸掌柜视角-主单待验收状态/子单待验收状态阶段发起售后",
        "丸掌柜视角-主单待验收状态/子单待验收状态阶段处理售后",
        "丸掌柜视角-主单待验收状态/子单待验收状态阶段取消售后",
        "丸掌柜视角-主单待验收状态/子单待验收状态-同意验收完结主单",
        # 完成/售后后的申诉。
        "丸掌柜视角-已完成状态发起申诉",
        "丸掌柜视角-已售后状态发起申诉",
        "丸友集确认赔偿后申诉完成",
        "丸友集驳回申诉",
    ]
    by_title = {item["用例标题"]: item for item in CASES}
    ordered_cases = [by_title[title] for title in flow_titles if title in by_title]
    used_titles = {item["用例标题"] for item in ordered_cases}
    ordered_cases.extend(item for item in CASES if item["用例标题"] not in used_titles)
    for index, item in enumerate(ordered_cases, 1):
        item["用例编号"] = f"S-FLOW-{index:03d}"
        if index <= len(NORMALIZED_FLOW_TITLES):
            item["用例标题"] = NORMALIZED_FLOW_TITLES[index - 1]

    output = Path("scripts/order_status_flow_cases.json")
    output.write_text(json.dumps(ordered_cases, ensure_ascii=False, indent=2), encoding="utf-8")
    print(f"wrote {len(ordered_cases)} cases to {output}")


if __name__ == "__main__":
    main()
