## ADDED Requirements

### Requirement: 卡授权预检
系统 SHALL 提供卡授权预检接口，检查待授权卡的状态和设备绑定情况。

**接口**：`POST /api/admin/enterprises/:id/allocate-cards/preview`

**请求参数**：
- `id`：企业ID（路径参数）
- `iccids`：需要授权的 ICCID 列表

**响应字段**：
- `standalone_cards`：可直接授权的卡（未绑定设备）
- `device_bundles`：需要整体授权的设备包（含设备下所有卡）
- `failed_items`：失败的卡（不存在/无权限）
- `summary`：汇总信息（standalone_card_count, device_count, device_card_count, total_card_count, failed_count）

#### Scenario: 预检未绑定设备的卡
- **WHEN** 预检的卡未绑定设备
- **THEN** 卡出现在 `standalone_cards` 列表中
- **AND** 可以单独授权

#### Scenario: 预检绑定设备的卡
- **WHEN** 预检的卡绑定了设备
- **THEN** 返回设备包信息（包含设备下所有卡）
- **AND** 标记触发卡（用户选择的卡）
- **AND** 标记连带卡（同设备的其他卡）

#### Scenario: 预检不存在或无权限的卡
- **WHEN** 预检的卡不存在或当前用户无权限
- **THEN** 卡出现在 `failed_items` 列表中
- **AND** 包含失败原因

---

### Requirement: 授权卡给企业
系统 SHALL 提供将卡授权给企业的接口，不改变卡的归属。

**接口**：`POST /api/admin/enterprises/:id/allocate-cards`

**请求参数**：
- `id`：企业ID（路径参数）
- `iccids`：需要授权的 ICCID 列表
- `confirm_device_bundles`：确认整体授权设备下所有卡（必须为 true）

**响应字段**：
- `success_count`：成功数量
- `fail_count`：失败数量
- `failed_items`：失败详情
- `allocated_devices`：连带授权的设备列表

#### Scenario: 授权独立卡
- **WHEN** 授权未绑定设备的卡
- **THEN** 创建授权记录（enterprise_id, iot_card_id, status=1）
- **AND** 卡的 owner 不变（仍属于代理商）

#### Scenario: 授权绑定设备的卡
- **WHEN** 授权绑定设备的卡
- **THEN** 设备下所有卡一起授权
- **AND** 返回连带授权的设备信息

#### Scenario: 必须确认整体授权
- **WHEN** `confirm_device_bundles` 不为 true 且存在设备包
- **THEN** 返回错误：请确认整体授权设备下所有卡

#### Scenario: 重复授权
- **WHEN** 卡已授权给该企业
- **THEN** 跳过该卡（幂等）
- **AND** 不计入失败

---

### Requirement: 回收卡授权
系统 SHALL 提供回收企业卡授权的接口。

**接口**：`POST /api/admin/enterprises/:id/recall-cards`

**请求参数**：
- `id`：企业ID（路径参数）
- `iccids`：需要回收授权的 ICCID 列表

**响应字段**：
- `success_count`、`fail_count`、`failed_items`
- `recalled_devices`：连带回收的设备列表

#### Scenario: 回收授权
- **WHEN** 回收企业的卡授权
- **THEN** 更新授权记录状态为已回收（status=0）
- **AND** 卡的 owner 不变

#### Scenario: 设备卡整体回收
- **WHEN** 回收的卡绑定了设备
- **THEN** 设备下所有卡的授权一起回收

#### Scenario: 卡未授权给该企业
- **WHEN** 卡未授权给该企业
- **THEN** 返回失败：该卡未授权给此企业

---

### Requirement: 企业卡列表查询
系统 SHALL 提供查询企业被授权卡的接口。

**接口**：`GET /api/admin/enterprises/:id/cards`

**请求参数**：
- `id`：企业ID（路径参数）
- `page`、`page_size`：分页
- `status`：卡状态
- `carrier_id`：运营商ID
- `iccid`：ICCID（模糊查询）
- `device_no`：设备号（模糊查询）

**响应字段**：
- 卡信息（id, iccid, msisdn, device_id, device_no）
- 运营商信息（carrier_id, carrier_name）
- 套餐信息（package_id, package_name）
- 状态信息（status, status_name, network_status, network_status_name）

#### Scenario: 查询企业被授权的卡
- **WHEN** 查询企业卡列表
- **THEN** 通过授权表过滤，只返回被授权且有效的卡

#### Scenario: 关联查询设备信息
- **WHEN** 返回卡列表
- **THEN** 如果卡绑定设备，返回设备号

---

### Requirement: 企业操作卡-停机
系统 SHALL 允许企业对被授权的卡执行停机操作。

**接口**：`POST /api/admin/enterprises/:id/cards/:card_id/suspend`

#### Scenario: 停机被授权的卡
- **WHEN** 企业对被授权的卡执行停机
- **THEN** 验证卡已授权给该企业
- **AND** 调用运营商接口执行停机
- **AND** 更新卡的 network_status = 0

#### Scenario: 操作未授权的卡
- **WHEN** 企业尝试操作未授权的卡
- **THEN** 返回权限错误

---

### Requirement: 企业操作卡-复机
系统 SHALL 允许企业对被授权的卡执行复机操作。

**接口**：`POST /api/admin/enterprises/:id/cards/:card_id/resume`

#### Scenario: 复机被授权的卡
- **WHEN** 企业对被授权的卡执行复机
- **THEN** 验证卡已授权给该企业
- **AND** 调用运营商接口执行复机
- **AND** 更新卡的 network_status = 1

---

### Requirement: 企业用户数据权限过滤
系统 SHALL 在 GORM Callback 中对企业用户查询 IotCard 做特殊处理。

#### Scenario: 企业用户查询卡
- **WHEN** 企业用户查询 IotCard 表
- **THEN** 自动过滤：只返回被授权且有效的卡
- **AND** 过滤条件：`id IN (SELECT iot_card_id FROM tb_enterprise_card_authorization WHERE enterprise_id = ? AND status = 1)`

#### Scenario: 企业用户查询设备
- **WHEN** 企业用户查询设备
- **THEN** 通过卡的授权间接查询
- **AND** 只返回绑定了被授权卡的设备
