diff --git a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java index 33af6e76a..e09a78361 100644 --- a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java +++ b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java @@ -101,6 +101,8 @@ public interface ErrorCodeConstants { ErrorCode WAREHOUSE_LOCATION_CODE_EXISTS = new ErrorCode(1_030_400_005, "库位编码不存在"); ErrorCode WAREHOUSE_LOCATION_NOT_EXISTS = new ErrorCode(1_030_400_006, "库位不存在"); ErrorCode WAREHOUSE_LOCATION_WAREHOUSE_AREA_NOT_MATCH = new ErrorCode(1_030_400_007, "暂无匹配库位信息"); + ErrorCode PALLET_NOT_EXISTS = new ErrorCode(1_030_400_008, "托盘不存在"); + ErrorCode PALLET_CODE_EXISTS = new ErrorCode(1_030_400_009, "托盘编码已存在"); // ========== ERP 其它入库单 1-030-401-000 ========== ErrorCode STOCK_IN_NOT_EXISTS = new ErrorCode(1_030_401_000, "其它入库单不存在"); @@ -160,6 +162,9 @@ public interface ErrorCodeConstants { ErrorCode STOCK_CHECK_AUDIT_FAIL_STATUS = new ErrorCode(1_030_403_011, "审核失败,只有审核中的盘点单才能审核"); ErrorCode STOCK_CHECK_AUDIT_FAIL_USER = new ErrorCode(1_030_403_012, "审核失败,当前用户不是指定审核人"); ErrorCode STOCK_CHECK_AUDIT_FAIL_RESULT = new ErrorCode(1_030_403_013, "审核失败,审核结果只支持通过或驳回"); + ErrorCode STOCK_CHECK_SOURCE_TYPE_NOT_EXISTS = new ErrorCode(1_030_403_014, "盘点单生成来源类型不存在"); + ErrorCode STOCK_CODE_EXISTS = new ErrorCode(1_030_403_014, "盘点单编码已存在"); + // ========== ERP 产品库存 1-030-404-000 ========== ErrorCode STOCK_COUNT_NEGATIVE = new ErrorCode(1_030_404_000, "操作失败,产品({})所在仓库({})的库存:{},小于变更数量:{}"); diff --git a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/stock/ErpStockCheckSourceTypeEnum.java b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/stock/ErpStockCheckSourceTypeEnum.java new file mode 100644 index 000000000..06dcd5982 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/stock/ErpStockCheckSourceTypeEnum.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.erp.enums.stock; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +@RequiredArgsConstructor +@Getter +public enum ErpStockCheckSourceTypeEnum implements IntArrayValuable { + + BY_LOCATION(1, "按库存"), + BY_PRODUCT(2, "按产品"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ErpStockCheckSourceTypeEnum::getType).toArray(); + + private final Integer type; + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/pallet/ErpPalletController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/pallet/ErpPalletController.java new file mode 100644 index 000000000..cbf0d2bc6 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/pallet/ErpPalletController.java @@ -0,0 +1,82 @@ +package cn.iocoder.yudao.module.erp.controller.admin.pallet; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.erp.controller.admin.pallet.vo.ErpPalletPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.pallet.vo.ErpPalletRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.pallet.vo.ErpPalletSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.pallet.ErpPalletDO; +import cn.iocoder.yudao.module.erp.service.pallet.ErpPalletService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; + +@Tag(name = "管理后台 - ERP 托盘") +@RestController +@RequestMapping("/erp/pallet") +@Validated +public class ErpPalletController { + + @Resource + private ErpPalletService palletService; + + @PostMapping("/create") + @Operation(summary = "创建托盘") + @PreAuthorize("@ss.hasPermission('erp:pallet:create')") + public CommonResult createPallet(@Valid @RequestBody ErpPalletSaveReqVO createReqVO) { + return success(palletService.createPallet(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新托盘") + @PreAuthorize("@ss.hasPermission('erp:pallet:update')") + public CommonResult updatePallet(@Valid @RequestBody ErpPalletSaveReqVO updateReqVO) { + palletService.updatePallet(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除托盘") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('erp:pallet:delete')") + public CommonResult deletePallet(@RequestParam("id") Long id) { + palletService.deletePallet(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得托盘") + @Parameter(name = "id", description = "编号", required = true, example = "1") + @PreAuthorize("@ss.hasPermission('erp:pallet:query')") + public CommonResult getPallet(@RequestParam("id") Long id) { + ErpPalletDO pallet = palletService.getPallet(id); + return success(BeanUtils.toBean(pallet, ErpPalletRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得托盘分页") + @PreAuthorize("@ss.hasPermission('erp:pallet:query')") + public CommonResult> getPalletPage(@Valid ErpPalletPageReqVO pageReqVO) { + PageResult pageResult = palletService.getPalletPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, ErpPalletRespVO.class)); + } + + @GetMapping("/simple-list") + @Operation(summary = "获得托盘精简列表") + @Parameter(name = "status", description = "托盘状态", example = "1") + public CommonResult> getPalletSimpleList(@RequestParam(value = "status", required = false) Integer status) { + List list = palletService.getPalletListByStatus(status); + return success(convertList(list, item -> BeanUtils.toBean(item, ErpPalletRespVO.class))); + } +} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/pallet/enums/ErpPalletStatusEnum.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/pallet/enums/ErpPalletStatusEnum.java new file mode 100644 index 000000000..a08e3447d --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/pallet/enums/ErpPalletStatusEnum.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.erp.controller.admin.pallet.enums; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +@Getter +@AllArgsConstructor +public enum ErpPalletStatusEnum implements IntArrayValuable { + + IDLE(1, "空闲"), + OCCUPIED(2, "占用"), + SCRAPPED(3, "报废"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ErpPalletStatusEnum::getStatus).toArray(); + + private final Integer status; + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } +} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/pallet/enums/ErpPalletTypeEnum.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/pallet/enums/ErpPalletTypeEnum.java new file mode 100644 index 000000000..cea997b7b --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/pallet/enums/ErpPalletTypeEnum.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.erp.controller.admin.pallet.enums; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +@Getter +@AllArgsConstructor +public enum ErpPalletTypeEnum implements IntArrayValuable { + + PLASTIC(1, "塑料"), + STEEL(2, "钢质"), + WOOD(3, "木托盘"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ErpPalletTypeEnum::getType).toArray(); + + private final Integer type; + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } +} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/pallet/vo/ErpPalletPageReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/pallet/vo/ErpPalletPageReqVO.java new file mode 100644 index 000000000..fa05fb24d --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/pallet/vo/ErpPalletPageReqVO.java @@ -0,0 +1,59 @@ +package cn.iocoder.yudao.module.erp.controller.admin.pallet.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.erp.controller.admin.pallet.enums.ErpPalletStatusEnum; +import cn.iocoder.yudao.module.erp.controller.admin.pallet.enums.ErpPalletTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDate; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - ERP 托盘分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ErpPalletPageReqVO extends PageParam { + + @Schema(description = "托盘编码", example = "TP202506100001") + private String code; + + @Schema(description = "托盘类型", example = "1") + @InEnum(ErpPalletTypeEnum.class) + private Integer palletType; + + @Schema(description = "托盘状态", example = "1") + @InEnum(ErpPalletStatusEnum.class) + private Integer status; + + @Schema(description = "仓库编号", example = "1") + private Long warehouseId; + + @Schema(description = "库区编号", example = "11") + private Long areaId; + + @Schema(description = "生产任务单号", example = "PLAN20250610001") + private String planCode; + + @Schema(description = "产品编号", example = "1001") + private Long productId; + + @Schema(description = "采购日期") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) + private LocalDate[] purchaseDate; + + @Schema(description = "投入使用日期") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) + private LocalDate[] useDate; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; +} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/pallet/vo/ErpPalletRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/pallet/vo/ErpPalletRespVO.java new file mode 100644 index 000000000..0144a353b --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/pallet/vo/ErpPalletRespVO.java @@ -0,0 +1,84 @@ +package cn.iocoder.yudao.module.erp.controller.admin.pallet.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - ERP 托盘 Response VO") +@Data +@ExcelIgnoreUnannotated +public class ErpPalletRespVO { + + @Schema(description = "托盘编号", example = "1") + @ExcelProperty("托盘编号") + private Long id; + + @Schema(description = "托盘编码", example = "TP202506100001") + @ExcelProperty("托盘编码") + private String code; + + @Schema(description = "托盘类型", example = "1") + @ExcelProperty("托盘类型") + private Integer palletType; + + @Schema(description = "托盘规格", example = "1200×1000×150") + @ExcelProperty("托盘规格") + private String specification; + + @Schema(description = "额定承载重量", example = "1000") + @ExcelProperty("额定承载重量") + private BigDecimal ratedLoadWeight; + + @Schema(description = "单位", example = "kg") + @ExcelProperty("单位") + private String unit; + + @Schema(description = "托盘状态", example = "1") + @ExcelProperty("托盘状态") + private Integer status; + + @Schema(description = "仓库编号", example = "1") + @ExcelProperty("仓库编号") + private Long warehouseId; + + @Schema(description = "库区编号", example = "11") + @ExcelProperty("库区编号") + private Long areaId; + + @Schema(description = "生产任务单号", example = "PLAN20250610001") + @ExcelProperty("生产任务单号") + private String planCode; + + @Schema(description = "产品编号", example = "1001") + @ExcelProperty("产品编号") + private Long productId; + + @Schema(description = "产品数量", example = "120") + @ExcelProperty("产品数量") + private BigDecimal productCount; + + @Schema(description = "二维码", example = "https://xxx.com/qrcode/pallet/1") + @ExcelProperty("二维码") + private String qrcode; + + @Schema(description = "采购日期", example = "2025-06-10") + @ExcelProperty("采购日期") + private LocalDate purchaseDate; + + @Schema(description = "投入使用日期", example = "2025-06-11") + @ExcelProperty("投入使用日期") + private LocalDate useDate; + + @Schema(description = "备注", example = "用于成品周转") + @ExcelProperty("备注") + private String remark; + + @Schema(description = "创建时间") + @ExcelProperty("创建时间") + private LocalDateTime createTime; +} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/pallet/vo/ErpPalletSaveReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/pallet/vo/ErpPalletSaveReqVO.java new file mode 100644 index 000000000..09155b306 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/pallet/vo/ErpPalletSaveReqVO.java @@ -0,0 +1,73 @@ +package cn.iocoder.yudao.module.erp.controller.admin.pallet.vo; + +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.erp.controller.admin.pallet.enums.ErpPalletStatusEnum; +import cn.iocoder.yudao.module.erp.controller.admin.pallet.enums.ErpPalletTypeEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDate; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; + +@Schema(description = "管理后台 - ERP 托盘新增/修改 Request VO") +@Data +public class ErpPalletSaveReqVO { + + @Schema(description = "托盘编号", example = "1") + private Long id; + + @Schema(description = "托盘编码", example = "TP202506100001") + private String code; + + @Schema(description = "托盘类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "托盘类型不能为空") + @InEnum(ErpPalletTypeEnum.class) + private Integer palletType; + + @Schema(description = "托盘规格(长×宽×高)", example = "1200×1000×150") + private String specification; + + @Schema(description = "额定承载重量", example = "1000") + private BigDecimal ratedLoadWeight; + + @Schema(description = "单位", example = "kg") + private String unit; + + @Schema(description = "托盘状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "托盘状态不能为空") + @InEnum(ErpPalletStatusEnum.class) + private Integer status; + + @Schema(description = "仓库编号", example = "1") + private Long warehouseId; + + @Schema(description = "库区编号", example = "11") + private Long areaId; + + @Schema(description = "生产任务单号", example = "PLAN20250610001") + private String planCode; + + @Schema(description = "产品编号", example = "1001") + private Long productId; + + @Schema(description = "产品数量", example = "120") + private BigDecimal productCount; + + @Schema(description = "二维码", example = "https://xxx.com/qrcode/pallet/1") + private String qrcode; + + @Schema(description = "采购日期", example = "2025-06-10") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) + private LocalDate purchaseDate; + + @Schema(description = "投入使用日期", example = "2025-06-11") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) + private LocalDate useDate; + + @Schema(description = "备注", example = "用于成品周转") + private String remark; +} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockCheckController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockCheckController.java index 72370a12f..ac138d679 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockCheckController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockCheckController.java @@ -10,7 +10,8 @@ import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.framework.ratelimiter.core.annotation.RateLimiter; -import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckApproveRecordRespVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckAuditReqVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckGenerateByLocationReqVO; @@ -25,6 +26,7 @@ import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckItemDO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO; import cn.iocoder.yudao.module.erp.dal.dataobject.warehousearea.WarehouseAreaDO; import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.product.ErpProductUnitService; import cn.iocoder.yudao.module.erp.service.stock.ErpStockCheckService; import cn.iocoder.yudao.module.erp.service.stock.ErpWarehouseService; import cn.iocoder.yudao.module.erp.service.warehousearea.WarehouseAreaService; @@ -71,6 +73,8 @@ public class ErpStockCheckController { @Resource private ErpProductService productService; @Resource + private ErpProductUnitService productUnitService; + @Resource private ErpWarehouseService warehouseService; @Resource private WarehouseAreaService warehouseAreaService; @@ -189,10 +193,12 @@ public class ErpStockCheckController { List stockCheckItemList = stockCheckService.getStockCheckItemListByCheckIds( convertSet(pageResult.getList(), ErpStockCheckDO::getId)); Map> stockCheckItemMap = convertMultiMap(stockCheckItemList, ErpStockCheckItemDO::getCheckId); + Map userMap = adminUserApi.getUserMap(convertListByFlatMap(pageResult.getList(), + stockCheck -> Stream.of(NumberUtils.parseLong(stockCheck.getCreator()), stockCheck.getAuditUserId()))); return BeanUtils.toBean(pageResult, ErpStockCheckRespVO.class, stockCheck -> { stockCheck.setItems(buildItemRespList(stockCheckItemMap.get(stockCheck.getId()))); stockCheck.setProductNames(CollUtil.join(stockCheck.getItems(), ",", ErpStockCheckRespVO.Item::getProductName)); - fillUserInfo(stockCheck); + fillUserInfo(stockCheck, userMap); }); } @@ -210,12 +216,18 @@ public class ErpStockCheckController { if (CollUtil.isEmpty(itemList)) { return new ArrayList<>(); } - Map productMap = productService.getProductVOMap(convertSet(itemList, ErpStockCheckItemDO::getProductId)); + Map productMap = productService.getProductMap(convertSet(itemList, ErpStockCheckItemDO::getProductId)); + Map unitMap = productUnitService.getProductUnitMap(convertSet(itemList, item -> { + ErpProductDO product = productMap.get(item.getProductId()); + return product != null ? product.getUnitId() : null; + })); Map warehouseMap = warehouseService.getWarehouseMap(convertSet(itemList, ErpStockCheckItemDO::getWarehouseId)); Map areaMap = warehouseAreaService.getWarehouseAreaMap(convertSet(itemList, ErpStockCheckItemDO::getAreaId)); return BeanUtils.toBean(itemList, ErpStockCheckRespVO.Item.class, item -> { MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) - .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())); + .setProductBarCode(product.getBarCode())); + MapUtils.findAndThen(productMap, item.getProductId(), product -> + MapUtils.findAndThen(unitMap, product.getUnitId(), unit -> item.setProductUnitName(unit.getName()))); MapUtils.findAndThen(warehouseMap, item.getWarehouseId(), warehouse -> item.setWarehouseName(warehouse.getName())); if (item.getAreaName() == null) { MapUtils.findAndThen(areaMap, item.getAreaId(), area -> item.setAreaName(area.getAreaName())); @@ -228,6 +240,10 @@ public class ErpStockCheckController { userIds.add(NumberUtils.parseLong(stockCheck.getCreator())); userIds.add(stockCheck.getAuditUserId()); Map userMap = adminUserApi.getUserMap(userIds); + fillUserInfo(stockCheck, userMap); + } + + private void fillUserInfo(ErpStockCheckRespVO stockCheck, Map userMap) { MapUtils.findAndThen(userMap, NumberUtils.parseLong(stockCheck.getCreator()), user -> stockCheck.setCreatorName(user.getNickname())); MapUtils.findAndThen(userMap, stockCheck.getAuditUserId(), user -> stockCheck.setAuditUserName(user.getNickname())); } diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpWarehouseController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpWarehouseController.java index f25a6b627..d87830a28 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpWarehouseController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpWarehouseController.java @@ -5,13 +5,17 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 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.validation.InEnum; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.erp.controller.admin.stock.enums.ErpWarehouseCategoryEnum; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehousePageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehouseSummaryRespVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehouseRespVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehouseSaveReqVO; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO; import cn.iocoder.yudao.module.erp.service.stock.ErpWarehouseService; +import cn.iocoder.yudao.module.erp.service.stock.ErpWarehouseSummaryService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameters; @@ -38,6 +42,8 @@ public class ErpWarehouseController { @Resource private ErpWarehouseService warehouseService; + @Resource + private ErpWarehouseSummaryService warehouseSummaryService; @PostMapping("/create") @Operation(summary = "创建仓库") @@ -93,10 +99,21 @@ public class ErpWarehouseController { @GetMapping("/simple-list") @Operation(summary = "获得仓库精简列表", description = "只包含被开启的仓库,主要用于前端的下拉选项") - public CommonResult> getWarehouseSimpleList() { - List list = warehouseService.getWarehouseListByStatus(CommonStatusEnum.ENABLE.getStatus()); + @Parameter(name = "categoryType", description = "仓库分类", example = "1") + public CommonResult> getWarehouseSimpleList( + @RequestParam(value = "categoryType", required = false) Integer categoryType) { + List list = warehouseService.getWarehouseListByStatus(CommonStatusEnum.ENABLE.getStatus(), categoryType); return success(convertList(list, warehouse -> new ErpWarehouseRespVO().setId(warehouse.getId()) - .setName(warehouse.getName()).setDefaultStatus(warehouse.getDefaultStatus()))); + .setName(warehouse.getName()).setCategoryType(warehouse.getCategoryType()) + .setDefaultStatus(warehouse.getDefaultStatus()))); + } + + @GetMapping("/summary") + @Operation(summary = "获得仓库总览") + @Parameter(name = "warehouseId", description = "仓库编号", required = true, example = "1") + @PreAuthorize("@ss.hasPermission('erp:warehouse:query')") + public CommonResult getWarehouseSummary(@RequestParam("warehouseId") Long warehouseId) { + return success(warehouseSummaryService.getWarehouseSummary(warehouseId)); } @GetMapping("/export-excel") diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/enums/ErpWarehouseCategoryEnum.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/enums/ErpWarehouseCategoryEnum.java new file mode 100644 index 000000000..96e0c7423 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/enums/ErpWarehouseCategoryEnum.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.enums; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Arrays; + +@Getter +@AllArgsConstructor +public enum ErpWarehouseCategoryEnum implements IntArrayValuable { + + PRODUCT(1, "产品"), + MATERIAL(2, "物料"), + SPARE_PART(3, "备件"), + OTHER(4, "其他"); + + public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(ErpWarehouseCategoryEnum::getCategory).toArray(); + + private final Integer category; + private final String name; + + @Override + public int[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckGenerateByLocationReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckGenerateByLocationReqVO.java index f7ff71bd0..a01758ad0 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckGenerateByLocationReqVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckGenerateByLocationReqVO.java @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; -import javax.validation.constraints.NotEmpty; import java.util.List; @Schema(description = "管理后台 - ERP 库存盘点按仓库/库区生成盘点项 Request VO") @@ -16,8 +15,8 @@ public class ErpStockCheckGenerateByLocationReqVO { @Schema(description = "库区编号列表", example = "[11,12]") private List areaIds; - @Schema(description = "是否允许为空,默认 false", example = "false") - private Boolean allowEmpty; + @Schema(description = "是否允许为空库存,默认 true", example = "true") + private Boolean allowEmpty = Boolean.TRUE; public boolean validSelection() { return (warehouseIds != null && !warehouseIds.isEmpty()) || (areaIds != null && !areaIds.isEmpty()); diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckGenerateByProductReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckGenerateByProductReqVO.java index 76564c842..5ead9c285 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckGenerateByProductReqVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckGenerateByProductReqVO.java @@ -14,4 +14,7 @@ public class ErpStockCheckGenerateByProductReqVO { @NotEmpty(message = "产品编号列表不能为空") private List productIds; + @Schema(description = "是否允许为空库存,默认 true", example = "true") + private Boolean allowEmpty = Boolean.TRUE; + } diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckRespVO.java index ee93dfa40..339471138 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckRespVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckRespVO.java @@ -2,8 +2,14 @@ package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check; import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat; import cn.iocoder.yudao.framework.excel.core.convert.DictConvert; +import static cn.iocoder.yudao.module.erp.enums.DictTypeConstants.PRODUCT_CATEGORY_TYPE; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import io.swagger.v3.oas.annotations.media.Schema; import javax.validation.constraints.NotNull; import lombok.Data; @@ -29,8 +35,16 @@ public class ErpStockCheckRespVO { @Schema(description = "盘点时间", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("盘点时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonSerialize(using = LocalDateTimeSerializer.class) + @JsonDeserialize(using = LocalDateTimeDeserializer.class) private LocalDateTime checkTime; + @Schema(description = "生成来源类型:1-按库存,2-按产品", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty(value = "生成来源类型", converter = DictConvert.class) + @DictFormat("erp_stock_check_source_type") + private Integer sourceType; + @Schema(description = "合计数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "15663") @ExcelProperty("合计数量") private BigDecimal totalCount; @@ -104,8 +118,7 @@ public class ErpStockCheckRespVO { @NotNull(message = "账面数量不能为空") private BigDecimal stockCount; - @Schema(description = "实际数量(实际库存)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") - @NotNull(message = "实际数量不能为空") + @Schema(description = "实际数量(实际库存)", example = "100.00") private BigDecimal actualCount; @Schema(description = "盈亏数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckSaveReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckSaveReqVO.java index cf04eca64..48125b098 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckSaveReqVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/check/ErpStockCheckSaveReqVO.java @@ -1,6 +1,13 @@ package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; +import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer; import io.swagger.v3.oas.annotations.media.Schema; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.erp.enums.stock.ErpStockCheckSourceTypeEnum; import lombok.Data; import javax.validation.Valid; @@ -17,17 +24,28 @@ public class ErpStockCheckSaveReqVO { @Schema(description = "盘点编号", example = "11756") private Long id; + @Schema(description = "盘点编码", example = "11756") + private String code; + @Schema(description = "盘点时间", requiredMode = Schema.RequiredMode.REQUIRED) @NotNull(message = "盘点时间不能为空") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @JsonSerialize(using = LocalDateTimeSerializer.class) + @JsonDeserialize(using = LocalDateTimeDeserializer.class) private LocalDateTime checkTime; + @Schema(description = "生成来源类型:1-按库存,2-按产品", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "生成来源类型不能为空") + @InEnum(ErpStockCheckSourceTypeEnum.class) + private Integer sourceType; + @Schema(description = "备注", example = "随便") private String remark; @Schema(description = "附件 URL", example = "https://www.iocoder.cn/1.doc") private String fileUrl; - @Schema(description = "盘点项列表", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "盘点项列表", implementation = Item.class) @NotEmpty(message = "盘点项列表不能为空") @Valid private List items; @@ -56,8 +74,7 @@ public class ErpStockCheckSaveReqVO { @NotNull(message = "账面数量不能为空") private BigDecimal stockCount; - @Schema(description = "实际数量(实际库存)", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00") - @NotNull(message = "实际数量不能为空") + @Schema(description = "实际数量(实际库存)", example = "100.00") private BigDecimal actualCount; @Schema(description = "盈亏数量,服务端自动按 实际数量 - 账面数量 计算", example = "100.00") diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInPageReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInPageReqVO.java index e744085a8..508b5b5a0 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInPageReqVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/in/ErpStockInPageReqVO.java @@ -31,7 +31,7 @@ public class ErpStockInPageReqVO extends PageParam { private LocalDateTime[] inTime; @Schema(description = "状态", example = "10") - @InEnum(ErpStockInStatusEnum.class) +// @InEnum(ErpStockInStatusEnum.class) private List statusList; @Schema(description = "入库类型", example = "其它入库") diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/out/ErpStockOutPageReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/out/ErpStockOutPageReqVO.java index 1679296bf..6173ab455 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/out/ErpStockOutPageReqVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/out/ErpStockOutPageReqVO.java @@ -40,7 +40,7 @@ public class ErpStockOutPageReqVO extends PageParam { private LocalDateTime[] outTime; @Schema(description = "状态", example = "10") - @InEnum(ErpStockOutStatusEnum.class) +// @InEnum(ErpStockOutStatusEnum.class) private List statusList; @Schema(description = "审核人编号", example = "1") diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehousePageReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehousePageReqVO.java index 11f97e4fc..e6da3112a 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehousePageReqVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehousePageReqVO.java @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.erp.controller.admin.stock.enums.ErpWarehouseCategoryEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; @@ -17,10 +18,14 @@ public class ErpWarehousePageReqVO extends PageParam { @Schema(description = "仓库名称", example = "李四") private String name; + @Schema(description = "仓库分类", example = "1") + @InEnum(ErpWarehouseCategoryEnum.class) + private Integer categoryType; + @Schema(description = "开启状态", example = "1") @InEnum(CommonStatusEnum.class) private Integer status; @Schema(description = "id集合导出用") private String ids; -} \ No newline at end of file +} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehouseRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehouseRespVO.java index e51086788..ba0509e2d 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehouseRespVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehouseRespVO.java @@ -27,6 +27,10 @@ public class ErpWarehouseRespVO { @ExcelProperty("仓库名称") private String name; + @Schema(description = "仓库分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("仓库分类") + private Integer categoryType; + @Schema(description = "仓库地址", example = "上海陆家嘴") @ExcelProperty("仓库地址") private String address; @@ -78,5 +82,4 @@ public class ErpWarehouseRespVO { @Schema(description = "库位列表") private List locationList; - } diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehouseSaveReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehouseSaveReqVO.java index 96e843979..ce3e200d4 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehouseSaveReqVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehouseSaveReqVO.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.erp.controller.admin.stock.enums.ErpWarehouseCategoryEnum; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -20,6 +21,11 @@ public class ErpWarehouseSaveReqVO { @NotEmpty(message = "仓库名称不能为空") private String name; + @Schema(description = "仓库分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "仓库分类不能为空") + @InEnum(ErpWarehouseCategoryEnum.class) + private Integer categoryType; + @Schema(description = "仓库地址", example = "上海陆家嘴") private String address; diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehouseSummaryRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehouseSummaryRespVO.java new file mode 100644 index 000000000..b78704822 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/warehouse/ErpWarehouseSummaryRespVO.java @@ -0,0 +1,66 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; + +@Schema(description = "管理后台 - ERP 仓库总览 Response VO") +@Data +public class ErpWarehouseSummaryRespVO { + + @Schema(description = "仓库编号", example = "1") + private Long warehouseId; + + @Schema(description = "仓库名称", example = "A仓") + private String warehouseName; + + @Schema(description = "产品库存量", example = "1000") + private BigDecimal productStockCount; + + @Schema(description = "产品库存展示", example = "2托3包4个") + private String productStockDisplay; + + @Schema(description = "物料库存量", example = "1000") + private BigDecimal materialStockCount; + + @Schema(description = "物料库存展示", example = "10采购单位20库存单位") + private String materialStockDisplay; + + @Schema(description = "备件库存量", example = "1000") + private BigDecimal sparePartStockCount; + + @Schema(description = "备件库存展示", example = "10采购单位20库存单位") + private String sparePartStockDisplay; + + @Schema(description = "今日入库单数量", example = "5") + private Long todayStockInOrderCount; + + @Schema(description = "今日入库明细行数量", example = "18") + private Long todayStockInItemCount; + + @Schema(description = "今日入库产成品展示", example = "2托3包4个") + private String todayProductStockInDisplay; + + @Schema(description = "今日入库物料展示", example = "100个") + private String todayMaterialStockInDisplay; + + @Schema(description = "今日入库备件展示", example = "100个") + private String todaySparePartStockInDisplay; + + @Schema(description = "今日出库单数量", example = "3") + private Long todayStockOutOrderCount; + + @Schema(description = "今日出库明细行数量", example = "10") + private Long todayStockOutItemCount; + + @Schema(description = "今日出库产成品展示", example = "2托3包4个") + private String todayProductStockOutDisplay; + + @Schema(description = "今日出库物料展示", example = "100个") + private String todayMaterialStockOutDisplay; + + @Schema(description = "今日出库备件展示", example = "100个") + private String todaySparePartStockOutDisplay; + +} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/pallet/ErpPalletDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/pallet/ErpPalletDO.java new file mode 100644 index 000000000..726c9bf19 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/pallet/ErpPalletDO.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.pallet; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.ToString; + +import java.math.BigDecimal; +import java.time.LocalDate; + +@TableName("erp_pallet") +@KeySequence("erp_pallet_seq") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpPalletDO extends BaseDO { + + @TableId + private Long id; + private String code; + private Integer palletType; + private String specification; + private BigDecimal ratedLoadWeight; + private String unit; + private Integer status; + private Long warehouseId; + private Long areaId; + private String planCode; + private Long productId; + private BigDecimal productCount; + private String qrcode; + private LocalDate purchaseDate; + private LocalDate useDate; + private String remark; +} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockCheckDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockCheckDO.java index 54130f443..2986a7b76 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockCheckDO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockCheckDO.java @@ -37,6 +37,10 @@ public class ErpStockCheckDO extends BaseDO { * 盘点时间 */ private LocalDateTime checkTime; + /** + * 生成来源类型:1-按库存,2-按产品 + */ + private Integer sourceType; /** * 合计数量 */ diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpWarehouseDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpWarehouseDO.java index 4f206173f..ffe8a45db 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpWarehouseDO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpWarehouseDO.java @@ -32,6 +32,10 @@ public class ErpWarehouseDO extends BaseDO { * 仓库名称 */ private String name; + /** + * 仓库分类 + */ + private Integer categoryType; /** * 仓库地址 */ @@ -67,4 +71,4 @@ public class ErpWarehouseDO extends BaseDO { */ private Boolean defaultStatus; -} \ No newline at end of file +} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/pallet/ErpPalletMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/pallet/ErpPalletMapper.java new file mode 100644 index 000000000..f353dc732 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/pallet/ErpPalletMapper.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.pallet; + +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.erp.controller.admin.pallet.vo.ErpPalletPageReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.pallet.ErpPalletDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface ErpPalletMapper extends BaseMapperX { + + default PageResult selectPage(ErpPalletPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(ErpPalletDO::getCode, reqVO.getCode()) + .eqIfPresent(ErpPalletDO::getPalletType, reqVO.getPalletType()) + .eqIfPresent(ErpPalletDO::getStatus, reqVO.getStatus()) + .eqIfPresent(ErpPalletDO::getWarehouseId, reqVO.getWarehouseId()) + .eqIfPresent(ErpPalletDO::getAreaId, reqVO.getAreaId()) + .likeIfPresent(ErpPalletDO::getPlanCode, reqVO.getPlanCode()) + .eqIfPresent(ErpPalletDO::getProductId, reqVO.getProductId()) + .betweenIfPresent(ErpPalletDO::getPurchaseDate, reqVO.getPurchaseDate()) + .betweenIfPresent(ErpPalletDO::getUseDate, reqVO.getUseDate()) + .betweenIfPresent(ErpPalletDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(ErpPalletDO::getId)); + } + + default ErpPalletDO selectByCode(String code) { + return selectOne(ErpPalletDO::getCode, code); + } + + default List selectListByStatus(Integer status) { + if (status == null) { + return selectList(); + } + return selectList(ErpPalletDO::getStatus, status); + } +} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockCheckMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockCheckMapper.java index 6db811513..e57f430e0 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockCheckMapper.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockCheckMapper.java @@ -5,8 +5,6 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckPageReqVO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckDO; -import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockCheckItemDO; -import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInDO; import com.alibaba.excel.util.StringUtils; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; @@ -32,10 +30,14 @@ public interface ErpStockCheckMapper extends BaseMapperX { .eqIfPresent(ErpStockCheckDO::getCreator, reqVO.getCreator()) .orderByDesc(ErpStockCheckDO::getId); if (reqVO.getWarehouseId() != null || reqVO.getProductId() != null) { - query.leftJoin(ErpStockCheckItemDO.class, ErpStockCheckItemDO::getCheckId, ErpStockCheckDO::getId) - .eq(reqVO.getWarehouseId() != null, ErpStockCheckItemDO::getWarehouseId, reqVO.getWarehouseId()) - .eq(reqVO.getProductId() != null, ErpStockCheckItemDO::getProductId, reqVO.getProductId()) - .groupBy(ErpStockCheckDO::getId); // 避免 1 对多查询,产生相同的 1 + StringBuilder itemFilterSql = new StringBuilder("select distinct check_id from erp_stock_check_item where deleted = 0"); + if (reqVO.getWarehouseId() != null) { + itemFilterSql.append(" and warehouse_id = ").append(reqVO.getWarehouseId()); + } + if (reqVO.getProductId() != null) { + itemFilterSql.append(" and product_id = ").append(reqVO.getProductId()); + } + query.inSql(ErpStockCheckDO::getId, itemFilterSql.toString()); } @@ -61,4 +63,4 @@ public interface ErpStockCheckMapper extends BaseMapperX { return selectOne(ErpStockCheckDO::getNo, no); } -} \ No newline at end of file +} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMapper.java index f16283cf4..d30d61f4c 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMapper.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMapper.java @@ -83,11 +83,31 @@ public interface ErpStockMapper extends BaseMapperX { return selectList(query); } + default List selectListByWarehouseIdsAndAreaIds(List warehouseIds, List areaIds, + boolean nonZeroOnly) { + LambdaQueryWrapperX query = new LambdaQueryWrapperX() + .inIfPresent(ErpStockDO::getWarehouseId, warehouseIds) + .inIfPresent(ErpStockDO::getAreaId, areaIds); + if (nonZeroOnly) { + query.ne(ErpStockDO::getCount, BigDecimal.ZERO); + } + return selectList(query); + } + default List selectListByProductIds(List productIds) { return selectList(new LambdaQueryWrapperX() .inIfPresent(ErpStockDO::getProductId, productIds)); } + default List selectListByProductIds(List productIds, boolean nonZeroOnly) { + LambdaQueryWrapperX query = new LambdaQueryWrapperX() + .inIfPresent(ErpStockDO::getProductId, productIds); + if (nonZeroOnly) { + query.ne(ErpStockDO::getCount, BigDecimal.ZERO); + } + return selectList(query); + } + default List selectListByProductIdsAndWarehouseIdsAndAreaIds(Collection productIds, Collection warehouseIds, Collection areaIds) { diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpWarehouseMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpWarehouseMapper.java index 792610dd4..d12c0c32f 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpWarehouseMapper.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpWarehouseMapper.java @@ -24,6 +24,7 @@ public interface ErpWarehouseMapper extends BaseMapperX { LambdaQueryWrapperX erpWarehouseDOLambdaQueryWrapperX = new LambdaQueryWrapperX() .likeIfPresent(ErpWarehouseDO::getName, reqVO.getName()) + .eqIfPresent(ErpWarehouseDO::getCategoryType, reqVO.getCategoryType()) .eqIfPresent(ErpWarehouseDO::getStatus, reqVO.getStatus()) .orderByDesc(ErpWarehouseDO::getId); @@ -43,8 +44,11 @@ public interface ErpWarehouseMapper extends BaseMapperX { return selectOne(ErpWarehouseDO::getDefaultStatus, true); } - default List selectListByStatus(Integer status) { - return selectList(ErpWarehouseDO::getStatus, status); + default List selectListByStatus(Integer status, Integer categoryType) { + return selectList(new LambdaQueryWrapperX() + .eqIfPresent(ErpWarehouseDO::getStatus, status) + .eqIfPresent(ErpWarehouseDO::getCategoryType, categoryType) + .orderByDesc(ErpWarehouseDO::getId)); } -} \ No newline at end of file +} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/pallet/ErpPalletService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/pallet/ErpPalletService.java new file mode 100644 index 000000000..6d13decd8 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/pallet/ErpPalletService.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.erp.service.pallet; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.erp.controller.admin.pallet.vo.ErpPalletPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.pallet.vo.ErpPalletSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.pallet.ErpPalletDO; + +import javax.validation.Valid; +import java.util.List; + +public interface ErpPalletService { + + Long createPallet(@Valid ErpPalletSaveReqVO createReqVO); + + void updatePallet(@Valid ErpPalletSaveReqVO updateReqVO); + + void deletePallet(Long id); + + ErpPalletDO getPallet(Long id); + + PageResult getPalletPage(ErpPalletPageReqVO pageReqVO); + + List getPalletListByStatus(Integer status); +} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/pallet/ErpPalletServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/pallet/ErpPalletServiceImpl.java new file mode 100644 index 000000000..296a77c35 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/pallet/ErpPalletServiceImpl.java @@ -0,0 +1,144 @@ +package cn.iocoder.yudao.module.erp.service.pallet; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.erp.controller.admin.autocode.util.AutoCodeUtil; +import cn.iocoder.yudao.module.erp.controller.admin.pallet.vo.ErpPalletPageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.pallet.vo.ErpPalletSaveReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.pallet.ErpPalletDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.warehousearea.WarehouseAreaDO; +import cn.iocoder.yudao.module.erp.dal.mysql.pallet.ErpPalletMapper; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import cn.iocoder.yudao.module.erp.service.stock.ErpWarehouseService; +import cn.iocoder.yudao.module.erp.service.warehousearea.WarehouseAreaService; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.Collections; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.PALLET_CODE_EXISTS; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.PALLET_NOT_EXISTS; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.PRODUCT_NOT_EXISTS; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.WAREHOUSE_AREA_NOT_EXISTS; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.WAREHOUSE_LOCATION_WAREHOUSE_AREA_NOT_MATCH; + +@Service +@Validated +public class ErpPalletServiceImpl implements ErpPalletService { + + @Resource + private ErpPalletMapper palletMapper; + @Resource + private AutoCodeUtil autoCodeUtil; + @Resource + private ErpWarehouseService warehouseService; + @Resource + private WarehouseAreaService warehouseAreaService; + @Resource + private ErpProductService productService; + + @Override + public Long createPallet(ErpPalletSaveReqVO createReqVO) { + validateWarehouseAreaMatch(createReqVO.getWarehouseId(), createReqVO.getAreaId()); + validateProductExists(createReqVO.getProductId()); + ErpPalletDO pallet = BeanUtils.toBean(createReqVO, ErpPalletDO.class); + if (StringUtils.isBlank(pallet.getCode())) { + pallet.setCode(autoCodeUtil.genSerialCode("PALLET_CODE_GENERATE", null)); + } else { + validateCodeUnique(null, pallet.getCode()); + } + if (StringUtils.isBlank(pallet.getQrcode())) { + pallet.setQrcode(pallet.getCode()); + } + palletMapper.insert(pallet); + return pallet.getId(); + } + + @Override + public void updatePallet(ErpPalletSaveReqVO updateReqVO) { + ErpPalletDO pallet = validatePalletExists(updateReqVO.getId()); + validateWarehouseAreaMatch(updateReqVO.getWarehouseId(), updateReqVO.getAreaId()); + validateProductExists(updateReqVO.getProductId()); + ErpPalletDO updateObj = BeanUtils.toBean(updateReqVO, ErpPalletDO.class); + if (StringUtils.isBlank(updateObj.getCode())) { + updateObj.setCode(pallet.getCode()); + } else { + validateCodeUnique(updateObj.getId(), updateObj.getCode()); + } + if (StringUtils.isBlank(updateObj.getQrcode())) { + updateObj.setQrcode(updateObj.getCode()); + } + palletMapper.updateById(updateObj); + } + + @Override + public void deletePallet(Long id) { + validatePalletExists(id); + palletMapper.deleteById(id); + } + + @Override + public ErpPalletDO getPallet(Long id) { + return palletMapper.selectById(id); + } + + @Override + public PageResult getPalletPage(ErpPalletPageReqVO pageReqVO) { + return palletMapper.selectPage(pageReqVO); + } + + @Override + public List getPalletListByStatus(Integer status) { + return palletMapper.selectListByStatus(status); + } + + private ErpPalletDO validatePalletExists(Long id) { + ErpPalletDO pallet = palletMapper.selectById(id); + if (pallet == null) { + throw exception(PALLET_NOT_EXISTS); + } + return pallet; + } + + private void validateCodeUnique(Long id, String code) { + ErpPalletDO pallet = palletMapper.selectByCode(code); + if (pallet == null) { + return; + } + if (id == null || !pallet.getId().equals(id)) { + throw exception(PALLET_CODE_EXISTS); + } + } + + private void validateWarehouseAreaMatch(Long warehouseId, Long areaId) { + if (warehouseId == null && areaId == null) { + return; + } + if (warehouseId != null && warehouseService.validWarehouseList(Collections.singleton(warehouseId)).isEmpty()) { + throw exception(cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.WAREHOUSE_NOT_EXISTS); + } + if (areaId == null) { + return; + } + WarehouseAreaDO area = warehouseAreaService.getWarehouseArea(areaId); + if (area == null) { + throw exception(WAREHOUSE_AREA_NOT_EXISTS); + } + if (warehouseId == null || !warehouseId.equals(area.getWarehouseId())) { + throw exception(WAREHOUSE_LOCATION_WAREHOUSE_AREA_NOT_MATCH); + } + } + + private void validateProductExists(Long productId) { + if (productId == null) { + return; + } + if (productService.validProductList(Collections.singleton(productId)).isEmpty()) { + throw exception(PRODUCT_NOT_EXISTS); + } + } +} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockCheckServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockCheckServiceImpl.java index 53badaa8d..22339826a 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockCheckServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockCheckServiceImpl.java @@ -7,7 +7,7 @@ import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; -import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.autocode.util.AutoCodeUtil; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckAuditReqVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckGenerateByLocationReqVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.check.ErpStockCheckGenerateByProductReqVO; @@ -29,6 +29,7 @@ import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockMapper; import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO; import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; import cn.iocoder.yudao.module.erp.enums.stock.ErpStockCheckApproveActionEnum; +import cn.iocoder.yudao.module.erp.enums.stock.ErpStockCheckSourceTypeEnum; import cn.iocoder.yudao.module.erp.enums.stock.ErpStockRecordBizTypeEnum; import cn.iocoder.yudao.module.erp.service.product.ErpProductService; import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockRecordCreateReqBO; @@ -36,6 +37,9 @@ import cn.iocoder.yudao.module.erp.service.warehousearea.WarehouseAreaService; import cn.iocoder.yudao.module.system.api.permission.PermissionApi; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum; +import com.baomidou.mybatisplus.core.toolkit.StringUtils; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -55,22 +59,7 @@ import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils. import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue; -import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_CHECK_APPROVE_FAIL; -import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_CHECK_AUDIT_FAIL_RESULT; -import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_CHECK_AUDIT_FAIL_STATUS; -import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_CHECK_AUDIT_FAIL_USER; -import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_CHECK_DELETE_FAIL_APPROVE; -import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_CHECK_DELETE_FAIL_PROCESS; -import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_CHECK_NOT_EXISTS; -import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_CHECK_NO_EXISTS; -import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_CHECK_PROCESS_FAIL; -import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_CHECK_SUBMIT_FAIL_AUDIT_USER_EMPTY; -import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_CHECK_SUBMIT_FAIL_STATUS; -import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_CHECK_SUBMIT_FAIL_USER; -import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_CHECK_UPDATE_FAIL_APPROVE; -import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.STOCK_CHECK_UPDATE_FAIL_PROCESS; -import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.WAREHOUSE_AREA_NOT_EXISTS; -import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.WAREHOUSE_LOCATION_WAREHOUSE_AREA_NOT_MATCH; +import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; @Service @Validated @@ -98,18 +87,34 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService { private AdminUserApi adminUserApi; @Resource private PermissionApi permissionApi; + @Autowired + private AutoCodeUtil autoCodeUtil; @Override @Transactional(rollbackFor = Exception.class) public Long createStockCheck(ErpStockCheckSaveReqVO createReqVO) { + String code = createReqVO.getCode(); + + validateSourceType(createReqVO.getSourceType()); List stockCheckItems = validateStockCheckItems(createReqVO.getItems()); - String no = noRedisDAO.generate(ErpNoRedisDAO.STOCK_CHECK_NO_PREFIX); - if (stockCheckMapper.selectByNo(no) != null) { - throw exception(STOCK_CHECK_NO_EXISTS); +// String no = noRedisDAO.generate(ErpNoRedisDAO.STOCK_CHECK_NO_PREFIX); +// if (stockCheckMapper.selectByNo(no) != null) { +// throw exception(STOCK_CHECK_NO_EXISTS); +// } + boolean autoGeneratedCode = StringUtils.isBlank(code); + + if (autoGeneratedCode) { + code = autoCodeUtil.genSerialCode("INVENTORY_EXECUTION_CODE", null); + } else { + if (stockCheckMapper.selectOne(Wrappers.lambdaQuery() + .eq(ErpStockCheckDO::getNo, code)) != null) { + throw exception(STOCK_CODE_EXISTS); + } } + String finalCode = code; ErpStockCheckDO stockCheck = BeanUtils.toBean(createReqVO, ErpStockCheckDO.class, in -> in - .setNo(no) + .setNo(finalCode) .setStatus(ErpAuditStatus.DRAFT.getStatus()) .setTotalCount(getSumValue(stockCheckItems, ErpStockCheckItemDO::getCount, BigDecimal::add, BigDecimal.ZERO)) .setTotalPrice(getSumValue(stockCheckItems, ErpStockCheckItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO))); @@ -130,6 +135,7 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService { throw exception(STOCK_CHECK_UPDATE_FAIL_PROCESS, stockCheck.getNo()); } + validateSourceType(updateReqVO.getSourceType()); List stockCheckItems = validateStockCheckItems(updateReqVO.getItems()); ErpStockCheckDO updateObj = BeanUtils.toBean(updateReqVO, ErpStockCheckDO.class, in -> in .setTotalCount(getSumValue(stockCheckItems, ErpStockCheckItemDO::getCount, BigDecimal::add, BigDecimal.ZERO)) @@ -288,10 +294,9 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService { if (reqVO == null || !reqVO.validSelection()) { return Collections.emptyList(); } - List stockList = stockMapper.selectListByWarehouseIdsAndAreaIds(reqVO.getWarehouseIds(), reqVO.getAreaIds()); - if (!Boolean.TRUE.equals(reqVO.getAllowEmpty())) { - stockList = filterNonZeroStocks(stockList); - } + boolean nonZeroOnly = Boolean.FALSE.equals(reqVO.getAllowEmpty()); + List stockList = stockMapper.selectListByWarehouseIdsAndAreaIds( + reqVO.getWarehouseIds(), reqVO.getAreaIds(), nonZeroOnly); return buildPreviewItems(stockList); } @@ -300,7 +305,9 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService { if (reqVO == null || CollUtil.isEmpty(reqVO.getProductIds())) { return Collections.emptyList(); } - return buildPreviewItems(filterNonZeroStocks(stockMapper.selectListByProductIds(reqVO.getProductIds()))); + boolean nonZeroOnly = Boolean.FALSE.equals(reqVO.getAllowEmpty()); + List stockList = stockMapper.selectListByProductIds(reqVO.getProductIds(), nonZeroOnly); + return buildPreviewItems(stockList); } private List filterNonZeroStocks(List stockList) { @@ -320,7 +327,8 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService { if (CollUtil.isEmpty(stockList)) { return Collections.emptyList(); } - Map productMap = productService.getProductMap(convertSet(stockList, ErpStockDO::getProductId)); + Collection productIds = convertSet(stockList, ErpStockDO::getProductId); + Map productMap = productService.getProductMap(productIds); Map warehouseMap = warehouseService.getWarehouseMap(convertSet(stockList, ErpStockDO::getWarehouseId)); Map areaMap = warehouseAreaService.getWarehouseAreaMap(convertSet(stockList, ErpStockDO::getAreaId)); List result = new ArrayList<>(); @@ -331,7 +339,7 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService { item.setAreaName(stock.getAreaName()); item.setProductId(stock.getProductId()); item.setStockCount(stock.getCount() != null ? stock.getCount() : BigDecimal.ZERO); - item.setActualCount(stock.getCount() != null ? stock.getCount() : BigDecimal.ZERO); + item.setActualCount(null); item.setCount(BigDecimal.ZERO); MapUtils.findAndThen(warehouseMap, stock.getWarehouseId(), warehouse -> item.setWarehouseName(warehouse.getName())); if (item.getAreaName() == null) { @@ -339,13 +347,10 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService { } ErpProductDO productDO = productMap.get(stock.getProductId()); item.setProductPrice(resolveProductPrice(productDO)); + item.setProductUnitName(stock.getUnitName()); if (productDO != null) { item.setProductName(productDO.getName()); item.setProductBarCode(productDO.getBarCode()); - ErpProductRespVO productVO = productService.getProduct(productDO.getId()); - if (productVO != null) { - item.setProductUnitName(productVO.getUnitName()); - } } result.add(item); } @@ -426,8 +431,8 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService { ErpProductDO productDO = productMap.get(item.getProductId()); WarehouseAreaDO area = item.getAreaId() != null ? areaMap.get(item.getAreaId()) : null; BigDecimal stockCount = item.getStockCount() != null ? item.getStockCount() : BigDecimal.ZERO; - BigDecimal actualCount = item.getActualCount() != null ? item.getActualCount() : BigDecimal.ZERO; - BigDecimal count = actualCount.subtract(stockCount); + BigDecimal actualCount = item.getActualCount(); + BigDecimal count = actualCount != null ? actualCount.subtract(stockCount) : null; BigDecimal productPrice = item.getProductPrice() != null ? item.getProductPrice() : resolveProductPrice(productDO); return ErpStockCheckItemDO.builder() .id(item.getId()) @@ -440,7 +445,7 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService { .stockCount(stockCount) .actualCount(actualCount) .count(count) - .totalPrice(MoneyUtils.priceMultiply(productPrice, count)) + .totalPrice(count != null ? MoneyUtils.priceMultiply(productPrice, count) : null) .remark(item.getRemark()) .build(); }); @@ -484,4 +489,11 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService { return stockCheck; } + private void validateSourceType(Integer sourceType) { + if (!ErpStockCheckSourceTypeEnum.BY_LOCATION.getType().equals(sourceType) + && !ErpStockCheckSourceTypeEnum.BY_PRODUCT.getType().equals(sourceType)) { + throw exception(STOCK_CHECK_SOURCE_TYPE_NOT_EXISTS); + } + } + } diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseService.java index 0d514cabb..5271a804b 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseService.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseService.java @@ -75,7 +75,7 @@ public interface ErpWarehouseService { * @param status 状态 * @return 仓库列表 */ - List getWarehouseListByStatus(Integer status); + List getWarehouseListByStatus(Integer status, Integer categoryType); /** * 获得仓库列表 diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseServiceImpl.java index 10eade2f5..38e377f63 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseServiceImpl.java @@ -128,8 +128,8 @@ public class ErpWarehouseServiceImpl implements ErpWarehouseService { } @Override - public List getWarehouseListByStatus(Integer status) { - return warehouseMapper.selectListByStatus(status); + public List getWarehouseListByStatus(Integer status, Integer categoryType) { + return warehouseMapper.selectListByStatus(status, categoryType); } @Override diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseSummaryService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseSummaryService.java new file mode 100644 index 000000000..fc0bde160 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseSummaryService.java @@ -0,0 +1,9 @@ +package cn.iocoder.yudao.module.erp.service.stock; + +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehouseSummaryRespVO; + +public interface ErpWarehouseSummaryService { + + ErpWarehouseSummaryRespVO getWarehouseSummary(Long warehouseId); + +} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseSummaryServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseSummaryServiceImpl.java new file mode 100644 index 000000000..c9ac20c6d --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpWarehouseSummaryServiceImpl.java @@ -0,0 +1,261 @@ +package cn.iocoder.yudao.module.erp.service.stock; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ErpProductRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.warehouse.ErpWarehouseSummaryRespVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInItemDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutItemDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO; +import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockInItemMapper; +import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockInMapper; +import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockMapper; +import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockOutItemMapper; +import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockOutMapper; +import cn.iocoder.yudao.module.erp.service.product.ErpProductService; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +@Service +@Validated +public class ErpWarehouseSummaryServiceImpl implements ErpWarehouseSummaryService { + + @Resource + private ErpWarehouseService warehouseService; + @Resource + private ErpStockMapper stockMapper; + @Resource + private ErpStockInMapper stockInMapper; + @Resource + private ErpStockInItemMapper stockInItemMapper; + @Resource + private ErpStockOutMapper stockOutMapper; + @Resource + private ErpStockOutItemMapper stockOutItemMapper; + @Resource + private ErpProductService productService; + + @Override + public ErpWarehouseSummaryRespVO getWarehouseSummary(Long warehouseId) { + ErpWarehouseDO warehouse = warehouseService.getWarehouse(warehouseId); + ErpWarehouseSummaryRespVO respVO = new ErpWarehouseSummaryRespVO(); + respVO.setWarehouseId(warehouseId); + respVO.setWarehouseName(warehouse != null ? warehouse.getName() : null); + + List stockList = stockMapper.selectListByWarehouseIdsAndAreaIds(Collections.singletonList(warehouseId), null); + fillStockSummary(respVO, stockList); + + LocalDateTime beginTime = LocalDate.now().atStartOfDay(); + LocalDateTime endTime = beginTime.plusDays(1); + fillTodayInSummary(respVO, warehouseId, beginTime, endTime); + fillTodayOutSummary(respVO, warehouseId, beginTime, endTime); + return respVO; + } + + private void fillStockSummary(ErpWarehouseSummaryRespVO respVO, List stockList) { + if (CollUtil.isEmpty(stockList)) { + respVO.setProductStockCount(BigDecimal.ZERO); + respVO.setMaterialStockCount(BigDecimal.ZERO); + respVO.setSparePartStockCount(BigDecimal.ZERO); + respVO.setProductStockDisplay(formatProductDisplay(BigDecimal.ZERO, null, null, null)); + respVO.setMaterialStockDisplay(formatUnitDisplay(BigDecimal.ZERO, null, null, null)); + respVO.setSparePartStockDisplay(formatUnitDisplay(BigDecimal.ZERO, null, null, null)); + return; + } + + Map> categoryMap = stockList.stream().collect(Collectors.groupingBy(this::resolveCategoryType)); + BigDecimal productCount = sumCount(categoryMap.get(1)); + BigDecimal materialCount = sumCount(categoryMap.get(2)); + BigDecimal sparePartCount = sumCount(categoryMap.get(3)); + + respVO.setProductStockCount(productCount); + respVO.setMaterialStockCount(materialCount); + respVO.setSparePartStockCount(sparePartCount); + + ErpStockDO productStock = firstStock(categoryMap.get(1)); + ErpStockDO materialStock = firstStock(categoryMap.get(2)); + ErpStockDO sparePartStock = firstStock(categoryMap.get(3)); + respVO.setProductStockDisplay(formatProductDisplay(productCount, + productStock != null ? productStock.getPalletTotalQuantity() : null, + productStock != null ? productStock.getPalletPackageQuantity() : null, + productStock != null ? productStock.getPackageQuantity() : null)); + respVO.setMaterialStockDisplay(formatUnitDisplay(materialCount, + materialStock != null ? materialStock.getPurchaseUnitConvertQuantity() : null, + materialStock != null ? materialStock.getPurchaseUnitName() : null, + materialStock != null ? materialStock.getUnitName() : null)); + respVO.setSparePartStockDisplay(formatUnitDisplay(sparePartCount, + sparePartStock != null ? sparePartStock.getPurchaseUnitConvertQuantity() : null, + sparePartStock != null ? sparePartStock.getPurchaseUnitName() : null, + sparePartStock != null ? sparePartStock.getUnitName() : null)); + } + + private void fillTodayInSummary(ErpWarehouseSummaryRespVO respVO, Long warehouseId, LocalDateTime beginTime, LocalDateTime endTime) { + List stockInList = stockInMapper.selectList(new LambdaQueryWrapper() + .eq(ErpStockInDO::getStatus, 20) + .between(ErpStockInDO::getInTime, beginTime, endTime)); + List inIds = stockInList.stream() + .filter(stockIn -> hasWarehouseIn(stockIn.getId(), warehouseId)) + .map(ErpStockInDO::getId) + .collect(Collectors.toList()); + respVO.setTodayStockInOrderCount((long) inIds.size()); + + List itemList = stockInItemMapper.selectListByInIds(inIds); + respVO.setTodayStockInItemCount((long) itemList.size()); + fillInOutDisplay(respVO, true, itemList); + } + + private void fillTodayOutSummary(ErpWarehouseSummaryRespVO respVO, Long warehouseId, LocalDateTime beginTime, LocalDateTime endTime) { + List stockOutList = stockOutMapper.selectList(new LambdaQueryWrapper() + .eq(ErpStockOutDO::getStatus, 20) + .between(ErpStockOutDO::getOutTime, beginTime, endTime)); + List outIds = stockOutList.stream() + .filter(stockOut -> hasWarehouseOut(stockOut.getId(), warehouseId)) + .map(ErpStockOutDO::getId) + .collect(Collectors.toList()); + respVO.setTodayStockOutOrderCount((long) outIds.size()); + + List itemList = stockOutItemMapper.selectListByOutIds(outIds); + respVO.setTodayStockOutItemCount((long) itemList.size()); + fillInOutDisplay(respVO, false, itemList); + } + + private void fillInOutDisplay(ErpWarehouseSummaryRespVO respVO, boolean inbound, List itemList) { + if (CollUtil.isEmpty(itemList)) { + if (inbound) { + respVO.setTodayProductStockInDisplay(formatProductDisplay(BigDecimal.ZERO, null, null, null)); + respVO.setTodayMaterialStockInDisplay(formatUnitDisplay(BigDecimal.ZERO, null, null, null)); + respVO.setTodaySparePartStockInDisplay(formatUnitDisplay(BigDecimal.ZERO, null, null, null)); + } else { + respVO.setTodayProductStockOutDisplay(formatProductDisplay(BigDecimal.ZERO, null, null, null)); + respVO.setTodayMaterialStockOutDisplay(formatUnitDisplay(BigDecimal.ZERO, null, null, null)); + respVO.setTodaySparePartStockOutDisplay(formatUnitDisplay(BigDecimal.ZERO, null, null, null)); + } + return; + } + + Set productIds = itemList.stream() + .map(item -> item instanceof ErpStockInItemDO ? ((ErpStockInItemDO) item).getProductId() : ((ErpStockOutItemDO) item).getProductId()) + .collect(Collectors.toSet()); + Map productMap = productService.getProductVOMap(productIds); + + BigDecimal productCount = BigDecimal.ZERO; + BigDecimal materialCount = BigDecimal.ZERO; + BigDecimal sparePartCount = BigDecimal.ZERO; + + for (Object item : itemList) { + Long productId = item instanceof ErpStockInItemDO ? ((ErpStockInItemDO) item).getProductId() : ((ErpStockOutItemDO) item).getProductId(); + BigDecimal count = item instanceof ErpStockInItemDO ? ((ErpStockInItemDO) item).getCount() : ((ErpStockOutItemDO) item).getCount(); + ErpProductRespVO product = productMap.get(productId); + Integer categoryType = product != null ? product.getCategoryType() : null; + if (Integer.valueOf(1).equals(categoryType)) { + productCount = productCount.add(safeCount(count)); + } else if (Integer.valueOf(2).equals(categoryType)) { + materialCount = materialCount.add(safeCount(count)); + } else if (Integer.valueOf(3).equals(categoryType)) { + sparePartCount = sparePartCount.add(safeCount(count)); + } + } + + if (inbound) { + respVO.setTodayProductStockInDisplay(formatProductDisplay(productCount, null, null, null)); + respVO.setTodayMaterialStockInDisplay(formatUnitDisplay(materialCount, null, null, null)); + respVO.setTodaySparePartStockInDisplay(formatUnitDisplay(sparePartCount, null, null, null)); + } else { + respVO.setTodayProductStockOutDisplay(formatProductDisplay(productCount, null, null, null)); + respVO.setTodayMaterialStockOutDisplay(formatUnitDisplay(materialCount, null, null, null)); + respVO.setTodaySparePartStockOutDisplay(formatUnitDisplay(sparePartCount, null, null, null)); + } + } + + private boolean hasWarehouseIn(Long inId, Long warehouseId) { + return stockInItemMapper.selectListByInId(inId).stream().anyMatch(item -> warehouseId.equals(item.getWarehouseId())); + } + + private boolean hasWarehouseOut(Long outId, Long warehouseId) { + return stockOutItemMapper.selectListByOutId(outId).stream().anyMatch(item -> warehouseId.equals(item.getWarehouseId())); + } + + private Integer resolveCategoryType(ErpStockDO stock) { + if (stock.getCategoryType() != null) { + return stock.getCategoryType(); + } + ErpProductRespVO product = productService.getProductVOMap(Collections.singleton(stock.getProductId())).get(stock.getProductId()); + return product != null ? product.getCategoryType() : null; + } + + private ErpStockDO firstStock(List list) { + return CollUtil.isEmpty(list) ? null : list.get(0); + } + + private BigDecimal sumCount(List list) { + if (CollUtil.isEmpty(list)) { + return BigDecimal.ZERO; + } + BigDecimal total = BigDecimal.ZERO; + for (ErpStockDO stock : list) { + total = total.add(safeCount(stock.getCount())); + } + return total; + } + + private BigDecimal safeCount(BigDecimal count) { + return count == null ? BigDecimal.ZERO : count; + } + + private String formatProductDisplay(BigDecimal count, BigDecimal palletTotalQuantity, BigDecimal palletPackageQuantity, + BigDecimal packageQuantity) { + BigDecimal safeCount = safeCount(count); + if (palletTotalQuantity == null || palletTotalQuantity.compareTo(BigDecimal.ZERO) <= 0) { + return formatNumber(safeCount) + "个"; + } + BigDecimal palletCount = safeCount.divideToIntegralValue(palletTotalQuantity); + BigDecimal remainAfterPallet = safeCount.remainder(palletTotalQuantity); + if (palletPackageQuantity == null || palletPackageQuantity.compareTo(BigDecimal.ZERO) <= 0) { + return formatNumber(palletCount) + "托" + formatNumber(remainAfterPallet) + "个"; + } + BigDecimal packageCount = remainAfterPallet.divideToIntegralValue(palletPackageQuantity); + BigDecimal remainAfterPackage = remainAfterPallet.remainder(palletPackageQuantity); + if (packageQuantity == null || packageQuantity.compareTo(BigDecimal.ZERO) <= 0) { + return formatNumber(palletCount) + "托" + formatNumber(packageCount) + "包" + formatNumber(remainAfterPackage) + "个"; + } + BigDecimal unitCount = remainAfterPackage.divideToIntegralValue(packageQuantity); + return formatNumber(palletCount) + "托" + formatNumber(packageCount) + "包" + formatNumber(unitCount) + "个"; + } + + private String formatUnitDisplay(BigDecimal count, BigDecimal purchaseUnitConvertQuantity, String purchaseUnitName, String unitName) { + BigDecimal safeCount = safeCount(count); + if (purchaseUnitConvertQuantity == null || purchaseUnitConvertQuantity.compareTo(BigDecimal.ZERO) <= 0 + || purchaseUnitName == null || unitName == null) { + return formatNumber(safeCount) + (unitName != null ? unitName : "个"); + } + BigDecimal purchaseCount = safeCount.divideToIntegralValue(purchaseUnitConvertQuantity); + BigDecimal unitCount = safeCount.remainder(purchaseUnitConvertQuantity); + StringBuilder display = new StringBuilder(); + if (purchaseCount.compareTo(BigDecimal.ZERO) > 0) { + display.append(formatNumber(purchaseCount)).append(purchaseUnitName); + } + if (unitCount.compareTo(BigDecimal.ZERO) > 0 || display.length() == 0) { + display.append(formatNumber(unitCount)).append(unitName); + } + return display.toString(); + } + + private String formatNumber(BigDecimal value) { + return value == null ? "0" : value.stripTrailingZeros().toPlainString(); + } + +}