$ErrorActionPreference = 'Stop'

$Root = (Resolve-Path '.').Path
$Source = Join-Path $Root 'SaaS主站_丸友集_丸掌柜_全流程闭环测试用例_细化版.xlsx'
$Output = Join-Path $Root 'SaaS主站_丸友集_丸掌柜_全流程闭环测试用例_深度引申版.xlsx'

function New-Steps {
    param([string[]]$Items)
    $result = @()
    for ($i = 0; $i -lt $Items.Count; $i++) {
        $result += ('{0}. {1}' -f ($i + 1), $Items[$i])
    }
    return ($result -join "`n")
}

function Add-Row {
    param($Worksheet, [object[]]$Values)
    $row = $Worksheet.UsedRange.Rows.Count + 1
    for ($i = 0; $i -lt $Values.Count; $i++) {
        $Worksheet.Cells.Item($row, $i + 1).Value2 = [string]$Values[$i]
    }
    $Worksheet.Rows.Item($row).WrapText = $true
    $Worksheet.Rows.Item($row).VerticalAlignment = -4160
}

function Write-RowAt {
    param($Worksheet, [int]$Row, [object[]]$Values)
    for ($i = 0; $i -lt $Values.Count; $i++) {
        $Worksheet.Cells.Item($Row, $i + 1).Value2 = [string]$Values[$i]
    }
    $Worksheet.Rows.Item($Row).WrapText = $true
    $Worksheet.Rows.Item($Row).VerticalAlignment = -4160
}

function Format-Sheet {
    param($Worksheet, [int]$MaxWidth = 55)
    $Worksheet.UsedRange.WrapText = $true
    $Worksheet.UsedRange.VerticalAlignment = -4160
    $Worksheet.Columns.AutoFit() | Out-Null
    for ($c = 1; $c -le $Worksheet.UsedRange.Columns.Count; $c++) {
        if ($Worksheet.Columns.Item($c).ColumnWidth -gt $MaxWidth) {
            $Worksheet.Columns.Item($c).ColumnWidth = $MaxWidth
        }
    }
}

$cases = @(
    @(
        'E2E-ORDER-006','P0','丸掌柜外来订单-手工录单来源扩展闭环','丸掌柜 -> 丸友集',
        '在原E2E-ORDER-001/002基础上，校验外来订单来源为手工录单时完整生成主单和1个子单并发布到丸友集',
        '已完成E2E-AUTH-001~003、E2E-PUSH-001/003；推单策略启用；丸友集工作室可接单',
        '订单来源：手工录单；主单：E2E-MANUAL；子单数：1；策略：E2E推单策略；价格模式：固定发单价',
        (New-Steps @(
            '登录丸掌柜企业账号。',
            '进入订单管理-手工录单，点击新增订单。',
            '填写主单基础信息，确认订单来源为手工录单或默认手工录单来源。',
            '点击添加子单。',
            '在子单中选择已启用的E2E推单策略。',
            '填写子单服务项目、游戏、区服、数量、固定发单价、交付要求和备注。',
            '保存子单，回到主单页面确认子单列表出现1条记录。',
            '保存主单，进入订单详情核对主单号、子单号、策略名称、金额。',
            '点击发布/提交/确认发布。',
            '登录丸友集企业管理员，进入工作室履约应用-抢单大厅。',
            '按主单号、来源单号或标题搜索该外来订单。',
            '主站如有监管入口，使用主站账号查询同一订单。'
        )),
        '丸掌柜主单和子单保存成功；发布后丸掌柜状态进入已发布/待接单；丸友集抢单大厅出现该外来订单；主站可查到订单或至少不出现异常。',
        '主单号、子单号、来源、策略名称、工作室、金额、数量在丸掌柜/丸友集/主站一致；这是后续撤销、多子单、分配、价格模式用例的基线。',
        '由原E2E-ORDER-001/002引申，作为外来订单手工录单main流程。'
    ),
    @(
        'E2E-ORDER-007','P0','丸掌柜外来订单-抖音录单来源正向闭环','丸掌柜 -> 丸友集',
        '在原手工录单链路基础上，校验订单来源切换为抖音录单后正向流程与手工录单一致',
        '抖音录单入口/店铺授权/订单来源配置可用；其他前置同E2E-ORDER-006',
        '订单来源：抖音录单；抖音订单号：E2E-DY；子单数：1；策略：E2E推单策略；价格模式：固定发单价',
        (New-Steps @(
            '登录丸掌柜具备抖音录单权限的账号。',
            '进入订单管理中抖音录单、抖音订单或对应来源入口。',
            '创建或导入一笔抖音来源订单，记录抖音订单号和丸掌柜主单号。',
            '打开订单详情，确认订单来源展示为抖音或外部抖音来源。',
            '点击添加子单。',
            '选择E2E推单策略并填写与手工录单相同的子单必填字段。',
            '保存子单并保存主单。',
            '发布该订单。',
            '登录丸友集企业管理员，进入工作室履约应用-抢单大厅。',
            '搜索抖音订单号或丸掌柜主单号。',
            '确认订单来源、标题、价格、服务类型展示正确。',
            '继续执行管理员接外部订单，确认能进入订单列表。'
        )),
        '抖音来源订单可完成添加子单、保存、发布；丸友集可见并可接入；正向状态流转与手工录单一致。',
        '抖音订单号、丸掌柜主单号、丸友集外部订单号映射一致；来源字段不能丢失或误显示为手工录单。',
        '由E2E-ORDER-001/002引申；撤销差异在撤销分支中单独细化。'
    ),
    @(
        'E2E-CANCEL-001','P1','手工录单主单保存后未发布撤销','丸掌柜',
        '在原E2E-ORDER-001保存主单后、E2E-ORDER-002发布前，验证主单撤销不会生成丸友集任务',
        '已保存手工录单主单和1个子单；订单尚未发布',
        '主单：E2E-CANCEL-BEFORE-PUBLISH；子单：1；策略：E2E推单策略',
        (New-Steps @(
            '登录丸掌柜。',
            '进入订单管理-手工录单列表。',
            '创建主单并添加1个子单，保存但不发布。',
            '回到订单列表，搜索该主单。',
            '点击撤销/取消/删除，填写撤销原因。',
            '确认撤销操作。',
            '刷新丸掌柜订单列表并打开订单详情。',
            '登录丸友集企业管理员，进入抢单大厅。',
            '按主单号、标题、来源单号搜索。',
            '主站如有监管入口，查询该主单状态。'
        )),
        '丸掌柜主单状态变为撤销/已取消/已关闭；子单同步关闭或不可发布；丸友集抢单大厅不存在该任务；无接单、履约、收益记录。',
        '撤销发生在发布前，因此丸友集和打手侧不应产生任何可见任务；主站状态应与丸掌柜一致。',
        '挂在原E2E-ORDER-001与E2E-ORDER-002之间。'
    ),
    @(
        'E2E-CANCEL-002','P1','外来订单发布后未被丸友集接单前撤销','丸掌柜 -> 丸友集',
        '在原E2E-ORDER-002发布后、E2E-WORKFLOW-001管理员接外部订单前，验证撤销从抢单大厅移除',
        '订单已发布到丸友集抢单大厅；管理员尚未接外部订单',
        '订单来源：手工录单或抖音录单；子单数：1；状态：待接外部订单',
        (New-Steps @(
            '执行E2E-ORDER-006或E2E-ORDER-007直到丸友集抢单大厅可见订单。',
            '不要执行管理员接单。',
            '回到丸掌柜订单详情或列表。',
            '点击撤销/取消发布/关闭订单。',
            '填写撤销原因并提交。',
            '刷新丸掌柜订单详情，记录主单和子单状态。',
            '登录丸友集企业管理员，刷新抢单大厅。',
            '按订单号再次搜索该任务。',
            '检查丸友集订单列表中是否误生成订单。',
            '检查主站监管状态。'
        )),
        '丸掌柜撤销成功；丸友集抢单大厅中该订单消失或状态变为不可接；丸友集订单列表不应生成已接订单；无打手订单和收益。',
        '丸掌柜撤销状态需要回写到丸友集；来源单号、撤销原因、撤销时间可追踪。',
        '适用于手工录单和抖音录单，抖音外部取消是否同步需另确认。'
    ),
    @(
        'E2E-CANCEL-003','P1','丸友集管理员接外部订单后立即发单前撤销','丸掌柜 -> 丸友集',
        '在原E2E-WORKFLOW-001之后、E2E-WORKFLOW-002立即发单前，验证工作室已接单但未分发给打手时撤销',
        '外部订单已被丸友集企业管理员从抢单大厅接入订单列表；尚未立即发单给打手',
        '订单来源：外部应用/丸掌柜；工作室订单状态：已接入/待发单',
        (New-Steps @(
            '执行E2E-WORKFLOW-001，使外部订单进入工作室履约应用-订单列表。',
            '不要点击立即发单。',
            '记录丸友集订单列表中的订单状态、价格、来源。',
            '在丸友集订单详情尝试撤销/拒单/关闭，若无入口则回到丸掌柜发起撤销。',
            '填写撤销原因并提交。',
            '刷新丸友集订单列表。',
            '登录丸掌柜查看主单和子单状态。',
            '登录打手账号进入抢单大厅搜索该订单。',
            '主站查询订单状态。'
        )),
        '工作室订单关闭或撤销完成；打手抢单大厅不可见；丸掌柜状态同步为撤销中/撤销完成或显示工作室撤销结果；无打手接单记录。',
        '管理员接外部订单后的撤销不能遗留可发单任务；丸掌柜与丸友集状态需要一致。',
        '按钮文案可能是拒单/撤销/关闭，按实际页面落断言。'
    ),
    @(
        'E2E-CANCEL-004','P1','打手抢单后提交成果前撤销','丸友集 -> 丸掌柜',
        '在原E2E-WORKFLOW-002之后、E2E-FULFILL-001前，验证打手已抢单但未履约时撤销',
        '外部订单已由管理员立即发单；打手已抢单；打手我的订单中存在待履约订单',
        '订单来源：外部应用；打手状态：待履约/进行中',
        (New-Steps @(
            '执行E2E-WORKFLOW-002直到打手抢单成功。',
            '打手进入我的订单确认订单状态为待履约或进行中。',
            '不要提交成果。',
            '使用丸友集企业管理员打开工作室履约应用-订单列表或打手订单详情。',
            '发起撤销/取消打手订单/终止履约，填写原因。',
            '若撤销入口在丸掌柜，则切换丸掌柜账号从主单或子单详情发起撤销。',
            '打手刷新我的订单。',
            '打手进入抢单大厅确认该订单是否重新释放或关闭。',
            '丸掌柜查看子单状态、打手信息、撤销原因。',
            '主站查看接单记录和撤销记录。'
        )),
        '撤销后打手我的订单状态变为已取消/撤销完成/终止；不能继续提交成果；丸掌柜子单不应显示可验收；是否重新释放到抢单大厅按业务规则明确。',
        '打手、工作室订单、丸掌柜子单的撤销状态和责任方一致；如涉及补偿/扣罚需生成可追踪记录。',
        '这是很多节点撤销的关键分支之一。'
    ),
    @(
        'E2E-CANCEL-005','P1','打手提交成果后上游验收前撤销或驳回','丸友集 -> 丸掌柜',
        '在原E2E-FULFILL-001之后、E2E-FULFILL-002申请上游验收/丸掌柜验收前，验证成果已提交后的异常流转',
        '打手已提交成果；工作室订单状态为待验收/待申请上游验收',
        '成果内容：E2E提交成果；撤销/驳回原因：E2E成果需终止',
        (New-Steps @(
            '执行E2E-FULFILL-001直到打手提交成果成功。',
            '使用丸友集企业管理员进入工作室履约应用-订单列表。',
            '打开该订单，查看打手提交的成果内容和附件。',
            '不要直接申请上游验收，先尝试驳回成果或撤销订单。',
            '填写驳回/撤销原因并提交。',
            '打手登录我的订单，查看状态和原因。',
            '丸掌柜登录订单详情查看是否出现待验收记录。',
            '若已经申请上游验收，则丸掌柜执行验收驳回并填写原因。',
            '打手重新提交成果或确认订单关闭。',
            '检查收入明细是否未生成收益。'
        )),
        '成果被驳回时打手可见原因并可重新提交；撤销时订单关闭且不可继续提交；未验收通过前不应生成收入。',
        '成果内容、驳回原因、撤销原因在管理员/打手/丸掌柜侧一致；驳回不结算，通过才结算。',
        '由原E2E-DELIVERY-003和E2E-FULFILL-002引申。'
    ),
    @(
        'E2E-MULTI-001','P1','手工录单一主两子一次发出-同策略同工作室','丸掌柜 -> 丸友集',
        '在原E2E-ORDER-005基础上细化：一个主单一次添加2个子单，两个子单使用同一推单策略',
        '页面支持一个主单添加多个子单；E2E推单策略启用',
        '主单：E2E-MULTI-SAME；子单1/子单2；策略相同；价格模式：固定发单价',
        (New-Steps @(
            '登录丸掌柜进入订单管理-手工录单。',
            '新增主单并填写主单基础信息。',
            '点击添加子单，创建子单1。',
            '子单1选择E2E推单策略，填写服务项目、数量、固定发单价和交付要求。',
            '保存子单1。',
            '再次点击添加子单，创建子单2。',
            '子单2选择同一E2E推单策略，填写不同标题或服务项目。',
            '保存子单2。',
            '在主单页面确认子单列表存在2条记录且金额汇总正确。',
            '保存并发布主单。',
            '丸友集管理员进入抢单大厅，按主单号搜索。',
            '确认系统按实际规则展示2条子任务或1个主单含2个子单。',
            '分别接入两个子单并查看工作室订单列表。'
        )),
        '两个子单均保存并发布成功；丸友集可识别两个子单；主单金额与子单金额合计一致；两个子单状态可独立流转。',
        '主单号相同、子单号不同；子单策略、价格、状态在丸掌柜和丸友集一致。',
        '基于原E2E-ORDER-005，不是新增孤立流程。'
    ),
    @(
        'E2E-MULTI-002','P1','手工录单一主两子一次发出-不同策略不同工作室','丸掌柜 -> 丸友集',
        '在原多子单用例基础上，验证同一主单的两个子单分别推送到不同授权工作室',
        '存在两个已启用推单策略，分别绑定工作室A和工作室B',
        '主单：E2E-MULTI-DIFF；子单1策略A；子单2策略B',
        (New-Steps @(
            '登录丸掌柜。',
            '确认推单配置中策略A绑定工作室A、策略B绑定工作室B。',
            '进入手工录单新增主单。',
            '添加子单1并选择策略A。',
            '填写子单1金额、数量、服务项目并保存。',
            '添加子单2并选择策略B。',
            '填写子单2金额、数量、服务项目并保存。',
            '保存并发布主单。',
            '登录丸友集工作室A账号，在抢单大厅搜索主单号。',
            '确认只看到或只能处理子单1。',
            '登录丸友集工作室B账号，在抢单大厅搜索主单号。',
            '确认只看到或只能处理子单2。',
            '尝试工作室A访问子单2详情或接单。'
        )),
        '两个子单分别进入对应工作室可见范围；跨工作室不可见或不可操作；主单仍能汇总两个子单状态。',
        '策略与工作室授权关系隔离正确；主单汇总不破坏子单级权限。',
        '由E2E-ORDER-004与E2E-ORDER-005组合引申。'
    ),
    @(
        'E2E-MULTI-003','P1','第1个子单完成后续发第2个子单','丸掌柜 -> 丸友集 -> 丸掌柜',
        '验证主单先发1个子单并完成后，仍可继续追加或续发第2个子单',
        '页面支持完成后追加/续发子单；第1子单已完成并结算或待结算',
        '主单：E2E-MULTI-CONTINUE；第1子单已完成；第2子单待新增',
        (New-Steps @(
            '按E2E-ORDER-006创建主单并只添加子单1。',
            '发布子单1对应任务。',
            '丸友集管理员接入订单并立即发单。',
            '打手抢单并提交成果。',
            '管理员申请上游验收，丸掌柜验收通过。',
            '确认子单1状态为已完成，打手收入已生成或待生成。',
            '回到丸掌柜主单详情。',
            '点击追加子单/添加子单/续发子单入口。',
            '创建子单2并选择推单策略。',
            '保存并发布子单2。',
            '丸友集抢单大厅搜索同一主单号。',
            '完成子单2接单、履约、验收。',
            '检查主单最终状态和两个子单状态。'
        )),
        '子单1完成后，主单不应因第1子单完成而阻断续发；子单2可独立发布和完成；全部子单结束后主单最终完成。',
        '主单汇总状态、子单完成状态、收入流水按子单维度正确关联。',
        '覆盖“1单完成后续发另1子单”的重点分支。'
    ),
    @(
        'E2E-DISPATCH-001','P1','企业内部分发-流向抢单大厅','丸友集',
        '在原E2E-WORKFLOW-002立即发单步骤中，选择抢单大厅分配方式',
        '外部订单已进入工作室订单列表；企业存在多个打手',
        '分配方式：抢单大厅；发单价：固定价',
        (New-Steps @(
            '执行E2E-WORKFLOW-001使外部订单进入工作室订单列表。',
            '管理员打开订单详情。',
            '点击立即发单。',
            '选择分配方式为抢单大厅/公开抢单。',
            '填写发单价、服务时限、订单标题、备注。',
            '提交发单。',
            '打手A登录打手应用-抢单大厅搜索订单。',
            '打手B登录打手应用-抢单大厅搜索订单。',
            '打手A立即抢单。',
            '打手B刷新抢单大厅并尝试搜索或抢单。',
            '管理员查看订单列表和打手信息。'
        )),
        '发单后多个符合条件打手可见；一个打手抢单成功后其他打手不可重复抢；订单进入抢单成功打手的我的订单。',
        '抢单大厅、我的订单、工作室订单列表中的订单号、价格、打手信息一致。',
        '细化原E2E-WORKFLOW-002的分配方式分支。'
    ),
    @(
        'E2E-DISPATCH-002','P1','企业内部分发-指派打手','丸友集',
        '在原E2E-WORKFLOW-002立即发单步骤中，选择指派打手',
        '外部订单已进入工作室订单列表；至少存在打手A和打手B',
        '分配方式：指派打手；被指派打手：A',
        (New-Steps @(
            '管理员进入工作室履约应用-订单列表。',
            '打开目标外部订单。',
            '点击立即发单。',
            '选择分配方式为指派打手。',
            '在打手选择框中选择打手A。',
            '填写发单价、时限和交付要求。',
            '提交发单。',
            '使用打手A登录打手应用，查看我的订单或待处理任务。',
            '使用打手B登录打手应用，搜索同一订单。',
            '打手A确认接单或处理任务。',
            '管理员查看订单详情中的打手信息。'
        )),
        '只有被指派打手A可见或可处理该订单；打手B不可见或不可抢；管理员侧显示指派打手为A。',
        '指派关系、打手手机号/昵称、订单状态在管理员和打手A侧一致。',
        '需要验证指派后是否还需要打手确认接单。'
    ),
    @(
        'E2E-DISPATCH-003','P1','企业内部分发-智能派单','丸友集',
        '在原E2E-WORKFLOW-002立即发单步骤中，选择智能派单并校验策略命中',
        '外部订单已进入工作室订单列表；智能派单规则已配置；候选打手满足规则',
        '分配方式：智能派单；候选打手：按规则命中',
        (New-Steps @(
            '管理员确认智能派单规则启用，例如按在线状态、技能、服务项目或负载。',
            '进入工作室订单列表打开目标订单。',
            '点击立即发单。',
            '选择分配方式为智能派单。',
            '填写或确认发单价、服务时限、订单标题。',
            '提交发单。',
            '查看系统返回的派单结果或订单详情中的承接打手。',
            '使用命中打手登录，查看我的订单。',
            '使用未命中打手登录，确认不可处理该订单。',
            '管理员查看订单详情中的派单方式和打手信息。'
        )),
        '智能派单成功并命中符合规则的打手；未命中打手不可操作；订单不应留在公共抢单大厅被任意抢。',
        '派单方式、命中打手、规则依据如页面展示需可追踪。',
        '智能派单规则细节待产品/页面确认。'
    ),
    @(
        'E2E-PRICE-001','P1','发单设置-固定发单价金额贯穿闭环','丸掌柜 -> 丸友集',
        '在原推单配置和立即发单基础上，验证固定发单价从配置到结算一致',
        '推单配置或发单设置支持固定发单价；订单可完成验收',
        '固定发单价：例如10.00；数量：1',
        (New-Steps @(
            '登录丸掌柜进入推单配置或发单设置。',
            '新增或编辑策略，将价格模式设置为固定发单价。',
            '填写固定发单价并保存策略。',
            '进入手工录单创建主单和子单，选择该策略。',
            '保存并发布订单。',
            '丸友集管理员接外部订单并立即发单给打手。',
            '打手抢单并提交成果。',
            '管理员申请上游验收，丸掌柜验收通过。',
            '查看丸掌柜订单金额。',
            '查看丸友集工作室订单金额。',
            '查看打手我的收入。',
            '主站查看结算记录。'
        )),
        '子单展示金额、打手可见发单价、验收后收入/结算金额均按固定发单价规则生成。',
        '金额单位、小数精度、订单号关联在丸掌柜/丸友集/主站一致。',
        '原E2E-FIN-001金额一致性的固定价分支。'
    ),
    @(
        'E2E-PRICE-002','P1','发单设置-百分比发单价计算闭环','丸掌柜 -> 丸友集',
        '验证价格模式为百分比发单价时，子单价和收入按主单金额计算',
        '发单设置支持百分比发单价；主单金额可控',
        '主单金额：100.00；百分比：例如30%；预期子单价：按规则计算',
        (New-Steps @(
            '登录丸掌柜进入推单配置或发单设置。',
            '新增或编辑策略，价格模式选择百分比发单价。',
            '填写百分比值、最低价/最高价/取整规则如页面要求。',
            '创建手工录单主单，填写主单金额。',
            '添加子单并选择百分比策略。',
            '保存子单后查看系统计算出的子单价。',
            '发布订单并在丸友集抢单大厅查看价格。',
            '管理员接单并按任一分配方式发给打手。',
            '打手完成订单，丸掌柜验收通过。',
            '查看结算记录和打手收入。',
            '更换一个不同主单金额重复一次，验证计算随主单金额变化。'
        )),
        '子单发单价按百分比规则计算；小数、最低价、封顶规则符合页面或产品规则；结算金额与计算结果一致。',
        '主单金额、百分比、计算价、最终收入可追踪；不同金额样本不应复用旧价格。',
        '规则未确认时先记录实际计算结果，待确认公式后固化断言。'
    ),
    @(
        'E2E-PRICE-003','P1','发单设置-SKU报价匹配闭环','丸掌柜 -> 丸友集',
        '验证价格模式为SKU报价时，不同SKU订单匹配对应发单价',
        'SKU报价表已配置；手工录单可选择或录入SKU',
        'SKU-A报价、SKU-B报价；订单包含目标SKU',
        (New-Steps @(
            '登录丸掌柜进入发单设置或SKU报价配置。',
            '配置SKU-A和SKU-B的发单价，并保存。',
            '进入手工录单创建主单。',
            '选择或填写SKU-A相关商品/服务项目。',
            '添加子单并选择SKU报价策略。',
            '保存子单，核对子单价格是否命中SKU-A报价。',
            '发布订单并在丸友集查看展示价格。',
            '完成接单、履约、验收和收入检查。',
            '重复创建SKU-B订单，核对价格命中SKU-B。',
            '创建未配置SKU的订单，观察系统提示或默认规则。'
        )),
        '已配置SKU能命中对应报价；不同SKU价格不同且不串价；未配置SKU有明确拦截或默认规则；结算金额与SKU报价一致。',
        'SKU名称/编码、报价、订单服务项目、子单价格在丸掌柜和丸友集一致。',
        '多SKU、多数量、组合SKU需在待确认项继续细化。'
    ),
    @(
        'E2E-PENALTY-001','P1','已完成子单处罚追缴闭环','丸友集/丸掌柜 -> 财务/收入',
        '在原E2E-FULFILL-002验收通过和收入生成后，验证对已完成子单发起处罚追缴',
        '外部订单子单已完成；打手我的收入已生成；处罚入口可访问',
        '处罚对象：打手或工作室；处罚金额：小于等于收入金额；原因：E2E处罚',
        (New-Steps @(
            '执行E2E-FULFILL-002直到丸掌柜验收通过，打手我的收入出现记录。',
            '记录订单号、子单号、打手收入金额和收入状态。',
            '使用有处罚权限的管理员账号登录。',
            '进入处罚/追缴入口，或从订单详情进入处罚操作。',
            '选择目标订单和目标子单。',
            '选择责任方：打手或工作室。',
            '填写处罚原因、处罚金额、凭证或备注。',
            '提交处罚申请。',
            '如存在审核流程，使用审核账号通过处罚申请。',
            '打手登录我的收入或账户流水查看扣减/追缴记录。',
            '管理员查看处罚单状态。',
            '丸掌柜或主站查看订单关联处罚记录。'
        )),
        '已完成子单可按权限发起处罚追缴；审核通过后生成扣减/追缴流水；原订单完成状态不应被错误回退；处罚记录可追踪。',
        '处罚单号、订单号、责任方、金额、扣减流水在管理员/打手/财务视角一致。',
        '覆盖“履约结束后处罚追缴”的已完成分支。'
    ),
    @(
        'E2E-PENALTY-002','P1','撤销完成子单处罚追缴闭环','丸友集/丸掌柜 -> 财务/收入',
        '验证状态为撤销完成的子单仍需按规则进行处罚追缴或明确拦截',
        '存在撤销完成子单；曾发生打手接单或履约动作；处罚入口可访问',
        '子单状态：撤销完成；处罚原因：E2E撤销责任追缴',
        (New-Steps @(
            '执行E2E-CANCEL-004或E2E-CANCEL-005构造撤销完成子单。',
            '记录撤销节点、责任方、是否已有收入或冻结金额。',
            '使用管理员账号打开该子单详情。',
            '查找处罚/追缴入口。',
            '若入口可用，选择责任方、填写金额和原因并提交。',
            '若入口不可用，记录系统提示和权限限制。',
            '如需审核，使用审核账号审批。',
            '打手或工作室账号查看收入/流水/处罚记录。',
            '主站或财务账号查看追缴流水。',
            '重复对同一子单发起处罚，验证重复处罚限制。'
        )),
        '若业务允许，撤销完成子单可生成处罚追缴并有流水；若业务不允许，系统需明确拦截；不得重复扣款或生成无归属流水。',
        '撤销状态、处罚状态、收入/流水状态一致；重复处罚有明确限制。',
        '覆盖“撤销完成子单处罚追缴”的分支。'
    ),
    @(
        'E2E-ACCOUNT-001','P0','外来订单全链路账号登录与权限切换闭环','丸掌柜 -> 丸友集 -> 主站',
        '重新梳理不同账号在外来订单链路中的登录、菜单、操作权限和越权限制',
        '账号已准备：丸掌柜商家/客服、丸友集企业管理员、打手、主站管理员、处罚审核或财务账号',
        '账号矩阵：商家、客服、企业管理员、打手、主站管理员、财务/审核',
        (New-Steps @(
            '使用丸掌柜商家主账号登录，确认可进入手工录单、抖音录单、工作室管理、推单配置、订单验收。',
            '使用丸掌柜客服或子账号登录，确认可进入允许的收单/打手订单/验收入口。',
            '使用丸友集企业管理员登录，确认可进入工作室履约应用、抢单大厅、订单列表、立即发单。',
            '使用打手账号登录，确认可进入打手应用-抢单大厅、我的订单、我的收入。',
            '使用主站管理员wangss登录，确认可监管企业、应用、订单或结算记录。',
            '使用财务/审核账号登录，确认可查看结算、处罚、追缴入口。',
            '分别用打手账号访问企业管理员配置入口。',
            '分别用客服账号访问工作室管理/授权密钥等管理员入口。',
            '分别用企业B账号搜索企业A订单。',
            '记录每个账号可见菜单、可执行动作、不可执行动作和提示。'
        )),
        '各账号只能访问其角色允许的菜单和数据；越权入口不可见或操作被拦截；外来订单全链路可由正确账号串联完成。',
        '账号、角色、企业归属、菜单权限、数据隔离一致；后续自动化需固定账号矩阵。',
        '对应“重新梳理不同账号登录情况”。'
    ),
    @(
        'E2E-MAIN-002','P0','外来订单手工录单main流程-一主一子-固定价-抢单大厅','丸掌柜 -> 丸友集 -> 丸掌柜 -> 主站',
        '从原E2E-MAIN-001中抽出外来订单履约main流程，作为后续分支的稳定基线',
        '企业、应用、授权、管理授权、工作室授权、推单配置、打手账号均已准备',
        '来源：手工录单；子单：1；分配方式：抢单大厅；价格模式：固定发单价',
        (New-Steps @(
            '丸掌柜商家登录并确认推单策略启用。',
            '进入手工录单创建主单。',
            '添加1个子单并选择固定价策略。',
            '保存并发布订单。',
            '丸友集企业管理员进入抢单大厅接外部订单。',
            '管理员进入订单列表，选择抢单大厅方式立即发单。',
            '打手进入抢单大厅并抢单。',
            '打手进入我的订单提交成果。',
            '管理员在工作室订单列表申请上游验收。',
            '丸掌柜商家进入验收入口并验收通过。',
            '主站查看监管或结算记录。',
            '打手进入我的收入查看收益。'
        )),
        '手工录单外来订单一主一子全链路完成；最终子单已完成，主单已完成或按规则完成；收入生成。',
        '这是外来订单手工录单main流程，后续撤销、多子单、价格、分配都从该流程节点派生。',
        '加入P0主链路。'
    ),
    @(
        'E2E-MAIN-003','P0','外来订单抖音录单main流程-一主一子-固定价-抢单大厅','丸掌柜 -> 丸友集 -> 丸掌柜 -> 主站',
        '在E2E-MAIN-002基础上将来源替换为抖音录单，验证正向链路一致',
        '抖音来源入口可用；其他前置同E2E-MAIN-002',
        '来源：抖音录单；子单：1；分配方式：抢单大厅；价格模式：固定发单价',
        (New-Steps @(
            '丸掌柜抖音录单账号登录。',
            '进入抖音录单或抖音订单入口。',
            '创建或导入抖音来源主单。',
            '添加1个子单并选择固定价策略。',
            '保存并发布订单。',
            '丸友集企业管理员在抢单大厅搜索抖音订单。',
            '管理员接外部订单并立即发单到抢单大厅。',
            '打手抢单并提交成果。',
            '管理员申请上游验收。',
            '丸掌柜验收通过。',
            '主站查看订单/结算监管。',
            '打手查看我的收入。'
        )),
        '抖音录单正向链路与手工录单一致完成；来源字段全程保留；收入生成。',
        '抖音订单号、丸掌柜主单号、丸友集订单号映射一致。',
        '抖音撤销差异不放在main流程，另走撤销分支研究。'
    )
)

$excel = New-Object -ComObject Excel.Application
$excel.Visible = $false
$excel.DisplayAlerts = $false
try {
    if (Test-Path $Output) { Remove-Item $Output -Force }
    $wb = $excel.Workbooks.Open($Source)
    $wb.SaveAs($Output, 51)

    $wsAll = $wb.Worksheets.Item('全流程闭环用例')
    $wsP0 = $wb.Worksheets.Item('P0主链路用例')
    $wsSeq = $wb.Worksheets.Item('P0执行顺序')
    $wsData = $wb.Worksheets.Item('测试数据与账号')
    $wsState = $wb.Worksheets.Item('状态流转断言')
    $wsTodo = $wb.Worksheets.Item('待确认项')

    foreach ($case in $cases) {
        Add-Row $wsAll $case
        if ($case[1] -eq 'P0') {
            Add-Row $wsP0 $case
        }
    }

    Add-Row $wsSeq @('24','外来订单main流程A','丸掌柜-手工录单；丸友集-抢单大厅/订单列表；打手应用；丸掌柜验收','执行E2E-MAIN-002：手工录单一主一子、固定价、抢单大厅、验收通过、收入生成','手工录单外来订单main流程可闭环')
    Add-Row $wsSeq @('25','外来订单main流程B','丸掌柜-抖音录单；丸友集；打手应用；丸掌柜验收','执行E2E-MAIN-003：抖音录单正向链路，先不展开撤销差异','抖音正向与手工正向一致，来源字段保留')
    Add-Row $wsSeq @('26','分支扩展批次','撤销、多子单、分配方式、价格模式、处罚追缴','按E2E-CANCEL、E2E-MULTI、E2E-DISPATCH、E2E-PRICE、E2E-PENALTY分批执行','每条分支都能回溯到原main流程节点')

    Add-Row $wsData @('丸掌柜抖音录单账号','丸掌柜','抖音录单来源订单创建、发布、撤销研究','需确认店铺授权、抖音订单同步方式和撤销回传规则')
    Add-Row $wsData @('丸掌柜客服/子账号','丸掌柜','收单应用、打手订单、验收或协作权限验证','用于E2E-ACCOUNT-001，权限以实际角色配置为准')
    Add-Row $wsData @('处罚/财务审核账号','丸友集/丸掌柜/主站','履约结束后处罚追缴、结算流水验证','若无独立账号，先由管理员账号代查并记录差异')

    Add-Row $wsState @('外来订单撤销-发布前','主单撤销/关闭；子单不可发布','丸友集不可见任务','订单监管为撤销或无任务','发布前撤销不得生成抢单大厅任务、打手订单、收入')
    Add-Row $wsState @('外来订单撤销-发布后未接','订单撤销完成或取消发布','抢单大厅任务消失或不可接','监管状态同步撤销','撤销要从丸友集公池/私单中移除，不得遗留可接任务')
    Add-Row $wsState @('外来订单撤销-打手已接','子单撤销中/撤销完成，不可验收','打手我的订单关闭或终止','接单记录和撤销记录可查','打手不能继续提交成果；是否补偿/追缴按规则记录')
    Add-Row $wsState @('一主多子汇总','主单展示多个子单及汇总状态','各子单按策略进入对应工作室','监管可查看主子关系','子单状态独立，主单状态由全部子单完成/撤销规则决定')
    Add-Row $wsState @('价格模式','订单金额、子单发单价、验收金额一致','打手可见金额和收入按规则计算','结算金额可监管','固定价/百分比/SKU报价的计算结果贯穿全链路')
    Add-Row $wsState @('处罚追缴','原订单终态保留，追加处罚记录','责任方可见扣减/追缴流水','财务/监管可查处罚单','已完成/撤销完成子单处罚不得重复扣款，流水需可追踪')

    Add-Row $wsTodo @('抖音录单撤销与手工录单撤销在各节点的入口、状态、外部回传是否一致','抖音录单撤销分支','先按正向P0执行，撤销按E2E-CANCEL对应节点逐个实测后固化断言')
    Add-Row $wsTodo @('一主多子是否支持一次发多个、完成后续发、撤销后续发，以及主单终态汇总规则','多子单分支','按E2E-MULTI-001~003分批确认，不能只写一个粗略多子单用例')
    Add-Row $wsTodo @('指派打手和智能派单是否在丸掌柜推单配置阶段选择，还是丸友集管理员立即发单阶段选择','分配方式分支','执行E2E-DISPATCH-001~003时记录真实入口并回填步骤')
    Add-Row $wsTodo @('固定发单价、百分比发单价、SKU报价的配置入口、计算公式、小数规则、未命中SKU规则','价格模式分支','执行E2E-PRICE-001~003，先记录实际计算，再补精确公式')
    Add-Row $wsTodo @('已完成/撤销完成子单处罚追缴的权限、审核流、金额上限、重复处罚限制','处罚追缴分支','执行E2E-PENALTY-001~002，区分允许追缴和系统拦截两种预期')
    Add-Row $wsTodo @('丸掌柜商家、客服、丸友集企业管理员、打手、主站、财务/审核账号的菜单和数据隔离','账号登录矩阵','执行E2E-ACCOUNT-001后将账号矩阵固化到测试数据与账号sheet')

    $matrix = $wb.Worksheets.Add([Type]::Missing, $wb.Worksheets.Item($wb.Worksheets.Count))
    $matrix.Name = '外来订单分支矩阵'
    $matrixRows = @(
        @('分支维度','原表依赖节点','新增/引申用例','覆盖点','优先级','说明'),
        @('订单来源','E2E-ORDER-001/002','E2E-ORDER-006、E2E-ORDER-007、E2E-MAIN-002/003','手工录单、抖音录单正向一致；抖音撤销待单独研究','P0/P1','不是新增孤立流程，而是替换原手工录单来源'),
        @('撤销节点','E2E-ORDER-001/002、E2E-WORKFLOW-001/002、E2E-FULFILL-001/002','E2E-CANCEL-001~005','发布前、发布后未接、工作室已接、打手已接、成果已提交','P1','每个撤销都挂在原流程节点之间'),
        @('主子单结构','E2E-ORDER-005','E2E-MULTI-001~003','一主一子、一次两子、不同策略、完成后续发','P1','主单汇总和子单独立状态是核心断言'),
        @('分配方式','E2E-WORKFLOW-002','E2E-DISPATCH-001~003','抢单大厅、指派打手、智能派单','P1','细化立即发单步骤的不同流向'),
        @('价格模式','E2E-PUSH-003、E2E-FIN-001','E2E-PRICE-001~003','固定发单价、百分比发单价、SKU报价','P1','金额从配置、子单、打手可见价、结算、收入贯穿校验'),
        @('处罚追缴','E2E-FULFILL-002、撤销分支','E2E-PENALTY-001~002','已完成子单、撤销完成子单处罚追缴','P1','履约结束后的治理流程'),
        @('账号登录','测试数据与账号、E2E-PERM-002','E2E-ACCOUNT-001','商家、客服、管理员、打手、主站、财务/审核','P0','先固化可用账号和最小权限')
    )
    for ($i = 0; $i -lt $matrixRows.Count; $i++) {
        Write-RowAt $matrix ($i + 1) $matrixRows[$i]
    }
    $matrix.Rows.Item(1).Font.Bold = $true
    $matrix.Rows.Item(1).Interior.ColorIndex = 37

    foreach ($ws in @($wsAll, $wsP0, $wsSeq, $wsData, $wsState, $wsTodo, $matrix)) {
        Format-Sheet $ws
    }
    $wb.Worksheets.Item('说明').Activate()
    $wb.Save()
    $wb.Close($true)
}
finally {
    $excel.Quit()
}

$excel2 = New-Object -ComObject Excel.Application
$excel2.Visible = $false
$excel2.DisplayAlerts = $false
try {
    $wb2 = $excel2.Workbooks.Open($Output)
    Write-Output 'excel_open_ok=True'
    Write-Output ('sheets=' + $wb2.Worksheets.Count)
    Write-Output ('all_cases_rows=' + $wb2.Worksheets.Item('全流程闭环用例').UsedRange.Rows.Count)
    Write-Output ('p0_rows=' + $wb2.Worksheets.Item('P0主链路用例').UsedRange.Rows.Count)
    Write-Output ('matrix_rows=' + $wb2.Worksheets.Item('外来订单分支矩阵').UsedRange.Rows.Count)
    $wb2.Close($false)
}
finally {
    $excel2.Quit()
}

Write-Output $Output
