docs/material_stock_adjust.md
@@ -15,11 +15,11 @@ ## 新增 API ### 库存调整(自定义出入库) ### 自定义入库 | 方法 | 路径 | 说明 | |------|------|------| | POST | /mes/wm/material-stock/adjust | 库存调整(正数=入库,负数=出库) | | POST | /mes/wm/material-stock/adjust-in | 自定义入库 | **请求参数:** @@ -32,8 +32,38 @@ | batchId | Long | 否 | 批次ID | | batchCode | String | 否 | 批次号 | | vendorId | Long | 否 | 供应商ID | | quantity | BigDecimal | 是 | 调整数量(正数=入库,负数=出库) | | reason | String | 否 | 调整原因 | | quantity | BigDecimal | 是 | 入库数量(必须大于0) | | reason | String | 否 | 入库原因 | **响应:** ```json { "code": 0, "data": 123, // 库存记录ID "msg": "操作成功" } ``` ### 自定义出库 | 方法 | 路径 | 说明 | |------|------|------| | POST | /mes/wm/material-stock/adjust-out | 自定义出库 | **请求参数:** | 参数 | 类型 | 必填 | 说明 | |------|------|------|------| | itemId | Long | 是 | 物料ID | | warehouseId | Long | 是 | 仓库ID | | locationId | Long | 是 | 库区ID | | areaId | Long | 是 | 库位ID | | batchId | Long | 否 | 批次ID | | batchCode | String | 否 | 批次号 | | vendorId | Long | 否 | 供应商ID | | quantity | BigDecimal | 是 | 出库数量(必须大于0) | | reason | String | 否 | 出库原因 | **响应:** @@ -57,6 +87,10 @@ ### 2. 库存调整弹窗 **操作类型选择:** - 用户首先选择操作类型:入库 / 出库 - 根据操作类型调用不同的 API **表单字段:** | 字段 | 类型 | 必填 | 说明 | @@ -67,8 +101,8 @@ | 库位 | 选择器 | 是 | 根据库区联动加载库位 | | 批次 | 选择器 | 否 | 弹出批次选择对话框(如果物料启用批次管理) | | 供应商 | 选择器 | 否 | 下拉选择供应商 | | 调整数量 | 数字输入 | 是 | 正数=入库,负数=出库 | | 调整原因 | 文本输入 | 否 | 填写调整原因 | | 入库数量/出库数量 | 数字输入 | 是 | 必须大于0 | | 入库原因/出库原因 | 文本输入 | 否 | 填写原因 | **联动逻辑:** @@ -81,16 +115,18 @@ **提交逻辑:** 1. 校验必填字段 2. 调用 API `/mes/wm/material-stock/adjust` 3. 成功后提示"调整成功",刷新列表页 2. 根据操作类型调用不同 API: - 入库:`/mes/wm/material-stock/adjust-in` - 出库:`/mes/wm/material-stock/adjust-out` 3. 成功后提示"入库成功"/"出库成功",刷新列表页 4. 失败时显示错误信息 ## 业务规则说明 | 场景 | 规则 | |------|------| | 入库(quantity > 0) | 自动创建库存记录(如果不存在),增加库存数量 | | 出库(quantity < 0) | 校验库存记录存在且数量充足,扣减库存数量 | | 入库 | 自动创建库存记录(如果不存在),增加库存数量 | | 出库 | 校验库存记录存在且数量充足,扣减库存数量 | | 批次管理 | 物料启用批次管理时,必须选择批次 | | 库位混放 | 根据库位配置的混放规则校验 | @@ -107,7 +143,7 @@ ## 注意事项 - 调整数量不能为0 - 入库数量/出库数量必须大于0 - 出库时必须保证库存充足 - 调整操作会记录库存事务流水,便于追溯 - 建议在调整原因中填写详细的调整原因,便于后续查询和审计 - 入库和出库操作会分别记录库存事务流水,便于追溯 - 建议在原因中填写详细说明,便于后续查询和审计 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/MesWmMaterialStockController.java
@@ -100,11 +100,18 @@ return success(true); } @PostMapping("/adjust") @Operation(summary = "库存调整(自定义出入库)") @PostMapping("/adjust-in") @Operation(summary = "自定义入库") @PreAuthorize("@ss.hasPermission('mes:wm-material-stock:adjust')") public CommonResult<Long> adjustMaterialStock(@Valid @RequestBody MesWmMaterialStockAdjustReqVO reqVO) { return success(materialStockService.adjustMaterialStock(reqVO)); public CommonResult<Long> adjustMaterialStockIn(@Valid @RequestBody MesWmMaterialStockAdjustReqVO reqVO) { return success(materialStockService.adjustMaterialStockIn(reqVO)); } @PostMapping("/adjust-out") @Operation(summary = "自定义出库") @PreAuthorize("@ss.hasPermission('mes:wm-material-stock:adjust')") public CommonResult<Long> adjustMaterialStockOut(@Valid @RequestBody MesWmMaterialStockAdjustReqVO reqVO) { return success(materialStockService.adjustMaterialStockOut(reqVO)); } @GetMapping("/export-excel") yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockAdjustReqVO.java
@@ -2,6 +2,7 @@ import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Positive; import lombok.Data; import java.math.BigDecimal; @@ -38,11 +39,12 @@ @Schema(description = "供应商ID", example = "1") private Long vendorId; @Schema(description = "调整数量(正数=入库,负数=出库)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") @NotNull(message = "调整数量不能为空") @Schema(description = "数量(必须大于0)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") @NotNull(message = "数量不能为空") @Positive(message = "数量必须大于0") private BigDecimal quantity; @Schema(description = "调整原因", example = "盘点调整") @Schema(description = "原因", example = "盘点调整") private String reason; } yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockService.java
@@ -150,11 +150,19 @@ Long warehouseId, Long locationId, Long areaId, BigDecimal quantity); /** * 库存调整(自定义出入库) * 自定义入库 * * @param reqVO 调整请求 * @return 库存事务流水ID * @param reqVO 入库请求 * @return 库存记录ID */ Long adjustMaterialStock(@Valid MesWmMaterialStockAdjustReqVO reqVO); Long adjustMaterialStockIn(@Valid MesWmMaterialStockAdjustReqVO reqVO); /** * 自定义出库 * * @param reqVO 出库请求 * @return 库存记录ID */ Long adjustMaterialStockOut(@Valid MesWmMaterialStockAdjustReqVO reqVO); } yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockServiceImpl.java
@@ -243,22 +243,31 @@ @Override @Transactional(rollbackFor = Exception.class) public Long adjustMaterialStock(MesWmMaterialStockAdjustReqVO reqVO) { public Long adjustMaterialStockIn(MesWmMaterialStockAdjustReqVO reqVO) { return doAdjustMaterialStock(reqVO, true); } @Override @Transactional(rollbackFor = Exception.class) public Long adjustMaterialStockOut(MesWmMaterialStockAdjustReqVO reqVO) { return doAdjustMaterialStock(reqVO, false); } /** * 执行库存调整 * * @param reqVO 调整请求 * @param isInbound 是否为入库(true=入库,false=出库) * @return 库存记录ID */ private Long doAdjustMaterialStock(MesWmMaterialStockAdjustReqVO reqVO, boolean isInbound) { // 1. 校验物料存在且启用 MesMdmItemDO item = mdmItemService.validateItemExistsAndEnable(reqVO.getItemId()); // 2. 判断是入库还是出库 BigDecimal quantity = reqVO.getQuantity(); if (quantity == null || quantity.compareTo(BigDecimal.ZERO) == 0) { throw exception(WM_MATERIAL_STOCK_QUANTITY_INVALID); } boolean isInbound = quantity.compareTo(BigDecimal.ZERO) > 0; int bizType = isInbound ? MesBizTypeConstants.WM_STOCK_ADJUST_IN : MesBizTypeConstants.WM_STOCK_ADJUST_OUT; // 3. 校验库位混放规则 // 2. 校验库位混放规则 checkAreaMixingRule(reqVO.getAreaId(), reqVO.getItemId(), reqVO.getBatchId()); // 4. 获取或创建库存记录 // 3. 获取或创建库存记录 MesWmMaterialStockDO stock = getOrCreateMaterialStock( reqVO.getItemId(), reqVO.getWarehouseId(), @@ -270,10 +279,14 @@ LocalDateTime.now() ); // 4. 计算变动数量:入库为正,出库为负 BigDecimal quantity = isInbound ? reqVO.getQuantity() : reqVO.getQuantity().negate(); // 5. 更新库存数量(出库时校验库存充足) updateMaterialStockQuantity(stock.getId(), quantity, !isInbound); // 6. 创建库存事务流水 int bizType = isInbound ? MesBizTypeConstants.WM_STOCK_ADJUST_IN : MesBizTypeConstants.WM_STOCK_ADJUST_OUT; MesWmTransactionSaveReqDTO transaction = new MesWmTransactionSaveReqDTO() .setType(isInbound ? MesWmTransactionTypeEnum.IN.getType() : MesWmTransactionTypeEnum.OUT.getType()) .setBizType(bizType)