29 KiB
2026-05-26 会话记忆
本周聚焦
- 只关注 tiny-erp,不处理其他项目
- 只关注 md(主数据) 和 im(库存) 两个模块
- 不再关注 om(销售)、mc(采购)、fin(财务)、home、system 等其他模块
模块路径确认
包路径: com.witsoft.erp
项目路径: /home/yangxuan/Projects/IdeaProjects/tiny-erp
md 模块(主数据)
module/md/ — 已完整实现
category— 物料分类customer— 客户factory— 工厂material— 物料supplier— 供应商warehouse— 仓库
im 模块(库存)
module/im/ — 已完整实现
inbound— 入库单(含采购入库、生产入库)outbound— 出库单stock— 库存查询、库存流水、呆滞分析stocktake— 库存盘点(含快速盘点)
原记忆清理
旧记忆(memory/2026-05-23.md)中关于 bd 模块的命名实际上是 md(代码实际使用的是 md,不是 bd)。
ome/mc/fin/home/system 模块依然存在但不处理。
注释规范(已写入 MEMORY.md)
- 所有公共接口和类必须包含 Javadoc
- 注释语言:中文描述业务背景,技术术语保留英文(如 NPE)
- 禁止生成 "Gets the value of X" 这类无意义的 getter/setter 注释
- 复杂算法必须在代码块上方解释核心逻辑
- 禁止使用 HTML 标签
开发注意事项(已写入 MEMORY.md)
- 复用优先:逻辑雷同时提取公共方法复用
- 业务表仅存物料 id:物料相关字段仅存
material_id,其他数据通过关联查询填充 - 填充在 Service 层:关联数据填充逻辑统一在 Service 层处理
- 首个版本直接改 DDL:脚本直接修改建表语句,不需要写 ALTER TABLE
- 字典优先用 DictService:字典取值优先使用 DictService 公共方法
库存业务表字段清理
背景: 业务表只存物料 ID,物料编码/名称/规格/单位通过关联查询填充。
DDL 改动(50-inventory.sql):
im_stock— 移除 material_code, material_name, spec, unitim_stock_transaction— 移除 material_code, material_nameim_inbound_item— 移除 material_code, material_name, spec, unitim_outbound_item— 移除 material_code, material_name, spec, unit
实体类: Stock, StockTransaction, InboundItem, OutboundItem — 移除对应字段
请求 DTO: InboundItemSaveReqDTO, OutboundItemSaveReqDTO, StocktakeItemSaveReqDTO, QuickStocktakeItemDTO — 只保留 materialId
接口改动:
- StockTransactionService.recordTransaction() — 移除 materialCode/materialName 参数
- MaterialService — 新增 searchMaterialIdsByKeyword() 方法
Service 改动:
- StockTransactionServiceImpl — keyword 搜索改为两步(先查物料表匹配 ID);DTO 填充从 materialInfoMap 读取
- StockServiceImpl — 同上
- InboundServiceImpl — saveItems 不 set 冗余字段;recordTransaction 去参;history 从 material 填充
- OutboundServiceImpl — 同上
- MaterialServiceImpl — 实现 searchMaterialIdsByKeyword()
编译验证: mvn compile -q ✅
Git 提交约定
- commit 跳过 application.yml —
git add时用git add . -- ':!application.yml'或手动排除 - commit 后不要 push — 只做本地提交,不推送远程
2026-05-26 会话记忆
物料信息填充公共服务 (MaterialFillService)
核心设计决策
-
实体设计原则
InboundItem和OutboundItem只存储materialId- 不存储物料编码、名称、规格、单位等字段
- 防止物料信息变更后历史数据不一致
-
批量查询模式
List<Long> materialIds = items.stream().map(Item::getMaterialId).collect(Collectors.toList()); Map<Long, MaterialInfoDTO> materialInfoMap = materialFillService.getMaterialInfoMap(materialIds);- 避免 N+1 查询问题
- 一次查询所有物料信息,性能更优
-
Service 层填充
- 所有物料信息填充逻辑在 Service 层处理
- Controller 只负责返回 DTO
- 不放在 Mapper 或 Controller 层
修改的 Service 类(共 6 个)
| Service | 方法 | 用途 |
|---|---|---|
| InboundServiceImpl | executeInbound(), cancel() | 入库/冲销时记录流水 |
| OutboundServiceImpl | executeOutbound(), cancel() | 出库/冲销时记录流水 |
| FinAccountsAutoServiceImpl | createApFromInbound(), cancelApFromInbound() | 采购应付联动 |
| FinAccountsAutoServiceImpl | createArFromOutbound(), cancelArFromOutbound() | 销售应收联动 |
| HomeServiceImpl | getLatestNews() | 首页动态显示 |
| DeliveryServiceImpl | confirmOutbound() | 发货确认 |
物料类型字典
- Dict Type:
material_type - 值:
P-原材料,SA-半成品,FG-成品 - SQL 脚本:
scripts/postgresql/22-material-type-dict.sql
Git 状态
- 所有修改已 commit(13+ commits)
- 禁止 push - 用户明确要求
- 分支:master
经验教训
- 修改实体类后,所有引用该实类的地方都要检查
- 编译错误可能分散在多个模块(im, fin, home, om)
- 使用
mvn clean compile确保完整编译,避免 IDE 缓存误导
2026-05-26 会话记忆
本周聚焦
- 只关注 tiny-erp,不处理其他项目
- 只关注 md(主数据) 和 im(库存) 两个模块
- 不再关注 om(销售)、mc(采购)、fin(财务)、home、system 等其他模块
模块路径确认
包路径: com.witsoft.erp
项目路径: /home/yangxuan/Projects/IdeaProjects/tiny-erp
md 模块(主数据)
module/md/ — 已完整实现
category— 物料分类customer— 客户factory— 工厂material— 物料supplier— 供应商warehouse— 仓库
im 模块(库存)
module/im/ — 已完整实现
inbound— 入库单(含采购入库、生产入库)outbound— 出库单stock— 库存查询、库存流水、呆滞分析stocktake— 库存盘点(含快速盘点)
原记忆清理
旧记忆(memory/2026-05-23.md)中关于 bd 模块的命名实际上是 md(代码实际使用的是 md,不是 bd)。
ome/mc/fin/home/system 模块依然存在但不处理。
注释规范(已写入 MEMORY.md)
- 所有公共接口和类必须包含 Javadoc
- 注释语言:中文描述业务背景,技术术语保留英文(如 NPE)
- 禁止生成 "Gets the value of X" 这类无意义的 getter/setter 注释
- 复杂算法必须在代码块上方解释核心逻辑
- 禁止使用 HTML 标签
开发注意事项(已写入 MEMORY.md)
- 复用优先:逻辑雷同时提取公共方法复用
- 业务表仅存物料 id:物料相关字段仅存
material_id,其他数据通过关联查询填充 - 填充在 Service 层:关联数据填充逻辑统一在 Service 层处理
- 首个版本直接改 DDL:脚本直接修改建表语句,不需要写 ALTER TABLE
- 字典优先用 DictService:字典取值优先使用 DictService 公共方法
Git 提交约定
- commit 跳过 application.yml —
git add . -- ':!application.yml'排除,防止泄露配置 - commit 后不要 push — 只做本地 commit,不推送远程仓库
库存业务表字段清理
背景: 业务表只存物料 ID,物料编码/名称/规格/单位通过关联查询填充。
DDL 改动(50-inventory.sql):
im_stock— 移除 material_code, material_name, spec, unitim_stock_transaction— 移除 material_code, material_nameim_inbound_item— 移除 material_code, material_name, spec, unitim_outbound_item— 移除 material_code, material_name, spec, unit
实体类: Stock, StockTransaction, InboundItem, OutboundItem — 移除对应字段
请求 DTO: InboundItemSaveReqDTO, OutboundItemSaveReqDTO, StocktakeItemSaveReqDTO, QuickStocktakeItemDTO — 只保留 materialId
接口改动:
- StockTransactionService.recordTransaction() — 移除 materialCode/materialName 参数
- MaterialService — 新增 searchMaterialIdsByKeyword() 方法
Service 改动:
- StockTransactionServiceImpl — keyword 搜索改为两步(先查物料表匹配 ID);DTO 填充从 materialInfoMap 读取
- StockServiceImpl — 同上
- InboundServiceImpl — saveItems 不 set 冗余字段;recordTransaction 去参;history 从 material 填充
- OutboundServiceImpl — 同上
- MaterialServiceImpl — 实现 searchMaterialIdsByKeyword()
编译验证: mvn compile -q ✅
物料信息填充公共服务 (MaterialFillService)
核心设计决策
-
实体设计原则
InboundItem和OutboundItem只存储materialId- 不存储物料编码、名称、规格、单位等字段
- 防止物料信息变更后历史数据不一致
-
批量查询模式
List<Long> materialIds = items.stream().map(Item::getMaterialId).collect(Collectors.toList()); Map<Long, MaterialInfoDTO> materialInfoMap = materialFillService.getMaterialInfoMap(materialIds);- 避免 N+1 查询问题
- 一次查询所有物料信息,性能更优
-
Service 层填充
- 所有物料信息填充逻辑在 Service 层处理
- Controller 只负责返回 DTO
- 不放在 Mapper 或 Controller 层
修改的 Service 类(共 6 个)
| Service | 方法 | 用途 |
|---|---|---|
| InboundServiceImpl | executeInbound(), cancel() | 入库/冲销时记录流水 |
| OutboundServiceImpl | executeOutbound(), cancel() | 出库/冲销时记录流水 |
| FinAccountsAutoServiceImpl | createApFromInbound(), cancelApFromInbound() | 采购应付联动 |
| FinAccountsAutoServiceImpl | createArFromOutbound(), cancelArFromOutbound() | 销售应收联动 |
| HomeServiceImpl | getLatestNews() | 首页动态显示 |
| DeliveryServiceImpl | confirmOutbound() | 发货确认 |
物料类型字典
- Dict Type:
material_type - 值:
P-原材料,SA-半成品,FG-成品 - SQL 脚本:
scripts/postgresql/22-material-type-dict.sql
Git 状态
- 所有修改已 commit(13+ commits)
- 禁止 push - 用户明确要求
- 分支:master
物料选择器(Material Selector)
新增物料选择器功能,用于入库/出库操作时弹窗选物料。
接口
| 接口 | 位置 | 数据源 | 仓库参数 |
|---|---|---|---|
POST /im/inbound/material-selector |
InboundController | md_material | 不需要 |
POST /im/outbound/material-selector |
OutboundController | im_stock JOIN md_material | 需要 warehouseId |
请求参数(MaterialSelectorReqDTO → md.material.dto)
categoryId— 0=常用物料,>0=按分类筛选keyword— 物料编码/名称/规格关键字warehouseId— 出库场景需要- 继承
PageQuery(pageNum, pageSize)
常用物料 TOP10 逻辑
- 口径: 近 30 天出入库明细条目数最多的 10 个物料
- 入库:
im_inbound_itemGROUP BY material_id ORDER BY COUNT(*) DESC LIMIT 10 - 出库:
im_outbound_item同上 - SQL 放 Mapper XML(方便后续扩展)
分类筛选逻辑
- 入库: MyBatis Plus LambdaQueryWrapper 查
md_material表,按category_id+keyword分页 - 出库: XML 联表
im_stock JOIN md_material,按category_id+keyword+warehouseId分页,只查库存 > 0 的数据
响应
- 复用
StockPageDTO(im.stock.dto) - 物料编码/名称/规格/单位/分类等从
MaterialFillService填充
新增文件(7个)
| 文件 | 路径 |
|---|---|
| MaterialSelectorReqDTO | md.material.dto |
| MaterialSelectorService | md.material.service |
| MaterialSelectorServiceImpl | md.material.service.impl |
| InboundItemMapper.xml | resources/mapper/im/ |
| OutboundItemMapper.xml | resources/mapper/im/ |
| StockMapper.xml | resources/mapper/im/ |
修改文件(5个)
| 文件 | 改动 |
|---|---|
| InboundItemMapper.java | + selectRecentMaterialIds() |
| OutboundItemMapper.java | + selectRecentMaterialIds() |
| StockMapper.java | + selectStockPage() / countStockPage() |
| InboundController.java | + /material-selector 端点 |
| OutboundController.java | + /material-selector 端点 |
历史单据创建人名称
改动
- InboundHistoryItemDTO — 新增
creatorName字段 - OutboundHistoryItemDTO — 新增
creatorName字段 - InboundServiceImpl.listHistory() — 收集 creators → 批量查 sys_user(username→nickname) → 填充
- OutboundServiceImpl.listHistory() — 同上
逻辑
- 从单据列表收集所有
creator(用户名) userService.lambdaQuery().in(User::getUsername, creators).list()- 转
Map<String, String>(username → nickname) - 逐行
dto.setCreatorName() - 一次 SQL,不 N+1
2026-05-26 会话记忆
本周聚焦
- 只关注 tiny-erp,不处理其他项目
- 只关注 md(主数据) 和 im(库存) 两个模块
- 不再关注 om(销售)、mc(采购)、fin(财务)、home、system 等其他模块
模块路径确认
包路径: com.witsoft.erp
项目路径: /home/yangxuan/Projects/IdeaProjects/tiny-erp
md 模块(主数据)
module/md/ — 已完整实现
category— 物料分类customer— 客户factory— 工厂material— 物料supplier— 供应商warehouse— 仓库
im 模块(库存)
module/im/ — 已完整实现
inbound— 入库单(含采购入库、生产入库)outbound— 出库单stock— 库存查询、库存流水、呆滞分析stocktake— 库存盘点(含快速盘点)
原记忆清理
旧记忆(memory/2026-05-23.md)中关于 bd 模块的命名实际上是 md(代码实际使用的是 md,不是 bd)。
ome/mc/fin/home/system 模块依然存在但不处理。
注释规范(已写入 MEMORY.md)
- 所有公共接口和类必须包含 Javadoc
- 注释语言:中文描述业务背景,技术术语保留英文(如 NPE)
- 禁止生成 "Gets the value of X" 这类无意义的 getter/setter 注释
- 复杂算法必须在代码块上方解释核心逻辑
- 禁止使用 HTML 标签
开发注意事项(已写入 MEMORY.md)
- 复用优先:逻辑雷同时提取公共方法复用
- 业务表仅存物料 id:物料相关字段仅存
material_id,其他数据通过关联查询填充 - 填充在 Service 层:关联数据填充逻辑统一在 Service 层处理
- 首个版本直接改 DDL:脚本直接修改建表语句,不需要写 ALTER TABLE
- 字典优先用 DictService:字典取值优先使用 DictService 公共方法
Git 提交约定
- commit 跳过 application.yml —
git add . -- ':!application.yml'排除,防止泄露配置 - commit 后不要 push — 只做本地 commit,不推送远程仓库
库存业务表字段清理
背景: 业务表只存物料 ID,物料编码/名称/规格/单位通过关联查询填充。
DDL 改动(50-inventory.sql):
im_stock— 移除 material_code, material_name, spec, unitim_stock_transaction— 移除 material_code, material_nameim_inbound_item— 移除 material_code, material_name, spec, unitim_outbound_item— 移除 material_code, material_name, spec, unit
实体类: Stock, StockTransaction, InboundItem, OutboundItem — 移除对应字段
请求 DTO: InboundItemSaveReqDTO, OutboundItemSaveReqDTO, StocktakeItemSaveReqDTO, QuickStocktakeItemDTO — 只保留 materialId
接口改动:
- StockTransactionService.recordTransaction() — 移除 materialCode/materialName 参数
- MaterialService — 新增 searchMaterialIdsByKeyword() 方法
Service 改动:
- StockTransactionServiceImpl — keyword 搜索改为两步(先查物料表匹配 ID);DTO 填充从 materialInfoMap 读取
- StockServiceImpl — 同上
- InboundServiceImpl — saveItems 不 set 冗余字段;recordTransaction 去参;history 从 material 填充
- OutboundServiceImpl — 同上
- MaterialServiceImpl — 实现 searchMaterialIdsByKeyword()
编译验证: mvn compile -q ✅
物料信息填充公共服务 (MaterialFillService)
核心设计决策
-
实体设计原则
InboundItem和OutboundItem只存储materialId- 不存储物料编码、名称、规格、单位等字段
- 防止物料信息变更后历史数据不一致
-
批量查询模式
List<Long> materialIds = items.stream().map(Item::getMaterialId).collect(Collectors.toList()); Map<Long, MaterialInfoDTO> materialInfoMap = materialFillService.getMaterialInfoMap(materialIds);- 避免 N+1 查询问题
- 一次查询所有物料信息,性能更优
-
Service 层填充
- 所有物料信息填充逻辑在 Service 层处理
- Controller 只负责返回 DTO
- 不放在 Mapper 或 Controller 层
修改的 Service 类(共 6 个)
| Service | 方法 | 用途 |
|---|---|---|
| InboundServiceImpl | executeInbound(), cancel() | 入库/冲销时记录流水 |
| OutboundServiceImpl | executeOutbound(), cancel() | 出库/冲销时记录流水 |
| FinAccountsAutoServiceImpl | createApFromInbound(), cancelApFromInbound() | 采购应付联动 |
| FinAccountsAutoServiceImpl | createArFromOutbound(), cancelArFromOutbound() | 销售应收联动 |
| HomeServiceImpl | getLatestNews() | 首页动态显示 |
| DeliveryServiceImpl | confirmOutbound() | 发货确认 |
物料类型字典
- Dict Type:
material_type - 值:
P-原材料,SA-半成品,FG-成品 - SQL 脚本:
scripts/postgresql/22-material-type-dict.sql
Git 状态
- 所有修改已 commit(13+ commits)
- 禁止 push - 用户明确要求
- 分支:master
物料选择器(Material Selector)
新增物料选择器功能,用于入库/出库操作时弹窗选物料。
接口
| 接口 | 位置 | 数据源 | 仓库参数 |
|---|---|---|---|
POST /im/inbound/material-selector |
InboundController | md_material | 不需要 |
POST /im/outbound/material-selector |
OutboundController | im_stock JOIN md_material | 需要 warehouseId |
请求参数(MaterialSelectorReqDTO → md.material.dto)
categoryId— 0=常用物料,>0=按分类筛选keyword— 物料编码/名称/规格关键字warehouseId— 出库场景需要- 继承
PageQuery(pageNum, pageSize)
常用物料 TOP10 逻辑
- 口径: 近 30 天出入库明细条目数最多的 10 个物料
- 入库:
im_inbound_itemGROUP BY material_id ORDER BY COUNT(*) DESC LIMIT 10 - 出库:
im_outbound_item同上 - SQL 放 Mapper XML(方便后续扩展)
分类筛选逻辑
- 入库: MyBatis Plus LambdaQueryWrapper 查
md_material表,按category_id+keyword分页 - 出库: XML 联表
im_stock JOIN md_material,按category_id+keyword+warehouseId分页,只查库存 > 0 的数据
响应
- 复用
StockPageDTO(im.stock.dto) - 物料编码/名称/规格/单位/分类等从
MaterialFillService填充
新增文件(7个)
| 文件 | 路径 |
|---|---|
| MaterialSelectorReqDTO | md.material.dto |
| MaterialSelectorService | md.material.service |
| MaterialSelectorServiceImpl | md.material.service.impl |
| InboundItemMapper.xml | resources/mapper/im/ |
| OutboundItemMapper.xml | resources/mapper/im/ |
| StockMapper.xml | resources/mapper/im/ |
修改文件(5个)
| 文件 | 改动 |
|---|---|
| InboundItemMapper.java | + selectRecentMaterialIds() |
| OutboundItemMapper.java | + selectRecentMaterialIds() |
| StockMapper.java | + selectStockPage() / countStockPage() |
| InboundController.java | + /material-selector 端点 |
| OutboundController.java | + /material-selector 端点 |
历史单据创建人名称
改动
- InboundHistoryItemDTO — 新增
creatorName字段 - OutboundHistoryItemDTO — 新增
creatorName字段 - InboundServiceImpl.listHistory() — 收集 creators → 批量查 sys_user(username→nickname) → 填充
- OutboundServiceImpl.listHistory() — 同上
逻辑
- 从单据列表收集所有
creator(用户名) userService.lambdaQuery().in(User::getUsername, creators).list()- 转
Map<String, String>(username → nickname) - 逐行
dto.setCreatorName() - 一次 SQL,不 N+1
实体名称字段清理(SupplierName/CustomerName/WarehouseName)
背景
单据实体(Inbound、Outbound、PurchaseOrder、SalesOrder、Delivery)及其 Item 实体中,之前还存储了供应商名称、客户名称、仓库名称等冗余字段。本次清理全部移除,只存 ID,显示名称通过 master-data 查询填充。
涉及实体
- Inbound — 移除
supplierName,warehouseName - Outbound — 移除
customerName,warehouseName - PurchaseOrder — 移除
supplierName - PurchaseOrderItem — 移除了
materialCode,materialName,spec,unit(之前已完成) - SalesOrder — 移除
customerName - SalesOrderItem — 移除了物料冗余字段(之前已完成)
- Delivery — 移除
customerName - DeliveryItem — 移除了物料冗余字段(之前已完成)
DTO 改动
- InboundSaveReqDTO / PurchaseInboundSaveReqDTO / ProductionInboundSaveReqDTO — 只保留 supplierId/warehouseId,移除 supplierName/warehouseName
- OutboundSaveReqDTO / SalesOutboundSaveReqDTO / MaterialOutboundSaveReqDTO — 只保留 customerId/warehouseId,移除 customerName/warehouseName
- InboundHistoryItemDTO / OutboundHistoryItemDTO — 保留 display name 字段(响应 DTO 需要显示),通过 master-data lookup 填充
不做改动
- Ar.java / Ap.java — 保留 customerName / supplierName 作为财务历史快照
- InboundHistoryItemDTO / OutboundHistoryItemDTO — 保留 name 字段供前端展示
主要 Service 改动
| 文件 | 改动内容 |
|---|---|
| InboundServiceImpl.java | 注入 WarehouseMapper;移除 entity setSupplierName/setWarehouseName;history DTO 名通过 supplierMapper + warehouseMapper 批量 lookup;autoInboundFromOrder 用 supplierId 取代 supplierName;updatePurchaseOrderAfterInbound 用 supplierId 查询 |
| OutboundServiceImpl.java | 注入 WarehouseMapper;移除 entity setCustomerName;history DTO 名通过 customerMapper + warehouseMapper 批量 lookup |
| FinAccountsAutoServiceImpl.java | createApFromInbound/cancelApFromInbound 使用 supplierMapper 查询 supplierName 填充 Ap;createArFromOutbound/cancelArFromOutbound 使用 customerMapper 查询 customerName |
| PurchaseOrderServiceImpl.java | setSupplierName(reqDTO.getSupplierName()) → setSupplierId(reqDTO.getSupplierId()) |
| SalesOrderServiceImpl.java | setCustomerName(reqDTO.getCustomerName()) → setCustomerId(reqDTO.getCustomerId()) |
| DeliveryServiceImpl.java | setCustomerName(order.getCustomerName()) → setCustomerId(order.getCustomerId());item 用 materialFillService 填充物料信息 |
控制器查询条件
- PurchaseOrderController / SalesOrderController / DeliveryController — 查询条件从名称改为 ID
编译验证
mvn clean compile✅ — 零错误
集成测试(InboundOutboundIntegrationTest)
文件路径
src/test/java/com/witsoft/erp/im/InboundOutboundIntegrationTest.java
设计
- 使用
TestRestTemplate,webEnvironment = RANDOM_PORT @TestMethodOrder(MethodOrderer.OrderAnnotation.class)按顺序执行- 复用已有的
Result<T>泛型返回包装类
测试覆盖(11 个用例)
| 序号 | 端点 | 说明 |
|---|---|---|
| 1 | POST /erp/system/user/login | 登录获取 Bearer token |
| 2 | POST /erp/im/inbound/production | 生产入库(2 行物料) |
| 3 | POST /erp/im/inbound/purchase | 采购入库(含单价) |
| 4 | POST /erp/im/inbound/history-list | 查询入库历史 |
| 5 | POST /erp/im/outbound/material | 领料出库 |
| 6 | POST /erp/im/outbound/sales | 销售出库(含单价) |
| 7 | POST /erp/im/outbound/history-list | 查询出库历史 |
| 8 | POST /erp/im/inbound/auto-from-order | 自动入库(基于采购订单) |
| 9 | POST /erp/im/stock/transaction/page | 查询库存流水 |
| 10 | DELETE /erp/im/inbound/{id} | 撤销入库单 |
| 11 | DELETE /erp/im/outbound/{id} | 撤销出库单 |
注意事项
application.yml中server.servlet.context-path: /erp,所有路径须带/erp前缀- 测试需要准备基础数据:物料 ID=3/4、供应商 ID=1、客户 ID=1、仓库 ID=1、采购订单 ID=1
- 当前
authToken未通过 TestRestTemplate 的 basic auth,走的是 token-auth 模式 - 登录密码写的是
***,需要按实际数据库密码修改TEST_PASSWORD常量
Controller 集成测试(TestRestTemplate)
现有测试文件
| 测试类 | 路径 | 用例数 | 覆盖 Controller |
|---|---|---|---|
| InboundOutboundIntegrationTest | im/InboundOutboundIntegrationTest.java |
11 | Inbound + Outbound(合并) |
| StockControllerTest | im/stock/StockControllerTest.java |
17 | StockController |
| StocktakeControllerTest | im/stocktake/StocktakeControllerTest.java |
17 | StocktakeController |
| InboundControllerTest | im/inbound/InboundControllerTest.java |
21 | InboundController |
| OutboundControllerTest | im/outbound/OutboundControllerTest.java |
21 | OutboundController |
测试设计模式(所有测试统一)
- TestRestTemplate + RANDOM_PORT — 自动分配端口,避免冲突
- @TestMethodOrder(OrderAnnotation.class) — 按 Order 顺序执行
- CONTEXT_PATH = "/erp" — 手动拼接,因为自动 context-path 处理不可靠
- assumeToken() 守卫 — 登录失败后通过
Assumptions.assumeTrue(authToken != null)跳过后续测试,避免 403 - 密码可配置 —
System.getProperty("test.password", "admin123"),通过-Dtest.password=xxx覆盖 - url() 辅助方法 —
"http://localhost:" + port + CONTEXT_PATH + path
InboundControllerTest(21 用例)
| 序号 | 端点 | 验证 |
|---|---|---|
| 1 | POST /system/user/login | 登录获取 Bearer token |
| 2-3 | POST /im/inbound/material-selector | 物料选择器(分类筛选) |
| 4-6 | POST /im/inbound | 新增 + 明细为空/类型为空校验边界 |
| 7-8 | GET /im/inbound/{id} | 详情 / 不存在返回 null |
| 9 | GET /im/inbound/{id}/items | 明细列表 |
| 10 | PUT /im/inbound | 修改 |
| 11-12 | PUT /im/inbound/{id}/cancel | 撤销 / 重复撤销 400 |
| 13-14 | DELETE /im/inbound/{id} | 删除 |
| 15-16 | POST /im/inbound/page | 分页(全查/仓库筛选) |
| 17 | POST /im/inbound/history-list | 历史明细列表 |
| 18 | POST /im/inbound/production | 生产入库 |
| 19-20 | POST /im/inbound/purchase | 采购入库 / 供应商为空 400 |
| 21 | POST /im/inbound/auto-from-order | 自动入库-订单不存在 400 |
OutboundControllerTest(21 用例)
| 序号 | 端点 | 验证 |
|---|---|---|
| 1 | POST /system/user/login | 登录 |
| 2-3 | POST /im/outbound/material-selector | 物料选择器 |
| 4-6 | POST /im/outbound | 新增 + 明细为空/客户为空校验 |
| 7-8 | GET /im/outbound/{id} | 详情 / 不存在 |
| 9 | GET /im/outbound/{id}/items | 明细 |
| 10 | PUT /im/outbound | 修改 |
| 11-12 | PUT /im/outbound/{id}/cancel | 撤销 / 重复撤销 400 |
| 13-14 | DELETE /im/outbound/{id} | 删除 |
| 15-16 | POST /im/outbound/page | 分页(全查/客户筛选) |
| 17 | POST /im/outbound/history-list | 历史明细 |
| 18-19 | POST /im/outbound/material | 领料出库 / 明细为空 400 |
| 20-21 | POST /im/outbound/sales | 销售出库 / 客户为空 400 |
StockControllerTest(17 用例)
覆盖 StockController 全部 4 个端点:
| 序号 | 端点 | 验证 |
|---|---|---|
| 1 | POST /system/user/login | 登录 |
| 2-6 | POST /im/stock/page | 空参数、仓库筛选、关键字、无匹配关键字、自定义分页 |
| 7-11 | POST /im/stock/list | 空、仓库、关键字、预警筛选、无匹配关键字 |
| 12-13 | GET /im/stock/{materialId} | 存在/不存在 |
| 14-16 | PUT /im/stock/safe-qty | 正常设置、物料不存在 400、参数校验 |
| 17 | POST /im/stock/page | DTO 字段完整性验证 |
StocktakeControllerTest(17 用例)
覆盖 StocktakeController 全部 10 个端点:
| 序号 | 端点 | 验证 |
|---|---|---|
| 1 | POST /system/user/login | 登录 |
| 2-3 | POST /im/stocktake | 新增(草稿)/ 明细为空 400 |
| 4-5 | GET /im/stocktake/{id} | 详情 / 不存在 |
| 6 | GET /im/stocktake/{id}/items | 明细(含物料信息) |
| 7 | PUT /im/stocktake | 修改 |
| 8-9 | PUT /im/stocktake/{id}/audit | 审核 / 重复审核 400 |
| 10-11 | PUT /im/stocktake/{id}/cancel | 作废 |
| 12 | DELETE /im/stocktake/{id} | 删除 |
| 13 | POST /im/stocktake/quick-save | 快速盘点(创建即审核) |
| 14-15 | POST /im/stocktake/page | 分页(筛选/空 body) |
| 16-17 | POST /im/stocktake/history-list | 历史明细(空条件) |
已知问题
- InboundController.getPage() 有两个 @RequestBody — 测试用 Map 代理
- OutboundController.getPage() 同理
- StocktakeController.getPage() 同理
- 密码默认
admin123,通过-Dtest.password=xxx配置 - IntelliJ 解析
junit-platform-launcher:1.8.2失败,已在 pom.xml 中添加依赖