# open-api-device-operations Specification

## ADDED Requirements

### Requirement: 设备切网开放接口

系统 SHALL 提供 `POST /api/open/v1/devices/switch-card` 接口，允许代理对多卡设备执行切网操作（切换到指定 ICCID）。请求 body MUST 包含 `device_no`（虚拟号或 IMEI）和 `iccid`（目标卡 ICCID）。

系统 MUST 校验该设备的 `shop_id` 在当前代理管辖店铺范围内，否则返回 `CodeForbidden`。权限校验通过后，系统 MUST 复用 `device.Service.GatewaySwitchCard` 执行切网，底层调用 Gateway 接口。

响应 data MUST 为空对象（操作成功即可）。

#### Scenario: 切网成功

- **WHEN** 代理对管辖范围内的多卡设备传入有效目标 ICCID 执行切网
- **THEN** 系统调用 Gateway 切换设备到目标 ICCID，返回成功

#### Scenario: 无权限设备切网

- **WHEN** 代理对不在自己管辖店铺范围内的设备执行切网
- **THEN** 系统返回 `CodeForbidden`，不调用 Gateway

#### Scenario: 设备标识符不存在

- **WHEN** 代理传入的 `device_no` 无法解析为任何设备
- **THEN** 系统返回 `CodeForbidden`，消息为"无权限操作该资源或资源不存在"

---

### Requirement: 设备重启开放接口

系统 SHALL 提供 `POST /api/open/v1/devices/reboot` 接口，允许代理对设备执行重启操作。请求 body MUST 包含 `device_no`（虚拟号或 IMEI）。

系统 MUST 校验该设备的 `shop_id` 在当前代理管辖店铺范围内，否则返回 `CodeForbidden`。权限校验通过后，系统 MUST 复用 `device.Service.GatewayRebootDevice` 执行重启。

响应 data MUST 为空对象。

#### Scenario: 重启成功

- **WHEN** 代理对管辖范围内的设备执行重启
- **THEN** 系统调用 Gateway 重启设备，返回成功

#### Scenario: 无权限设备重启

- **WHEN** 代理对不在自己管辖店铺范围内的设备执行重启
- **THEN** 系统返回 `CodeForbidden`，不调用 Gateway

---

### Requirement: 设备恢复出厂开放接口

系统 SHALL 提供 `POST /api/open/v1/devices/reset` 接口，允许代理对设备执行恢复出厂设置操作。请求 body MUST 包含 `device_no`（虚拟号或 IMEI）。

系统 MUST 校验该设备的 `shop_id` 在当前代理管辖店铺范围内，否则返回 `CodeForbidden`。权限校验通过后，系统 MUST 复用 `device.Service.GatewayResetDevice` 执行恢复出厂。

响应 data MUST 为空对象。

#### Scenario: 恢复出厂成功

- **WHEN** 代理对管辖范围内的设备执行恢复出厂
- **THEN** 系统调用 Gateway 恢复设备出厂设置，返回成功

#### Scenario: 无权限设备恢复出厂

- **WHEN** 代理对不在自己管辖店铺范围内的设备执行恢复出厂
- **THEN** 系统返回 `CodeForbidden`，不调用 Gateway

---

### Requirement: 设备操作开放接口权限校验

系统 SHALL 对所有设备操作开放接口（switch-card、reboot、reset）统一执行权限校验。校验逻辑 MUST 为：通过设备标识符（虚拟号或 IMEI）查询设备，若设备不存在或 `device.ShopID` 不在当前代理的 `SubordinateShopIDs` 中，则返回 `CodeForbidden`，消息为"无权限操作该资源或资源不存在"，不区分"不存在"与"无权限"以防止信息泄露。

#### Scenario: 设备属于代理管辖店铺

- **WHEN** 设备的 `shop_id` 在代理的 `SubordinateShopIDs` 中
- **THEN** 系统允许执行操作

#### Scenario: 设备不属于代理管辖店铺

- **WHEN** 设备的 `shop_id` 不在代理的 `SubordinateShopIDs` 中
- **THEN** 系统返回 `CodeForbidden`，消息为"无权限操作该资源或资源不存在"

#### Scenario: 设备 shop_id 为 NULL（平台库存）

- **WHEN** 设备的 `shop_id` 为 NULL（平台库存设备）
- **THEN** 系统返回 `CodeForbidden`，代理无权操作平台库存设备
