# asset-wallet-query Specification

## Purpose
Admin 端资产钱包查询，允许平台用户和代理账号查询指定物联网卡或设备的钱包余额概况及收支流水，流水包含可跳转的来源编号（充值单号 / 订单号）。

## Requirements

### Requirement: Admin 端查询资产钱包概况

系统 SHALL 提供 `GET /api/admin/assets/:asset_type/:id/wallet` 接口，允许平台用户和代理账号查询指定卡或设备的钱包余额概况。

**接口规格**：
- 路径参数 `asset_type`：`card` 或 `device`
- 路径参数 `id`：资产数据库 ID（uint）
- 无请求体
- 返回字段：`wallet_id`、`resource_type`、`resource_id`、`balance`、`frozen_balance`、`available_balance`、`currency`、`status`、`status_text`、`created_at`、`updated_at`

**权限规则**：
- 平台用户/超级管理员：可查询所有资产钱包
- 代理账号：只能查询 `shop_id_tag IN (当前店铺及下级店铺)` 的资产钱包（由 `ApplyShopTagFilter` 自动过滤）
- 企业账号：Handler 层直接返回 403，禁止访问

#### Scenario: 平台用户查询卡钱包概况

- **WHEN** 平台用户请求 `GET /api/admin/assets/card/456/wallet`，该卡存在钱包记录，余额 100 元，冻结 0 元
- **THEN** 系统返回 200，`balance=10000`，`frozen_balance=0`，`available_balance=10000`，`status=1`，`status_text="正常"`

#### Scenario: 代理账号查询下级资产钱包

- **WHEN** 代理账号（shop_id=10）请求 `GET /api/admin/assets/device/789/wallet`，该设备的 `shop_id_tag` 在该代理的下级店铺范围内
- **THEN** 系统返回 200，返回该设备的钱包详情

#### Scenario: 代理账号查询越权资产钱包

- **WHEN** 代理账号（shop_id=10）请求 `GET /api/admin/assets/card/999/wallet`，该卡的 `shop_id_tag` 不在该代理的下级店铺范围内
- **THEN** 系统返回 404，错误消息为"该资产暂无钱包记录"（不区分"无权"与"不存在"）

#### Scenario: 企业账号请求被拒绝

- **WHEN** 企业账号请求 `GET /api/admin/assets/card/456/wallet`
- **THEN** 系统返回 403，错误消息为"企业账号无权查看钱包信息"

#### Scenario: 资产无钱包记录

- **WHEN** 平台用户请求 `GET /api/admin/assets/card/456/wallet`，该卡尚未创建钱包（未充值过）
- **THEN** 系统返回 404，错误消息为"该资产暂无钱包记录"

---

### Requirement: Admin 端查询资产钱包流水列表

系统 SHALL 提供 `GET /api/admin/assets/:asset_type/:id/wallet/transactions` 接口，允许平台用户和代理账号分页查询指定资产的钱包收支流水，每条流水包含可跳转的来源编号。

**接口规格**：
- 路径参数：同上
- 查询参数：`page`（默认 1）、`page_size`（默认 20，最大 100）、`transaction_type`（可选过滤）、`start_time`（可选）、`end_time`（可选）
- 流水按 `created_at` 倒序排列
- 每条流水返回：`id`、`transaction_type`、`transaction_type_text`、`amount`、`balance_before`、`balance_after`、`reference_type`、`reference_no`、`remark`、`created_at`

**来源编号跳转规则**：
- `reference_type = "recharge"` → `reference_no` 为充值单号（`CRCH…`），前端可跳转至充值单详情
- `reference_type = "order"` → `reference_no` 为订单号（`ORD…`），前端可跳转至订单详情

**权限规则**：与钱包概况接口相同

#### Scenario: 查询充值和扣款流水

- **WHEN** 平台用户请求 `GET /api/admin/assets/card/456/wallet/transactions?page=1&page_size=20`，该卡有 1 条充值流水（100 元）和 1 条扣款流水（-30 元）
- **THEN** 系统返回 200，`total=2`，按时间倒序返回两条记录，充值流水 `amount=10000`、`reference_type="recharge"`、`reference_no="CRCH20260309001"`；扣款流水 `amount=-3000`、`reference_type="order"`、`reference_no="ORD20260310001"`

#### Scenario: 按交易类型过滤

- **WHEN** 平台用户请求 `GET /api/admin/assets/card/456/wallet/transactions?transaction_type=recharge`
- **THEN** 系统只返回 `transaction_type="recharge"` 的流水记录

#### Scenario: 分页超出范围

- **WHEN** 请求 `page_size=200`（超过最大值 100）
- **THEN** 系统返回 400，错误消息为参数验证失败

#### Scenario: 资产无流水记录

- **WHEN** 平台用户请求某资产的流水列表，该资产钱包存在但尚无任何流水
- **THEN** 系统返回 200，`list=[]`，`total=0`
