readd mom-backend dir
This commit is contained in:
503
mom-backend/docs/Testing/EBOM-API测试文档.md
Normal file
503
mom-backend/docs/Testing/EBOM-API测试文档.md
Normal file
@@ -0,0 +1,503 @@
|
||||
# EBOM / 产品BOM 后端 API 测试文档
|
||||
|
||||
> 依据前端 `erp-frontend-vue/src/api/rd/ebom.ts` 与后端 `MdBomController`、`MdProductBomController` 编写,用于接口联调与测试。
|
||||
> 生产计划单「选择EBOM单」弹窗依赖本组接口(见《mom系统生产计划单-页面开发说明文档》7.6.4、7.6.5)。
|
||||
|
||||
---
|
||||
|
||||
## 1. 约定说明
|
||||
|
||||
| 项目 | 说明 |
|
||||
|------|------|
|
||||
| 基础路径 | 网关/应用根路径 + 下表 path(如 `http://host:port/mes/md/bom`) |
|
||||
| 认证 | 需登录态,请求头带 Token(如 `Authorization: Bearer xxx`) |
|
||||
| 分页 | 列表接口支持 `pageNum`、`pageSize`,响应含 `rows`、`total` |
|
||||
| 通用响应 | 非分页接口通常为 `{ code, msg, data }`,code=200 表示成功 |
|
||||
|
||||
---
|
||||
|
||||
## 2. BOM 表头接口(MdBomController)
|
||||
|
||||
**Base path:** `/mes/md/bom`
|
||||
|
||||
### 2.1 查询 BOM 列表(分页)
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| 前端方法 | `listEbom(query)` / `listEbomDetail(query)` |
|
||||
| 方法 | GET |
|
||||
| 路径 | `/mes/md/bom/list` |
|
||||
| 权限 | 无特殊注解,依赖全局或菜单权限 |
|
||||
|
||||
**请求参数(Query,与 EbomQuery 对应):**
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| bomCode | string | 否 | BOM 编码,模糊 |
|
||||
| itemCode | string | 否 | 产品/物料编码,模糊 |
|
||||
| itemName | string | 否 | 产品/物料名称,模糊 |
|
||||
| itemTypeId | number | 否 | 物料分类 ID |
|
||||
| status | string | 否 | 单据状态:DRAFT / APPROVED |
|
||||
| businessStatus | string | 否 | 业务状态 |
|
||||
| beginDate | string | 否 | 开始日期 YYYY-MM-DD(映射 params.beginDate) |
|
||||
| endDate | string | 否 | 结束日期 YYYY-MM-DD |
|
||||
| pageNum | number | 否 | 页码,默认 1 |
|
||||
| pageSize | number | 否 | 每页条数,默认 10 |
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "查询成功",
|
||||
"rows": [
|
||||
{
|
||||
"bomId": 1,
|
||||
"bomCode": "BOM001",
|
||||
"bomName": "示例BOM",
|
||||
"itemId": 100,
|
||||
"itemCode": "ITEM01",
|
||||
"itemName": "产品A",
|
||||
"version": "V1.0",
|
||||
"versionDesc": "初版",
|
||||
"status": "DRAFT",
|
||||
"baseQty": 1,
|
||||
"createTime": "2026-01-01 10:00:00"
|
||||
}
|
||||
],
|
||||
"total": 1
|
||||
}
|
||||
```
|
||||
|
||||
**测试要点:**
|
||||
|
||||
- 无参数:返回分页列表,total 与 rows 长度一致或 total 为总条数。
|
||||
- 传 `status=APPROVED`:仅返回已审核 BOM。
|
||||
- 传 `itemCode` / `itemName`:按物料编码或名称筛选。
|
||||
- 传 `beginDate`、`endDate`:按创建日期范围筛选。
|
||||
|
||||
---
|
||||
|
||||
### 2.2 获取 BOM 详情(含明细行)
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| 前端方法 | `getEbom(bomId)` |
|
||||
| 方法 | GET |
|
||||
| 路径 | `/mes/md/bom/{bomId}` |
|
||||
| 权限 | `mes:md:bom:query` |
|
||||
|
||||
**路径参数:**
|
||||
|
||||
| 参数名 | 类型 | 说明 |
|
||||
|--------|------|------|
|
||||
| bomId | long | BOM 表头主键 |
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"data": {
|
||||
"bomId": 1,
|
||||
"bomCode": "BOM001",
|
||||
"bomName": "示例BOM",
|
||||
"itemId": 100,
|
||||
"itemCode": "ITEM01",
|
||||
"itemName": "产品A",
|
||||
"version": "V1.0",
|
||||
"versionDesc": "初版",
|
||||
"status": "DRAFT",
|
||||
"baseQty": 1,
|
||||
"lines": [
|
||||
{
|
||||
"bomId": 101,
|
||||
"bomCode": "BOM001",
|
||||
"bomItemId": 201,
|
||||
"bomItemCode": "MAT01",
|
||||
"bomItemName": "物料1",
|
||||
"quantity": 2,
|
||||
"unitName": "个",
|
||||
"lineNo": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**测试要点:**
|
||||
|
||||
- 存在 bomId:返回表头 + `lines` 数组(按 bomCode 关联的 md_product_bom 行)。
|
||||
- 不存在 bomId:返回 404 或 code≠200。
|
||||
- 用于生产计划单「选择EBOM单」确定后展示、或「查看」EBOM 详情。
|
||||
|
||||
---
|
||||
|
||||
### 2.3 新增 BOM 表头
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| 前端方法 | `addEbom(data)` |
|
||||
| 方法 | POST |
|
||||
| 路径 | `/mes/md/bom` |
|
||||
| Content-Type | application/json |
|
||||
| 权限 | `mes:md:bom:add` |
|
||||
|
||||
**请求体示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"bomCode": "BOM002",
|
||||
"bomName": "新BOM",
|
||||
"itemId": 100,
|
||||
"itemCode": "ITEM01",
|
||||
"itemName": "产品A",
|
||||
"unitName": "台",
|
||||
"baseQty": 1,
|
||||
"version": "V1.0",
|
||||
"versionDesc": "初版",
|
||||
"status": "DRAFT",
|
||||
"enableFlag": "Y",
|
||||
"remark": "备注"
|
||||
}
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"data": { "bomId": 2 }
|
||||
}
|
||||
```
|
||||
|
||||
**测试要点:**
|
||||
|
||||
- bomCode 重复:应返回业务错误提示。
|
||||
- 必填项缺失(如 bomCode、itemId 等):返回参数校验错误。
|
||||
|
||||
---
|
||||
|
||||
### 2.4 修改 BOM 表头
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| 前端方法 | `updateEbom(data)` |
|
||||
| 方法 | PUT |
|
||||
| 路径 | `/mes/md/bom` |
|
||||
| Content-Type | application/json |
|
||||
| 权限 | `mes:md:bom:edit` |
|
||||
|
||||
**请求体:** 与新增类似,需带 `bomId`。
|
||||
|
||||
**测试要点:**
|
||||
|
||||
- 仅更新传入字段;审核后是否允许修改依业务配置。
|
||||
|
||||
---
|
||||
|
||||
### 2.5 删除 BOM 表头
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| 前端方法 | `deleteEbom(ids)` |
|
||||
| 方法 | DELETE |
|
||||
| 路径 | `/mes/md/bom/{bomIds}` |
|
||||
| 权限 | `mes:md:bom:remove` |
|
||||
|
||||
**路径参数:** `bomIds` 为多个时逗号分隔,如 `1,2,3`。
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功"
|
||||
}
|
||||
```
|
||||
|
||||
**测试要点:**
|
||||
|
||||
- 单条:`DELETE /mes/md/bom/1`。
|
||||
- 多条:`DELETE /mes/md/bom/1,2,3`。
|
||||
- 逻辑删除(del_flag=1)时,列表不再返回已删记录。
|
||||
|
||||
---
|
||||
|
||||
### 2.6 审核 EBOM
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| 前端方法 | `approveEbom(bomId)` |
|
||||
| 方法 | PUT |
|
||||
| 路径 | `/mes/md/bom/approve` |
|
||||
| Content-Type | application/json |
|
||||
| 权限 | `mes:md:bom:edit` |
|
||||
|
||||
**请求体:**
|
||||
|
||||
```json
|
||||
{
|
||||
"bomId": 1
|
||||
}
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功"
|
||||
}
|
||||
```
|
||||
|
||||
**测试要点:**
|
||||
|
||||
- 成功:对应 BOM 的 `status` 更新为 `APPROVED`。
|
||||
- 缺少 bomId:返回「bomId 不能为空」或 code≠200。
|
||||
|
||||
---
|
||||
|
||||
### 2.7 反审核 EBOM
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| 前端方法 | `unapproveEbom(bomId)` |
|
||||
| 方法 | PUT |
|
||||
| 路径 | `/mes/md/bom/reject` |
|
||||
| Content-Type | application/json |
|
||||
| 权限 | `mes:md:bom:edit` |
|
||||
|
||||
**请求体:**
|
||||
|
||||
```json
|
||||
{
|
||||
"bomId": 1
|
||||
}
|
||||
```
|
||||
|
||||
**测试要点:**
|
||||
|
||||
- 成功:对应 BOM 的 `status` 更新为 `DRAFT`。
|
||||
|
||||
---
|
||||
|
||||
### 2.8 导出 BOM 列表(GET)
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| 前端方法 | `exportEbom(query)` |
|
||||
| 方法 | GET |
|
||||
| 路径 | `/mes/md/bom/export` |
|
||||
| 权限 | `mes:md:bom:export` |
|
||||
|
||||
**请求参数:** 与 2.1 列表查询一致(bomCode、itemCode、status、beginDate、endDate 等)。
|
||||
|
||||
**响应:** 二进制流(Excel),`Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet` 或类似;前端使用 `responseType: 'blob'`。
|
||||
|
||||
**测试要点:**
|
||||
|
||||
- 带与列表相同的查询条件,返回 Excel 文件且可打开。
|
||||
- 无权限时返回 403。
|
||||
|
||||
---
|
||||
|
||||
## 3. BOM 明细行接口(MdProductBomController)
|
||||
|
||||
**Base path:** `/mes/md/bom/line`
|
||||
|
||||
### 3.1 查询 BOM 明细列表(分页)
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| 前端方法 | `listEbomLines(query)` |
|
||||
| 方法 | GET |
|
||||
| 路径 | `/mes/md/bom/line/list` |
|
||||
|
||||
**请求参数(Query):**
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| bomCode | string | 否 | BOM 编码,精确或模糊(依后端实现) |
|
||||
| pageNum | number | 否 | 页码 |
|
||||
| pageSize | number | 否 | 每页条数 |
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "查询成功",
|
||||
"rows": [
|
||||
{
|
||||
"bomId": 101,
|
||||
"bomCode": "BOM001",
|
||||
"bomItemId": 201,
|
||||
"bomItemCode": "MAT01",
|
||||
"bomItemName": "物料1",
|
||||
"quantity": 2,
|
||||
"unitName": "个",
|
||||
"lineNo": 1,
|
||||
"supplyType": "PRODUCE"
|
||||
}
|
||||
],
|
||||
"total": 1
|
||||
}
|
||||
```
|
||||
|
||||
**测试要点:**
|
||||
|
||||
- 按 `bomCode` 筛选某 BOM 下的所有明细行。
|
||||
|
||||
---
|
||||
|
||||
### 3.2 获取单条 BOM 明细
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| 方法 | GET |
|
||||
| 路径 | `/mes/md/bom/line/{bomId}` |
|
||||
| 权限 | `mes:md:mditem:query` |
|
||||
|
||||
**说明:** 此处 `bomId` 为明细表主键(md_product_bom 行 ID)。前端 EBOM 模块未单独调用该接口,详情通过 2.2 表头详情中的 `lines` 获取。
|
||||
|
||||
---
|
||||
|
||||
### 3.3 新增 BOM 明细
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| 前端方法 | `addEbomLine(data)` |
|
||||
| 方法 | POST |
|
||||
| 路径 | `/mes/md/bom/line` |
|
||||
| Content-Type | application/json |
|
||||
| 权限 | `mes:md:mditem:add` |
|
||||
|
||||
**请求体示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"bomCode": "BOM001",
|
||||
"itemId": 100,
|
||||
"bomItemId": 201,
|
||||
"bomItemCode": "MAT01",
|
||||
"bomItemName": "物料1",
|
||||
"quantity": 2,
|
||||
"unitOfMeasure": "个",
|
||||
"lineNo": 1,
|
||||
"supplyType": "PRODUCE"
|
||||
}
|
||||
```
|
||||
|
||||
**测试要点:**
|
||||
|
||||
- `bomItemId == itemId`(产品作为自身 BOM 物料):后端应返回「产品不能作为自身的BOM物料!」。
|
||||
|
||||
---
|
||||
|
||||
### 3.4 修改 BOM 明细
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| 前端方法 | `updateEbomLine(data)` |
|
||||
| 方法 | PUT |
|
||||
| 路径 | `/mes/md/bom/line` |
|
||||
| Content-Type | application/json |
|
||||
| 权限 | `mes:md:mditem:edit` |
|
||||
|
||||
**请求体:** 需带明细主键(如 `bomId` 在 line 表中表示行 ID)。
|
||||
|
||||
---
|
||||
|
||||
### 3.5 删除 BOM 明细
|
||||
|
||||
| 项目 | 内容 |
|
||||
|------|------|
|
||||
| 前端方法 | `deleteEbomLine(ids)` |
|
||||
| 方法 | DELETE |
|
||||
| 路径 | `/mes/md/bom/line/{bomIds}` |
|
||||
| 权限 | `mes:md:mditem:remove` |
|
||||
|
||||
**路径参数:** 多个 ID 逗号分隔,如 `101,102`。此处为明细行主键(md_product_bom 表 PK)。
|
||||
|
||||
---
|
||||
|
||||
## 4. 前端与后端接口对照表
|
||||
|
||||
| 前端 API(ebom.ts) | 方法 | 后端路径 |
|
||||
|---------------------|------|----------|
|
||||
| listEbom / listEbomDetail | GET | /mes/md/bom/list |
|
||||
| getEbom(bomId) | GET | /mes/md/bom/{bomId} |
|
||||
| addEbom(data) | POST | /mes/md/bom |
|
||||
| updateEbom(data) | PUT | /mes/md/bom |
|
||||
| deleteEbom(ids) | DELETE | /mes/md/bom/{bomIds} |
|
||||
| approveEbom(bomId) | PUT | /mes/md/bom/approve |
|
||||
| unapproveEbom(bomId) | PUT | /mes/md/bom/reject |
|
||||
| exportEbom(query) | GET | /mes/md/bom/export |
|
||||
| listEbomLines(query) | GET | /mes/md/bom/line/list |
|
||||
| addEbomLine(data) | POST | /mes/md/bom/line |
|
||||
| updateEbomLine(data) | PUT | /mes/md/bom/line |
|
||||
| deleteEbomLine(ids) | DELETE | /mes/md/bom/line/{bomIds} |
|
||||
|
||||
---
|
||||
|
||||
## 5. 生产计划单场景联调要点
|
||||
|
||||
- **选择EBOM单弹窗(7.6.4)**:打开弹窗时调用 `GET /mes/md/bom/list`,建议带 `status=APPROVED`、可选 `itemCode`(引入产品)筛选;选中一条后点确定,前端将 `bomCode`/`version`/`versionDesc` 回填表头。
|
||||
- **EBOM 详情查看(7.6.5)**:点击「查看」时调用 `GET /mes/md/bom/{bomId}`,展示表头 + `lines`(子件明细)。
|
||||
- **列表分页与导出**:列表使用 `pageNum`、`pageSize`;导出使用 GET `/mes/md/bom/export` 且响应为 blob,与前端 `exportEbom` 一致。
|
||||
|
||||
---
|
||||
|
||||
## 6. 建议测试顺序
|
||||
|
||||
1. 列表:GET `/mes/md/bom/list`(无参、带 status、带 itemCode)。
|
||||
2. 详情:GET `/mes/md/bom/{bomId}`,校验含 `lines`。
|
||||
3. 新增:POST `/mes/md/bom`,再查列表/详情确认。
|
||||
4. 修改:PUT `/mes/md/bom`。
|
||||
5. 审核/反审核:PUT `/mes/md/bom/approve`、PUT `/mes/md/bom/reject`,再查详情校验 status。
|
||||
6. 导出:GET `/mes/md/bom/export`,保存为 Excel 并打开。
|
||||
7. 明细:GET `/mes/md/bom/line/list?bomCode=xxx`,POST/PUT/DELETE 明细,再查表头详情校验 `lines`。
|
||||
|
||||
---
|
||||
|
||||
## 7. 测试脚本执行说明
|
||||
|
||||
已提供脚本 **`run-ebom-api-tests.sh`**(与本文档同目录),按上述顺序自动调用各接口并汇总通过/失败。
|
||||
|
||||
**前置条件:**
|
||||
|
||||
- 后端已启动(如 `mvn spring-boot:run -pl ktg-admin`),且数据库、Redis 可用。
|
||||
- 若系统开启验证码,需在管理端关闭验证码,或先登录获取 Token 后设置环境变量再执行脚本。
|
||||
|
||||
**执行方式:**
|
||||
|
||||
```bash
|
||||
cd mom-backend/docs/Testing
|
||||
./run-ebom-api-tests.sh
|
||||
```
|
||||
|
||||
**环境变量(可选):**
|
||||
|
||||
| 变量 | 默认值 | 说明 |
|
||||
|------|--------|------|
|
||||
| BASE_URL | http://localhost:8080 | 后端根地址 |
|
||||
| TOKEN | (空则自动登录) | 若已持有 Token,可直接设置,跳过登录 |
|
||||
| USERNAME | admin | 自动登录时的用户名 |
|
||||
| PASSWORD | admin123 | 自动登录时的密码 |
|
||||
| RESULT_DIR | ./test-results | 响应与报告输出目录 |
|
||||
|
||||
**示例:指定地址与 Token:**
|
||||
|
||||
```bash
|
||||
export BASE_URL=http://192.168.8.66:8080
|
||||
export TOKEN=eyJhbGciOiJIUzUxMiJ9...
|
||||
./run-ebom-api-tests.sh
|
||||
```
|
||||
|
||||
**输出:**
|
||||
|
||||
- 控制台与 `RESULT_DIR` 下时间戳报告文件(如 `ebom-api-test-20260126-214351.txt`)中会打印每条用例的 **PASS/FAIL** 及最终 **PASS/FAIL 数量**。
|
||||
- 各接口响应 JSON 保存在 `RESULT_DIR/response_<用例名>.json`,便于排查失败原因。
|
||||
150
mom-backend/docs/Testing/run-ebom-api-tests.sh
Executable file
150
mom-backend/docs/Testing/run-ebom-api-tests.sh
Executable file
@@ -0,0 +1,150 @@
|
||||
#!/usr/bin/env bash
|
||||
# EBOM API 测试脚本(依据 docs/Testing/EBOM-API测试文档.md)
|
||||
# 使用:先启动后端(如 mvn spring-boot:run -pl ktg-admin),再执行本脚本。
|
||||
# 环境变量:BASE_URL(默认 http://localhost:8080)、TOKEN(可选,不设则尝试登录)、USERNAME、PASSWORD
|
||||
|
||||
set -e
|
||||
BASE_URL="${BASE_URL:-http://localhost:8080}"
|
||||
USERNAME="${USERNAME:-admin}"
|
||||
PASSWORD="${PASSWORD:-admin123}"
|
||||
RESULT_DIR="${RESULT_DIR:-./test-results}"
|
||||
mkdir -p "$RESULT_DIR"
|
||||
REPORT="$RESULT_DIR/ebom-api-test-$(date +%Y%m%d-%H%M%S).txt"
|
||||
PASS=0
|
||||
FAIL=0
|
||||
|
||||
log() { echo "[$(date +%H:%M:%S)] $*" | tee -a "$REPORT"; }
|
||||
run() {
|
||||
local name="$1"
|
||||
local method="$2"
|
||||
local path="$3"
|
||||
local data="$4"
|
||||
local extra="$5"
|
||||
local url="${BASE_URL}${path}"
|
||||
local out="$RESULT_DIR/response_${name}.json"
|
||||
local code=""
|
||||
if [[ "$method" == GET ]]; then
|
||||
if [[ -n "$extra" ]]; then
|
||||
url="${url}${extra}"
|
||||
fi
|
||||
code=$(curl -s -w '%{http_code}' -o "$out" -H "Authorization: Bearer ${TOKEN}" "$url")
|
||||
elif [[ "$method" == POST ]]; then
|
||||
code=$(curl -s -w '%{http_code}' -o "$out" -X POST -H "Content-Type: application/json" -H "Authorization: Bearer ${TOKEN}" -d "$data" "$url")
|
||||
elif [[ "$method" == PUT ]]; then
|
||||
code=$(curl -s -w '%{http_code}' -o "$out" -X PUT -H "Content-Type: application/json" -H "Authorization: Bearer ${TOKEN}" -d "$data" "$url")
|
||||
elif [[ "$method" == DELETE ]]; then
|
||||
code=$(curl -s -w '%{http_code}' -o "$out" -X DELETE -H "Authorization: Bearer ${TOKEN}" "$url")
|
||||
fi
|
||||
local json_code=""
|
||||
if [[ -f "$out" ]] && [[ -s "$out" ]]; then
|
||||
json_code=$(grep -o '"code"[[:space:]]*:[[:space:]]*[0-9]*' "$out" | head -1 | grep -o '[0-9]*' || true)
|
||||
fi
|
||||
if [[ "$code" == 200 ]] && { [[ -z "$json_code" ]] || [[ "$json_code" == "200" ]]; }; then
|
||||
log "PASS $name ($method $path)"
|
||||
((PASS++)) || true
|
||||
return 0
|
||||
else
|
||||
log "FAIL $name ($method $path) HTTP=$code jsonCode=$json_code"
|
||||
[[ -f "$out" ]] && log " body: $(head -c 500 "$out")"
|
||||
((FAIL++)) || true
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 登录获取 token(若未设置 TOKEN)
|
||||
if [[ -z "$TOKEN" ]]; then
|
||||
log "Login to get token..."
|
||||
login_out="$RESULT_DIR/login.json"
|
||||
http=$(curl -s -w '%{http_code}' -o "$login_out" -X POST -H "Content-Type: application/json" \
|
||||
-d "{\"username\":\"$USERNAME\",\"password\":\"$PASSWORD\",\"code\":\"\",\"uuid\":\"\"}" \
|
||||
"$BASE_URL/login")
|
||||
if [[ "$http" != 200 ]]; then
|
||||
log "Login failed (HTTP $http). Set TOKEN manually or disable captcha. body: $(cat "$login_out")"
|
||||
exit 1
|
||||
fi
|
||||
TOKEN=$(grep -o '"token"[[:space:]]*:[[:space:]]*"[^"]*"' "$login_out" | sed 's/.*:"\(.*\)"/\1/')
|
||||
if [[ -z "$TOKEN" ]]; then
|
||||
log "Login response had no token. body: $(cat "$login_out")"
|
||||
exit 1
|
||||
fi
|
||||
log "Token obtained."
|
||||
fi
|
||||
|
||||
log "========== EBOM API Tests =========="
|
||||
log "BASE_URL=$BASE_URL"
|
||||
|
||||
# 2.1 列表
|
||||
run "bom-list" "GET" "/mes/md/bom/list" "" ""
|
||||
run "bom-list-status" "GET" "/mes/md/bom/list" "" "?pageNum=1&pageSize=10&status=DRAFT"
|
||||
run "bom-list-itemCode" "GET" "/mes/md/bom/list" "" "?pageNum=1&pageSize=10"
|
||||
|
||||
# 2.2 详情(先取一条 id:从列表结果取第一个 bomId,若无则跳过)
|
||||
if [[ -f "$RESULT_DIR/response_bom-list.json" ]] && [[ -s "$RESULT_DIR/response_bom-list.json" ]]; then
|
||||
first_id=$(grep -o '"bomId"[[:space:]]*:[[:space:]]*[0-9]*' "$RESULT_DIR/response_bom-list.json" | head -1 | grep -o '[0-9]*' || true)
|
||||
if [[ -n "$first_id" ]]; then
|
||||
run "bom-get" "GET" "/mes/md/bom/$first_id" "" ""
|
||||
else
|
||||
log "SKIP bom-get (no bomId in list)"
|
||||
fi
|
||||
else
|
||||
log "SKIP bom-get (no list response)"
|
||||
fi
|
||||
|
||||
# 2.3 新增
|
||||
add_body='{"bomCode":"API-TEST-BOM-'$(date +%s)'","bomName":"API测试BOM","itemId":1,"itemCode":"ITEM01","itemName":"产品A","unitName":"台","baseQty":1,"version":"V1.0","versionDesc":"初版","status":"DRAFT","enableFlag":"Y","remark":"脚本测试"}'
|
||||
run "bom-add" "POST" "/mes/md/bom" "$add_body"
|
||||
|
||||
# 从新增响应取 bomId 用于后续修改/审核/删除
|
||||
new_bom_id=""
|
||||
if [[ -f "$RESULT_DIR/response_bom-add.json" ]]; then
|
||||
new_bom_id=$(grep -o '"bomId"[[:space:]]*:[[:space:]]*[0-9]*' "$RESULT_DIR/response_bom-add.json" | head -1 | grep -o '[0-9]*' || true)
|
||||
# 也可能在 data 里
|
||||
if [[ -z "$new_bom_id" ]]; then
|
||||
new_bom_id=$(grep -o '"data"[[:space:]]*:[[:space:]]*{[^}]*"bomId"[^}]*}' "$RESULT_DIR/response_bom-add.json" | grep -o '"bomId"[[:space:]]*:[[:space:]]*[0-9]*' | grep -o '[0-9]*' || true)
|
||||
fi
|
||||
fi
|
||||
|
||||
# 2.4 修改(若有新 id)
|
||||
if [[ -n "$new_bom_id" ]]; then
|
||||
update_body="{\"bomId\":$new_bom_id,\"bomCode\":\"API-TEST-BOM-UPD\",\"bomName\":\"API测试BOM(已改)\",\"itemId\":1,\"baseQty\":1,\"version\":\"V1.0\",\"status\":\"DRAFT\"}"
|
||||
run "bom-update" "PUT" "/mes/md/bom" "$update_body"
|
||||
fi
|
||||
|
||||
# 2.6 审核
|
||||
if [[ -n "$new_bom_id" ]]; then
|
||||
run "bom-approve" "PUT" "/mes/md/bom/approve" "{\"bomId\":$new_bom_id}"
|
||||
fi
|
||||
|
||||
# 2.7 反审核
|
||||
if [[ -n "$new_bom_id" ]]; then
|
||||
run "bom-reject" "PUT" "/mes/md/bom/reject" "{\"bomId\":$new_bom_id}"
|
||||
fi
|
||||
|
||||
# 2.8 导出(只检查 HTTP 200 或 403)
|
||||
export_url="${BASE_URL}/mes/md/bom/export?pageNum=1&pageSize=10"
|
||||
export_code=$(curl -s -w '%{http_code}' -o "$RESULT_DIR/response_bom-export.bin" -H "Authorization: Bearer ${TOKEN}" "$export_url")
|
||||
if [[ "$export_code" == 200 ]]; then
|
||||
log "PASS bom-export (GET /mes/md/bom/export)"
|
||||
((PASS++)) || true
|
||||
else
|
||||
log "FAIL bom-export HTTP=$export_code (may be 403 if no permission)"
|
||||
((FAIL++)) || true
|
||||
fi
|
||||
|
||||
# 3.1 明细列表
|
||||
run "line-list" "GET" "/mes/md/bom/line/list" "" "?pageNum=1&pageSize=10"
|
||||
|
||||
# 3.3 新增明细(需要有效的 bomCode/bomId,用上面 new_bom_id 或列表第一条的 bomCode)
|
||||
bom_code="API-TEST-BOM-UPD"
|
||||
if [[ -n "$new_bom_id" ]]; then
|
||||
line_add_body="{\"bomCode\":\"$bom_code\",\"itemId\":1,\"bomItemId\":2,\"bomItemCode\":\"MAT01\",\"bomItemName\":\"物料1\",\"quantity\":2,\"unitOfMeasure\":\"个\",\"lineNo\":1,\"supplyType\":\"PRODUCE\"}"
|
||||
run "line-add" "POST" "/mes/md/bom/line" "$line_add_body"
|
||||
fi
|
||||
|
||||
# 2.5 删除(放在最后,删除本次新增的 BOM)
|
||||
if [[ -n "$new_bom_id" ]]; then
|
||||
run "bom-delete" "DELETE" "/mes/md/bom/$new_bom_id" "" ""
|
||||
fi
|
||||
|
||||
log "========== Result: PASS=$PASS FAIL=$FAIL =========="
|
||||
[[ $FAIL -gt 0 ]] && exit 1 || exit 0
|
||||
@@ -0,0 +1 @@
|
||||
[21:43:51] Login to get token...
|
||||
709
mom-backend/docs/Testing/采购计划单-API测试文档.md
Normal file
709
mom-backend/docs/Testing/采购计划单-API测试文档.md
Normal file
@@ -0,0 +1,709 @@
|
||||
# 采购计划单 后端 API 测试文档
|
||||
|
||||
> 依据 PRD《mom系统采购计划单-页面开发说明文档》与后端 `MpPurchaseController` 编写,用于接口联调与测试。
|
||||
> 采购计划单为扁平表结构(erp_mp_purchase),同一 purchase_code 下可有多条物料记录。
|
||||
|
||||
---
|
||||
|
||||
## 1. 约定说明
|
||||
|
||||
| 项目 | 说明 |
|
||||
|------|------|
|
||||
| 基础路径 | 网关/应用根路径 + 下表 path(如 `http://host:port/erp/mp/purchase`) |
|
||||
| 认证 | 需登录态,请求头带 Token(如 `Authorization: Bearer xxx`) |
|
||||
| 分页 | 列表接口支持 `pageNum`、`pageSize`,响应含 `rows`、`total` |
|
||||
| 通用响应 | 非分页接口通常为 `{ code, msg, data }`,code=200 表示成功 |
|
||||
| 单据状态 | PREPARE=开立/草稿, APPROVED=已审核, REJECTED=退回 |
|
||||
| 业务状态 | NORMAL=正常, PAUSE=暂停, CANCEL=取消, COMPLETED=完成 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 接口总览
|
||||
|
||||
| 序号 | 功能 | 方法 | 路径 | 说明 |
|
||||
|------|------|------|------|------|
|
||||
| 1 | 明细视图列表 | GET | `/erp/mp/purchase/list` | 扁平列表,每行一条物料 |
|
||||
| 2 | 单据视图列表 | GET | `/erp/mp/purchase/docList` | 按 purchase_code 聚合 |
|
||||
| 3 | 底部汇总 | GET | `/erp/mp/purchase/summary` | 采购数量/已订数量合计 |
|
||||
| 4 | 获取详情(ID) | GET | `/erp/mp/purchase/{purchaseId}` | 按 ID 获取单条记录 |
|
||||
| 5 | 获取详情(编码) | GET | `/erp/mp/purchase/detail/{purchaseCode}` | 表头+明细行聚合 |
|
||||
| 6 | 生成编码 | GET | `/erp/mp/purchase/genCode` | 生成 CGJH000XXX |
|
||||
| 7 | 新增 | POST | `/erp/mp/purchase` | 创建采购计划 |
|
||||
| 8 | 修改 | PUT | `/erp/mp/purchase` | 更新采购计划 |
|
||||
| 9 | 删除(ID) | DELETE | `/erp/mp/purchase/{purchaseIds}` | 按 ID 删除(支持多个) |
|
||||
| 10 | 删除(编码) | DELETE | `/erp/mp/purchase/byCode/{purchaseCode}` | 按编码删除整单 |
|
||||
| 11 | 审核 | PUT | `/erp/mp/purchase/approve/{purchaseIds}` | 批量审核 |
|
||||
| 12 | 反审核 | PUT | `/erp/mp/purchase/unapprove/{purchaseIds}` | 批量反审核 |
|
||||
| 13 | 导出 | POST | `/erp/mp/purchase/export` | 导出 Excel |
|
||||
| 14 | 从MBOM生成 | POST | `/erp/mp/purchase/generate/{mbomId}` | 根据物料清单生成 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 接口详细说明
|
||||
|
||||
### 3.1 明细视图列表(GET /erp/mp/purchase/list)
|
||||
|
||||
**请求参数(Query):**
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| pageNum | integer | 否 | 页码,默认 1 |
|
||||
| pageSize | integer | 否 | 每页条数,默认 100 |
|
||||
| salesOrderCode | string | 否 | 销售订单号/跟单单号(模糊) |
|
||||
| purchaseCode | string | 否 | 单据编码(模糊) |
|
||||
| itemCode | string | 否 | 物料编码(模糊) |
|
||||
| itemName | string | 否 | 物料名称(模糊) |
|
||||
| needType | integer | 否 | 用料需求:0=订单用料,1=库存备料 |
|
||||
| params[beginDate] | string | 否 | 开始日期 yyyy-MM-dd |
|
||||
| params[endDate] | string | 否 | 结束日期 yyyy-MM-dd |
|
||||
| params[itemTypeId] | string | 否 | 物料分类ID(快捷筛选) |
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"total": 70,
|
||||
"rows": [
|
||||
{
|
||||
"purchaseId": 31,
|
||||
"purchaseCode": "CGJH000033",
|
||||
"purchaseDate": "2026-02-06",
|
||||
"status": "APPROVED",
|
||||
"businessType": "原材料",
|
||||
"businessStatus": "NORMAL",
|
||||
"needType": 0,
|
||||
"salesOrderCode": "XSDD000091",
|
||||
"deliveryDate": "2026-02-27",
|
||||
"planCode": "SCJH000096",
|
||||
"itemId": 100,
|
||||
"itemCode": "1000000002",
|
||||
"itemName": "微星 MAG B760M MORTAR WIFI DDR5 主板",
|
||||
"specification": "",
|
||||
"unitName": "台",
|
||||
"demandQty": 60.00,
|
||||
"availableQty": -30.00,
|
||||
"purchaseQty": 60.00,
|
||||
"orderedQty": 0.00,
|
||||
"operatorName": "admin"
|
||||
}
|
||||
],
|
||||
"code": 200,
|
||||
"msg": "查询成功"
|
||||
}
|
||||
```
|
||||
|
||||
**curl 测试命令:**
|
||||
|
||||
```bash
|
||||
# 明细视图 - 基本查询
|
||||
curl -X GET "http://localhost:8080/erp/mp/purchase/list?pageNum=1&pageSize=100&needType=0" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
|
||||
# 明细视图 - 按销售订单号搜索
|
||||
curl -X GET "http://localhost:8080/erp/mp/purchase/list?salesOrderCode=XSDD000091&pageNum=1&pageSize=100" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
|
||||
# 明细视图 - 按物料编码搜索
|
||||
curl -X GET "http://localhost:8080/erp/mp/purchase/list?itemCode=1000000002&pageNum=1&pageSize=100" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
|
||||
# 明细视图 - 按日期范围搜索
|
||||
curl -X GET "http://localhost:8080/erp/mp/purchase/list?params%5BbeginDate%5D=2026-02-01¶ms%5BendDate%5D=2026-02-28&pageNum=1&pageSize=100" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.2 单据视图列表(GET /erp/mp/purchase/docList)
|
||||
|
||||
**请求参数(Query):**
|
||||
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| pageNum | integer | 否 | 页码,默认 1 |
|
||||
| pageSize | integer | 否 | 每页条数,默认 100 |
|
||||
| purchaseCode | string | 否 | 单据编码(模糊) |
|
||||
| status | string | 否 | 单据状态:PREPARE/APPROVED/REJECTED |
|
||||
| businessStatus | string | 否 | 业务状态:NORMAL/PAUSE/CANCEL/COMPLETED |
|
||||
| needType | integer | 否 | 用料需求 |
|
||||
| params[beginDate] | string | 否 | 开始日期 |
|
||||
| params[endDate] | string | 否 | 结束日期 |
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"total": 31,
|
||||
"rows": [
|
||||
{
|
||||
"purchaseId": 31,
|
||||
"purchaseCode": "CGJH000033",
|
||||
"purchaseDate": "2026-02-06",
|
||||
"status": "APPROVED",
|
||||
"businessType": "原材料",
|
||||
"businessStatus": "NORMAL",
|
||||
"deptName": "采购部",
|
||||
"operatorName": "admin",
|
||||
"approverName": "admin",
|
||||
"approveDate": "2026-02-06 14:30:00",
|
||||
"purchaseQty": 180.00,
|
||||
"orderedQty": 60.00
|
||||
}
|
||||
],
|
||||
"code": 200,
|
||||
"msg": "查询成功"
|
||||
}
|
||||
```
|
||||
|
||||
**curl 测试命令:**
|
||||
|
||||
```bash
|
||||
# 单据视图 - 基本查询
|
||||
curl -X GET "http://localhost:8080/erp/mp/purchase/docList?pageNum=1&pageSize=100" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
|
||||
# 单据视图 - 按状态筛选(仅草稿)
|
||||
curl -X GET "http://localhost:8080/erp/mp/purchase/docList?status=PREPARE&pageNum=1&pageSize=100" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
|
||||
# 单据视图 - 按业务状态筛选
|
||||
curl -X GET "http://localhost:8080/erp/mp/purchase/docList?businessStatus=NORMAL&pageNum=1&pageSize=100" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.3 底部汇总(GET /erp/mp/purchase/summary)
|
||||
|
||||
返回当前查询条件下的采购数量和已订数量合计。查询条件与明细视图列表一致。
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"data": {
|
||||
"totalPurchaseQty": 15084075.00,
|
||||
"totalOrderedQty": 68549.00
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**curl 测试命令:**
|
||||
|
||||
```bash
|
||||
# 汇总 - 全量
|
||||
curl -X GET "http://localhost:8080/erp/mp/purchase/summary" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
|
||||
# 汇总 - 带搜索条件
|
||||
curl -X GET "http://localhost:8080/erp/mp/purchase/summary?salesOrderCode=XSDD000091" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.4 获取详情 - 按 ID(GET /erp/mp/purchase/{purchaseId})
|
||||
|
||||
返回单条采购计划记录(扁平结构,对应一个物料行)。
|
||||
|
||||
**curl 测试命令:**
|
||||
|
||||
```bash
|
||||
curl -X GET "http://localhost:8080/erp/mp/purchase/31" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.5 获取详情 - 按编码(GET /erp/mp/purchase/detail/{purchaseCode})
|
||||
|
||||
按 purchaseCode 聚合返回表头+物料明细行,用于查看/编辑页面。
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"data": {
|
||||
"purchaseCode": "CGJH000032",
|
||||
"purchaseDate": "2026-02-07",
|
||||
"status": "PREPARE",
|
||||
"businessType": "原材料",
|
||||
"businessStatus": "NORMAL",
|
||||
"needType": 0,
|
||||
"planId": 96,
|
||||
"planCode": "SCJH000096",
|
||||
"salesOrderId": 81,
|
||||
"salesOrderCode": "XSDD000081",
|
||||
"salesUserName": "周桂东",
|
||||
"deliveryDate": "2026-01-23",
|
||||
"deptId": null,
|
||||
"deptName": null,
|
||||
"operatorId": 1,
|
||||
"operatorName": "admin",
|
||||
"operatorName2": null,
|
||||
"approverId": null,
|
||||
"approverName": null,
|
||||
"approveDate": null,
|
||||
"totalQuantity": 170,
|
||||
"remark": null,
|
||||
"headerItemCode": "0103000002",
|
||||
"headerItemName": "组装电脑5400",
|
||||
"lines": [
|
||||
{
|
||||
"purchaseId": 101,
|
||||
"purchaseCode": "CGJH000032",
|
||||
"itemCode": "1000000001",
|
||||
"itemName": "英特尔Core i5-14600KF",
|
||||
"specification": "",
|
||||
"unitName": "台",
|
||||
"demandDate": "2026-02-18",
|
||||
"demandQty": 10.00,
|
||||
"availableQty": -30.00,
|
||||
"purchaseQty": 170.00,
|
||||
"orderedQty": 0.00,
|
||||
"remark": ""
|
||||
},
|
||||
{
|
||||
"purchaseId": 102,
|
||||
"purchaseCode": "CGJH000032",
|
||||
"itemCode": "1000000002",
|
||||
"itemName": "微星 MAG B760M 主板",
|
||||
"specification": "",
|
||||
"unitName": "台",
|
||||
"demandDate": "2026-02-18",
|
||||
"demandQty": 10.00,
|
||||
"availableQty": 5.00,
|
||||
"purchaseQty": 5.00,
|
||||
"orderedQty": 0.00,
|
||||
"remark": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**curl 测试命令:**
|
||||
|
||||
```bash
|
||||
curl -X GET "http://localhost:8080/erp/mp/purchase/detail/CGJH000032" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.6 生成编码(GET /erp/mp/purchase/genCode)
|
||||
|
||||
自动生成下一个采购计划编码,格式:CGJH + 6位流水号。
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"data": "CGJH000034"
|
||||
}
|
||||
```
|
||||
|
||||
**curl 测试命令:**
|
||||
|
||||
```bash
|
||||
curl -X GET "http://localhost:8080/erp/mp/purchase/genCode" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.7 新增采购计划(POST /erp/mp/purchase)
|
||||
|
||||
新增单条物料的采购计划记录。若需创建包含多条物料的单据,需多次调用此接口使用相同的 purchaseCode。
|
||||
|
||||
**请求体:**
|
||||
|
||||
```json
|
||||
{
|
||||
"purchaseCode": "CGJH000034",
|
||||
"purchaseDate": "2026-02-07",
|
||||
"businessType": "原材料",
|
||||
"businessStatus": "NORMAL",
|
||||
"needType": 0,
|
||||
"planId": 96,
|
||||
"planCode": "SCJH000096",
|
||||
"salesOrderId": 81,
|
||||
"salesOrderCode": "XSDD000081",
|
||||
"salesUserName": "周桂东",
|
||||
"deliveryDate": "2026-01-23",
|
||||
"itemId": 201,
|
||||
"itemCode": "1000000001",
|
||||
"itemName": "英特尔Core i5-14600KF",
|
||||
"specification": "",
|
||||
"unitName": "台",
|
||||
"demandQty": 170.00,
|
||||
"demandDate": "2026-02-18",
|
||||
"availableQty": -30.00,
|
||||
"purchaseQty": 170.00,
|
||||
"totalQuantity": 170,
|
||||
"remark": ""
|
||||
}
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"purchaseId": 201
|
||||
}
|
||||
```
|
||||
|
||||
**curl 测试命令:**
|
||||
|
||||
```bash
|
||||
curl -X POST "http://localhost:8080/erp/mp/purchase" \
|
||||
-H "Authorization: Bearer {token}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"purchaseCode": "CGJH000034",
|
||||
"purchaseDate": "2026-02-07",
|
||||
"businessType": "原材料",
|
||||
"needType": 0,
|
||||
"planCode": "SCJH000096",
|
||||
"salesOrderCode": "XSDD000081",
|
||||
"itemCode": "1000000001",
|
||||
"itemName": "英特尔Core i5-14600KF",
|
||||
"unitName": "台",
|
||||
"demandQty": 170.00,
|
||||
"purchaseQty": 170.00
|
||||
}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.8 修改采购计划(PUT /erp/mp/purchase)
|
||||
|
||||
更新单条采购计划记录,必须包含 purchaseId。
|
||||
|
||||
**请求体:**
|
||||
|
||||
```json
|
||||
{
|
||||
"purchaseId": 201,
|
||||
"purchaseQty": 200.00,
|
||||
"demandDate": "2026-02-20",
|
||||
"remark": "修改采购数量"
|
||||
}
|
||||
```
|
||||
|
||||
**curl 测试命令:**
|
||||
|
||||
```bash
|
||||
curl -X PUT "http://localhost:8080/erp/mp/purchase" \
|
||||
-H "Authorization: Bearer {token}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"purchaseId": 201,
|
||||
"purchaseQty": 200.00,
|
||||
"remark": "修改采购数量"
|
||||
}'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.9 删除 - 按 ID(DELETE /erp/mp/purchase/{purchaseIds})
|
||||
|
||||
批量删除(逻辑删除)。仅允许草稿(PREPARE)和退回(REJECTED)状态。
|
||||
|
||||
**路径参数:**
|
||||
|
||||
| 参数名 | 类型 | 说明 |
|
||||
|--------|------|------|
|
||||
| purchaseIds | Long[] | 采购计划ID,多个用逗号分隔 |
|
||||
|
||||
**curl 测试命令:**
|
||||
|
||||
```bash
|
||||
# 单条删除
|
||||
curl -X DELETE "http://localhost:8080/erp/mp/purchase/201" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
|
||||
# 批量删除
|
||||
curl -X DELETE "http://localhost:8080/erp/mp/purchase/201,202,203" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
```
|
||||
|
||||
**错误场景测试:**
|
||||
|
||||
```bash
|
||||
# 尝试删除已审核状态的记录(应返回错误)
|
||||
curl -X DELETE "http://localhost:8080/erp/mp/purchase/31" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
# 预期: {"code": 500, "msg": "编码为[CGJH000033]的单据不是草稿/退回状态,不允许删除!"}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.10 删除 - 按编码(DELETE /erp/mp/purchase/byCode/{purchaseCode})
|
||||
|
||||
按采购计划编码删除同一单据下所有物料行(单据视图使用)。
|
||||
|
||||
**curl 测试命令:**
|
||||
|
||||
```bash
|
||||
curl -X DELETE "http://localhost:8080/erp/mp/purchase/byCode/CGJH000034" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.11 审核(PUT /erp/mp/purchase/approve/{purchaseIds})
|
||||
|
||||
批量审核采购计划。支持逗号分隔的 ID 字符串。同一 purchaseCode 下所有行同时审核。
|
||||
|
||||
**路径参数:**
|
||||
|
||||
| 参数名 | 类型 | 说明 |
|
||||
|--------|------|------|
|
||||
| purchaseIds | String | 采购计划ID,多个用逗号分隔 |
|
||||
|
||||
**前置条件:** 单据状态必须为 PREPARE(草稿)
|
||||
|
||||
**curl 测试命令:**
|
||||
|
||||
```bash
|
||||
# 单条审核
|
||||
curl -X PUT "http://localhost:8080/erp/mp/purchase/approve/201" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
|
||||
# 批量审核
|
||||
curl -X PUT "http://localhost:8080/erp/mp/purchase/approve/201,202,203" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "成功审核 3 条单据"
|
||||
}
|
||||
```
|
||||
|
||||
**错误场景测试:**
|
||||
|
||||
```bash
|
||||
# 尝试审核已审核的记录
|
||||
curl -X PUT "http://localhost:8080/erp/mp/purchase/approve/31" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
# 预期: {"code": 500, "msg": "编码为[CGJH000033]的单据不是草稿状态,不能审核!"}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.12 反审核(PUT /erp/mp/purchase/unapprove/{purchaseIds})
|
||||
|
||||
批量反审核采购计划。支持逗号分隔的 ID 字符串。同一 purchaseCode 下所有行同时反审核。
|
||||
|
||||
反审核后状态变为 PREPARE(草稿),清空审核员和审核日期。
|
||||
|
||||
**路径参数:**
|
||||
|
||||
| 参数名 | 类型 | 说明 |
|
||||
|--------|------|------|
|
||||
| purchaseIds | String | 采购计划ID,多个用逗号分隔 |
|
||||
|
||||
**前置条件:** 单据状态必须为 APPROVED(已审核)
|
||||
|
||||
**curl 测试命令:**
|
||||
|
||||
```bash
|
||||
# 单条反审核
|
||||
curl -X PUT "http://localhost:8080/erp/mp/purchase/unapprove/31" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
|
||||
# 批量反审核
|
||||
curl -X PUT "http://localhost:8080/erp/mp/purchase/unapprove/31,32,33" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "成功反审核 1 条单据"
|
||||
}
|
||||
```
|
||||
|
||||
**错误场景测试:**
|
||||
|
||||
```bash
|
||||
# 尝试反审核草稿状态的记录
|
||||
curl -X PUT "http://localhost:8080/erp/mp/purchase/unapprove/201" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
# 预期: {"code": 500, "msg": "编码为[CGJH000034]的单据不是已审核状态,不能反审核!"}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.13 导出(POST /erp/mp/purchase/export)
|
||||
|
||||
导出采购计划列表到 Excel 文件。请求参数与明细视图列表一致。
|
||||
|
||||
**curl 测试命令:**
|
||||
|
||||
```bash
|
||||
curl -X POST "http://localhost:8080/erp/mp/purchase/export" \
|
||||
-H "Authorization: Bearer {token}" \
|
||||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||||
-o "采购计划单.xlsx"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.14 从 MBOM 生成采购计划(POST /erp/mp/purchase/generate/{mbomId})
|
||||
|
||||
根据物料清单(MBOM)中供应方式为"采购"的物料,自动生成采购计划。
|
||||
|
||||
**路径参数:**
|
||||
|
||||
| 参数名 | 类型 | 说明 |
|
||||
|--------|------|------|
|
||||
| mbomId | Long | 物料清单ID |
|
||||
|
||||
**curl 测试命令:**
|
||||
|
||||
```bash
|
||||
curl -X POST "http://localhost:8080/erp/mp/purchase/generate/1" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
```
|
||||
|
||||
**响应示例:**
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "成功生成 5 条采购计划"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 典型测试流程
|
||||
|
||||
### 4.1 完整业务流程测试
|
||||
|
||||
```bash
|
||||
# 步骤1: 生成编码
|
||||
curl -X GET "http://localhost:8080/erp/mp/purchase/genCode" -H "Authorization: Bearer {token}"
|
||||
# 记录返回的编码,如 CGJH000034
|
||||
|
||||
# 步骤2: 新增采购计划(第一条物料)
|
||||
curl -X POST "http://localhost:8080/erp/mp/purchase" \
|
||||
-H "Authorization: Bearer {token}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"purchaseCode": "CGJH000034",
|
||||
"purchaseDate": "2026-02-07",
|
||||
"businessType": "原材料",
|
||||
"needType": 0,
|
||||
"itemCode": "1000000001",
|
||||
"itemName": "英特尔Core i5-14600KF",
|
||||
"unitName": "台",
|
||||
"demandQty": 170.00,
|
||||
"purchaseQty": 170.00
|
||||
}'
|
||||
# 记录返回的 purchaseId
|
||||
|
||||
# 步骤3: 新增同单据第二条物料
|
||||
curl -X POST "http://localhost:8080/erp/mp/purchase" \
|
||||
-H "Authorization: Bearer {token}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"purchaseCode": "CGJH000034",
|
||||
"purchaseDate": "2026-02-07",
|
||||
"businessType": "原材料",
|
||||
"needType": 0,
|
||||
"itemCode": "1000000002",
|
||||
"itemName": "微星 MAG B760M 主板",
|
||||
"unitName": "台",
|
||||
"demandQty": 170.00,
|
||||
"purchaseQty": 170.00
|
||||
}'
|
||||
|
||||
# 步骤4: 查询明细视图,验证新增数据
|
||||
curl -X GET "http://localhost:8080/erp/mp/purchase/list?purchaseCode=CGJH000034" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
|
||||
# 步骤5: 查询单据视图,验证聚合
|
||||
curl -X GET "http://localhost:8080/erp/mp/purchase/docList?purchaseCode=CGJH000034" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
|
||||
# 步骤6: 查询详情
|
||||
curl -X GET "http://localhost:8080/erp/mp/purchase/detail/CGJH000034" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
|
||||
# 步骤7: 查询汇总
|
||||
curl -X GET "http://localhost:8080/erp/mp/purchase/summary?purchaseCode=CGJH000034" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
|
||||
# 步骤8: 审核
|
||||
curl -X PUT "http://localhost:8080/erp/mp/purchase/approve/{purchaseId}" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
|
||||
# 步骤9: 验证审核后状态
|
||||
curl -X GET "http://localhost:8080/erp/mp/purchase/detail/CGJH000034" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
# 预期: status=APPROVED, approverName 不为空
|
||||
|
||||
# 步骤10: 反审核
|
||||
curl -X PUT "http://localhost:8080/erp/mp/purchase/unapprove/{purchaseId}" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
|
||||
# 步骤11: 验证反审核后状态
|
||||
curl -X GET "http://localhost:8080/erp/mp/purchase/detail/CGJH000034" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
# 预期: status=PREPARE, approverName=null
|
||||
|
||||
# 步骤12: 删除
|
||||
curl -X DELETE "http://localhost:8080/erp/mp/purchase/byCode/CGJH000034" \
|
||||
-H "Authorization: Bearer {token}"
|
||||
```
|
||||
|
||||
### 4.2 边界条件测试
|
||||
|
||||
| 测试点 | 操作 | 预期结果 |
|
||||
|--------|------|----------|
|
||||
| 删除已审核单据 | DELETE /erp/mp/purchase/{已审核ID} | 返回错误:不允许删除 |
|
||||
| 审核非草稿单据 | PUT /approve/{非PREPARE的ID} | 返回错误:不是草稿状态 |
|
||||
| 反审核非审核单据 | PUT /unapprove/{非APPROVED的ID} | 返回错误:不是已审核状态 |
|
||||
| 查询不存在的编码 | GET /detail/CGJH999999 | 返回错误:采购计划单不存在 |
|
||||
| 重复编码新增 | POST 使用已存在的编码 | 返回错误:编码已存在 |
|
||||
| 空列表汇总 | GET /summary?purchaseCode=不存在 | 返回 {totalPurchaseQty: 0, totalOrderedQty: 0} |
|
||||
|
||||
---
|
||||
|
||||
## 5. PRD 对照验证
|
||||
|
||||
| PRD 接口要求 | 后端实现 | 状态 |
|
||||
|-------------|----------|------|
|
||||
| 查询采购计划列表 (明细视图) | GET /erp/mp/purchase/list | ✅ 已实现 |
|
||||
| 查询采购计划列表 (单据视图) | GET /erp/mp/purchase/docList | ✅ 已实现 |
|
||||
| 底部汇总统计 | GET /erp/mp/purchase/summary | ✅ 已实现 |
|
||||
| 获取详情 (按ID) | GET /erp/mp/purchase/{purchaseId} | ✅ 已实现 |
|
||||
| 获取详情 (按编码, 表头+明细) | GET /erp/mp/purchase/detail/{purchaseCode} | ✅ 已实现 |
|
||||
| 生成采购计划编码 | GET /erp/mp/purchase/genCode | ✅ 已实现 |
|
||||
| 新增采购计划 | POST /erp/mp/purchase | ✅ 已实现 |
|
||||
| 修改采购计划 | PUT /erp/mp/purchase | ✅ 已实现 |
|
||||
| 删除采购计划 (按ID) | DELETE /erp/mp/purchase/{purchaseIds} | ✅ 已实现 |
|
||||
| 删除采购计划 (按编码) | DELETE /erp/mp/purchase/byCode/{purchaseCode} | ✅ 已实现 |
|
||||
| 审核采购计划 (支持批量) | PUT /erp/mp/purchase/approve/{purchaseIds} | ✅ 已实现 |
|
||||
| 反审核采购计划 (支持批量) | PUT /erp/mp/purchase/unapprove/{purchaseIds} | ✅ 已实现 |
|
||||
| 导出 | POST /erp/mp/purchase/export | ✅ 已实现 |
|
||||
| 从MBOM生成 | POST /erp/mp/purchase/generate/{mbomId} | ✅ 已实现 |
|
||||
| 生产计划列表 (引入用) | 复用 GET /erp/mp/plan/list | ✅ 已有 |
|
||||
| 物料选择 | 复用 GET /md/item/list (或类似) | ✅ 已有 |
|
||||
Reference in New Issue
Block a user