from __future__ import annotations

import json
import sys
from pathlib import Path


ROOT = Path(__file__).resolve().parents[1]
WORKBOOK = ROOT / "SaaS_E2E测试用例_单Sheet用例测试列表.xlsx"
JSON_OUTPUT = ROOT / "runtime" / "testcase_excel_incremental_updates.json"


HEADERS = [
    "用例编号",
    "用例层级",
    "来源/组合依据",
    "所属模块",
    "用例标题",
    "登录平台/角色账号",
    "前置条件",
    "测试数据",
    "执行步骤",
    "预期结果",
    "跨端/状态断言",
    "可组合/被引用关系",
    "自动化状态",
    "备注",
]


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


def case_row(
    case_id: str,
    level: str,
    source: str,
    module: str,
    title: str,
    login: str,
    precondition: str,
    data: str,
    action_steps: list[str],
    expected: str,
    assertion: str,
    relation: str,
    status: str = "待自动化",
    remark: str = "",
) -> list[str]:
    return [
        case_id,
        level,
        source,
        module,
        title,
        login,
        precondition,
        data,
        steps(action_steps),
        expected,
        assertion,
        relation,
        status,
        remark,
    ]


UPDATES = {
    "B-MULTI-001": case_row(
        "B-MULTI-001",
        "分支小用例",
        "页面只读探测：丸友集已接单行存在立即发单；已完成行未见立即发单；原“一主两子一次发出”假设废弃",
        "主子单",
        "一主单续建子单条件校验",
        "丸掌柜：企业主账号；丸友集：工作室主账号；打手应用：打手子账号（按子单状态切换）。",
        "丸掌柜已创建主单并已派给丸友集；丸友集主账号可在工作室履约应用-订单列表查看该主单。",
        "来源单号、订单标题、当前子单状态=已接单/代练中/待验收/已完成/已取消或已撤销。",
        [
            "登录丸掌柜主账号，进入丸掌柜-商家管理-订单管理。",
            "按来源单号或订单标题搜索目标主单。",
            "查看主单行的订单状态、子单状态和操作区，确认不存在“一次创建两个子单/批量创建子单”的入口。",
            "登录丸友集主账号，进入丸友集-工作室履约应用-订单列表。",
            "按来源单号或订单标题搜索同一订单。",
            "在当前子单状态为已接单且打手接单价为0、代练费支出总和为0时，查看是否存在立即发单。",
            "点击立即发单但不提交，检查弹框是否为创建当前子单/选择分配方式，而不是一次发多个子单。",
            "关闭弹框，切换或准备子单状态为代练中、待验收、已完成、已取消/已撤销的订单分别查询。",
            "逐一记录各状态下是否出现立即发单或再次创建子单入口。",
            "如出现再次发单入口，继续验证前一子单必须处于已完成、已取消、已撤销或其他终态后才能创建下一子单。",
        ],
        "页面不支持一主单两子单一次发出；再次创建子单必须基于前一子单状态满足页面限制，具体允许终态以页面按钮出现为准。",
        "丸掌柜订单管理、丸友集订单列表的主单号/来源单号一致；同一时间只允许一个有效履约子单推进；非终态子单存在时不应允许再次创建有效子单。",
        "替代原一主两子一次发出用例；被F-MULTI-001引用",
        "待自动化",
        "已按用户反馈纠正：不再设计“一次发两子单”。已完成/已撤销等终态是否允许续建需继续用真实订单验证。",
    ),
    "F-MULTI-001": case_row(
        "F-MULTI-001",
        "组合流程用例",
        "B-MULTI-001 -> A-TASK-001 -> A-DELIVERY-001/002 -> B-MULTI-002",
        "多子单流程",
        "一主单按子单终态续建下一子单",
        "丸掌柜：企业主账号；丸友集：工作室主账号；打手应用：打手子账号。",
        "一主单已存在第一笔子单；第一笔子单已完成、已取消、已撤销或其他页面允许的终态。",
        "来源单号、订单标题、第一子单编号、第二子单发单信息、分配方式、打手账号。",
        [
            "先执行用例B-MULTI-001，确认当前主单不存在一次发多个子单入口，并确认续建子单的允许状态。",
            "执行第一子单流程：丸友集立即发单，打手接单，打手提交验收，丸友集审核或撤销至页面允许的终态。",
            "登录丸友集主账号，进入丸友集-工作室履约应用-订单列表。",
            "搜索同一来源单号，确认第一子单已处于允许续建的终态。",
            "点击立即发单或页面展示的再次发单入口。",
            "填写第二子单的分配方式、发单价、服务时限、订单要求等字段。",
            "确认发单。",
            "登录打手账号，进入打手应用-抢单大厅或我的订单。",
            "确认第二子单出现并可按正常流程履约。",
            "回到丸掌柜-商家管理-订单管理，确认主单下子单计数和状态聚合正确。",
        ],
        "一主单多子单只能按顺序续建；前一有效子单未到允许终态时不能创建下一子单。",
        "第一子单和第二子单的子单号、状态、金额、打手信息相互独立；主单状态按所有子单状态聚合。",
        "组合举证：第一子单终态 -> 续建第二子单 -> 第二子单履约",
        "待自动化",
        "替代原“一主两子一次发出并分别履约”。",
    ),
}


NEW_ROWS = [
    case_row(
        "A-DELIVERY-002A",
        "脚本引申原子用例",
        "test_e2e_delivery_002_upstream_acceptance_settlement.py：apply_upstream_acceptance 内部先 approve_sub_order_acceptance",
        "1级-2级验收",
        "丸友集验收打手子单并校验打手收入",
        "丸友集：工作室主账号；打手应用：打手子账号。",
        "打手已完成子单并提交验收；丸友集工作室订单列表中该子单处于待验收；打手账号可登录。",
        "来源单号、订单标题、子单号、打手账号、预期打手收入金额。",
        [
            "先执行用例A-DELIVERY-001，打手在打手应用-我的订单提交验收。",
            "登录丸友集主账号。",
            "进入丸友集-工作室履约应用-订单列表。",
            "按来源单号或订单标题搜索订单。",
            "确认订单行或子单行状态为待验收。",
            "点击操作，打开子单列表或子单详情。",
            "在子单操作区点击同意验收。",
            "在确认弹窗中确认同意验收。",
            "关闭子单弹窗并刷新订单列表。",
            "确认子单状态变为已完成或进入可申请上游验收状态。",
            "登录打手子账号。",
            "进入打手应用-我的收入。",
            "按来源单号或订单标题搜索收入记录。",
            "核对收入金额、订单标题、打手账号和收入状态。",
        ],
        "1级-2级验收完成：丸友集同意验收后，打手侧应产生或更新该子单收入记录。",
        "丸友集订单列表子单状态、打手我的收入、来源单号、订单标题、收入金额一致；该用例不要求丸掌柜验收主单。",
        "由A-DELIVERY-002拆分；被F-ACCEPTANCE-L1L2-001、F-MAIN-001引用",
        "待自动化",
        "用户要求拆分 DELIVERY-002：先独立覆盖1级打手到2级丸友集。",
    ),
    case_row(
        "A-DELIVERY-002B",
        "脚本引申原子用例",
        "test_e2e_delivery_002_upstream_acceptance_settlement.py：complete_upstream_order + verify_player_income_for_order",
        "2级-3级验收",
        "丸掌柜验收主单成功并复核打手收入",
        "丸友集：工作室主账号；丸掌柜：企业主账号；打手应用：打手子账号。",
        "丸友集已完成子单验收；丸友集已申请上游验收或订单处于等待上游验收；丸掌柜账号可登录。",
        "来源单号、订单标题、子单号、丸掌柜账号、丸友集账号、打手账号、预期打手收入金额。",
        [
            "先执行用例A-DELIVERY-002A，完成丸友集对子单的同意验收和打手收入初步校验。",
            "登录丸友集主账号。",
            "进入丸友集-工作室履约应用-订单列表。",
            "按来源单号或订单标题搜索订单。",
            "点击申请上游验收。",
            "按页面要求填写验收说明、上传验收材料或确认已有材料。",
            "提交上游验收申请。",
            "登录丸掌柜主账号。",
            "进入丸掌柜-商家管理-订单管理。",
            "按来源单号或订单标题搜索订单。",
            "点击确认验收/验收通过/完结主单。",
            "在弹窗中确认验收通过。",
            "如页面提示存在未完成子单，返回丸友集侧补齐子单验收后再重试。",
            "登录丸友集主账号，进入工作室履约应用-订单列表，确认订单状态为已完成/待结算或页面完成态。",
            "登录打手子账号，进入打手应用-我的收入，再次核对该订单收入记录。",
        ],
        "2级-3级验收完成：丸掌柜验收通过后，主单进入完成态；打手收入记录仍存在且金额不被错误变更。",
        "丸掌柜订单管理、丸友集订单列表、打手我的收入三端来源单号/订单标题/状态/金额一致。",
        "由A-DELIVERY-002拆分；被F-ACCEPTANCE-L2L3-001、F-MAIN-001、F-SETTLE-L2L3-001引用",
        "待自动化",
        "用户要求拆分 DELIVERY-002：再独立覆盖2级丸友集到3级丸掌柜。",
    ),
    case_row(
        "F-ACCEPTANCE-L1L2-001",
        "组合流程用例",
        "A-TASK-001 -> A-DELIVERY-001 -> A-DELIVERY-002A",
        "1级-2级验收流程",
        "打手完成子单后丸友集验收并校验打手收入",
        "丸友集：工作室主账号；打手应用：打手子账号。",
        "丸友集已接外部订单并发给打手；打手已接单。",
        "来源单号、订单标题、子单号、打手账号、预期收入金额。",
        [
            "执行用例A-TASK-001，丸友集接外部订单并发给打手。",
            "执行用例A-DELIVERY-001，打手完成子单并提交验收。",
            "执行用例A-DELIVERY-002A，丸友集同意验收子单。",
            "进入打手应用-我的收入。",
            "按来源单号或订单标题搜索收入记录。",
            "核对收入金额和状态。",
        ],
        "打手到丸友集的1级-2级验收闭环完成，打手收入可被校验。",
        "该流程不依赖丸掌柜验收主单；只验证打手子单、丸友集验收和打手收入。",
        "新拆分组合流程",
        "待自动化",
        "从 DELIVERY-002 大流程拆出。",
    ),
    case_row(
        "F-ACCEPTANCE-L2L3-001",
        "组合流程用例",
        "A-DELIVERY-002A -> A-DELIVERY-002B",
        "2级-3级验收流程",
        "丸友集申请上游验收后丸掌柜验收并复核打手收入",
        "丸友集：工作室主账号；丸掌柜：企业主账号；打手应用：打手子账号。",
        "1级-2级验收已完成；丸友集可申请上游验收；丸掌柜可验收主单。",
        "来源单号、订单标题、主单号、子单号、打手账号、预期收入金额。",
        [
            "先执行用例A-DELIVERY-002A，确认丸友集已同意验收打手子单。",
            "执行用例A-DELIVERY-002B，丸友集申请上游验收并由丸掌柜验收通过。",
            "进入丸掌柜-商家管理-订单管理，确认主单状态为已完成或页面完成态。",
            "进入丸友集-工作室履约应用-订单列表，确认订单状态为已完成/待结算或页面完成态。",
            "进入打手应用-我的收入，复核收入记录仍正确。",
        ],
        "丸友集到丸掌柜的2级-3级验收闭环完成，主单完成且打手收入记录不丢失、不误改。",
        "丸掌柜主单状态、丸友集订单状态、打手收入金额三端一致。",
        "新拆分组合流程",
        "待自动化",
        "从 DELIVERY-002 大流程拆出。",
    ),
    case_row(
        "B-WZG-AFTER-ACCEPT-001",
        "分支小用例",
        "A-DELIVERY-002B之后的丸掌柜验收后置分支",
        "丸掌柜验收后分支",
        "丸掌柜验收第1单子单后处罚第1单",
        "丸掌柜：企业主账号或处罚权限账号；丸友集：工作室主账号；打手应用：打手子账号。",
        "第1单子单已由丸友集验收，并已由丸掌柜验收通过；订单处于已完成或可处罚追缴状态。",
        "来源单号、订单标题、第1子单号、处罚对象、处罚金额、处罚原因、举证材料。",
        [
            "先执行用例A-DELIVERY-002B，完成丸掌柜对第1单子单/主单的验收。",
            "登录丸掌柜主账号。",
            "进入丸掌柜-商家管理-订单管理。",
            "按来源单号或订单标题搜索订单。",
            "打开订单操作区或子单详情。",
            "选择第1单子单对应的处罚/追缴/发起申诉/处罚追缴入口。",
            "填写处罚对象、处罚原因、处罚金额和说明。",
            "按页面要求上传或关联举证材料。",
            "提交处罚申请。",
            "进入处罚记录/操作日志查看处理结果。",
            "登录丸友集主账号，进入工作室履约应用-订单列表，确认处罚状态同步。",
            "登录打手账号，进入打手应用-我的收入或账单记录，确认收入/结算金额按处罚规则调整。",
        ],
        "丸掌柜验收第1单后可对第1单发起处罚追缴；处罚记录可追溯，金额影响同步到相关结算或收入。",
        "丸掌柜处罚记录、丸友集订单记录、打手收入/账单金额一致；处罚不能误影响其他子单。",
        "被F-WZG-AFTER-ACCEPT-BRANCH-001引用",
        "待自动化",
        "处罚入口和审批/生效规则需继续按页面确认。",
    ),
    case_row(
        "B-WZG-AFTER-ACCEPT-002",
        "分支小用例",
        "A-DELIVERY-002B + B-MULTI-002",
        "丸掌柜验收后分支",
        "丸掌柜验收第1单后继续发第2单",
        "丸掌柜：企业主账号；丸友集：工作室主账号；打手应用：打手子账号。",
        "第1单子单已由丸掌柜验收通过；主单未被最终关闭，页面允许继续发第2单或丸友集侧允许续建下一子单。",
        "来源单号、订单标题、第1子单号、第2子单发单价、第2子单分配方式、打手账号。",
        [
            "先执行用例A-DELIVERY-002B，完成丸掌柜对第1单的验收。",
            "登录丸友集主账号。",
            "进入丸友集-工作室履约应用-订单列表。",
            "按来源单号或订单标题搜索同一主单。",
            "确认第1单子单已进入已完成或页面允许续发的终态。",
            "查看是否出现立即发单/再次发单入口。",
            "点击立即发单或再次发单入口。",
            "填写第2单子单的分配方式、发单价、服务时限和订单要求。",
            "确认发单。",
            "登录打手账号，进入打手应用-抢单大厅或我的订单，确认第2单可见。",
            "登录丸掌柜主账号，进入丸掌柜-商家管理-订单管理，确认同一主单下子单计数更新。",
        ],
        "丸掌柜验收第1单后，如主单未最终关闭且页面允许，可继续发第2单；第2单作为新子单独立履约。",
        "第1单和第2单的子单状态、金额、打手信息独立；主单聚合状态正确。",
        "被F-WZG-AFTER-ACCEPT-BRANCH-001、F-MULTI-001引用",
        "待自动化",
        "如果丸掌柜一键验收并完成主单后不允许续发，则该分支应以前置条件区分。",
    ),
    case_row(
        "B-WZG-AFTER-ACCEPT-003",
        "分支小用例",
        "A-DELIVERY-002B之后的丸掌柜验收后置分支",
        "丸掌柜验收后分支",
        "丸掌柜验收第1单子单后发起售后",
        "丸掌柜：企业主账号或售后权限账号；丸友集：工作室主账号；打手应用：打手子账号（如需举证）。",
        "第1单子单已由丸掌柜验收通过；订单操作区存在主单售后/发起售后/创建工单等入口。",
        "来源单号、订单标题、第1子单号、售后类型、售后原因、退款/扣款金额、举证材料。",
        [
            "先执行用例A-DELIVERY-002B，完成丸掌柜对第1单的验收。",
            "登录丸掌柜主账号。",
            "进入丸掌柜-商家管理-订单管理。",
            "按来源单号或订单标题搜索订单。",
            "点击主单售后/发起售后/创建工单入口。",
            "选择售后类型。",
            "填写售后原因、金额影响和备注说明。",
            "上传或关联售后举证材料。",
            "提交售后申请。",
            "刷新订单列表，确认订单状态进入售后中或页面实际售后状态。",
            "登录丸友集主账号，进入工作室履约应用-订单列表，确认售后状态同步。",
            "如售后影响打手收入，登录打手账号进入我的收入核对金额或冻结状态。",
        ],
        "丸掌柜验收第1单后仍可发起售后；订单进入售后分支，后续结算/处罚/追缴按售后结果处理。",
        "丸掌柜售后记录、丸友集订单状态、打手收入影响一致；售后不应误关闭其他未处理子单。",
        "被F-WZG-AFTER-ACCEPT-BRANCH-001引用",
        "待自动化",
        "售后状态、退款/扣款规则需结合页面继续细化。",
    ),
    case_row(
        "B-WZG-AFTER-ACCEPT-004",
        "分支小用例",
        "A-DELIVERY-002B之后的丸掌柜验收后置分支",
        "丸掌柜验收后分支",
        "丸掌柜一键验收并完成主单",
        "丸掌柜：企业主账号；丸友集：工作室主账号；打手应用：打手子账号。",
        "第1单子单已由丸友集验收并申请上游验收；不存在未完成/未验收的其他有效子单。",
        "来源单号、订单标题、主单号、第1子单号、验收说明。",
        [
            "先执行用例A-DELIVERY-002A，丸友集验收打手子单。",
            "登录丸友集主账号，进入丸友集-工作室履约应用-订单列表。",
            "按来源单号或订单标题搜索订单。",
            "点击申请上游验收并提交材料。",
            "登录丸掌柜主账号。",
            "进入丸掌柜-商家管理-订单管理。",
            "按来源单号或订单标题搜索订单。",
            "点击一键验收/确认验收/验收通过/完结主单。",
            "在弹窗中填写验收说明并确认。",
            "刷新订单列表，确认主单状态为已完成，完成时间有值。",
            "登录丸友集主账号，确认工作室订单状态为已完成/待结算或页面完成态。",
            "登录打手账号，进入打手应用-我的收入，确认收入记录仍正确。",
        ],
        "在不存在未完成有效子单时，丸掌柜可一键验收并完成主单。",
        "丸掌柜主单已完成、丸友集订单完成态、打手收入记录三端一致；若存在未完成子单，应提示不可完结主单。",
        "被F-WZG-AFTER-ACCEPT-BRANCH-001、F-ACCEPTANCE-L2L3-001引用",
        "待自动化",
        "对应当前自动化里的complete_upstream_order和未完成子单拦截。",
    ),
    case_row(
        "F-WZG-AFTER-ACCEPT-BRANCH-001",
        "组合流程用例",
        "A-DELIVERY-002A -> A-DELIVERY-002B -> B-WZG-AFTER-ACCEPT-001/002/003/004",
        "丸掌柜验收后分支流程",
        "丸掌柜验收第1单后的四类后置分支",
        "丸掌柜：企业主账号；丸友集：工作室主账号；打手应用：打手子账号。",
        "第1单子单已完成1级-2级验收；丸友集已申请上游验收；丸掌柜可处理验收。",
        "来源单号、订单标题、第1子单号、处罚/售后/续发/完结所需数据。",
        [
            "先执行用例A-DELIVERY-002A，完成丸友集验收子单。",
            "先执行用例A-DELIVERY-002B，完成丸掌柜验收第1单。",
            "分支一：执行B-WZG-AFTER-ACCEPT-001，丸掌柜验收后处罚第1单。",
            "分支二：执行B-WZG-AFTER-ACCEPT-002，丸掌柜验收后继续发第2单。",
            "分支三：执行B-WZG-AFTER-ACCEPT-003，丸掌柜验收后发起售后。",
            "分支四：执行B-WZG-AFTER-ACCEPT-004，丸掌柜一键验收并完成主单。",
            "分别回到丸掌柜订单管理、丸友集订单列表、打手收入页面核对状态和金额影响。",
        ],
        "丸掌柜验收第1单后不是单一路径，需分别覆盖处罚、续发第2单、售后、一键验收完成主单四类后置分支。",
        "四类分支互斥条件、入口按钮、状态流转和金额影响清晰；不能把完成主单后的场景误用于可续发场景。",
        "验收后组合分支",
        "待自动化",
        "用户新增分支要求。",
    ),
    case_row(
        "B-MULTI-002",
        "分支小用例",
        "页面规则待验证：前一子单终态后续建下一子单",
        "主子单",
        "前一子单完成后续建下一子单",
        "丸友集：工作室主账号；丸掌柜：企业主账号；打手应用：打手子账号。",
        "第一子单已完成，丸友集订单列表可查看同一主单。",
        "来源单号、订单标题、第一子单编号、第二子单发单价、第二子单分配方式。",
        [
            "登录丸友集主账号。",
            "进入丸友集-工作室履约应用-订单列表。",
            "按来源单号搜索主单。",
            "确认第一子单状态为已完成。",
            "查看订单行是否出现立即发单/再次发单入口。",
            "点击入口进入发单弹框。",
            "填写第二子单的分配方式、发单价、服务时限和订单要求。",
            "提交发单。",
            "进入打手应用-抢单大厅或我的订单，确认第二子单可见。",
            "回到丸掌柜-商家管理-订单管理，确认主单子单计数更新。",
        ],
        "第一子单已完成后，如页面允许，应能续建第二子单；如页面不允许，应给出明确限制提示。",
        "主单号一致；两个子单状态、金额、打手信息独立；不会把第二子单覆盖到第一子单。",
        "被F-MULTI-001引用",
        "待自动化",
        "允许状态需继续查验：已完成是重点候选。",
    ),
    case_row(
        "B-MULTI-003",
        "分支小用例",
        "页面规则待验证：前一子单撤销/取消后续建下一子单",
        "主子单",
        "前一子单撤销或取消后续建下一子单",
        "丸友集：工作室主账号；丸掌柜：企业主账号；审批账号：按撤销审批流配置。",
        "第一子单已发起撤销并审批通过，状态进入已取消/已撤销或页面展示的终态。",
        "来源单号、订单标题、撤销原因、审批意见、第二子单发单信息。",
        [
            "登录丸友集主账号，进入丸友集-工作室履约应用-订单列表。",
            "搜索目标订单。",
            "对第一子单点击申请撤销。",
            "填写撤销原因并提交。",
            "使用审批角色登录对应审批入口。",
            "查询撤销申请并审核通过。",
            "回到丸友集订单列表，确认第一子单进入已取消/已撤销或页面终态。",
            "查看是否出现立即发单/再次发单入口。",
            "如入口出现，创建第二子单并提交发单。",
            "登录丸掌柜主账号，进入丸掌柜-商家管理-订单管理，确认主单子单状态聚合正确。",
        ],
        "子单撤销必须经过审批；审批通过并进入终态后，才允许按页面规则续建下一子单。",
        "撤销申请、审批记录、子单终态、再次发单入口、主单状态在丸友集和丸掌柜侧一致。",
        "被F-MULTI-001、F-CANCEL-APPROVAL-001引用",
        "待自动化",
        "允许状态需继续查验：已取消/已撤销是重点候选。",
    ),
    case_row(
        "B-CANCEL-APPROVAL-001",
        "分支小用例",
        "页面只读探测：丸友集已接单行存在申请撤销",
        "撤销审批",
        "丸友集已接单未发给打手时申请撤销并审批",
        "丸友集：工作室主账号；丸掌柜：企业主账号或审批账号。",
        "丸友集已在抢单大厅确认接单，订单进入工作室履约应用-订单列表；尚未发给打手。",
        "来源单号、订单标题、撤销原因、审批意见。",
        [
            "登录丸友集主账号。",
            "进入丸友集-工作室履约应用-订单列表。",
            "按来源单号搜索订单。",
            "确认订单行状态为已接单，且操作区存在申请撤销。",
            "点击申请撤销。",
            "填写撤销原因并提交。",
            "登录丸掌柜主账号或撤销审批账号。",
            "进入对应撤销审批/订单管理待处理入口。",
            "搜索该来源单号。",
            "审核通过撤销申请。",
            "回到丸友集订单列表和丸掌柜订单管理，确认订单不可继续发给打手。",
        ],
        "子单/外部订单撤销不是直接完成，必须先提交申请并经审批通过。",
        "申请记录、审批状态、订单状态、下游可操作按钮一致；审批前不应直接消失或完成撤销。",
        "补充分支：撤销审批",
        "待自动化",
        "审批入口需继续探测精确菜单。",
    ),
    case_row(
        "B-CANCEL-APPROVAL-002",
        "分支小用例",
        "用户规则补充：子单每个节点撤销均需审批",
        "撤销审批",
        "已发给打手后申请撤销并审批",
        "丸友集：工作室主账号；打手应用：打手子账号；丸掌柜：企业主账号或审批账号。",
        "子单已发给打手，状态为待接单、代练中或待验收。",
        "来源单号、订单标题、子单号、打手账号、撤销原因、审批意见。",
        [
            "登录丸友集主账号。",
            "进入丸友集-工作室履约应用-订单列表。",
            "搜索目标订单并打开操作/子单详情。",
            "在子单操作区点击申请撤销或撤销相关入口。",
            "填写撤销原因并提交。",
            "登录审批账号。",
            "进入撤销审批/订单待处理入口。",
            "按来源单号或子单号搜索撤销申请。",
            "审核通过。",
            "登录打手账号，进入打手应用-我的订单，确认该子单不可继续履约或状态已同步。",
            "登录丸掌柜主账号，进入订单管理确认子单状态同步。",
        ],
        "待接单、代练中、待验收等节点的撤销均走申请和审批，不应无审批直接撤销。",
        "丸友集、打手应用、丸掌柜三端状态一致；审批记录可追溯。",
        "补充分支：撤销审批",
        "待自动化",
        "需要按状态分别细化为待接单撤销、代练中撤销、待验收撤销。",
    ),
    case_row(
        "B-SETTLE-WYJ-APPLY-001",
        "分支小用例",
        "页面只读探测：结算账单-丸友集说明文案和状态栏",
        "丸掌柜给丸友集结算",
        "丸友集工作室发起全部结算申请",
        "丸友集：工作室主账号。",
        "丸友集存在已完成且可结算的外部订单；工作室打款账户信息已完善或可进入完善入口。",
        "发单商户、业务单号、申请金额合计、实际结算金额、申请/批次号。",
        [
            "登录丸友集主账号。",
            "进入丸友集-结算中心-结算明细-丸友集。",
            "筛选结算状态为待确认打款信息或待结算的明细。",
            "勾选或选择需要向发单商户结算的全部订单明细。",
            "发起全部结算申请。",
            "进入丸友集-结算中心-结算账单-丸友集。",
            "查看新生成的申请/批次号。",
            "核对申请金额合计、实际结算金额、手续费和发单商户。",
        ],
        "丸友集工作室可基于已完成订单发起面向发单商户的结算申请，并生成结算账单。",
        "结算明细与结算账单金额、业务单号、发单商户一致；账单状态进入待确认打款信息或页面实际初始状态。",
        "被F-SETTLE-L2L3-001引用",
        "待自动化",
        "页面说明：查看由本工作室发起的全部结算申请及当前进度。",
    ),
    case_row(
        "B-SETTLE-WYJ-CONFIRM-PAYINFO-001",
        "分支小用例",
        "页面只读探测：结算账单-丸友集存在待确认打款信息和确认打款信息按钮",
        "丸掌柜给丸友集结算",
        "丸友集确认打款信息",
        "丸友集：工作室主账号。",
        "结算账单-丸友集中存在状态=待确认打款信息的账单；页面存在确认打款信息操作。",
        "申请/批次号、发单商户、打款账户信息、申请金额合计、实际结算金额。",
        [
            "登录丸友集主账号。",
            "进入丸友集-结算中心-结算账单-丸友集。",
            "在查询栏选择账单状态为待确认打款信息。",
            "搜索目标申请/批次号。",
            "点击确认打款信息。",
            "核对打款账户信息、发单商户、申请金额合计、实际结算金额。",
            "确认提交打款信息。",
            "返回结算账单列表。",
            "确认账单状态流转到等待发单商户打款或页面实际下一状态。",
        ],
        "每笔结算申请都需要丸友集确认打款信息，确认后才能等待发单商户打款。",
        "确认前后状态变化、打款账户信息、操作日志一致。",
        "被F-SETTLE-L2L3-001引用",
        "待自动化",
        "当前探测样本状态=待确认打款信息，操作=确认打款信息/操作日志。",
    ),
    case_row(
        "B-SETTLE-WYJ-CONFIRM-MERCHANT-PAY-001",
        "分支小用例",
        "页面说明文案：发单商户打款后结算单进入待工作室确认",
        "丸掌柜给丸友集结算",
        "发单商户打款后丸友集确认收款",
        "丸掌柜：企业主账号；丸友集：工作室主账号。",
        "丸友集已确认打款信息；丸掌柜或发单商户已完成打款；结算单进入待工作室确认。",
        "申请/批次号、打款时间、实际结算金额、打款流水、确认意见。",
        [
            "登录丸掌柜主账号。",
            "进入丸掌柜侧结算中心或给工作室打款入口。",
            "搜索丸友集发起的申请/批次号。",
            "完成审核和打款。",
            "登录丸友集主账号。",
            "进入丸友集-结算中心-结算账单-丸友集。",
            "筛选状态为待工作室确认或页面实际待确认状态。",
            "搜索同一申请/批次号。",
            "核对打款金额、打款时间、打款方式。",
            "点击确认收款/确认商户打款。",
            "进入结算明细-丸友集，确认相关订单结算状态变为已结算。",
        ],
        "发单商户打款后，丸友集必须确认收款；确认后订单结算表状态变为已结算。",
        "丸掌柜打款记录、丸友集结算账单、结算明细状态和金额一致。",
        "被F-SETTLE-L2L3-001引用",
        "待自动化",
        "页面文案明确：发单商户打款后进入待工作室确认，工作室确认后订单结算表状态变为已结算。",
    ),
    case_row(
        "B-SETTLE-WYJ-EMP-BILL-INIT-001",
        "分支小用例",
        "用户补充：丸友集主账号可在员工结算汇总-账单待发起发起打手结算账单",
        "丸友集给打手结算",
        "丸友集主账号从员工结算汇总发起打手账单",
        "丸友集：工作室主账号；打手应用：打手子账号（用于结果核对）。",
        "丸友集已验收打手子单；打手收入已生成；该收入尚未由打手在我的收入中一键结算。",
        "来源单号、订单标题、子单号、打手账号、员工结算汇总金额、账单号。",
        [
            "先执行用例A-DELIVERY-002A，丸友集验收打手子单并校验打手收入。",
            "登录丸友集主账号。",
            "进入丸友集-工作室基础应用-员工结算汇总。",
            "切换到或筛选账单待发起。",
            "按打手账号、来源单号、订单标题或结算周期搜索目标记录。",
            "核对打手、订单、收入金额、可结算金额。",
            "勾选目标记录。",
            "点击发起账单/生成账单。",
            "确认账单范围、金额和打款对象。",
            "提交发起账单。",
            "进入丸友集-工作室基础应用-结算账单列表。",
            "搜索新生成账单，确认状态进入待审核/待打款或页面实际待处理状态。",
            "登录打手账号，进入打手应用-我的收入，确认该收入已关联结算申请或状态已同步。",
        ],
        "丸友集主账号可从员工结算汇总的账单待发起入口，为打手收入发起结算账单。",
        "员工结算汇总记录、结算账单列表、打手我的收入三处金额和状态一致；不能与打手一键结算重复生成账单。",
        "被F-SETTLE-L1L2-001引用",
        "待自动化",
        "这是打手账单发起入口的第二条分支：丸友集主账号代发起/后台发起。",
    ),
    case_row(
        "B-WYJ-SELF-FULFILL-001",
        "分支小用例",
        "用户补充：丸友集接单后可由丸友集主账号名义完成订单并申请上游验收",
        "丸友集自履约",
        "丸友集主账号立即发单后自行完成订单",
        "丸友集：工作室主账号；丸掌柜：企业主账号。",
        "丸掌柜已将外来订单派给丸友集；丸友集主账号已在抢单大厅确认接单，订单进入工作室履约应用-订单列表。",
        "来源单号、订单标题、主单号、子单号、丸友集工作室、订单金额、交付说明/验收材料。",
        [
            "登录丸友集主账号。",
            "进入丸友集-工作室履约应用-抢单大厅。",
            "按来源单号或订单标题搜索丸掌柜派来的外部订单。",
            "点击确认接单/立即接单。",
            "进入丸友集-工作室履约应用-订单列表。",
            "按来源单号或订单标题搜索已接订单。",
            "点击立即发单。",
            "在发单弹框中选择或确认以工作室/丸友集主账号名义履约的方式。",
            "填写发单价、服务时限、交付要求等必填字段。",
            "确认发单。",
            "回到订单列表，打开该订单操作或子单详情。",
            "以丸友集主账号名义完成订单，填写交付说明并上传或确认验收材料。",
            "确认订单/子单进入待上游验收或可申请上游验收状态。",
            "点击申请上游验收，提交给丸掌柜。",
        ],
        "丸友集可在接到丸掌柜订单后，以工作室/主账号名义完成订单并申请上游验收；该分支不产生打手接单、打手我的订单、打手收入。",
        "丸掌柜订单管理、丸友集订单列表的来源单号/订单标题/金额一致；打手应用不应出现该订单收入或待履约记录。",
        "被F-WYJ-SELF-FULFILL-L2L3-001引用",
        "待自动化",
        "该分支后续只进入2级-3级结算，不进入1级-2级打手结算。",
    ),
    case_row(
        "F-WYJ-SELF-FULFILL-L2L3-001",
        "组合流程用例",
        "A-ORDER-001 -> B-WYJ-SELF-FULFILL-001 -> A-DELIVERY-002B去除打手复核 -> B-SETTLE-WYJ-APPLY-001 -> B-SETTLE-WYJ-CONFIRM-PAYINFO-001 -> B-SETTLE-WZG-TO-WYJ-PAY-001 -> B-SETTLE-WYJ-CONFIRM-MERCHANT-PAY-001",
        "丸友集自履约2级-3级流程",
        "丸友集自行完成订单后申请上游验收并进入2级-3级结算",
        "丸友集：工作室主账号；丸掌柜：企业主账号。",
        "丸友集已接到丸掌柜外部订单；本分支不使用打手账号。",
        "来源单号、订单标题、主单号、子单号、丸友集工作室、申请/批次号、结算金额。",
        [
            "执行用例A-ORDER-001，丸掌柜创建外来订单并派给丸友集。",
            "执行用例B-WYJ-SELF-FULFILL-001，丸友集主账号接单、立即发单、自行完成订单并申请上游验收。",
            "登录丸掌柜主账号。",
            "进入丸掌柜-商家管理-订单管理。",
            "按来源单号或订单标题搜索订单。",
            "执行丸掌柜验收通过/完结主单。",
            "登录丸友集主账号。",
            "进入丸友集-结算中心-结算明细-丸友集，确认该订单产生2级-3级可结算明细。",
            "执行用例B-SETTLE-WYJ-APPLY-001，丸友集发起全部结算申请。",
            "执行用例B-SETTLE-WYJ-CONFIRM-PAYINFO-001，丸友集确认打款信息。",
            "执行用例B-SETTLE-WZG-TO-WYJ-PAY-001，丸掌柜给丸友集打款。",
            "执行用例B-SETTLE-WYJ-CONFIRM-MERCHANT-PAY-001，丸友集确认收款。",
            "确认该流程没有打手收入、打手一键结算、员工结算汇总中的打手账单。",
        ],
        "丸友集自履约分支只形成丸友集与丸掌柜之间的2级-3级验收和结算，不涉及打手结算。",
        "丸掌柜验收状态、丸友集结算明细、结算账单、收款确认一致；打手侧无订单和收入记录。",
        "自履约组合分支",
        "待自动化",
        "用户新增分支：丸友集主账号名义完成订单。",
    ),
]


FLOW_UPDATE = case_row(
    "F-SETTLE-L2L3-001",
    "组合流程用例",
    "A-ORDER-001 -> A-TASK-001 -> A-DELIVERY-001 -> A-DELIVERY-002A -> A-DELIVERY-002B -> B-SETTLE-WYJ-APPLY-001 -> B-SETTLE-WYJ-CONFIRM-PAYINFO-001 -> B-SETTLE-WZG-TO-WYJ-PAY-001 -> B-SETTLE-WYJ-CONFIRM-MERCHANT-PAY-001",
    "2级-3级结算流程",
    "丸友集发起结算申请，丸掌柜打款，丸友集确认收款",
    "丸友集：工作室主账号；丸掌柜：企业主账号。",
    "打手已完成子单；丸友集已申请上游验收；丸掌柜验收通过；丸友集存在可结算明细。",
    "来源单号、订单标题、业务单号、申请/批次号、申请金额合计、实际结算金额、打款账户信息。",
    [
        "先执行用例A-ORDER-001，丸掌柜创建外来订单并派到丸友集。",
        "先执行用例A-TASK-001，丸友集接外部订单并发给打手。",
        "先执行用例A-DELIVERY-001，打手完成子单并提交验收。",
        "先执行用例A-DELIVERY-002A，丸友集验收打手子单并校验打手收入。",
        "先执行用例A-DELIVERY-002B，丸友集申请上游验收，丸掌柜验收通过，并复核打手收入。",
        "执行用例B-SETTLE-WYJ-APPLY-001，丸友集在结算中心发起全部结算申请。",
        "执行用例B-SETTLE-WYJ-CONFIRM-PAYINFO-001，丸友集确认打款信息。",
        "执行用例B-SETTLE-WZG-TO-WYJ-PAY-001，丸掌柜对丸友集结算账单审核并打款。",
        "执行用例B-SETTLE-WYJ-CONFIRM-MERCHANT-PAY-001，丸友集确认收到发单商户打款。",
        "进入丸友集-结算中心-结算明细-丸友集，确认订单结算状态变为已结算。",
        "回到丸掌柜结算入口，核对账单状态和打款流水。",
    ],
    "2级-3级结算由丸友集工作室发起结算申请，确认打款信息；丸掌柜打款后，丸友集确认收款，最终明细为已结算。",
    "申请/批次号、业务单号、金额、打款账户、打款时间、结算状态在丸友集和丸掌柜两侧一致。",
    "组合举证：丸友集发起申请 -> 确认打款信息 -> 丸掌柜打款 -> 丸友集确认收款 -> 已结算",
    "待自动化",
    "按结算账单-丸友集真实页面文案重构。",
)


FLOW_L1L2_SETTLEMENT_UPDATE = case_row(
    "F-SETTLE-L1L2-001",
    "组合流程用例",
    "A-TASK-001 -> A-DELIVERY-001 -> A-DELIVERY-002A -> B-SETTLE-PLAYER-APPLY-001 或 B-SETTLE-WYJ-EMP-BILL-INIT-001 -> B-SETTLE-WANYOUJI-PAY-001",
    "1级-2级结算流程",
    "丸友集验收子单后，打手账单两种入口发起并由丸友集打款",
    "丸友集：工作室主账号；打手应用：打手子账号。",
    "打手已完成子单并提交验收；丸友集已同意验收子单；打手我的收入已生成可结算记录。",
    "来源单号、订单标题、子单号、打手账号、收入金额、结算申请号/账单号。",
    [
        "先执行用例A-TASK-001，丸友集接外部订单并发给打手。",
        "先执行用例A-DELIVERY-001，打手完成子单并提交验收。",
        "先执行用例A-DELIVERY-002A，丸友集同意验收子单并校验打手收入。",
        "执行用例B-SETTLE-PLAYER-ACCOUNT-001，确认打手打款账户已完善。",
        "登录打手子账号。",
        "进入打手应用-我的收入。",
        "搜索该来源单号或订单标题。",
        "确认收入记录为可结算/待结算。",
        "入口分支一：执行用例B-SETTLE-PLAYER-APPLY-001，打手点击一键结算并提交账单申请。",
        "入口分支二：执行用例B-SETTLE-WYJ-EMP-BILL-INIT-001，丸友集主账号在员工结算汇总-账单待发起中发起打手账单。",
        "确认同一笔收入只能生成一笔有效结算账单，不能两个入口重复生成。",
        "登录丸友集主账号。",
        "进入丸友集-工作室基础应用-财务结算列表。",
        "进行员工结算汇总。",
        "进入丸友集-工作室基础应用-结算账单列表。",
        "审核打手账单并提交打款。",
        "回到打手应用-我的收入，确认状态为已结算/已打款。",
    ],
    "1级-2级结算独立成立：只要丸友集已验收打手子单并生成收入，可由打手端或丸友集后台发起账单，不依赖丸掌柜验收主单。",
    "打手收入、员工结算汇总、结算账单列表、丸友集打款账单金额一致；两个发起入口不能重复生成账单。",
    "组合举证：丸友集验收子单 -> 打手收入可结算 -> 打手端/丸友集后台发起账单 -> 丸友集给打手打款",
    "待自动化",
    "根据用户补充：拆分1-2级验收后，打手发起账单流程可单独成立。",
)


FLOW_PLAYER_BILLING_INDEPENDENT = case_row(
    "F-PLAYER-BILLING-001",
    "组合流程用例",
    "A-DELIVERY-002A -> B-SETTLE-PLAYER-APPLY-001",
    "打手账单流程",
    "丸友集验收后打手独立发起账单",
    "打手应用：打手子账号；丸友集：工作室主账号（用于前置验收核对）。",
    "丸友集已同意验收子单；打手应用-我的收入中已出现该订单收入。",
    "来源单号、订单标题、子单号、打手账号、收入金额。",
    [
        "先执行用例A-DELIVERY-002A，丸友集验收打手子单并校验打手收入。",
        "登录打手子账号。",
        "进入打手应用-我的收入。",
        "按来源单号或订单标题搜索收入记录。",
        "确认收入金额、订单标题、收入状态正确。",
        "点击一键结算。",
        "确认结算范围和结算金额。",
        "提交结算申请。",
        "刷新我的收入或结算记录。",
        "确认生成结算申请/账单，状态进入待丸友集处理或页面实际待处理状态。",
    ],
    "打手在丸友集验收子单后即可独立发起账单；不需要等待丸掌柜验收主单。",
    "打手收入记录、结算申请金额、结算申请状态一致；后续由丸友集财务结算流程处理。",
    "被F-SETTLE-L1L2-001引用",
    "待自动化",
    "这是从 DELIVERY-002 拆分后新增的独立账单流程。",
)


FLOW_MAIN_001_UPDATE = case_row(
    "F-MAIN-001",
    "组合流程用例",
    "A-SAAS-001 -> A-SAAS-003 -> A-AUTH-001 -> A-PUSH-001 -> A-PUSH-003 -> A-ORDER-001",
    "主流程",
    "注册开通授权配置发单接单主流程闭环",
    "租户企业主账号；主站后台管理员；丸友集工作室主账号；丸掌柜企业主账号。",
    "测试手机号可注册或可复用；主站管理员可审批商户认证和应用开通；丸友集与丸掌柜账号具备授权、推单配置和发单权限。",
    "租户手机号、企业认证资料、丸友集授权密钥、丸掌柜固定账号、推单策略名称、来源单号、订单标题。",
    [
        "先执行用例A-SAAS-001，租户注册企业并由主站完成商户认证。",
        "先执行用例A-SAAS-003，已认证商户申请开通丸友集并由主站审批。",
        "先执行用例A-AUTH-001，丸友集生成授权密钥并绑定丸掌柜完成权限配置。",
        "先执行用例A-PUSH-001，丸掌柜新增丸友集工作室授权。",
        "先执行用例A-PUSH-003，丸掌柜新增推单配置策略。",
        "先执行用例A-ORDER-001，丸掌柜手工录单创建外来订单并发布到丸友集。",
        "登录丸友集工作室主账号。",
        "进入收单应用-抢单大厅。",
        "按来源单号或订单标题查询订单。",
        "确认订单出现在抢单大厅，订单标题、来源单号、发单价、发单方信息与丸掌柜发单数据一致。",
    ],
    "从租户注册、商户认证、丸友集开通、授权绑定、丸掌柜推单配置到外来订单发布完成；丸友集抢单大厅可查询到丸掌柜发布的订单。",
    "主站审批结果、丸友集应用状态、授权绑定关系、丸掌柜推单策略、丸友集抢单大厅订单数据一致。",
    "组合举证：main_001代码主流程；可作为后续订单履约和结算流程前置。",
    "已自动化",
    "依据 e2e/tests/组合大流程/test_e2e_main_001_full_closed_loop.py 更新；代码使用固定丸掌柜账号作为已具备应用前置的账号。",
)


FLOW_MAIN_002_UPDATE = case_row(
    "F-MAIN-002",
    "组合流程用例",
    "A-ORDER-001 -> A-TASK-001 -> A-DELIVERY-001 -> A-DELIVERY-002 -> B-SETTLE-PLAYER-ACCOUNT-001 -> B-SETTLE-PLAYER-APPLY-001",
    "主流程",
    "丸掌柜发单到打手提交结算账单主流程",
    "丸掌柜：企业主账号；丸友集：工作室主账号；打手应用：打手子账号。",
    "丸掌柜已完成丸友集授权和推单配置；丸友集可在抢单大厅接单；打手账号可进入抢单大厅、打手订单、我的收入；打手打款账户可完善。",
    "来源单号、订单标题、子单号、打手账号、验收截图、收入金额、打款账户信息、结算账单号。",
    [
        "先执行用例A-ORDER-001，丸掌柜手工录单创建外来订单并发布到丸友集。",
        "先执行用例A-TASK-001，丸友集接外部订单并发给打手，打手抢单。",
        "先执行用例A-DELIVERY-001，打手提交验收，主账号查看待验收。",
        "先执行用例A-DELIVERY-002，丸友集验收打手子单并校验打手收入。",
        "执行用例B-SETTLE-PLAYER-ACCOUNT-001，完善或校验打手打款账户信息。",
        "执行用例B-SETTLE-PLAYER-APPLY-001，打手在我的收入中对已完成订单一键结算。",
        "登录丸友集工作室主账号。",
        "进入工作室基础应用-员工结算汇总。",
        "按打手账号、来源单号或订单标题查询。",
        "打开结算汇总详情，核对打手提交账单的订单、收入金额和结算金额。",
        "进入工作室基础应用-结算账单列表。",
        "确认该打手账单已生成，账单状态进入待审核或页面实际待处理状态。",
    ],
    "丸掌柜订单经丸友集发给打手后，打手完成验收并由丸友集确认；打手收入可结算，打手可提交结算账单，丸友集后台可查询到账单汇总。",
    "订单流转状态、子单验收状态、打手我的收入、员工结算汇总、结算账单列表金额和账号一致。",
    "组合举证：main_002代码主流程；覆盖1级打手到2级丸友集的验收和账单发起，不包含丸掌柜对丸友集的2级-3级打款。",
    "已自动化",
    "依据 e2e/tests/组合大流程/test_e2e_main_002_order_to_player_settlement.py 新增。",
)


def used_rows(ws) -> int:
    return ws.UsedRange.Rows.Count


def find_row(ws, case_id: str) -> int | None:
    max_row = used_rows(ws)
    for row in range(2, max_row + 1):
        if str(ws.Cells(row, 1).Text).strip() == case_id:
            return row
    return None


def write_row(ws, row: int, values: list[str]) -> None:
    for col, value in enumerate(values, start=1):
        ws.Cells(row, col).Value = value


def append_row_like_previous(ws, values: list[str]) -> int:
    row = used_rows(ws) + 1
    ws.Rows(row - 1).Copy()
    ws.Rows(row).PasteSpecial(Paste=-4122)  # xlPasteFormats
    write_row(ws, row, values)
    ws.Rows(row).WrapText = True
    ws.Rows(row).VerticalAlignment = -4160
    return row


def update_or_append(ws, values: list[str]) -> str:
    row = find_row(ws, values[0])
    if row:
        write_row(ws, row, values)
        return f"updated {values[0]} at row {row}"
    row = append_row_like_previous(ws, values)
    return f"appended {values[0]} at row {row}"


def main() -> None:
    if "--json" in sys.argv:
        flow_updates = [value for value in UPDATES.values() if value[0].startswith("F-")]
        flow_updates.extend([value for value in NEW_ROWS if value[0].startswith("F-")])
        flow_updates.extend(
            [
                FLOW_UPDATE,
                FLOW_L1L2_SETTLEMENT_UPDATE,
                FLOW_PLAYER_BILLING_INDEPENDENT,
                FLOW_MAIN_001_UPDATE,
                FLOW_MAIN_002_UPDATE,
            ]
        )
        case_updates = [value for value in UPDATES.values() if not value[0].startswith("F-")]
        case_new_rows = [value for value in NEW_ROWS if not value[0].startswith("F-")]
        replacements = {
            "A-DELIVERY-002A": "A-DELIVERY-002",
            "A-DELIVERY-002B": "A-DELIVERY-003",
        }

        def replace_refs(values: list[str]) -> list[str]:
            updated = []
            for value in values:
                text = str(value)
                for old, new in replacements.items():
                    text = text.replace(old, new)
                text = text.replace("由A-DELIVERY-002拆分；", "")
                text = text.replace("由A-DELIVERY-002拆分", "")
                updated.append(text)
            return updated

        case_updates = [replace_refs(value) for value in case_updates]
        case_new_rows = [replace_refs(value) for value in case_new_rows]
        flow_updates = [replace_refs(value) for value in flow_updates]
        payload = {
            "delete_case_ids": ["A-DELIVERY-002", "A-DELIVERY-002A", "A-DELIVERY-002B"],
            "case_updates": case_updates,
            "case_new_rows": case_new_rows,
            "flow_updates": flow_updates,
        }
        JSON_OUTPUT.parent.mkdir(parents=True, exist_ok=True)
        JSON_OUTPUT.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8")
        print(JSON_OUTPUT)
        return

    import win32com.client

    if not WORKBOOK.exists():
        raise FileNotFoundError(WORKBOOK)

    excel = win32com.client.DispatchEx("Excel.Application")
    excel.Visible = False
    excel.DisplayAlerts = False
    try:
        wb = excel.Workbooks.Open(str(WORKBOOK))
        case_ws = wb.Worksheets("用例测试列表")
        flow_ws = wb.Worksheets("组合流程用例")

        results: list[str] = []
        for values in UPDATES.values():
            results.append(update_or_append(case_ws, values))
        for values in NEW_ROWS:
            results.append(update_or_append(case_ws, values))
        results.append(update_or_append(flow_ws, FLOW_UPDATE))

        wb.Save()
        wb.Close(SaveChanges=True)
        print("\n".join(results))
    finally:
        excel.Quit()


if __name__ == "__main__":
    main()
