# main-wallet-transactions Specification

## Purpose
预充值钱包（主钱包）交易流水查询，为管理员和代理提供主钱包的充值、扣款、退款等流水明细查看能力。

## ADDED Requirements

### Requirement: 预充值钱包流水查询

系统 SHALL 提供 `GET /api/admin/shops/:shop_id/main-wallet/transactions` 接口，分页返回指定代理店铺的预充值钱包（主钱包）交易流水记录。

**响应字段**（`MainWalletTransactionItem`）：
- `id`：流水记录 ID
- `transaction_type`：交易类型。主钱包可能出现的值为 `recharge`-充值入账 / `deduct`-套餐扣款 / `refund`-退款（当前 DB 数据仅见 `recharge`，`deduct` / `refund` 随代购扣款/退款业务上线而出现；接口不对类型做枚举白名单，透传 DB 原值）
- `transaction_subtype`：交易子类型（细分场景，如 `order_payment`，可为空）
- `amount`：变动金额（分，正数为入账，负数为扣款）
- `balance_before`：变动前余额（分）
- `balance_after`：变动后余额（分）
- `remark`：备注（可为空）
- `created_at`：流水时间

**查询参数**（`MainWalletTransactionListRequest`）：
- `shop_id`：路径参数，店铺 ID（必填）
- `page`：页码（默认 1）
- `page_size`：每页数量（默认 20，最大 100）
- `transaction_type`：按类型过滤（可选）
- `start_date`：开始日期，`YYYY-MM-DD`（可选）
- `end_date`：结束日期，`YYYY-MM-DD`（可选）

**实现要求**：
- **Service 层入口必须调用 `middleware.CanManageShop(ctx, shopID)` 做越权校验**，校验失败直接返回 `errors.CodeForbidden`；不得依赖 `GetMainWallet` 的隐式过滤（该方法不做权限校验）
- 先通过 `AgentWalletStore.GetMainWallet(shopID)` 获取主钱包；若不存在则返回空列表（`total=0`），不报错
- 使用 `AgentWalletTransactionStore.ListByWalletIDWithFilters / CountByWalletID`（task 2.2 新增）查询流水，支持 transaction_type 和日期过滤
- 旧方法 `ListByShopID / CountByShopID` 已在 task 2.3 删除（会跨钱包类型返回数据，易被误用）
- 结果按 `created_at DESC` 排序

#### Scenario: 平台人员查看指定代理的预充值流水

- **WHEN** 平台人员请求 `GET /shops/123/main-wallet/transactions`
- **THEN** 系统返回店铺 123 的主钱包流水，按时间倒序，含变动前后余额

#### Scenario: 代理查看自己的预充值流水

- **WHEN** 代理账号请求 `GET /shops/自己shop_id/main-wallet/transactions`
- **THEN** 系统返回该代理自己的主钱包流水记录

#### Scenario: 代理尝试查看他人流水被拦截

- **WHEN** 代理账号请求 `GET /shops/他人shop_id/main-wallet/transactions`
- **THEN** 系统返回 403 错误，消息为"无权限操作该资源或资源不存在"

#### Scenario: 代理暂无主钱包时返回空列表

- **WHEN** 代理从未充值，主钱包不存在
- **THEN** 系统返回空列表，`total` 为 0，不报错

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

- **WHEN** 传入 `transaction_type=recharge`
- **THEN** 系统只返回充值入账类型的流水

#### Scenario: 按日期范围过滤

- **WHEN** 传入 `start_date=2026-01-01&end_date=2026-03-31`
- **THEN** 系统只返回该日期范围内的流水记录

#### Scenario: 企业账号无权访问

- **WHEN** 企业账号请求此接口
- **THEN** 系统返回 403 错误
