From 2d49ac272ee5e6c775e3a42e233711a9ec6e6e21 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Fri, 20 Feb 2026 08:26:46 +0800 Subject: [PATCH] feat(mes): 新增仓库管理-库存台账模块(wm_material_stock) --- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/MesWmMaterialStockController.java | 163 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockPageReqVO.java | 36 ++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockRespVO.java | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockSaveReqVO.java | 20 ++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/materialstock/MesWmMaterialStockDO.java | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstock/MesWmMaterialStockMapper.java | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java | 3 +++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockService.java | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockServiceImpl.java | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseAreaServiceImpl.java | 12 ++++++++++-- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseLocationServiceImpl.java | 14 +++++++++++--- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseServiceImpl.java | 10 +++++++++- 12 files changed, 747 insertions(+), 6 deletions(-) create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/MesWmMaterialStockController.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockPageReqVO.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockRespVO.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockSaveReqVO.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/materialstock/MesWmMaterialStockDO.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstock/MesWmMaterialStockMapper.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockService.java create mode 100644 yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockServiceImpl.java diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/MesWmMaterialStockController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/MesWmMaterialStockController.java new file mode 100644 index 0000000..026e9e9 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/MesWmMaterialStockController.java @@ -0,0 +1,163 @@ +package cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockPageReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockRespVO; +import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockSaveReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.vendor.MesMdVendorDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO; +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; +import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService; +import cn.iocoder.yudao.module.mes.service.md.vendor.MesMdVendorService; +import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderService; +import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService; +import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService; +import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseLocationService; +import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - MES 库存台账") +@RestController +@RequestMapping("/mes/wm/material-stock") +@Validated +public class MesWmMaterialStockController { + + @Resource + private MesWmMaterialStockService materialStockService; + + @Resource + private MesMdItemService itemService; + + @Resource + private MesMdUnitMeasureService unitMeasureService; + + @Resource + private MesWmWarehouseService warehouseService; + + @Resource + private MesWmWarehouseLocationService locationService; + + @Resource + private MesWmWarehouseAreaService areaService; + + @Resource + private MesMdVendorService vendorService; + + @Resource + private MesProWorkOrderService workOrderService; + + @GetMapping("/get") + @Operation(summary = "获得库存记录") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('mes:wm-material-stock:query')") + public CommonResult getMaterialStock(@RequestParam("id") Long id) { + MesWmMaterialStockDO stock = materialStockService.getMaterialStock(id); + if (stock == null) { + return success(null); + } + return success(buildRespVOList(Collections.singletonList(stock)).get(0)); + } + + @GetMapping("/page") + @Operation(summary = "获得库存台账分页") + @PreAuthorize("@ss.hasPermission('mes:wm-material-stock:query')") + public CommonResult> getMaterialStockPage( + @Valid MesWmMaterialStockPageReqVO pageReqVO) { + PageResult pageResult = materialStockService.getMaterialStockPage(pageReqVO); + return success(new PageResult<>(buildRespVOList(pageResult.getList()), pageResult.getTotal())); + } + + @PutMapping("/update-frozen") + @Operation(summary = "更新库存冻结状态") + @PreAuthorize("@ss.hasPermission('mes:wm-material-stock:update')") + public CommonResult updateMaterialStockFrozen( + @Valid @RequestBody MesWmMaterialStockSaveReqVO updateReqVO) { + materialStockService.updateMaterialStockFrozen(updateReqVO); + return success(true); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出库存台账 Excel") + @PreAuthorize("@ss.hasPermission('mes:wm-material-stock:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportMaterialStockExcel(@Valid MesWmMaterialStockPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + PageResult pageResult = materialStockService.getMaterialStockPage(pageReqVO); + ExcelUtils.write(response, "库存台账.xls", "数据", MesWmMaterialStockRespVO.class, + buildRespVOList(pageResult.getList())); + } + + // ==================== 拼接 VO ==================== + + private List buildRespVOList(List list) { + if (CollUtil.isEmpty(list)) { + return Collections.emptyList(); + } + // 1. 获得关联数据 + Map itemMap = itemService.getItemMap( + convertSet(list, MesWmMaterialStockDO::getItemId)); + Map unitMeasureMap = unitMeasureService.getUnitMeasureMap( + convertSet(list, MesWmMaterialStockDO::getUnitMeasureId)); + Map warehouseMap = warehouseService.getWarehouseMap( + convertSet(list, MesWmMaterialStockDO::getWarehouseId)); + Map locationMap = locationService.getWarehouseLocationMap( + convertSet(list, MesWmMaterialStockDO::getLocationId)); + Map areaMap = areaService.getWarehouseAreaMap( + convertSet(list, MesWmMaterialStockDO::getAreaId)); + Map vendorMap = vendorService.getVendorMap( + convertSet(list, MesWmMaterialStockDO::getVendorId)); + Map workOrderMap = workOrderService.getWorkOrderMap( + convertSet(list, MesWmMaterialStockDO::getWorkOrderId)); + // TODO @芋艿:待 mes_wm_batch 模块迁移后,补充 batchCode 的拼接 + + // 2. 构建结果 + return BeanUtils.toBean(list, MesWmMaterialStockRespVO.class, vo -> { + MapUtils.findAndThen(itemMap, vo.getItemId(), item -> + vo.setItemCode(item.getCode()).setItemName(item.getName()).setSpecification(item.getSpecification())); + MapUtils.findAndThen(unitMeasureMap, vo.getUnitMeasureId(), + unitMeasure -> vo.setUnitMeasureName(unitMeasure.getName())); + MapUtils.findAndThen(warehouseMap, vo.getWarehouseId(), + warehouse -> vo.setWarehouseName(warehouse.getName())); + MapUtils.findAndThen(locationMap, vo.getLocationId(), + location -> vo.setLocationName(location.getName())); + MapUtils.findAndThen(areaMap, vo.getAreaId(), + area -> vo.setAreaName(area.getName())); + MapUtils.findAndThen(vendorMap, vo.getVendorId(), + vendor -> vo.setVendorName(vendor.getName())); + MapUtils.findAndThen(workOrderMap, vo.getWorkOrderId(), + workOrder -> vo.setWorkOrderCode(workOrder.getCode())); + }); + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockPageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockPageReqVO.java new file mode 100644 index 0000000..5d4a900 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockPageReqVO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - MES 库存台账分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MesWmMaterialStockPageReqVO extends PageParam { + + @Schema(description = "物料分类编号", example = "1") + private Long itemTypeId; + + @Schema(description = "物料编码", example = "M001") + private String itemCode; + + @Schema(description = "物料名称", example = "钢板") + private String itemName; + + @Schema(description = "批次号", example = "B20260101") + private String batchCode; + + @Schema(description = "仓库编号", example = "1") + private Long warehouseId; + + @Schema(description = "库区编号", example = "1") + private Long locationId; + + @Schema(description = "是否冻结", example = "false") + private Boolean frozen; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockRespVO.java new file mode 100644 index 0000000..8fc6548 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockRespVO.java @@ -0,0 +1,111 @@ +package cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo; + +import cn.idev.excel.annotation.ExcelIgnoreUnannotated; +import cn.idev.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - MES 库存台账 Response VO") +@Data +@ExcelIgnoreUnannotated +public class MesWmMaterialStockRespVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @ExcelProperty("编号") + private Long id; + + @Schema(description = "物料分类编号", example = "1") + private Long itemTypeId; + + @Schema(description = "物料编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long itemId; + + @Schema(description = "物料编码", example = "M001") + @ExcelProperty("物料编码") + private String itemCode; + + @Schema(description = "物料名称", example = "钢板") + @ExcelProperty("物料名称") + private String itemName; + + @Schema(description = "规格型号", example = "10mm*100mm") + @ExcelProperty("规格型号") + private String specification; + + @Schema(description = "计量单位编号", example = "1") + private Long unitMeasureId; + + @Schema(description = "计量单位名称", example = "千克") + @ExcelProperty("计量单位") + private String unitMeasureName; + + @Schema(description = "批次编号", example = "1") + private Long batchId; + + @Schema(description = "批次号", example = "B20260101") + @ExcelProperty("批次号") + private String batchCode; + + @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long warehouseId; + + @Schema(description = "仓库名称", example = "原料仓") + @ExcelProperty("仓库") + private String warehouseName; + + @Schema(description = "库区编号", example = "1") + private Long locationId; + + @Schema(description = "库区名称", example = "A 区") + @ExcelProperty("库区") + private String locationName; + + @Schema(description = "库位编号", example = "1") + private Long areaId; + + @Schema(description = "库位名称", example = "A-01") + @ExcelProperty("库位") + private String areaName; + + @Schema(description = "供应商编号", example = "1") + private Long vendorId; + + @Schema(description = "供应商名称", example = "某供应商") + @ExcelProperty("供应商") + private String vendorName; + + @Schema(description = "生产工单编号", example = "1") + private Long workOrderId; + + @Schema(description = "生产工单编码", example = "WO20260101") + @ExcelProperty("生产工单") + private String workOrderCode; + + @Schema(description = "在库数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.0000") + @ExcelProperty("在库数量") + private BigDecimal quantityOnhand; + + @Schema(description = "入库时间") + @ExcelProperty("入库时间") + private LocalDateTime recptDate; + + @Schema(description = "生产日期") + @ExcelProperty("生产日期") + private LocalDateTime productionDate; + + @Schema(description = "库存有效期") + @ExcelProperty("有效期") + private LocalDateTime expireDate; + + @Schema(description = "是否冻结", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") + @ExcelProperty("是否冻结") + private Boolean frozen; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockSaveReqVO.java new file mode 100644 index 0000000..eb08485 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/materialstock/vo/MesWmMaterialStockSaveReqVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +// TODO @AI:不应该叫 save?! +@Schema(description = "管理后台 - MES 库存台账冻结/解冻 Request VO") +@Data +public class MesWmMaterialStockSaveReqVO { + + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "编号不能为空") + private Long id; + + @Schema(description = "是否冻结", requiredMode = Schema.RequiredMode.REQUIRED, example = "false") + @NotNull(message = "冻结状态不能为空") + private Boolean frozen; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/materialstock/MesWmMaterialStockDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/materialstock/MesWmMaterialStockDO.java new file mode 100644 index 0000000..2fd0c5a --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/materialstock/MesWmMaterialStockDO.java @@ -0,0 +1,132 @@ +package cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemTypeDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.vendor.MesMdVendorDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +// TODO @芋艿:这个包名,还有优化的空间么?类似 erp_stock_record? +/** + * MES 库存台账(仓库现有量)DO + */ +@TableName("mes_wm_material_stock") +@KeySequence("mes_wm_material_stock_seq") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MesWmMaterialStockDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + // TODO @AI:是不是不用冗余?通过 itemId 查询; + /** + * 物料分类编号 + * + * 关联 {@link MesMdItemTypeDO#getId()} + */ + private Long itemTypeId; + /** + * 物料编号 + * + * 关联 {@link MesMdItemDO#getId()} + */ + private Long itemId; + // TODO @AI:是不是不用冗余?通过 itemId 查询; + /** + * 计量单位编号 + * + * 关联 {@link MesMdUnitMeasureDO#getId()} + */ + private Long unitMeasureId; + /** + * 批次编号 + * + * TODO @芋艿:待 mes_wm_batch 模块迁移后关联 + */ + private Long batchId; + /** + * 仓库编号 + * + * 关联 {@link MesWmWarehouseDO#getId()} + */ + private Long warehouseId; + /** + * 库区编号 + * + * 关联 {@link MesWmWarehouseLocationDO#getId()} + */ + private Long locationId; + /** + * 库位编号 + * + * 关联 {@link MesWmWarehouseAreaDO#getId()} + */ + private Long areaId; + /** + * 供应商编号 + * + * 关联 {@link MesMdVendorDO#getId()} + */ + private Long vendorId; + // TODO @AI:去关联下; + /** + * 生产工单编号 + * + * TODO @芋艿:待 mes_pro_work_order 模块完成后关联 + */ + private Long workOrderId; + /** + * 在库数量 + */ + private BigDecimal quantityOnhand; + /** + * 入库时间 + */ + private LocalDateTime recptDate; + /** + * 库存有效期 + */ + private LocalDateTime expireDate; + /** + * 生产日期 + */ + private LocalDateTime productionDate; + /** + * 是否冻结 + */ + private Boolean frozen; + /** + * 预留字段1 + */ + private String attribute1; + /** + * 预留字段2 + */ + private String attribute2; + /** + * 预留字段3 + */ + private Integer attribute3; + /** + * 预留字段4 + */ + private Integer attribute4; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstock/MesWmMaterialStockMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstock/MesWmMaterialStockMapper.java new file mode 100644 index 0000000..f13d12a --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/materialstock/MesWmMaterialStockMapper.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockPageReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO; +import org.apache.ibatis.annotations.Mapper; + +import java.math.BigDecimal; +import java.util.Collection; +import java.util.List; + +/** + * MES 库存台账 Mapper + */ +@Mapper +public interface MesWmMaterialStockMapper extends BaseMapperX { + + default PageResult selectPage(MesWmMaterialStockPageReqVO reqVO, + Collection itemTypeIds, + Collection itemIds) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .inIfPresent(MesWmMaterialStockDO::getItemTypeId, itemTypeIds) + .inIfPresent(MesWmMaterialStockDO::getItemId, itemIds) + .eqIfPresent(MesWmMaterialStockDO::getWarehouseId, reqVO.getWarehouseId()) + .eqIfPresent(MesWmMaterialStockDO::getLocationId, reqVO.getLocationId()) + .eqIfPresent(MesWmMaterialStockDO::getFrozen, reqVO.getFrozen()) + .ne(MesWmMaterialStockDO::getQuantityOnhand, BigDecimal.ZERO) + .orderByAsc(MesWmMaterialStockDO::getRecptDate)); + } + + default Long selectCountByWarehouseId(Long warehouseId) { + return selectCount(MesWmMaterialStockDO::getWarehouseId, warehouseId); + } + + default Long selectCountByLocationId(Long locationId) { + return selectCount(MesWmMaterialStockDO::getLocationId, locationId); + } + + default Long selectCountByAreaId(Long areaId) { + return selectCount(MesWmMaterialStockDO::getAreaId, areaId); + } + + default List selectListByIds(Collection ids) { + return selectByIds(ids); + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java index 8073e96..28ac24a 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java @@ -198,6 +198,7 @@ public interface ErrorCodeConstants { ErrorCode WM_WAREHOUSE_NAME_DUPLICATE = new ErrorCode(1_040_700_002, "仓库名称已存在"); ErrorCode WM_WAREHOUSE_HAS_LOCATION = new ErrorCode(1_040_700_003, "仓库下存在库区,无法删除"); ErrorCode WM_WAREHOUSE_HAS_WORKSTATION = new ErrorCode(1_040_700_004, "仓库已被工作站引用,无法删除"); + ErrorCode WM_WAREHOUSE_HAS_MATERIAL_STOCK = new ErrorCode(1_040_700_005, "仓库下有库存记录,无法删除"); // ========== MES 仓库管理-库区(1-040-701-000) ========== ErrorCode WM_WAREHOUSE_LOCATION_NOT_EXISTS = new ErrorCode(1_040_701_000, "库区不存在"); @@ -207,6 +208,7 @@ public interface ErrorCodeConstants { ErrorCode WM_WAREHOUSE_LOCATION_HAS_WORKSTATION = new ErrorCode(1_040_701_004, "库区已被工作站引用,无法删除"); ErrorCode WM_WAREHOUSE_REQUIRED = new ErrorCode(1_040_701_005, "选择库区时,仓库不能为空"); ErrorCode WM_WAREHOUSE_LOCATION_RELATION_INVALID = new ErrorCode(1_040_701_006, "库区不属于所选仓库"); + ErrorCode WM_WAREHOUSE_LOCATION_HAS_MATERIAL_STOCK = new ErrorCode(1_040_701_007, "库区下有库存记录,无法删除"); // ========== MES 仓库管理-库位(1-040-702-000) ========== ErrorCode WM_WAREHOUSE_AREA_NOT_EXISTS = new ErrorCode(1_040_702_000, "库位不存在"); @@ -215,6 +217,7 @@ public interface ErrorCodeConstants { ErrorCode WM_WAREHOUSE_AREA_HAS_WORKSTATION = new ErrorCode(1_040_702_003, "库位已被工作站引用,无法删除"); ErrorCode WM_WAREHOUSE_LOCATION_REQUIRED = new ErrorCode(1_040_702_004, "选择库位时,库区不能为空"); ErrorCode WM_WAREHOUSE_AREA_RELATION_INVALID = new ErrorCode(1_040_702_005, "库位不属于所选库区"); + ErrorCode WM_WAREHOUSE_AREA_HAS_MATERIAL_STOCK = new ErrorCode(1_040_702_006, "库位下有库存记录,无法删除"); // ========== MES 仓库管理-库存(1-040-703-000) ========== ErrorCode WM_MATERIAL_STOCK_NOT_EXISTS = new ErrorCode(1_040_703_000, "库存记录不存在"); diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockService.java new file mode 100644 index 0000000..0e4686d --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockService.java @@ -0,0 +1,87 @@ +package cn.iocoder.yudao.module.mes.service.wm.materialstock; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockPageReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockSaveReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO; +import jakarta.validation.Valid; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * MES 库存台账 Service 接口 + */ +public interface MesWmMaterialStockService { + + /** + * 获得库存记录 + * + * @param id 编号 + * @return 库存记录 + */ + MesWmMaterialStockDO getMaterialStock(Long id); + + /** + * 校验库存记录存在 + * + * @param id 编号 + * @return 库存记录 + */ + MesWmMaterialStockDO validateMaterialStockExists(Long id); + + /** + * 获得库存台账分页 + * + * @param pageReqVO 分页参数 + * @return 库存台账分页 + */ + PageResult getMaterialStockPage(MesWmMaterialStockPageReqVO pageReqVO); + + /** + * 更新库存冻结状态 + * + * @param updateReqVO 更新信息 + */ + void updateMaterialStockFrozen(@Valid MesWmMaterialStockSaveReqVO updateReqVO); + + /** + * 获得仓库下库存记录数量 + * + * @param warehouseId 仓库编号 + * @return 记录数量 + */ + Long getMaterialStockCountByWarehouseId(Long warehouseId); + + /** + * 获得库区下库存记录数量 + * + * @param locationId 库区编号 + * @return 记录数量 + */ + Long getMaterialStockCountByLocationId(Long locationId); + + /** + * 获得库位下库存记录数量 + * + * @param areaId 库位编号 + * @return 记录数量 + */ + Long getMaterialStockCountByAreaId(Long areaId); + + /** + * 按编号集合获得库存记录列表 + * + * @param ids 编号集合 + * @return 库存记录列表 + */ + List getMaterialStockList(Collection ids); + + default Map getMaterialStockMap(Collection ids) { + return convertMap(getMaterialStockList(ids), MesWmMaterialStockDO::getId); + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockServiceImpl.java new file mode 100644 index 0000000..7c34c22 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/materialstock/MesWmMaterialStockServiceImpl.java @@ -0,0 +1,116 @@ +package cn.iocoder.yudao.module.mes.service.wm.materialstock; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockPageReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockSaveReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemTypeDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO; +import cn.iocoder.yudao.module.mes.dal.mysql.md.item.MesMdItemMapper; +import cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstock.MesWmMaterialStockMapper; +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemTypeService; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.*; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_MATERIAL_STOCK_NOT_EXISTS; + +/** + * MES 库存台账 Service 实现类 + */ +@Service +@Validated +public class MesWmMaterialStockServiceImpl implements MesWmMaterialStockService { + + @Resource + private MesWmMaterialStockMapper materialStockMapper; + + @Resource + private MesMdItemTypeService itemTypeService; + + @Resource + private MesMdItemMapper itemMapper; + + @Override + public MesWmMaterialStockDO getMaterialStock(Long id) { + return materialStockMapper.selectById(id); + } + + @Override + public MesWmMaterialStockDO validateMaterialStockExists(Long id) { + MesWmMaterialStockDO stock = materialStockMapper.selectById(id); + if (stock == null) { + throw exception(WM_MATERIAL_STOCK_NOT_EXISTS); + } + return stock; + } + + @Override + public PageResult getMaterialStockPage(MesWmMaterialStockPageReqVO pageReqVO) { + // 1. 解析 itemTypeId:包含子分类 + Set itemTypeIds = null; + if (pageReqVO.getItemTypeId() != null) { + itemTypeIds = new HashSet<>(); + itemTypeIds.add(pageReqVO.getItemTypeId()); + List children = itemTypeService.getItemTypeChildrenList(pageReqVO.getItemTypeId()); + itemTypeIds.addAll(convertSet(children, MesMdItemTypeDO::getId)); + } + + // 2. 解析 itemCode/itemName:查 md_item 找匹配的 itemId 集合 + Set itemIds = null; + if (StrUtil.isNotBlank(pageReqVO.getItemCode()) || StrUtil.isNotBlank(pageReqVO.getItemName())) { + List matchingItems = itemMapper.selectList(new LambdaQueryWrapperX() + .eqIfPresent(MesMdItemDO::getCode, pageReqVO.getItemCode()) + .likeIfPresent(MesMdItemDO::getName, pageReqVO.getItemName())); + if (matchingItems.isEmpty()) { + return PageResult.empty(); + } + itemIds = convertSet(matchingItems, MesMdItemDO::getId); + } + + // 3. 分页查询 + return materialStockMapper.selectPage(pageReqVO, itemTypeIds, itemIds); + } + + @Override + public void updateMaterialStockFrozen(MesWmMaterialStockSaveReqVO updateReqVO) { + // 校验存在 + validateMaterialStockExists(updateReqVO.getId()); + // 更新冻结状态 + MesWmMaterialStockDO updateObj = new MesWmMaterialStockDO(); + updateObj.setId(updateReqVO.getId()); + updateObj.setFrozen(updateReqVO.getFrozen()); + materialStockMapper.updateById(updateObj); + } + + @Override + public Long getMaterialStockCountByWarehouseId(Long warehouseId) { + return materialStockMapper.selectCountByWarehouseId(warehouseId); + } + + @Override + public Long getMaterialStockCountByLocationId(Long locationId) { + return materialStockMapper.selectCountByLocationId(locationId); + } + + @Override + public Long getMaterialStockCountByAreaId(Long areaId) { + return materialStockMapper.selectCountByAreaId(areaId); + } + + @Override + public List getMaterialStockList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + return materialStockMapper.selectListByIds(ids); + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseAreaServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseAreaServiceImpl.java index 8060373..286b267 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseAreaServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseAreaServiceImpl.java @@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.warehouse.vo.area.MesWmWa import cn.iocoder.yudao.module.mes.controller.admin.wm.warehouse.vo.area.MesWmWarehouseAreaSaveReqVO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO; import cn.iocoder.yudao.module.mes.dal.mysql.md.workstation.MesMdWorkstationMapper; +import cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstock.MesWmMaterialStockMapper; import cn.iocoder.yudao.module.mes.dal.mysql.wm.warehouse.MesWmWarehouseAreaMapper; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; @@ -20,6 +21,7 @@ import java.util.List; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; +// TODO @AI:不应该直接跨模块调用 mapper,通过他们的 service 操作 /** * MES 库位 Service 实现类 */ @@ -34,6 +36,9 @@ public class MesWmWarehouseAreaServiceImpl implements MesWmWarehouseAreaService private MesMdWorkstationMapper workstationMapper; @Resource + private MesWmMaterialStockMapper materialStockMapper; + + @Resource private MesWmWarehouseLocationService locationService; @Override @@ -70,10 +75,13 @@ public class MesWmWarehouseAreaServiceImpl implements MesWmWarehouseAreaService // 校验存在 validateWarehouseAreaExists(id); // 校验是否被工作站引用 - if (ObjUtil.defaultIfNull(workstationMapper.selectCountByAreaId(id), 0L) > 0) { + if (workstationMapper.selectCountByAreaId(id) > 0) { throw exception(WM_WAREHOUSE_AREA_HAS_WORKSTATION); } - // DONE @芋艿:本轮范围不接入库存占用校验,待 mes_wm_material_stock 迁移后补充 + // 校验是否有库存记录 + if (materialStockMapper.selectCountByAreaId(id) > 0) { + throw exception(WM_WAREHOUSE_AREA_HAS_MATERIAL_STOCK); + } areaMapper.deleteById(id); } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseLocationServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseLocationServiceImpl.java index 6d8f606..26820a6 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseLocationServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseLocationServiceImpl.java @@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.warehouse.vo.location.Mes import cn.iocoder.yudao.module.mes.controller.admin.wm.warehouse.vo.location.MesWmWarehouseLocationSaveReqVO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO; import cn.iocoder.yudao.module.mes.dal.mysql.md.workstation.MesMdWorkstationMapper; +import cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstock.MesWmMaterialStockMapper; import cn.iocoder.yudao.module.mes.dal.mysql.wm.warehouse.MesWmWarehouseAreaMapper; import cn.iocoder.yudao.module.mes.dal.mysql.wm.warehouse.MesWmWarehouseLocationMapper; import jakarta.annotation.Resource; @@ -21,6 +22,7 @@ import java.util.List; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; +// TODO @AI:不应该直接跨模块调用 mapper,通过他们的 service 操作 /** * MES 库区 Service 实现类 */ @@ -38,6 +40,9 @@ public class MesWmWarehouseLocationServiceImpl implements MesWmWarehouseLocation private MesMdWorkstationMapper workstationMapper; @Resource + private MesWmMaterialStockMapper materialStockMapper; + + @Resource private MesWmWarehouseService warehouseService; @Override @@ -74,14 +79,17 @@ public class MesWmWarehouseLocationServiceImpl implements MesWmWarehouseLocation // 校验存在 validateWarehouseLocationExists(id); // 校验是否有库位 - if (ObjUtil.defaultIfNull(areaMapper.selectCountByLocationId(id), 0L) > 0) { + if (areaMapper.selectCountByLocationId(id) > 0) { throw exception(WM_WAREHOUSE_LOCATION_HAS_AREA); } // 校验是否被工作站引用 - if (ObjUtil.defaultIfNull(workstationMapper.selectCountByLocationId(id), 0L) > 0) { + if (workstationMapper.selectCountByLocationId(id) > 0) { throw exception(WM_WAREHOUSE_LOCATION_HAS_WORKSTATION); } - // DONE @芋艿:本轮范围不接入库存占用校验,待 mes_wm_material_stock 迁移后补充 + // 校验是否有库存记录 + if (materialStockMapper.selectCountByLocationId(id) > 0) { + throw exception(WM_WAREHOUSE_LOCATION_HAS_MATERIAL_STOCK); + } locationMapper.deleteById(id); } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseServiceImpl.java index 7297cca..2c11a93 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/warehouse/MesWmWarehouseServiceImpl.java @@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.mes.controller.admin.wm.warehouse.vo.MesWmWarehou import cn.iocoder.yudao.module.mes.controller.admin.wm.warehouse.vo.MesWmWarehouseSaveReqVO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO; import cn.iocoder.yudao.module.mes.dal.mysql.md.workstation.MesMdWorkstationMapper; +import cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstock.MesWmMaterialStockMapper; import cn.iocoder.yudao.module.mes.dal.mysql.wm.warehouse.MesWmWarehouseLocationMapper; import cn.iocoder.yudao.module.mes.dal.mysql.wm.warehouse.MesWmWarehouseMapper; import jakarta.annotation.Resource; @@ -21,6 +22,7 @@ import java.util.List; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; +// TODO @AI:不应该直接跨模块调用 mapper,通过他们的 service 操作 /** * MES 仓库 Service 实现类 */ @@ -37,6 +39,9 @@ public class MesWmWarehouseServiceImpl implements MesWmWarehouseService { @Resource private MesMdWorkstationMapper workstationMapper; + @Resource + private MesWmMaterialStockMapper materialStockMapper; + @Override public Long createWarehouse(MesWmWarehouseSaveReqVO createReqVO) { // 校验编码唯一 @@ -76,7 +81,10 @@ public class MesWmWarehouseServiceImpl implements MesWmWarehouseService { if (workstationMapper.selectCountByWarehouseId(id) > 0) { throw exception(WM_WAREHOUSE_HAS_WORKSTATION); } - // DONE @芋艿:本轮范围不接入库存占用校验,待 mes_wm_material_stock 迁移后补充 + // 校验是否有库存记录 + if (materialStockMapper.selectCountByWarehouseId(id) > 0) { + throw exception(WM_WAREHOUSE_HAS_MATERIAL_STOCK); + } // 删除 warehouseMapper.deleteById(id); -- libgit2 0.21.4