# open-api-device-traffic Specification

## ADDED Requirements

### Requirement: 设备套餐内流量查询开放接口

系统 SHALL 提供 `GET /api/open/v1/devices/traffic` 接口，按设备标识符查询设备级套餐内流量。请求参数 `device_no` MUST 支持虚拟号或 IMEI 中任一种可解析为设备的标识。系统 MUST 校验该设备的 `shop_id` 在当前代理管辖店铺范围内（`device.ShopID IN SubordinateShopIDs`），否则返回 `CodeForbidden`。

接口 MUST 只返回 `usage_type='device'` 的套餐使用记录，不返回单卡套餐信息。

响应 data MUST 包含：
- `device_no`：请求传入的设备标识符
- `active_total_flow_mb`：当前生效套餐总流量汇总
- `active_used_flow_mb`：当前生效套餐已用流量汇总
- `active_remaining_flow_mb`：当前生效套餐剩余流量汇总
- `active_expires_at`：当前生效套餐中最晚过期时间
- `active_packages`：当前生效套餐列表
- `pending_packages`：待生效套餐列表

流量口径 MUST 与 `/cards/traffic` 保持一致：
- 总流量使用 `data_limit_mb`
- 已用流量使用 `min(data_usage_mb * display_gain_ratio_snapshot, data_limit_mb)`
- 剩余流量使用 `max(data_limit_mb - used_flow_mb, 0)`
- 响应 MUST NOT 包含虚流量、停机阈值等内部字段

`active_packages` 每项 MUST 包含：`package_code`、`total_flow_mb`、`used_flow_mb`、`remaining_flow_mb`、`expires_at`、`start_at`、`package_name`、`series_name`、`package_type`、`package_type_name`。

`pending_packages` 每项 MUST 包含：`package_code`、`total_flow_mb`、`package_name`、`series_name`、`package_type`、`package_type_name`、`valid_days`、`priority`。

#### Scenario: 查询有生效套餐的设备流量

- **WHEN** 代理查询自己管辖范围内的设备，且该设备存在生效中的设备级套餐
- **THEN** 系统返回生效套餐列表、总流量、已用流量、剩余流量和最晚过期时间

#### Scenario: 查询待生效套餐

- **WHEN** 代理查询设备流量，且该设备存在待生效的设备级套餐
- **THEN** 系统在 `pending_packages` 中返回套餐编码、真总流量、套餐名称、系列名称、套餐类型、有效天数和生效优先级

#### Scenario: 查询无套餐的设备

- **WHEN** 代理查询有权限但当前无生效或待生效设备级套餐的设备
- **THEN** 系统返回空套餐列表，流量数值为 0

#### Scenario: 无权限设备

- **WHEN** 代理查询不在自己管辖店铺范围内的设备
- **THEN** 系统返回 `CodeForbidden`，消息为"无权限操作该资源或资源不存在"

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

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