> **前置条件** — 执行以下任何命令前，请先确认已完成认证。如未认证，参见 [`../../shb-shared/SKILL.md`](../../shb-shared/SKILL.md)。

# shb-cli part stock

备件库存查询：`stock search`（库存列表）、`stock distribution`（单备件在各仓库/个人库的分布）。

> **本文档出现的命令、子命令、flag、参数名、接口/JSON 字段名，以及取数过程（分页、数量判断、全量拉取、字段裁剪）都只供你后台执行，绝不出现在给用户的回复里**——不解释、不转述、不当理由说。回复只给业务结果与真实数量（如「共 30 条库存记录，其中 3 条库存不足」）。

## 库存 ≠ 备件

**库存记录 = 备件 × 仓库**，一个备件可以在多个仓库各有一条库存记录。`part search`/`part detail` 查的是备件本身（名称、规格、价格等静态信息，与仓库无关）；`part stock search` 查的是**某个备件在某个仓库的库存数量**。用户问"这个备件还有多少库存"要用 `stock search --sparepart-id <备件id>` 或 `stock distribution --id <备件id>`，不要用 `part detail`（detail 不含库存字段）。

## 搜索库存列表

### 快捷 flag 方式（推荐）

```bash
# 关键字搜索
shb-cli part stock search --keyword <关键字>

# 按备件类型筛选
shb-cli part stock search --type <类型>

# 按仓库筛选
shb-cli part stock search --repertory-id <仓库id>

# 查某个备件的库存分布（等价于 stock distribution，但走分页接口）
shb-cli part stock search --sparepart-id <备件id>

# 只看库存不足（低于安全库存）的记录
shb-cli part stock search --missing

# 按仓库分类筛选，逗号分隔：备件库/不良品库/区域库/备件其他库
shb-cli part stock search --repertory-type "备件库,区域库"

# 分页
shb-cli part stock search --page 1 --page-size 20

# 组合使用
shb-cli part stock search --keyword "刹车" --missing --page-size 20

# 格式化数据输出：字段文案和值都会转换为可读内容，可用 --fields 指定字段
shb-cli part stock search --keyword "刹车" --format-data --fields serialNumber,name,repertoryName,repertoryCount,safetyStock,stockStatus

# 获取全量数据：确定量不大就直接 --all 一次拿齐
shb-cli part stock search --missing --all --format-data --fields serialNumber,repertoryName,repertoryCount,safetyStock,stockStatus
```

### 完整 JSON body 方式

```bash
# 内联 JSON （推荐）
shb-cli part stock search --data '{"pageNum":1,"pageSize":10,"keyWord":"刹车","isMissingPart":1}'

# 从文件读取
shb-cli part stock search --file ./stock-search.json
```

**使用优先级：`--file` ＞ `--data` ＞ 快捷 flags**——传了 `--file` 或 `--data` 时快捷 flags 会被整体忽略（不合并）。常规筛选直接用快捷 flags；需要完整或复杂 JSON（如 `productTypeList`、时间范围、自定义 `sortBy`）时用 `--data`；`--file` 仅在本地已有现成 JSON 文件时用。

## 支持的搜索字段（JSON body，字段名为 SparepartRepertorySearchModelDTO）

| 字段 | 类型 | 说明 |
|------|------|------|
| `keyWord` | string | 关键字模糊搜索（**注意大写 W**，写成 `keyword` 会被后端静默忽略、不过滤） |
| `type` | string | 备件类型 |
| `standard` | string | 规格，模糊匹配 |
| `description` | string | 说明，模糊匹配 |
| `enable` | string | 备件启用状态：`"1"` 启用 / `"0"` 停用 |
| `isMissingPart` | int | `0` 全部（默认）/ `1` 只看库存不足的记录 |
| `repertoryTypeList` | string[] | 仓库分类过滤，取值：`备件库`/`不良品库`/`区域库`/`备件其他库` |
| `productTypeList` | string[] | 关联产品目录类型 ID 数组 |
| `repertoryId` | string | 指定仓库 id |
| `sparepartId` | string | 指定备件 id |
| `pageNum` | int | 页码，**从 1 开始**（默认 1） |
| `pageSize` | int | 每页条数，0 表示查全量 |
| `timeStart` / `timeEnd` | int | 创建时间范围，epoch 毫秒 |
| `sortBy` | object | 排序，如 `{"repertorySparepart.repertoryCount": true}`，`true` 为升序 |

> **flag 名与 JSON 字段名的对应**：快捷 flag 用**短横线**命名，`--data` 里的 JSON 用**驼峰**命名。对照：`--page`↔`pageNum`、`--page-size`↔`pageSize`、`--keyword`↔`keyWord`（注意大写 W）、`--type`↔`type`、`--repertory-id`↔`repertoryId`、`--sparepart-id`↔`sparepartId`、`--missing`（bool flag）↔`isMissingPart`（传 1 时才带这个字段，不传默认查全部）、`--repertory-type`（逗号分隔字符串）↔`repertoryTypeList`（数组）。

> `teamIds`/`operatorId` 由服务端根据当前登录用户自动注入做团队数据权限过滤，**不需要也不能**在请求里传，结果口径与用户在网页看到的一致。

## 获取全量数据：决策规则

**全量请求的处理顺序（`--all` 每个查询条件最多执行一次，别重复拉）：**

- **能判断数据量不大（≤500）**——按仓库 / 按类型 / 库存不足筛选的日常查询多属此类——**直接执行一次 `--all`** 拿齐即可，**无需先探量**（`--all` 自带总数与全部数据）。
- **不确定是否会超过 500**——先用 `--page-size 1` 探一次 `total`，再判断：`total ≤ 500` 用 `--all`，`total ≥ 501` 改分页叠加。

> **`--all` 用法要点：**
> - **必须 `--format-data --fields <少数列>` 两者一起**才能收窄输出，否则接口原始响应含全部嵌套字段容易被截断。
> - **每个查询条件最多执行一次**：`--all` 已遍历所有页、返回完整结果与总数，不要再补跑分页或再次 `--all`。

## --format-data 输出结构速查

`--format-data -o raw` 返回：

```json
{
  "page":    {"page": 1, "pageSize": 10, "totalElements": 30, "totalPages": 3},
  "columns": [{"field": "serialNumber", "label": "编号"}, ...],
  "rows":    [{"serialNumber": "SP-001", "name": "刹车片", "repertoryName": "总仓", "repertoryType": "备件库", "repertoryCount": "4", "safetyStock": "5", "stockStatus": "不足", ...}, ...]
}
```

不加 `--fields` 时默认输出字段：`serialNumber`（编号）、`name`（名称）、`type`（类型）、`standard`（规格）、`unit`（单位）、`repertoryName`（仓库名称）、`repertoryType`（仓库分类）、`repertoryCount`（库存数量）、`safetyStock`（安全库存）、`stockStatus`（库存状态，派生列）。

其余可选字段：`id`（库存记录内部 ID）、`sparepartId`（备件 ID）、`salePrice`（销售价格）、`enable`（备件启用状态）、`productTypeList`（关联产品类型，逗号分隔的名称串）。

### 字段说明

- 原始响应是嵌套结构（`sparepart{...}`、`repertory{...}` 子对象），`--format-data` 已自动展平为 `serialNumber`/`name`/`repertoryName`/`repertoryType` 这类扁平字段，无需自己拼路径。
- `safetyStock` 为空表示该仓库未给这个备件设置安全库存阈值，展示为「未设置」，**不是**库存为 0。
- `stockStatus`（库存状态）是派生列，综合两个信号：
  - `safetyStock` 已设置且当前库存 `repertoryCount` 已降到阈值以下 → 含「不足」
  - 后端预警标记为真 → 含「预警」
  - 两者都命中显示「不足/预警」；都不命中显示「正常」。

## 单备件库存分布

查某个备件在所有仓库（含个人库）的库存分布：

```bash
shb-cli part stock distribution --id <sparepartId>
```

- `--id` 必填，是备件的 `id`（UUID），来自 `part search`/`part stock search` 返回结果中的 `id`（备件搜索）或 `sparepartId`（库存搜索）字段。
- 返回一个**裸数组**（无 status/data 信封），每项含 `sparepartName`、`repertoryName`、`repertoryType`、`repertoryCount`，部分项含 `safetyStock`；`repertoryType` 为「个人库」时该条是某个人的个人备件库存，`repertoryName` 通常为空。
- 本命令**不支持** `--format-data`（原始字段已是扁平结构，可直接读取），需要按仓库分类/是否库存不足做进一步计算时用 `stock search` 代替（有 `--missing`、`--repertory-type` 过滤和 `--format-data` 格式化）。

## 典型组合场景

### 场景一：查某个备件的库存总览

```bash
# 1. 搜到备件，拿到 id
shb-cli part search --keyword "刹车片" --format-data --fields serialNumber,id,name

# 2. 查该备件在各仓库的库存分布
shb-cli part stock distribution --id <sparepartId>
```

### 场景二：查所有库存不足的备件

```bash
shb-cli part stock search --missing --all --format-data \
  --fields serialNumber,name,repertoryName,repertoryCount,safetyStock,stockStatus
```

## 注意

- `part stock search` 默认输出原始响应（裸 PageInfo：`{pageNum, pageSize, total, pages, list}`，**没有** status/data 信封，记录本身是嵌套结构）；需要字段文案、展平字段和值格式化时显式传 `--format-data`。
- 搜索结果为空时，检查 `repertory-id`/`repertory-type`/`type` 等筛选条件是否匹配当前租户下实际存在的值，以及当前登录用户是否有对应仓库的团队数据权限。
- **统计需求优先用计数查询**：只需要总数时用 `--page-size 1` 取 `page.totalElements`，不要为了数数把全量明细拉进来。
