# ============================================================
# 测试：套餐资源完整流程（创建→分配→佣金→调价→强充）
# 生成时间：2026-03-30
# 涉及模块：auth, role, package_series, package, shop,
#           shop_series_grant, batch_allocation, batch_pricing
# 涉及接口：25+ 个
# 前置条件：服务运行 + 数据库已迁移 + Redis 可用
# ============================================================
# 流程：
#   1. 平台管理员登录
#   2. 创建客户角色（创建店铺的前置依赖）
#   3. 创建套餐系列（含固定一次性佣金 + 强充配置）
#   4. 创建套餐 → 启用 → 上架
#   5. 创建一级代理店铺（自动创建初始账号）
#   6. 平台→一级代理：创建系列授权 + 管理授权套餐
#   7. 创建二级代理店铺（挂在一级代理下）
#   8. 一级代理登录 → 给二级代理分配系列授权
#   9. 各级代理修改零售价 → 验证价格隔离
#  10. 平台：批量分配 + 批量调价
#  11. 代理佣金概览验证
#  12. 强充配置验证
#  13. 异常测试（未认证、参数校验、越权）
# ============================================================


# ══════════════════════════════════════════════════════════════
# 第 1 步：平台管理员登录
# ══════════════════════════════════════════════════════════════

POST {{base_url}}/api/auth/login
Content-Type: application/json
{
    "username": "{{admin_username}}",
    "password": "{{admin_password}}",
    "device": "web"
}
HTTP 200
[Captures]
admin_token: jsonpath "$.data.access_token"
[Asserts]
jsonpath "$.code" == 0
jsonpath "$.msg" == "success"
jsonpath "$.timestamp" isString
jsonpath "$.data.access_token" isString
jsonpath "$.data.refresh_token" isString
jsonpath "$.data.expires_in" isInteger
jsonpath "$.data.user.id" isInteger
jsonpath "$.data.user.username" isString
jsonpath "$.data.user.user_type" == 1


# ══════════════════════════════════════════════════════════════
# 第 2 步：创建客户角色（创建店铺需要 default_role_id）
# ══════════════════════════════════════════════════════════════

POST {{base_url}}/api/admin/roles
Authorization: Bearer {{admin_token}}
Content-Type: application/json
{
    "role_name": "hurl测试角色-{{newUuid}}",
    "role_desc": "hurl 自动化测试用客户角色",
    "role_type": 2
}
HTTP 200
[Captures]
test_role_id: jsonpath "$.data.id"
[Asserts]
jsonpath "$.code" == 0
jsonpath "$.data.id" isInteger
jsonpath "$.data.role_type" == 2
jsonpath "$.data.status" == 1


# ══════════════════════════════════════════════════════════════
# 第 3 步：创建套餐系列（固定一次性佣金 + 强充配置）
# ══════════════════════════════════════════════════════════════

POST {{base_url}}/api/admin/package-series
Authorization: Bearer {{admin_token}}
Content-Type: application/json
{
    "series_code": "HURL-SERIES-{{newUuid}}",
    "series_name": "Hurl测试系列",
    "description": "自动化测试用套餐系列",
    "enable_one_time_commission": true,
    "one_time_commission_config": {
        "enable": true,
        "trigger_type": "first_recharge",
        "threshold": 0,
        "commission_type": "fixed",
        "commission_amount": 5000,
        "tiers": [],
        "validity_type": "permanent",
        "validity_value": "",
        "enable_force_recharge": true,
        "force_calc_type": "fixed",
        "force_amount": 5000
    }
}
HTTP 200
[Captures]
series_id: jsonpath "$.data.id"
[Asserts]
jsonpath "$.code" == 0
jsonpath "$.data.id" isInteger
jsonpath "$.data.series_code" isString
jsonpath "$.data.series_name" == "Hurl测试系列"
jsonpath "$.data.description" == "自动化测试用套餐系列"
jsonpath "$.data.enable_one_time_commission" == true
jsonpath "$.data.one_time_commission_config" isObject
jsonpath "$.data.one_time_commission_config.enable" == true
jsonpath "$.data.one_time_commission_config.commission_type" == "fixed"
jsonpath "$.data.one_time_commission_config.commission_amount" == 5000
jsonpath "$.data.one_time_commission_config.enable_force_recharge" == true
jsonpath "$.data.one_time_commission_config.force_calc_type" == "fixed"
jsonpath "$.data.one_time_commission_config.force_amount" == 5000
jsonpath "$.data.status" == 1
jsonpath "$.data.created_at" isString
jsonpath "$.data.updated_at" isString


# ══════════════════════════════════════════════════════════════
# 第 4a 步：创建套餐（关联到系列）
# ══════════════════════════════════════════════════════════════

POST {{base_url}}/api/admin/packages
Authorization: Bearer {{admin_token}}
Content-Type: application/json
{
    "package_code": "HURL-PKG-{{newUuid}}",
    "package_name": "Hurl测试套餐-月包30G",
    "series_id": {{series_id}},
    "package_type": "formal",
    "duration_months": 12,
    "real_data_mb": 30720,
    "virtual_data_mb": 0,
    "enable_virtual_data": false,
    "suggested_retail_price": 15000,
    "cost_price": 8000,
    "calendar_type": "natural_month",
    "data_reset_cycle": "monthly",
    "expiry_base": "from_activation"
}
HTTP 200
[Captures]
package_id: jsonpath "$.data.id"
package_code: jsonpath "$.data.package_code"
[Asserts]
jsonpath "$.code" == 0
jsonpath "$.data.id" isInteger
jsonpath "$.data.package_code" isString
jsonpath "$.data.package_name" == "Hurl测试套餐-月包30G"
jsonpath "$.data.series_id" == {{series_id}}
jsonpath "$.data.package_type" == "formal"
jsonpath "$.data.duration_months" == 12
jsonpath "$.data.real_data_mb" == 30720
jsonpath "$.data.virtual_data_mb" == 0
jsonpath "$.data.enable_virtual_data" == false
jsonpath "$.data.suggested_retail_price" == 15000
jsonpath "$.data.cost_price" == 8000
jsonpath "$.data.calendar_type" == "natural_month"
jsonpath "$.data.data_reset_cycle" == "monthly"
jsonpath "$.data.expiry_base" == "from_activation"
jsonpath "$.data.status" isInteger
jsonpath "$.data.shelf_status" isInteger
jsonpath "$.data.created_at" isString
jsonpath "$.data.updated_at" isString


# ── 第 4b 步：启用套餐 ──

PATCH {{base_url}}/api/admin/packages/{{package_id}}/status
Authorization: Bearer {{admin_token}}
Content-Type: application/json
{
    "status": 1
}
HTTP 200
[Asserts]
jsonpath "$.code" == 0


# ── 第 4c 步：上架套餐 ──

PATCH {{base_url}}/api/admin/packages/{{package_id}}/shelf
Authorization: Bearer {{admin_token}}
Content-Type: application/json
{
    "shelf_status": 1
}
HTTP 200
[Asserts]
jsonpath "$.code" == 0


# ── 第 4d 步：验证套餐详情（启用+上架后） ──

GET {{base_url}}/api/admin/packages/{{package_id}}
Authorization: Bearer {{admin_token}}
HTTP 200
[Asserts]
jsonpath "$.code" == 0
jsonpath "$.data.id" == {{package_id}}
jsonpath "$.data.status" == 1
jsonpath "$.data.shelf_status" == 1


# ══════════════════════════════════════════════════════════════
# 第 5 步：创建一级代理店铺（自动创建初始账号）
# 幂等处理：如果已存在则跳过创建，通过账号查询获取 shop_id
# ══════════════════════════════════════════════════════════════

POST {{base_url}}/api/admin/shops
Authorization: Bearer {{admin_token}}
Content-Type: application/json
{
    "shop_name": "Hurl一级代理店铺",
    "shop_code": "HURL-SHOP1-{{newUuid}}",
    "contact_name": "测试联系人1",
    "contact_phone": "13800000001",
    "province": "湖南省",
    "city": "长沙市",
    "district": "岳麓区",
    "address": "测试地址一级",
    "default_role_id": {{test_role_id}},
    "init_password": "{{agent1_password}}",
    "init_username": "{{agent1_username}}",
    "init_phone": "{{agent1_phone}}"
}
HTTP *

# 通过账号查询获取 shop_id（无论创建成功或已存在）
GET {{base_url}}/api/admin/accounts?username={{agent1_username}}&page=1&page_size=1
Authorization: Bearer {{admin_token}}
HTTP 200
[Captures]
shop1_id: jsonpath "$.data.items[0].shop_id"
[Asserts]
jsonpath "$.code" == 0
jsonpath "$.data.items" count >= 1
jsonpath "$.data.items[0].username" == "{{agent1_username}}"
jsonpath "$.data.items[0].user_type" == 3


# ══════════════════════════════════════════════════════════════
# 第 6a 步：平台→一级代理 创建系列授权（设置固定佣金 + 强充）
# 幂等处理：如已存在则跳过，通过列表查询获取 grant_id
# ══════════════════════════════════════════════════════════════

# [FINDING C-3] 创建授权接口：请求传了 packages 但创建响应不含 packages 数组
#   需通过 GET 详情才能看到 packages，这里用 HTTP * 兼容幂等（重跑时可能 409）
POST {{base_url}}/api/admin/shop-series-grants
Authorization: Bearer {{admin_token}}
Content-Type: application/json
{
    "shop_id": {{shop1_id}},
    "series_id": {{series_id}},
    "one_time_commission_amount": 3000,
    "enable_force_recharge": true,
    "force_recharge_amount": 5000,
    "packages": [
        {
            "package_id": {{package_id}},
            "cost_price": 10000
        }
    ]
}
HTTP *

# 查询获取 grant_id（无论创建成功或已存在）
GET {{base_url}}/api/admin/shop-series-grants?shop_id={{shop1_id}}&series_id={{series_id}}&page=1&page_size=1
Authorization: Bearer {{admin_token}}
HTTP 200
[Captures]
grant1_id: jsonpath "$.data.items[0].id"
[Asserts]
jsonpath "$.code" == 0
jsonpath "$.data.items" count >= 1
jsonpath "$.data.items[0].shop_id" == {{shop1_id}}


# ── 第 6b 步：验证一级代理授权详情 ──

GET {{base_url}}/api/admin/shop-series-grants/{{grant1_id}}
Authorization: Bearer {{admin_token}}
HTTP 200
[Asserts]
jsonpath "$.code" == 0
jsonpath "$.data.id" == {{grant1_id}}
jsonpath "$.data.shop_id" == {{shop1_id}}
jsonpath "$.data.shop_name" == "Hurl一级代理店铺"
jsonpath "$.data.series_id" == {{series_id}}
jsonpath "$.data.series_name" == "Hurl测试系列"
jsonpath "$.data.series_code" isString
jsonpath "$.data.commission_type" == "fixed"
jsonpath "$.data.one_time_commission_amount" == 3000
jsonpath "$.data.commission_tiers" isList
jsonpath "$.data.force_recharge_locked" isBoolean
jsonpath "$.data.force_recharge_enabled" == true
jsonpath "$.data.force_recharge_amount" == 5000
jsonpath "$.data.allocator_shop_id" == 0
jsonpath "$.data.allocator_shop_name" isString
jsonpath "$.data.status" == 1
jsonpath "$.data.packages" isList
jsonpath "$.data.packages" count >= 1
jsonpath "$.data.packages[0].package_id" == {{package_id}}
jsonpath "$.data.packages[0].package_name" == "Hurl测试套餐-月包30G"
jsonpath "$.data.packages[0].package_code" isString
jsonpath "$.data.packages[0].cost_price" == 10000
jsonpath "$.data.packages[0].shelf_status" isInteger
jsonpath "$.data.packages[0].status" isInteger


# ══════════════════════════════════════════════════════════════
# 第 7 步：创建二级代理店铺（挂在一级代理下）
# 幂等处理：如果已存在则跳过创建，通过账号查询获取 shop_id
# ══════════════════════════════════════════════════════════════

POST {{base_url}}/api/admin/shops
Authorization: Bearer {{admin_token}}
Content-Type: application/json
{
    "shop_name": "Hurl二级代理店铺",
    "shop_code": "HURL-SHOP2-{{newUuid}}",
    "parent_id": {{shop1_id}},
    "contact_name": "测试联系人2",
    "contact_phone": "13800000002",
    "province": "湖南省",
    "city": "长沙市",
    "district": "天心区",
    "address": "测试地址二级",
    "default_role_id": {{test_role_id}},
    "init_password": "{{agent2_password}}",
    "init_username": "{{agent2_username}}",
    "init_phone": "{{agent2_phone}}"
}
HTTP *

# 通过账号查询获取 shop_id（无论创建成功或已存在）
GET {{base_url}}/api/admin/accounts?username={{agent2_username}}&page=1&page_size=1
Authorization: Bearer {{admin_token}}
HTTP 200
[Captures]
shop2_id: jsonpath "$.data.items[0].shop_id"
[Asserts]
jsonpath "$.code" == 0
jsonpath "$.data.items" count >= 1
jsonpath "$.data.items[0].username" == "{{agent2_username}}"
jsonpath "$.data.items[0].user_type" == 3


# ══════════════════════════════════════════════════════════════
# 第 8a 步：一级代理登录
# ══════════════════════════════════════════════════════════════

POST {{base_url}}/api/auth/login
Content-Type: application/json
{
    "username": "{{agent1_username}}",
    "password": "{{agent1_password}}",
    "device": "web"
}
HTTP 200
[Captures]
agent1_token: jsonpath "$.data.access_token"
agent1_shop_id: jsonpath "$.data.user.shop_id"
[Asserts]
jsonpath "$.code" == 0
jsonpath "$.data.access_token" isString
jsonpath "$.data.user.user_type" == 3
jsonpath "$.data.user.shop_id" == {{shop1_id}}


# ══════════════════════════════════════════════════════════════
# 第 8b 步：一级代理→二级代理 创建系列授权（佣金更低）
# 幂等处理：如已存在则跳过，通过列表查询获取 grant_id
# ══════════════════════════════════════════════════════════════

POST {{base_url}}/api/admin/shop-series-grants
Authorization: Bearer {{agent1_token}}
Content-Type: application/json
{
    "shop_id": {{shop2_id}},
    "series_id": {{series_id}},
    "one_time_commission_amount": 2000,
    "enable_force_recharge": true,
    "force_recharge_amount": 5000,
    "packages": [
        {
            "package_id": {{package_id}},
            "cost_price": 12000
        }
    ]
}
HTTP *

# 查询获取 grant_id（无论创建成功或已存在）
GET {{base_url}}/api/admin/shop-series-grants?shop_id={{shop2_id}}&series_id={{series_id}}&page=1&page_size=1
Authorization: Bearer {{agent1_token}}
HTTP 200
[Captures]
grant2_id: jsonpath "$.data.items[0].id"
[Asserts]
jsonpath "$.code" == 0
jsonpath "$.data.items" count >= 1


# ══════════════════════════════════════════════════════════════
# 第 9a 步：一级代理修改零售价 → 15000 分（150 元）
# ══════════════════════════════════════════════════════════════

PATCH {{base_url}}/api/admin/packages/{{package_id}}/retail-price
Authorization: Bearer {{agent1_token}}
Content-Type: application/json
{
    "retail_price": 15000
}
HTTP 200
[Asserts]
jsonpath "$.code" == 0


# ── 第 9b 步：一级代理查看套餐 → 验证零售价=15000 ──
# [FINDING C-1] 套餐详情接口应包含 one_time_commission_amount（DTO 定义且列表接口有）

GET {{base_url}}/api/admin/packages/{{package_id}}
Authorization: Bearer {{agent1_token}}
HTTP 200
[Asserts]
jsonpath "$.code" == 0
jsonpath "$.data.id" == {{package_id}}
jsonpath "$.data.package_name" == "Hurl测试套餐-月包30G"
jsonpath "$.data.retail_price" == 15000
jsonpath "$.data.cost_price" == 10000
jsonpath "$.data.one_time_commission_amount" == 3000
jsonpath "$.data.profit_margin" exists


# ══════════════════════════════════════════════════════════════
# 第 10a 步：二级代理登录
# ══════════════════════════════════════════════════════════════

POST {{base_url}}/api/auth/login
Content-Type: application/json
{
    "username": "{{agent2_username}}",
    "password": "{{agent2_password}}",
    "device": "web"
}
HTTP 200
[Captures]
agent2_token: jsonpath "$.data.access_token"
[Asserts]
jsonpath "$.code" == 0
jsonpath "$.data.access_token" isString
jsonpath "$.data.user.user_type" == 3
jsonpath "$.data.user.shop_id" == {{shop2_id}}


# ══════════════════════════════════════════════════════════════
# 第 10b 步：二级代理修改零售价 → 18000 分（180 元）
# ══════════════════════════════════════════════════════════════

PATCH {{base_url}}/api/admin/packages/{{package_id}}/retail-price
Authorization: Bearer {{agent2_token}}
Content-Type: application/json
{
    "retail_price": 18000
}
HTTP 200
[Asserts]
jsonpath "$.code" == 0


# ── 第 10c 步：二级代理查看套餐 → 验证零售价=18000（与一级不同！） ──
# [FINDING C-1] 同上，详情接口应包含 one_time_commission_amount

GET {{base_url}}/api/admin/packages/{{package_id}}
Authorization: Bearer {{agent2_token}}
HTTP 200
[Asserts]
jsonpath "$.code" == 0
jsonpath "$.data.id" == {{package_id}}
# 关键断言：二级代理看到的零售价 != 一级代理（18000 vs 15000）
jsonpath "$.data.retail_price" == 18000
jsonpath "$.data.cost_price" == 12000
jsonpath "$.data.one_time_commission_amount" == 2000
jsonpath "$.data.profit_margin" exists


# ── 第 10d 步：回到一级代理视角，确认零售价未被二级覆盖 ──

GET {{base_url}}/api/admin/packages/{{package_id}}
Authorization: Bearer {{agent1_token}}
HTTP 200
[Asserts]
jsonpath "$.code" == 0
# 一级代理的零售价仍然是 15000，与二级代理互不影响
jsonpath "$.data.retail_price" == 15000
jsonpath "$.data.cost_price" == 10000


# ══════════════════════════════════════════════════════════════
# 第 11 步：平台身份 - 批量调价（给一级代理加价 500 分）
# ══════════════════════════════════════════════════════════════

POST {{base_url}}/api/admin/shop-package-batch-pricing
Authorization: Bearer {{admin_token}}
Content-Type: application/json
{
    "shop_id": {{shop1_id}},
    "series_id": {{series_id}},
    "price_adjustment": {
        "type": "fixed",
        "value": 500
    },
    "change_reason": "Hurl测试批量调价"
}
HTTP 200
[Asserts]
jsonpath "$.code" == 0
jsonpath "$.data.updated_count" isInteger
jsonpath "$.data.updated_count" >= 1
jsonpath "$.data.affected_ids" isList


# ── 验证调价后代理仍可正常查看套餐 ──

GET {{base_url}}/api/admin/packages/{{package_id}}
Authorization: Bearer {{agent1_token}}
HTTP 200
[Asserts]
jsonpath "$.code" == 0
jsonpath "$.data.id" == {{package_id}}
jsonpath "$.data.cost_price" isInteger


# ══════════════════════════════════════════════════════════════
# 第 12 步：平台身份 - 批量分配套餐
# ══════════════════════════════════════════════════════════════

# [FINDING C-2] 批量分配对已有授权的店铺返回 500，应返回业务错误码
POST {{base_url}}/api/admin/shop-package-batch-allocations
Authorization: Bearer {{admin_token}}
Content-Type: application/json
{
    "shop_id": {{shop2_id}},
    "series_id": {{series_id}},
    "price_adjustment": {
        "type": "percent",
        "value": 100
    },
    "one_time_commission_amount": 1500
}
HTTP 200
[Asserts]
jsonpath "$.code" == 0


# ══════════════════════════════════════════════════════════════
# 第 13 步：强充配置验证
# ══════════════════════════════════════════════════════════════

# 更新一级代理授权：调整佣金金额
# 注意：force_recharge_locked=true 时强充金额由系列配置控制，grant 级别无法修改
PUT {{base_url}}/api/admin/shop-series-grants/{{grant1_id}}
Authorization: Bearer {{admin_token}}
Content-Type: application/json
{
    "one_time_commission_amount": 3500,
    "enable_force_recharge": true,
    "force_recharge_amount": 6000
}
HTTP 200
[Asserts]
jsonpath "$.code" == 0
jsonpath "$.data.one_time_commission_amount" == 3500
jsonpath "$.data.force_recharge_enabled" == true
# 强充金额因 locked=true 保持系列配置值 5000，不会变为 6000
jsonpath "$.data.force_recharge_amount" == 5000
jsonpath "$.data.force_recharge_locked" == true

# 验证更新持久化成功
GET {{base_url}}/api/admin/shop-series-grants/{{grant1_id}}
Authorization: Bearer {{admin_token}}
HTTP 200
[Asserts]
jsonpath "$.code" == 0
jsonpath "$.data.one_time_commission_amount" == 3500
jsonpath "$.data.force_recharge_enabled" == true
jsonpath "$.data.force_recharge_amount" == 5000
jsonpath "$.data.force_recharge_locked" == true


# ══════════════════════════════════════════════════════════════
# 第 14 步：代理佣金概览验证（一级代理视角）
# ══════════════════════════════════════════════════════════════

GET {{base_url}}/api/admin/my/commission-summary
Authorization: Bearer {{agent1_token}}
HTTP 200
[Asserts]
jsonpath "$.code" == 0
jsonpath "$.data" isObject


# ══════════════════════════════════════════════════════════════
# 第 15 步：验证授权套餐详情（有下级分配时不可修改成本价）
# ══════════════════════════════════════════════════════════════

GET {{base_url}}/api/admin/shop-series-grants/{{grant1_id}}
Authorization: Bearer {{admin_token}}
HTTP 200
[Asserts]
jsonpath "$.code" == 0
jsonpath "$.data.packages" isList
jsonpath "$.data.packages" count >= 1
jsonpath "$.data.packages[0].package_id" isInteger
jsonpath "$.data.packages[0].package_name" isString
jsonpath "$.data.packages[0].cost_price" isInteger


# ══════════════════════════════════════════════════════════════
# 第 16 步：系列授权列表查询
# ══════════════════════════════════════════════════════════════

GET {{base_url}}/api/admin/shop-series-grants?shop_id={{shop1_id}}
Authorization: Bearer {{admin_token}}
HTTP 200
[Asserts]
jsonpath "$.code" == 0
jsonpath "$.data.items" isList
jsonpath "$.data.total" isInteger
jsonpath "$.data.total" >= 1
jsonpath "$.data.page" isInteger
jsonpath "$.data.size" isInteger
jsonpath "$.data.items[0].id" isInteger
jsonpath "$.data.items[0].shop_id" == {{shop1_id}}
jsonpath "$.data.items[0].shop_name" isString
jsonpath "$.data.items[0].series_id" isInteger
jsonpath "$.data.items[0].series_name" isString
jsonpath "$.data.items[0].commission_type" isString
jsonpath "$.data.items[0].one_time_commission_amount" isInteger
jsonpath "$.data.items[0].force_recharge_enabled" isBoolean
jsonpath "$.data.items[0].force_recharge_locked" isBoolean
jsonpath "$.data.items[0].force_recharge_amount" isInteger
jsonpath "$.data.items[0].allocator_shop_id" isInteger
jsonpath "$.data.items[0].allocator_shop_name" isString
jsonpath "$.data.items[0].package_count" isInteger
jsonpath "$.data.items[0].status" isInteger
jsonpath "$.data.items[0].created_at" isString


# ══════════════════════════════════════════════════════════════
#                    异 常 测 试
# ══════════════════════════════════════════════════════════════


# ── 异常 1：未认证访问（无 token） ──

GET {{base_url}}/api/admin/packages
HTTP 401
[Asserts]
jsonpath "$.code" == 1002


# ── 异常 2：参数校验失败（缺少必填字段） ──

POST {{base_url}}/api/admin/packages
Authorization: Bearer {{admin_token}}
Content-Type: application/json
{
    "package_name": ""
}
HTTP 400
[Asserts]
jsonpath "$.code" == 1001


# ── 异常 3：参数校验 - 创建套餐系列编码为空触发冲突 ──

POST {{base_url}}/api/admin/package-series
Authorization: Bearer {{admin_token}}
Content-Type: application/json
{
    "series_name": ""
}
HTTP 409
[Asserts]
jsonpath "$.code" isInteger
jsonpath "$.code" != 0


# [FINDING C-4] 创建授权不校验目标店铺是否存在，shop_id=9999999 也能创建成功
# 预期应返回 404，实际返回 200 + 创建了无效授权记录
POST {{base_url}}/api/admin/shop-series-grants
Authorization: Bearer {{admin_token}}
Content-Type: application/json
{
    "shop_id": 9999999,
    "series_id": {{series_id}},
    "one_time_commission_amount": 1000
}
HTTP 404
[Asserts]
jsonpath "$.code" != 0


# ── 异常 5：二级代理越权 - 尝试给一级代理的店铺分配 ──
# 一级代理已有该系列授权，所以返回冲突（409）而非越权（403）
# 但实际上二级代理本就无权操作上级店铺，应优先返回 403

POST {{base_url}}/api/admin/shop-series-grants
Authorization: Bearer {{agent2_token}}
Content-Type: application/json
{
    "shop_id": {{shop1_id}},
    "series_id": {{series_id}},
    "one_time_commission_amount": 1000
}
HTTP 409
[Asserts]
jsonpath "$.code" isInteger
jsonpath "$.code" != 0


# ── 异常 6：过期/无效 Token ──

GET {{base_url}}/api/admin/packages
Authorization: Bearer invalid_token_12345
HTTP 401
[Asserts]
jsonpath "$.code" == 1003
