## MODIFIED Requirements

### Requirement: 同时只能有一个生效中的主套餐

系统 SHALL 确保载体（设备/卡）同一时刻只能有一个 `package_type=formal` 且 `status=1` 的套餐。

**到期检测扩展**：过期检测 SHALL 同时覆盖 `status=1`（生效中）和 `status=2`（已耗尽）的主套餐。当 `expires_at <= now` 时，无论套餐当前是生效中还是已耗尽，均视为到期，触发下一个排队套餐激活。

**数据一致性保证**：
- 购买时检查：查询 `WHERE (iot_card_id/device_id)=? AND status=1 AND master_usage_id IS NULL`
- 并发控制：使用数据库事务避免并发插入多个生效中主套餐
- 激活时二次检查：激活前再次查询是否有生效中主套餐，避免并发激活

#### Scenario: 首次购买主套餐立即生效
- **GIVEN** 载体无任何主套餐记录
- **WHEN** 用户购买主套餐并支付成功
- **THEN** 系统创建 PackageUsage：`status=1`，`priority=1`，`activated_at=支付完成时间`，`expires_at=根据 calendar_type 计算`，`master_usage_id=NULL`

#### Scenario: 购买第二个主套餐自动排队
- **GIVEN** 载体已有 1 个生效中的主套餐（`priority=1`，`status=1`）
- **WHEN** 用户购买第 2 个主套餐
- **THEN** 系统创建 PackageUsage：`status=0`，`priority=2`，无 `activated_at` 和 `expires_at`

#### Scenario: 生效中主套餐到期触发下一个激活
- **GIVEN** 卡 C1 有生效中主套餐（`status=1`，`expires_at=过去时间`）和一个排队套餐（`status=0`）
- **WHEN** 过期检测任务扫描到该套餐
- **THEN** 生效中套餐更新为 `status=3 Expired`，加油包级联失效，下一个排队套餐激活为 `status=1`
- **AND** 如卡因流量耗尽停机（`stop_reason=traffic_exhausted`）且已实名，触发自动复机

#### Scenario: 已耗尽（Depleted）主套餐到期后触发下一个激活
- **GIVEN** 卡 C2 有已耗尽主套餐（`status=2 Depleted`，`expires_at=过去时间`）和一个预购排队套餐（`status=0`）
- **WHEN** 过期检测任务扫描（查询条件：`status IN (1,2) AND expires_at <= now AND master_usage_id IS NULL`）
- **THEN** 耗尽套餐更新为 `status=3 Expired`，加油包级联失效，预购排队套餐激活为 `status=1`
- **AND** 如卡因流量耗尽停机且已实名，触发自动复机

#### Scenario: 已耗尽套餐到期时加油包级联失效
- **GIVEN** 卡 C3 有耗尽主套餐（`status=2`，`expires_at=过去时间`），以及绑定到该主套餐的 1 个加油包（`status=1`，尚有剩余流量）
- **WHEN** 过期检测任务处理该主套餐
- **THEN** 主套餐更新为 `status=3`，加油包更新为 `status=4 Invalidated`（即使尚有剩余流量）
- **AND** 下一个排队主套餐激活

#### Scenario: 已耗尽套餐到期且无下一个排队套餐
- **GIVEN** 卡 C4 有耗尽主套餐（`status=2`，`expires_at=过去时间`），无排队套餐
- **WHEN** 过期检测任务处理该主套餐
- **THEN** 耗尽套餐更新为 `status=3`，加油包级联失效，无新套餐激活
- **AND** 卡的业务状态更新为 `IotCardStatusSuspended=4`（已停用）
