8 天以前 1c1daebcb9f89138a84e9a7643d1909bb1a5a342
1.仓储物流-自定义出入库分别新增接口
已修改5个文件
136 ■■■■ 文件已修改
docs/material_stock_adjust.md 62 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/MesWmMaterialStockController.java 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockAdjustReqVO.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockService.java 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockServiceImpl.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
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)