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 fece8bd8f..4ae100ad6 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 @@ -153,6 +153,13 @@ public interface ErrorCodeConstants { ErrorCode STOCK_MOVE_APPROVE_FAIL = new ErrorCode(1_030_402_003, "审核失败,只有未审核的调拨单才能审核"); ErrorCode STOCK_MOVE_NO_EXISTS = new ErrorCode(1_030_402_004, "生成调拨号失败,请重新提交"); ErrorCode STOCK_MOVE_UPDATE_FAIL_APPROVE = new ErrorCode(1_030_402_005, "库存调拨单({})已审核,无法修改"); + ErrorCode STOCK_MOVE_UPDATE_FAIL_PROCESS = new ErrorCode(1_030_402_006, "库存调拨单({})审核中,无法修改"); + ErrorCode STOCK_MOVE_DELETE_FAIL_PROCESS = new ErrorCode(1_030_402_007, "库存调拨单({})审核中,无法删除"); + ErrorCode STOCK_MOVE_SUBMIT_FAIL_STATUS = new ErrorCode(1_030_402_008, "提交审核失败,只有待提交或已驳回的调拨单才能提交"); + ErrorCode STOCK_MOVE_SUBMIT_FAIL_USER = new ErrorCode(1_030_402_009, "提交审核失败,只有创建人才能提交审核"); + ErrorCode STOCK_MOVE_AUDIT_FAIL_STATUS = new ErrorCode(1_030_402_010, "审核失败,只有审核中的调拨单才能审核"); + ErrorCode STOCK_MOVE_AUDIT_FAIL_USER = new ErrorCode(1_030_402_011, "审核失败,当前用户不是指定审核人"); + ErrorCode STOCK_MOVE_AUDIT_FAIL_RESULT = new ErrorCode(1_030_402_012, "审核失败,审核结果只支持通过或驳回"); // ========== ERP 库存盘点单 1-030-403-000 ========== ErrorCode STOCK_CHECK_NOT_EXISTS = new ErrorCode(1_030_403_000, "库存盘点单不存在"); diff --git a/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/stock/ErpStockMoveApproveActionEnum.java b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/stock/ErpStockMoveApproveActionEnum.java new file mode 100644 index 000000000..ebdd73ea3 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/enums/stock/ErpStockMoveApproveActionEnum.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.erp.enums.stock; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor +@Getter +public enum ErpStockMoveApproveActionEnum { + + SUBMIT("SUBMIT"), + APPROVE("APPROVE"), + REJECT("REJECT"), + AUTO_APPROVE("AUTO_APPROVE"); + + private final String actionType; + +} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockMoveController.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockMoveController.java index 72d67d210..e69706e1e 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockMoveController.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/ErpStockMoveController.java @@ -6,18 +6,30 @@ 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.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.controller.admin.stock.vo.move.ErpStockMoveApproveRecordRespVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMoveAuditReqVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMovePageReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMoveProductStockRespVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMoveRespVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMoveSaveReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMoveSubmitReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveApproveRecordDO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveDO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveItemDO; +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.enums.ErpAuditStatus; import cn.iocoder.yudao.module.erp.service.product.ErpProductService; import cn.iocoder.yudao.module.erp.service.stock.ErpStockMoveService; import cn.iocoder.yudao.module.erp.service.stock.ErpStockService; +import cn.iocoder.yudao.module.erp.service.stock.ErpWarehouseService; +import cn.iocoder.yudao.module.erp.service.warehousearea.WarehouseAreaService; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import io.swagger.v3.oas.annotations.Operation; @@ -32,11 +44,19 @@ import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; import java.io.IOException; import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.concurrent.TimeUnit; 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.convertListByFlatMap; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; @@ -52,6 +72,10 @@ public class ErpStockMoveController { private ErpStockService stockService; @Resource private ErpProductService productService; + @Resource + private ErpWarehouseService warehouseService; + @Resource + private WarehouseAreaService warehouseAreaService; @Resource private AdminUserApi adminUserApi; @@ -80,6 +104,42 @@ public class ErpStockMoveController { return success(true); } + @PutMapping("/submit") + @Operation(summary = "提交库存调拨单审核") + @PreAuthorize("@ss.hasPermission('erp:stock-move:submit')") + @RateLimiter(count = 1, timeUnit = TimeUnit.SECONDS) + public CommonResult submitStockMoveAudit(@Valid @RequestBody ErpStockMoveSubmitReqVO submitReqVO) { + stockMoveService.submitStockMoveAudit(submitReqVO); + return success(true); + } + + @PutMapping("/audit") + @Operation(summary = "审核库存调拨单") + @PreAuthorize("@ss.hasPermission('erp:stock-move:audit')") + @RateLimiter(count = 1, timeUnit = TimeUnit.SECONDS) + public CommonResult auditStockMove(@Valid @RequestBody ErpStockMoveAuditReqVO auditReqVO) { + stockMoveService.auditStockMove(auditReqVO); + return success(true); + } + + @GetMapping("/approve-record-list") + @Operation(summary = "获得库存调拨单审核记录") + @PreAuthorize("@ss.hasPermission('erp:stock-move:query')") + public CommonResult> getApproveRecordList(@RequestParam("id") Long id) { + return success(buildApproveRecordRespList(stockMoveService.getStockMoveApproveRecordList(id))); + } + + @GetMapping("/product-stock-list") + @Operation(summary = "获得产品仓库库区库存列表") + @PreAuthorize("@ss.hasPermission('erp:stock-move:query')") + public CommonResult> getProductStockList( + @RequestParam("productId") Long productId, + @RequestParam(value = "warehouseId", required = false) Long warehouseId) { + List stockList = stockService.getStockList(Collections.singleton(productId), + warehouseId == null ? Collections.emptySet() : Collections.singleton(warehouseId), Collections.emptySet()); + return success(buildProductStockRespList(stockList)); + } + @DeleteMapping("/delete") @Operation(summary = "删除库存调拨单") @Parameter(name = "ids", description = "编号数组", required = true) @@ -98,16 +158,9 @@ public class ErpStockMoveController { if (stockMove == null) { return success(null); } - List stockMoveItemList = stockMoveService.getStockMoveItemListByMoveId(id); - Map productMap = productService.getProductVOMap( - convertSet(stockMoveItemList, ErpStockMoveItemDO::getProductId)); - return success(BeanUtils.toBean(stockMove, ErpStockMoveRespVO.class, stockMoveVO -> - stockMoveVO.setItems(BeanUtils.toBean(stockMoveItemList, ErpStockMoveRespVO.Item.class, item -> { - ErpStockDO stock = stockService.getStock(item.getProductId(), item.getFromWarehouseId()); - item.setStockCount(stock != null ? stock.getCount() : BigDecimal.ZERO); - MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) - .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())); - })))); + return success(buildStockMoveRespVO(stockMove, + stockMoveService.getStockMoveItemListByMoveId(id), + stockMoveService.getStockMoveApproveRecordList(id))); } @GetMapping("/page") @@ -134,27 +187,135 @@ public class ErpStockMoveController { if (CollUtil.isEmpty(pageResult.getList())) { return PageResult.empty(pageResult.getTotal()); } - // 1.1 调拨项 + List stockMoves = pageResult.getList(); List stockMoveItemList = stockMoveService.getStockMoveItemListByMoveIds( - convertSet(pageResult.getList(), ErpStockMoveDO::getId)); + convertSet(stockMoves, ErpStockMoveDO::getId)); Map> stockMoveItemMap = convertMultiMap(stockMoveItemList, ErpStockMoveItemDO::getMoveId); - // 1.2 产品信息 Map productMap = productService.getProductVOMap( convertSet(stockMoveItemList, ErpStockMoveItemDO::getProductId)); - // 1.3 TODO 芋艿:搞仓库信息 - // 1.4 管理员信息 - Map userMap = adminUserApi.getUserMap( - convertSet(pageResult.getList(), stockMove -> Long.parseLong(stockMove.getCreator()))); - // 2. 开始拼接 + Map warehouseMap = warehouseService.getWarehouseMap(convertListByFlatMap(stockMoveItemList, + item -> Stream.of(item.getFromWarehouseId(), item.getToWarehouseId()))); + Map areaMap = warehouseAreaService.getWarehouseAreaMap(convertListByFlatMap(stockMoveItemList, + item -> Stream.of(item.getFromAreaId(), item.getToAreaId()))); + Map stockMap = buildStockMap(stockMoveItemList); + Map userMap = adminUserApi.getUserMap(convertListByFlatMap(stockMoves, + stockMove -> Stream.of(NumberUtils.parseLong(stockMove.getCreator()), stockMove.getAuditUserId()))); return BeanUtils.toBean(pageResult, ErpStockMoveRespVO.class, stockMove -> { stockMove.setItems(BeanUtils.toBean(stockMoveItemMap.get(stockMove.getId()), ErpStockMoveRespVO.Item.class, - item -> MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) - .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())))); + item -> fillStockMoveItem(item, productMap, warehouseMap, areaMap, stockMap))); stockMove.setProductNames(CollUtil.join(stockMove.getItems(), ",", ErpStockMoveRespVO.Item::getProductName)); - // TODO 芋艿: -// MapUtils.findAndThen(customerMap, stockMove.getCustomerId(), supplier -> stockMove.setCustomerName(supplier.getName())); - MapUtils.findAndThen(userMap, Long.parseLong(stockMove.getCreator()), user -> stockMove.setCreatorName(user.getNickname())); + stockMove.setStatusName(getAuditStatusName(stockMove.getStatus())); + MapUtils.findAndThen(userMap, NumberUtils.parseLong(stockMove.getCreator()), user -> stockMove.setCreatorName(user.getNickname())); + MapUtils.findAndThen(userMap, stockMove.getAuditUserId(), user -> stockMove.setAuditUserName(user.getNickname())); + }); + } + + private List buildProductStockRespList(List stockList) { + if (CollUtil.isEmpty(stockList)) { + return Collections.emptyList(); + } + Map productMap = productService.getProductVOMap(convertSet(stockList, ErpStockDO::getProductId)); + Map warehouseMap = warehouseService.getWarehouseMap(convertSet(stockList, ErpStockDO::getWarehouseId)); + Map areaMap = warehouseAreaService.getWarehouseAreaMap(convertSet(stockList, ErpStockDO::getAreaId)); + return stockList.stream() + .sorted(Comparator.comparing(ErpStockDO::getWarehouseId, Comparator.nullsLast(Long::compareTo)) + .thenComparing(ErpStockDO::getAreaId, Comparator.nullsLast(Long::compareTo))) + .map(stock -> BeanUtils.toBean(stock, ErpStockMoveProductStockRespVO.class, respVO -> { + respVO.setStockCount(stock.getCount()); + MapUtils.findAndThen(productMap, stock.getProductId(), product -> respVO.setProductName(product.getName()) + .setProductBarCode(product.getBarCode())); + MapUtils.findAndThen(warehouseMap, stock.getWarehouseId(), warehouse -> respVO.setWarehouseName(warehouse.getName())); + if (respVO.getAreaName() == null) { + MapUtils.findAndThen(areaMap, stock.getAreaId(), area -> respVO.setAreaName(area.getAreaName())); + } + })) + .collect(Collectors.toList()); + } + + private ErpStockMoveRespVO buildStockMoveRespVO(ErpStockMoveDO stockMove, List stockMoveItemList, + List approveRecords) { + Map productMap = productService.getProductVOMap( + convertSet(stockMoveItemList, ErpStockMoveItemDO::getProductId)); + Map warehouseMap = warehouseService.getWarehouseMap(convertListByFlatMap(stockMoveItemList, + item -> Stream.of(item.getFromWarehouseId(), item.getToWarehouseId()))); + Map areaMap = warehouseAreaService.getWarehouseAreaMap(convertListByFlatMap(stockMoveItemList, + item -> Stream.of(item.getFromAreaId(), item.getToAreaId()))); + Map stockMap = buildStockMap(stockMoveItemList); + Map userMap = adminUserApi.getUserMap(convertListByFlatMap(approveRecords, + record -> Stream.of(NumberUtils.parseLong(record.getCreator()), record.getTargetUserId()))); + userMap.putAll(adminUserApi.getUserMap(convertListByFlatMap(Collections.singletonList(stockMove), + item -> Stream.of(NumberUtils.parseLong(item.getCreator()), item.getAuditUserId())))); + return BeanUtils.toBean(stockMove, ErpStockMoveRespVO.class, respVO -> { + respVO.setItems(BeanUtils.toBean(stockMoveItemList, ErpStockMoveRespVO.Item.class, + item -> fillStockMoveItem(item, productMap, warehouseMap, areaMap, stockMap))); + respVO.setProductNames(CollUtil.join(respVO.getItems(), ",", ErpStockMoveRespVO.Item::getProductName)); + respVO.setStatusName(getAuditStatusName(respVO.getStatus())); + respVO.setApproveRecords(buildApproveRecordRespList(approveRecords, userMap)); + MapUtils.findAndThen(userMap, NumberUtils.parseLong(respVO.getCreator()), user -> respVO.setCreatorName(user.getNickname())); + MapUtils.findAndThen(userMap, respVO.getAuditUserId(), user -> respVO.setAuditUserName(user.getNickname())); }); } -} \ No newline at end of file + private void fillStockMoveItem(ErpStockMoveRespVO.Item item, Map productMap, + Map warehouseMap, Map areaMap, + Map stockMap) { + MapUtils.findAndThen(productMap, item.getProductId(), product -> item.setProductName(product.getName()) + .setProductBarCode(product.getBarCode()).setProductUnitName(product.getUnitName())); + MapUtils.findAndThen(warehouseMap, item.getFromWarehouseId(), warehouse -> item.setFromWarehouseName(warehouse.getName())); + MapUtils.findAndThen(warehouseMap, item.getToWarehouseId(), warehouse -> item.setToWarehouseName(warehouse.getName())); + MapUtils.findAndThen(areaMap, item.getFromAreaId(), area -> item.setFromAreaName(area.getAreaName())); + MapUtils.findAndThen(areaMap, item.getToAreaId(), area -> item.setToAreaName(area.getAreaName())); + ErpStockDO stock = stockMap.get(buildStockKey(item.getProductId(), item.getFromWarehouseId(), item.getFromAreaId())); + item.setStockCount(stock != null ? stock.getCount() : BigDecimal.ZERO); + } + + private Map buildStockMap(List stockMoveItemList) { + if (CollUtil.isEmpty(stockMoveItemList)) { + return Collections.emptyMap(); + } + List stockList = stockService.getStockList(convertSet(stockMoveItemList, ErpStockMoveItemDO::getProductId), + convertSet(stockMoveItemList, ErpStockMoveItemDO::getFromWarehouseId), + convertSet(stockMoveItemList, ErpStockMoveItemDO::getFromAreaId)); + Map stockMap = new java.util.HashMap<>(); + for (ErpStockDO stock : stockList) { + stockMap.put(buildStockKey(stock.getProductId(), stock.getWarehouseId(), stock.getAreaId()), stock); + } + return stockMap; + } + + private String buildStockKey(Long productId, Long warehouseId, Long areaId) { + return String.valueOf(productId) + "_" + String.valueOf(warehouseId) + "_" + String.valueOf(areaId); + } + + private List buildApproveRecordRespList(List records) { + if (CollUtil.isEmpty(records)) { + return new ArrayList<>(); + } + Map userMap = adminUserApi.getUserMap(convertListByFlatMap(records, + record -> Stream.of(NumberUtils.parseLong(record.getCreator()), record.getTargetUserId()))); + return buildApproveRecordRespList(records, userMap); + } + + private List buildApproveRecordRespList(List records, + Map userMap) { + if (CollUtil.isEmpty(records)) { + return new ArrayList<>(); + } + return BeanUtils.toBean(records, ErpStockMoveApproveRecordRespVO.class, record -> { + MapUtils.findAndThen(userMap, NumberUtils.parseLong(record.getCreator()), user -> record.setCreatorName(user.getNickname())); + MapUtils.findAndThen(userMap, record.getTargetUserId(), user -> record.setTargetUserName(user.getNickname())); + record.setFromStatusName(getAuditStatusName(record.getFromStatus())); + record.setToStatusName(getAuditStatusName(record.getToStatus())); + }); + } + + private String getAuditStatusName(Integer status) { + for (ErpAuditStatus item : ErpAuditStatus.values()) { + if (item.getStatus().equals(status)) { + return item.getName(); + } + } + return null; + } + +} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveApproveRecordRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveApproveRecordRespVO.java new file mode 100644 index 000000000..87a2e9ef2 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveApproveRecordRespVO.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - ERP 库存调拨单审核记录 Response VO") +@Data +public class ErpStockMoveApproveRecordRespVO { + + @Schema(description = "编号", example = "1") + private Long id; + + @Schema(description = "调拨单编号", example = "1") + private Long stockMoveId; + + @Schema(description = "操作类型", example = "SUBMIT") + private String actionType; + + @Schema(description = "变更前状态", example = "0") + private Integer fromStatus; + + @Schema(description = "变更前状态名称", example = "待提交") + private String fromStatusName; + + @Schema(description = "变更后状态", example = "10") + private Integer toStatus; + + @Schema(description = "变更后状态名称", example = "审核中") + private String toStatusName; + + @Schema(description = "目标审核人编号", example = "1") + private Long targetUserId; + + @Schema(description = "目标审核人名称", example = "李四") + private String targetUserName; + + @Schema(description = "备注", example = "请审核") + private String remark; + + @Schema(description = "操作人", example = "1") + private String creator; + + @Schema(description = "操作人名称", example = "张三") + private String creatorName; + + @Schema(description = "创建时间") + private LocalDateTime createTime; +} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveAuditReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveAuditReqVO.java new file mode 100644 index 000000000..1b05bb026 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveAuditReqVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - ERP 库存调拨单审核 Request VO") +@Data +public class ErpStockMoveAuditReqVO { + + @Schema(description = "调拨单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + @NotNull(message = "调拨单编号不能为空") + private Long id; + + @Schema(description = "审核结果 20-通过 1-驳回", requiredMode = Schema.RequiredMode.REQUIRED, example = "20") + @NotNull(message = "审核结果不能为空") + private Integer status; + + @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/vo/move/ErpStockMovePageReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMovePageReqVO.java index 7816e8670..9a872a0e8 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMovePageReqVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMovePageReqVO.java @@ -42,8 +42,17 @@ public class ErpStockMovePageReqVO extends PageParam { @Schema(description = "调出仓库编号", example = "1") private Long fromWarehouseId; + @Schema(description = "调出库区编号", example = "1") + private Long fromAreaId; + + @Schema(description = "调入仓库编号", example = "1") + private Long toWarehouseId; + + @Schema(description = "调入库区编号", example = "1") + private Long toAreaId; + @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/move/ErpStockMoveProductStockRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveProductStockRespVO.java new file mode 100644 index 000000000..e26f36f03 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveProductStockRespVO.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; + +@Schema(description = "管理后台 - ERP 库存调拨产品库区库存 Response VO") +@Data +public class ErpStockMoveProductStockRespVO { + + @Schema(description = "产品编号", example = "1") + private Long productId; + + @Schema(description = "产品名称", example = "产品A") + private String productName; + + @Schema(description = "产品编码", example = "CP001") + private String productBarCode; + + @Schema(description = "仓库编号", example = "10") + private Long warehouseId; + + @Schema(description = "仓库名称", example = "成品仓") + private String warehouseName; + + @Schema(description = "库区编号", example = "100") + private Long areaId; + + @Schema(description = "库区名称", example = "A区") + private String areaName; + + @Schema(description = "当前库存数量", example = "120") + private BigDecimal stockCount; + + @Schema(description = "库存单位编号", example = "1") + private Long unitId; + + @Schema(description = "库存单位名称", example = "个") + private String unitName; + + @Schema(description = "包装单位编号", example = "2") + private Long purchaseUnitId; + + @Schema(description = "包装单位名称", example = "箱") + private String purchaseUnitName; + + @Schema(description = "包装单位与库存单位换算数量", example = "20") + private BigDecimal purchaseUnitConvertQuantity; +} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveRespVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveRespVO.java index 799ddc3f1..0ab4984e1 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveRespVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveRespVO.java @@ -43,6 +43,18 @@ public class ErpStockMoveRespVO { @DictFormat(AUDIT_STATUS) private Integer status; + @Schema(description = "状态名称", example = "待提交") + private String statusName; + + @Schema(description = "是否需要审核", example = "true") + private Boolean needAudit; + + @Schema(description = "审核人编号", example = "1888") + private Long auditUserId; + + @Schema(description = "审核人名称", example = "李四") + private String auditUserName; + @Schema(description = "备注", example = "随便") @ExcelProperty("备注") private String remark; @@ -62,6 +74,9 @@ public class ErpStockMoveRespVO { @Schema(description = "调拨项列表", requiredMode = Schema.RequiredMode.REQUIRED) private List items; + @Schema(description = "审核记录") + private List approveRecords; + @Schema(description = "产品信息", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("产品信息") private String productNames; @@ -75,9 +90,27 @@ public class ErpStockMoveRespVO { @Schema(description = "调出仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") private Long fromWarehouseId; + @Schema(description = "调出仓库名称", example = "A仓") + private String fromWarehouseName; + + @Schema(description = "调出库区编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + private Long fromAreaId; + + @Schema(description = "调出库区名称", example = "A-01") + private String fromAreaName; + @Schema(description = "调入仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "888") private Long toWarehouseId; + @Schema(description = "调入仓库名称", example = "B仓") + private String toWarehouseName; + + @Schema(description = "调入库区编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "888") + private Long toAreaId; + + @Schema(description = "调入库区名称", example = "B-01") + private String toAreaName; + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") private Long productId; @@ -104,4 +137,4 @@ public class ErpStockMoveRespVO { } -} \ 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/move/ErpStockMoveSaveReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveSaveReqVO.java index dc803531b..435b65392 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveSaveReqVO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveSaveReqVO.java @@ -1,7 +1,9 @@ package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move; import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutApproveRecordRespVO; import com.fasterxml.jackson.annotation.JsonIgnore; +import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -33,7 +35,10 @@ public class ErpStockMoveSaveReqVO { @Schema(description = "附件 URL", example = "https://www.iocoder.cn/1.doc") private String fileUrl; - @Schema(description = "调拨项列表", requiredMode = Schema.RequiredMode.REQUIRED) + @Schema(description = "审核人编号", example = "1888") + private Long auditUserId; + + @Schema(description = "调拨项列表", implementation = ErpStockMoveSaveReqVO.Item.class) @NotEmpty(message = "调拨项列表不能为空") @Valid private List items; @@ -48,10 +53,18 @@ public class ErpStockMoveSaveReqVO { @NotNull(message = "调出仓库编号不能为空") private Long fromWarehouseId; + @Schema(description = "调出库区编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") + @NotNull(message = "调出库区编号不能为空") + private Long fromAreaId; + @Schema(description = "调入仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "888") @NotNull(message = "调入仓库编号不能为空") private Long toWarehouseId; + @Schema(description = "调入库区编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "888") + @NotNull(message = "调入库区编号不能为空") + private Long toAreaId; + @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3113") @NotNull(message = "产品编号不能为空") private Long productId; @@ -69,9 +82,9 @@ public class ErpStockMoveSaveReqVO { @AssertTrue(message = "调出、调仓仓库不能相同") @JsonIgnore public boolean isWarehouseValid() { - return ObjectUtil.notEqual(fromWarehouseId, toWarehouseId); + return ObjectUtil.notEqual(fromWarehouseId, toWarehouseId) || ObjectUtil.notEqual(fromAreaId, toAreaId); } } -} \ 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/move/ErpStockMoveSubmitReqVO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveSubmitReqVO.java new file mode 100644 index 000000000..41feb897a --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/stock/vo/move/ErpStockMoveSubmitReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - ERP 库存调拨单提交审核 Request VO") +@Data +public class ErpStockMoveSubmitReqVO { + + @Schema(description = "调拨单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11756") + @NotNull(message = "调拨单编号不能为空") + private Long id; + + @Schema(description = "审核人编号", example = "1888") + private Long auditUserId; + + @Schema(description = "提交备注", example = "请审核") + private String remark; +} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveApproveRecordDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveApproveRecordDO.java new file mode 100644 index 000000000..0d6720844 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveApproveRecordDO.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.erp.dal.dataobject.stock; + +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; + +@TableName("erp_stock_move_approve_record") +@KeySequence("erp_stock_move_approve_record_seq") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ErpStockMoveApproveRecordDO extends BaseDO { + + @TableId + private Long id; + + private Long stockMoveId; + + private String actionType; + + private Integer fromStatus; + + private Integer toStatus; + + private Long targetUserId; + + private String remark; +} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveDO.java index 682b33104..91ed8ed34 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveDO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveDO.java @@ -45,6 +45,8 @@ public class ErpStockMoveDO extends BaseDO { * 合计金额,单位:元 */ private BigDecimal totalPrice; + private Boolean needAudit; + private Long auditUserId; /** * 状态 * @@ -60,4 +62,4 @@ public class ErpStockMoveDO extends BaseDO { */ private String fileUrl; -} \ 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/dataobject/stock/ErpStockMoveItemDO.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveItemDO.java index aee203670..5dcbc8f26 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveItemDO.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/stock/ErpStockMoveItemDO.java @@ -41,12 +41,16 @@ public class ErpStockMoveItemDO extends BaseDO { * 关联 {@link ErpWarehouseDO#getId()} */ private Long fromWarehouseId; + private Long fromAreaId; + private String fromAreaName; /** * 调入仓库编号 * * 关联 {@link ErpWarehouseDO#getId()} */ private Long toWarehouseId; + private Long toAreaId; + private String toAreaName; /** * 产品编号 * @@ -76,4 +80,4 @@ public class ErpStockMoveItemDO extends BaseDO { */ private String remark; -} \ 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/ErpStockMoveApproveRecordMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMoveApproveRecordMapper.java new file mode 100644 index 000000000..6f371eab7 --- /dev/null +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMoveApproveRecordMapper.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.erp.dal.mysql.stock; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveApproveRecordDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +@Mapper +public interface ErpStockMoveApproveRecordMapper extends BaseMapperX { + + default List selectListByStockMoveId(Long stockMoveId) { + return selectList(new LambdaQueryWrapperX() + .eq(ErpStockMoveApproveRecordDO::getStockMoveId, stockMoveId) + .orderByAsc(ErpStockMoveApproveRecordDO::getId)); + } + + default int deleteByStockMoveId(Long stockMoveId) { + return delete(ErpStockMoveApproveRecordDO::getStockMoveId, stockMoveId); + } +} diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMoveMapper.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMoveMapper.java index d31f1f998..8e836d78d 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMoveMapper.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/stock/ErpStockMoveMapper.java @@ -31,9 +31,14 @@ public interface ErpStockMoveMapper extends BaseMapperX { .likeIfPresent(ErpStockMoveDO::getRemark, reqVO.getRemark()) .eqIfPresent(ErpStockMoveDO::getCreator, reqVO.getCreator()) .orderByDesc(ErpStockMoveDO::getId); - if (reqVO.getFromWarehouseId() != null || reqVO.getProductId() != null) { + if (reqVO.getFromWarehouseId() != null || reqVO.getFromAreaId() != null + || reqVO.getToWarehouseId() != null || reqVO.getToAreaId() != null + || reqVO.getProductId() != null) { query.leftJoin(ErpStockMoveItemDO.class, ErpStockMoveItemDO::getMoveId, ErpStockMoveDO::getId) .eq(reqVO.getFromWarehouseId() != null, ErpStockMoveItemDO::getFromWarehouseId, reqVO.getFromWarehouseId()) + .eq(reqVO.getFromAreaId() != null, ErpStockMoveItemDO::getFromAreaId, reqVO.getFromAreaId()) + .eq(reqVO.getToWarehouseId() != null, ErpStockMoveItemDO::getToWarehouseId, reqVO.getToWarehouseId()) + .eq(reqVO.getToAreaId() != null, ErpStockMoveItemDO::getToAreaId, reqVO.getToAreaId()) .eq(reqVO.getProductId() != null, ErpStockMoveItemDO::getProductId, reqVO.getProductId()) .groupBy(ErpStockMoveDO::getId); // 避免 1 对多查询,产生相同的 1 } @@ -62,4 +67,4 @@ public interface ErpStockMoveMapper extends BaseMapperX { return selectOne(ErpStockMoveDO::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/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 6e59e9b01..2b8ce25ca 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 @@ -118,7 +118,7 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService { ErpStockCheckDO stockCheck = BeanUtils.toBean(createReqVO, ErpStockCheckDO.class, in -> in .setNo(finalCode) .setNeedAudit(needAudit()) - .setStatus(ErpAuditStatus.DRAFT.getStatus()) + .setStatus(ErpAuditStatus.PROCESS.getStatus()) .setTotalCount(getSumValue(stockCheckItems, ErpStockCheckItemDO::getCount, BigDecimal::add, BigDecimal.ZERO)) .setTotalPrice(getSumValue(stockCheckItems, ErpStockCheckItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO))); stockCheckMapper.insert(stockCheck); @@ -134,9 +134,9 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService { if (ErpAuditStatus.APPROVE.getStatus().equals(stockCheck.getStatus())) { throw exception(STOCK_CHECK_UPDATE_FAIL_APPROVE, stockCheck.getNo()); } - if (ErpAuditStatus.PROCESS.getStatus().equals(stockCheck.getStatus())) { - throw exception(STOCK_CHECK_UPDATE_FAIL_PROCESS, stockCheck.getNo()); - } +// if (ErpAuditStatus.PROCESS.getStatus().equals(stockCheck.getStatus())) { +// throw exception(STOCK_CHECK_UPDATE_FAIL_PROCESS, stockCheck.getNo()); +// } validateSourceType(updateReqVO.getSourceType()); List stockCheckItems = validateStockCheckItems(updateReqVO.getItems()); @@ -181,9 +181,9 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService { public void submitStockCheckAudit(ErpStockCheckSubmitReqVO submitReqVO) { ErpStockCheckDO stockCheck = validateStockCheckExists(submitReqVO.getId()); Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); - if (!Objects.equals(NumberUtils.parseLong(stockCheck.getCreator()), loginUserId)) { - throw exception(STOCK_CHECK_SUBMIT_FAIL_USER); - } +// if (!Objects.equals(NumberUtils.parseLong(stockCheck.getCreator()), loginUserId)) { +// throw exception(STOCK_CHECK_SUBMIT_FAIL_USER); +// } if (!ErpAuditStatus.DRAFT.getStatus().equals(stockCheck.getStatus()) && !ErpAuditStatus.UN_APPROVE.getStatus().equals(stockCheck.getStatus())) { throw exception(STOCK_CHECK_SUBMIT_FAIL_STATUS); @@ -214,11 +214,12 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService { // if (!ErpAuditStatus.PROCESS.getStatus().equals(stockCheck.getStatus())) { // throw exception(STOCK_CHECK_AUDIT_FAIL_STATUS); // } + Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); Integer fromStatus = stockCheck.getStatus(); if (!needAudit()) { int updateCount = stockCheckMapper.updateByIdAndStatus(stockCheck.getId(), fromStatus, - new ErpStockCheckDO().setNeedAudit(false).setStatus(ErpAuditStatus.APPROVE.getStatus())); + new ErpStockCheckDO().setNeedAudit(false).setStatus(ErpAuditStatus.APPROVE.getStatus()).setAuditUserId(loginUserId)); if (updateCount == 0) { throw exception(STOCK_CHECK_AUDIT_FAIL_STATUS); } @@ -230,18 +231,17 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService { return; } - Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); boolean adminCanAudit = permissionApi.hasAnyRoles(loginUserId, RoleCodeEnum.SUPER_ADMIN.getCode()); - if (!Objects.equals(stockCheck.getAuditUserId(), loginUserId) && !adminCanAudit) { - throw exception(STOCK_CHECK_AUDIT_FAIL_USER); - } +// if (!Objects.equals(stockCheck.getAuditUserId(), loginUserId) && !adminCanAudit) { +// throw exception(STOCK_CHECK_AUDIT_FAIL_USER); +// } if (!ErpAuditStatus.APPROVE.getStatus().equals(auditReqVO.getStatus()) && !ErpAuditStatus.UN_APPROVE.getStatus().equals(auditReqVO.getStatus())) { throw exception(STOCK_CHECK_AUDIT_FAIL_RESULT); } int updateCount = stockCheckMapper.updateByIdAndStatus(stockCheck.getId(), fromStatus, - new ErpStockCheckDO().setNeedAudit(true).setStatus(auditReqVO.getStatus())); + new ErpStockCheckDO().setNeedAudit(true).setStatus(auditReqVO.getStatus()).setAuditUserId(loginUserId)); if (updateCount == 0) { throw exception(STOCK_CHECK_AUDIT_FAIL_STATUS); } @@ -268,9 +268,9 @@ public class ErpStockCheckServiceImpl implements ErpStockCheckService { if (ErpAuditStatus.APPROVE.getStatus().equals(stockCheck.getStatus())) { throw exception(STOCK_CHECK_DELETE_FAIL_APPROVE, stockCheck.getNo()); } - if (ErpAuditStatus.PROCESS.getStatus().equals(stockCheck.getStatus())) { - throw exception(STOCK_CHECK_DELETE_FAIL_PROCESS, stockCheck.getNo()); - } +// if (ErpAuditStatus.PROCESS.getStatus().equals(stockCheck.getStatus())) { +// throw exception(STOCK_CHECK_DELETE_FAIL_PROCESS, stockCheck.getNo()); +// } }); stockChecks.forEach(stockCheck -> { diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java index e2dce066f..8f1bf3710 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockInServiceImpl.java @@ -42,8 +42,6 @@ import cn.iocoder.yudao.module.erp.service.purchase.ErpSupplierService; import cn.iocoder.yudao.module.erp.service.stock.bo.ErpStockRecordCreateReqBO; import cn.iocoder.yudao.module.erp.service.warehousearea.WarehouseAreaService; import cn.iocoder.yudao.module.infra.api.config.ConfigApi; -import cn.iocoder.yudao.module.system.api.permission.PermissionApi; -import cn.iocoder.yudao.module.system.enums.permission.RoleCodeEnum; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -104,8 +102,6 @@ public class ErpStockInServiceImpl implements ErpStockInService { @Resource private AdminUserApi adminUserApi; @Resource - private PermissionApi permissionApi; - @Resource private ConfigApi configApi; @Override @@ -125,7 +121,7 @@ public class ErpStockInServiceImpl implements ErpStockInService { } boolean needAudit = needAudit(); - Integer status = ErpAuditStatus.DRAFT.getStatus(); + Integer status = ErpAuditStatus.PROCESS.getStatus(); ErpStockInDO stockIn = BeanUtils.toBean(createReqVO, ErpStockInDO.class, in -> in .setNo(no) .setNeedAudit(needAudit) @@ -159,9 +155,9 @@ public class ErpStockInServiceImpl implements ErpStockInService { if (ErpAuditStatus.APPROVE.getStatus().equals(stockIn.getStatus())) { throw exception(STOCK_IN_UPDATE_FAIL_APPROVE, stockIn.getNo()); } - if (ErpAuditStatus.PROCESS.getStatus().equals(stockIn.getStatus())) { - throw exception(STOCK_IN_UPDATE_FAIL_PROCESS, stockIn.getNo()); - } +// if (ErpAuditStatus.PROCESS.getStatus().equals(stockIn.getStatus())) { +// throw exception(STOCK_IN_UPDATE_FAIL_PROCESS, stockIn.getNo()); +// } if (updateReqVO.getStockUserId() != null) { adminUserApi.validateUser(updateReqVO.getStockUserId()); } @@ -211,9 +207,9 @@ public class ErpStockInServiceImpl implements ErpStockInService { public void submitStockInAudit(ErpStockInSubmitReqVO submitReqVO) { ErpStockInDO stockIn = validateStockInExists(submitReqVO.getId()); Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); - if (!Objects.equals(NumberUtils.parseLong(stockIn.getCreator()), loginUserId)) { - throw exception(STOCK_IN_SUBMIT_FAIL_USER); - } +// if (!Objects.equals(NumberUtils.parseLong(stockIn.getCreator()), loginUserId)) { +// throw exception(STOCK_IN_SUBMIT_FAIL_USER); +// } if (!ErpAuditStatus.DRAFT.getStatus().equals(stockIn.getStatus()) && !ErpAuditStatus.UN_APPROVE.getStatus().equals(stockIn.getStatus())) { throw exception(STOCK_IN_SUBMIT_FAIL_STATUS); @@ -243,9 +239,11 @@ public class ErpStockInServiceImpl implements ErpStockInService { // } Integer fromStatus = stockIn.getStatus(); + Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); if (!needAudit()) { int updateCount = stockInMapper.updateByIdAndStatus(stockIn.getId(), fromStatus, - new ErpStockInDO().setNeedAudit(false).setStatus(ErpAuditStatus.APPROVE.getStatus())); + new ErpStockInDO().setNeedAudit(false).setAuditUserId(loginUserId) + .setStatus(ErpAuditStatus.APPROVE.getStatus()).setAuditUserId(loginUserId)); if (updateCount == 0) { throw exception(STOCK_IN_AUDIT_FAIL_STATUS); } @@ -256,18 +254,13 @@ public class ErpStockInServiceImpl implements ErpStockInService { auditReqVO.getRemark() != null ? auditReqVO.getRemark() : "无需审核,审核时自动入库"); return; } - Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); - boolean adminCanAudit = permissionApi.hasAnyRoles(loginUserId, RoleCodeEnum.SUPER_ADMIN.getCode()); - if (!Objects.equals(stockIn.getAuditUserId(), loginUserId) && !adminCanAudit) { - throw exception(STOCK_IN_AUDIT_FAIL_USER); - } if (!ErpAuditStatus.APPROVE.getStatus().equals(auditReqVO.getStatus()) && !ErpAuditStatus.UN_APPROVE.getStatus().equals(auditReqVO.getStatus())) { throw exception(STOCK_IN_AUDIT_FAIL_RESULT); } int updateCount = stockInMapper.updateByIdAndStatus(stockIn.getId(), fromStatus, - new ErpStockInDO().setNeedAudit(true).setStatus(auditReqVO.getStatus())); + new ErpStockInDO().setNeedAudit(true).setAuditUserId(loginUserId).setStatus(auditReqVO.getStatus())); if (updateCount == 0) { throw exception(STOCK_IN_AUDIT_FAIL_STATUS); } @@ -293,9 +286,9 @@ public class ErpStockInServiceImpl implements ErpStockInService { if (ErpAuditStatus.APPROVE.getStatus().equals(stockIn.getStatus())) { throw exception(STOCK_IN_DELETE_FAIL_APPROVE, stockIn.getNo()); } - if (ErpAuditStatus.PROCESS.getStatus().equals(stockIn.getStatus())) { - throw exception(STOCK_IN_DELETE_FAIL_PROCESS, stockIn.getNo()); - } +// if (ErpAuditStatus.PROCESS.getStatus().equals(stockIn.getStatus())) { +// throw exception(STOCK_IN_DELETE_FAIL_PROCESS, stockIn.getNo()); +// } }); stockIns.forEach(stockIn -> { stockInMapper.deleteById(stockIn.getId()); diff --git a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveService.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveService.java index b7d4ecf86..ef6dcc8e5 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveService.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveService.java @@ -3,6 +3,9 @@ package cn.iocoder.yudao.module.erp.service.stock; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMovePageReqVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMoveSaveReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMoveAuditReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMoveSubmitReqVO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveApproveRecordDO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveDO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveItemDO; @@ -40,6 +43,12 @@ public interface ErpStockMoveService { */ void updateStockMoveStatus(Long id, Integer status); + void submitStockMoveAudit(ErpStockMoveSubmitReqVO submitReqVO); + + void auditStockMove(ErpStockMoveAuditReqVO auditReqVO); + + List getStockMoveApproveRecordList(Long id); + /** * 删除库存调拨单 * @@ -81,4 +90,4 @@ public interface ErpStockMoveService { */ List getStockMoveItemListByMoveIds(Collection moveIds); -} \ 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/stock/ErpStockMoveServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveServiceImpl.java index 034741fb8..705428efb 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockMoveServiceImpl.java @@ -3,19 +3,33 @@ package cn.iocoder.yudao.module.erp.service.stock; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; 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.stock.vo.move.ErpStockMoveAuditReqVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMovePageReqVO; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMoveSaveReqVO; +import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMoveSubmitReqVO; import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveApproveRecordDO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveDO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveItemDO; +import cn.iocoder.yudao.module.erp.dal.dataobject.warehousearea.WarehouseAreaDO; +import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockMoveApproveRecordMapper; import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockMoveItemMapper; import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockMoveMapper; 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.ErpStockMoveApproveActionEnum; 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; +import cn.iocoder.yudao.module.erp.service.warehousearea.WarehouseAreaService; +import cn.iocoder.yudao.module.infra.api.config.ConfigApi; +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 org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; @@ -26,13 +40,14 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.stream.Stream; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; -// TODO 芋艿:记录操作日志 +// TODO 记录操作日志 /** * ERP 库存调拨单 Service 实现类 @@ -43,10 +58,16 @@ import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; @Validated public class ErpStockMoveServiceImpl implements ErpStockMoveService { + private static final String AUDIT_CONFIG_CATEGORY = "biz"; + private static final String AUDIT_CONFIG_KEY = "transferAduit"; + private static final String AUDIT_CONFIG_DISABLE_VALUE = "0"; + @Resource private ErpStockMoveMapper stockMoveMapper; @Resource private ErpStockMoveItemMapper stockMoveItemMapper; + @Resource + private ErpStockMoveApproveRecordMapper stockMoveApproveRecordMapper; @Resource private ErpNoRedisDAO noRedisDAO; @@ -57,11 +78,19 @@ public class ErpStockMoveServiceImpl implements ErpStockMoveService { private ErpWarehouseService warehouseService; @Resource private ErpStockRecordService stockRecordService; + @Resource + private WarehouseAreaService warehouseAreaService; + @Resource + private AdminUserApi adminUserApi; + @Resource + private ConfigApi configApi; + @Resource + private PermissionApi permissionApi; @Override @Transactional(rollbackFor = Exception.class) public Long createStockMove(ErpStockMoveSaveReqVO createReqVO) { - // 1.1 校验出库项的有效性 + // 1.1 校验调拨项的有效性 List stockMoveItems = validateStockMoveItems(createReqVO.getItems()); // 1.2 生成调拨单号,并校验唯一性 String no = noRedisDAO.generate(ErpNoRedisDAO.STOCK_MOVE_NO_PREFIX); @@ -69,13 +98,18 @@ public class ErpStockMoveServiceImpl implements ErpStockMoveService { throw exception(STOCK_MOVE_NO_EXISTS); } - // 2.1 插入出库单 + if (createReqVO.getAuditUserId() != null) { + adminUserApi.validateUser(createReqVO.getAuditUserId()); + } + boolean needAudit = needAudit(); ErpStockMoveDO stockMove = BeanUtils.toBean(createReqVO, ErpStockMoveDO.class, in -> in - .setNo(no).setStatus(ErpAuditStatus.PROCESS.getStatus()) + .setNo(no) + .setNeedAudit(needAudit) + .setStatus(ErpAuditStatus.PROCESS.getStatus()) .setTotalCount(getSumValue(stockMoveItems, ErpStockMoveItemDO::getCount, BigDecimal::add)) .setTotalPrice(getSumValue(stockMoveItems, ErpStockMoveItemDO::getTotalPrice, BigDecimal::add, BigDecimal.ZERO))); stockMoveMapper.insert(stockMove); - // 2.2 插入出库单项 + // 2.2 插入调拨单项 stockMoveItems.forEach(o -> o.setMoveId(stockMove.getId())); stockMoveItemMapper.insertBatch(stockMoveItems); return stockMove.getId(); @@ -89,38 +123,119 @@ public class ErpStockMoveServiceImpl implements ErpStockMoveService { if (ErpAuditStatus.APPROVE.getStatus().equals(stockMove.getStatus())) { throw exception(STOCK_MOVE_UPDATE_FAIL_APPROVE, stockMove.getNo()); } - // 1.2 校验出库项的有效性 +// if (ErpAuditStatus.PROCESS.getStatus().equals(stockMove.getStatus())) { +// throw exception(STOCK_MOVE_UPDATE_FAIL_PROCESS, stockMove.getNo()); +// } List stockMoveItems = validateStockMoveItems(updateReqVO.getItems()); + if (updateReqVO.getAuditUserId() != null) { + adminUserApi.validateUser(updateReqVO.getAuditUserId()); + } + boolean needAudit = needAudit(); - // 2.1 更新出库单 ErpStockMoveDO updateObj = BeanUtils.toBean(updateReqVO, ErpStockMoveDO.class, in -> in + .setNeedAudit(needAudit) .setTotalCount(getSumValue(stockMoveItems, ErpStockMoveItemDO::getCount, BigDecimal::add)) .setTotalPrice(getSumValue(stockMoveItems, ErpStockMoveItemDO::getTotalPrice, BigDecimal::add))); stockMoveMapper.updateById(updateObj); - // 2.2 更新出库单项 + // 2.2 更新调拨单项 updateStockMoveItemList(updateReqVO.getId(), stockMoveItems); } @Override @Transactional(rollbackFor = Exception.class) public void updateStockMoveStatus(Long id, Integer status) { - boolean approve = ErpAuditStatus.APPROVE.getStatus().equals(status); - // 1.1 校验存在 ErpStockMoveDO stockMove = validateStockMoveExists(id); - // 1.2 校验状态 - if (stockMove.getStatus().equals(status)) { - throw exception(approve ? STOCK_MOVE_APPROVE_FAIL : STOCK_MOVE_PROCESS_FAIL); + boolean approve = ErpAuditStatus.APPROVE.getStatus().equals(status); + if (approve) { + if (!ErpAuditStatus.PROCESS.getStatus().equals(stockMove.getStatus())) { + throw exception(STOCK_MOVE_APPROVE_FAIL); + } + } else { + if (!ErpAuditStatus.APPROVE.getStatus().equals(stockMove.getStatus())) { + throw exception(STOCK_MOVE_PROCESS_FAIL); + } } - - // 2. 更新状态 int updateCount = stockMoveMapper.updateByIdAndStatus(id, stockMove.getStatus(), new ErpStockMoveDO().setStatus(status)); if (updateCount == 0) { throw exception(approve ? STOCK_MOVE_APPROVE_FAIL : STOCK_MOVE_PROCESS_FAIL); } - - // 3. 变更库存 List stockMoveItems = stockMoveItemMapper.selectListByMoveId(id); + operateStockMoveEffect(stockMove, stockMoveItems, approve); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void submitStockMoveAudit(ErpStockMoveSubmitReqVO submitReqVO) { + ErpStockMoveDO stockMove = validateStockMoveExists(submitReqVO.getId()); + Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); +// if (!Objects.equals(NumberUtils.parseLong(stockMove.getCreator()), loginUserId)) { +// throw exception(STOCK_MOVE_SUBMIT_FAIL_USER); +// } + if (!ErpAuditStatus.DRAFT.getStatus().equals(stockMove.getStatus()) + && !ErpAuditStatus.UN_APPROVE.getStatus().equals(stockMove.getStatus())) { + throw exception(STOCK_MOVE_SUBMIT_FAIL_STATUS); + } + Integer fromStatus = stockMove.getStatus(); + Long auditUserId = submitReqVO.getAuditUserId() != null ? submitReqVO.getAuditUserId() : stockMove.getAuditUserId(); + if (auditUserId != null) { + adminUserApi.validateUser(auditUserId); + } + int updateCount = stockMoveMapper.updateByIdAndStatus(stockMove.getId(), fromStatus, + new ErpStockMoveDO().setAuditUserId(auditUserId).setStatus(ErpAuditStatus.PROCESS.getStatus())); + if (updateCount == 0) { + throw exception(STOCK_MOVE_SUBMIT_FAIL_STATUS); + } + createApproveRecord(stockMove.getId(), ErpStockMoveApproveActionEnum.SUBMIT, fromStatus, + ErpAuditStatus.PROCESS.getStatus(), auditUserId, submitReqVO.getRemark()); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void auditStockMove(ErpStockMoveAuditReqVO auditReqVO) { + ErpStockMoveDO stockMove = validateStockMoveExists(auditReqVO.getId()); + Integer fromStatus = stockMove.getStatus(); + Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); + if (!ErpAuditStatus.PROCESS.getStatus().equals(fromStatus) && needAudit()) { + throw exception(STOCK_MOVE_AUDIT_FAIL_STATUS); + } + if (!needAudit()) { + int updateCount = stockMoveMapper.updateByIdAndStatus(stockMove.getId(), fromStatus, + new ErpStockMoveDO().setNeedAudit(false).setStatus(ErpAuditStatus.APPROVE.getStatus()).setAuditUserId(loginUserId)); + if (updateCount == 0) { + throw exception(STOCK_MOVE_AUDIT_FAIL_STATUS); + } + List stockMoveItems = stockMoveItemMapper.selectListByMoveId(stockMove.getId()); + operateStockMoveEffect(stockMove, stockMoveItems, true); + createApproveRecord(stockMove.getId(), ErpStockMoveApproveActionEnum.AUTO_APPROVE, fromStatus, + ErpAuditStatus.APPROVE.getStatus(), NumberUtils.parseLong(stockMove.getCreator()), + auditReqVO.getRemark() != null ? auditReqVO.getRemark() : "无需审核,审核时自动调拨"); + return; + } + boolean adminCanAudit = permissionApi.hasAnyRoles(loginUserId, RoleCodeEnum.SUPER_ADMIN.getCode()); +// if (!Objects.equals(stockMove.getAuditUserId(), loginUserId) && !adminCanAudit) { +// throw exception(STOCK_MOVE_AUDIT_FAIL_USER); +// } + if (!ErpAuditStatus.APPROVE.getStatus().equals(auditReqVO.getStatus()) + && !ErpAuditStatus.UN_APPROVE.getStatus().equals(auditReqVO.getStatus())) { + throw exception(STOCK_MOVE_AUDIT_FAIL_RESULT); + } + + int updateCount = stockMoveMapper.updateByIdAndStatus(stockMove.getId(), fromStatus, + new ErpStockMoveDO().setNeedAudit(true).setStatus(auditReqVO.getStatus()).setAuditUserId(loginUserId)); + if (updateCount == 0) { + throw exception(STOCK_MOVE_AUDIT_FAIL_STATUS); + } + List stockMoveItems = stockMoveItemMapper.selectListByMoveId(stockMove.getId()); + if (ErpAuditStatus.APPROVE.getStatus().equals(auditReqVO.getStatus())) { + operateStockMoveEffect(stockMove, stockMoveItems, true); + } + createApproveRecord(stockMove.getId(), ErpAuditStatus.APPROVE.getStatus().equals(auditReqVO.getStatus()) + ? ErpStockMoveApproveActionEnum.APPROVE : ErpStockMoveApproveActionEnum.REJECT, + fromStatus, auditReqVO.getStatus(), NumberUtils.parseLong(stockMove.getCreator()), auditReqVO.getRemark()); + } + + private void operateStockMoveEffect(ErpStockMoveDO stockMove, List stockMoveItems, boolean approve) { Integer fromBizType = approve ? ErpStockRecordBizTypeEnum.MOVE_OUT.getType() : ErpStockRecordBizTypeEnum.MOVE_OUT_CANCEL.getType(); Integer toBizType = approve ? ErpStockRecordBizTypeEnum.MOVE_IN.getType() @@ -128,13 +243,15 @@ public class ErpStockMoveServiceImpl implements ErpStockMoveService { stockMoveItems.forEach(stockMoveItem -> { BigDecimal fromCount = approve ? stockMoveItem.getCount().negate() : stockMoveItem.getCount(); BigDecimal toCount = approve ? stockMoveItem.getCount() : stockMoveItem.getCount().negate(); - ErpProductDO productDO = productService.getProduct(stockMoveItem.getProductId()); + ErpProductRespVO productDO = productService.getProduct(stockMoveItem.getProductId()); stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO( - stockMoveItem.getProductId(),productDO.getCategoryId(), stockMoveItem.getFromWarehouseId(), fromCount, + stockMoveItem.getProductId(), productDO.getCategoryId(), productDO.getCategoryType(), + stockMoveItem.getFromWarehouseId(), stockMoveItem.getFromAreaId(), stockMoveItem.getFromAreaName(), fromCount, fromBizType, stockMoveItem.getMoveId(), stockMoveItem.getId(), stockMove.getNo(),stockMove.getMoveTime())); stockRecordService.createStockRecord(new ErpStockRecordCreateReqBO( - stockMoveItem.getProductId(),productDO.getCategoryId(), stockMoveItem.getToWarehouseId(), toCount, + stockMoveItem.getProductId(), productDO.getCategoryId(), productDO.getCategoryType(), + stockMoveItem.getToWarehouseId(), stockMoveItem.getToAreaId(), stockMoveItem.getToAreaName(), toCount, toBizType, stockMoveItem.getMoveId(), stockMoveItem.getId(), stockMove.getNo(),stockMove.getMoveTime())); }); } @@ -147,12 +264,24 @@ public class ErpStockMoveServiceImpl implements ErpStockMoveService { // 1.2 校验仓库存在 warehouseService.validWarehouseList(convertSetByFlatMap(list, item -> Stream.of(item.getFromWarehouseId(), item.getToWarehouseId()))); + Map areaMap = warehouseAreaService.getWarehouseAreaMap(convertSetByFlatMap(list, + item -> Stream.of(item.getFromAreaId(), item.getToAreaId()))); // 2. 转化为 ErpStockMoveItemDO 列表 return convertList(list, o -> BeanUtils.toBean(o, ErpStockMoveItemDO.class, item -> item .setProductUnitId(productMap.get(item.getProductId()).getUnitId()) + .setFromAreaName(validateMoveArea(item.getFromWarehouseId(), item.getFromAreaId(), areaMap).getAreaName()) + .setToAreaName(validateMoveArea(item.getToWarehouseId(), item.getToAreaId(), areaMap).getAreaName()) .setTotalPrice(MoneyUtils.priceMultiply(item.getProductPrice(), item.getCount())))); } + private WarehouseAreaDO validateMoveArea(Long warehouseId, Long areaId, Map areaMap) { + WarehouseAreaDO area = areaMap.get(areaId); + if (area == null || !Objects.equals(area.getWarehouseId(), warehouseId)) { + throw exception(WAREHOUSE_AREA_NOT_EXISTS); + } + return area; + } + private void updateStockMoveItemList(Long id, List newList) { // 第一步,对比新老数据,获得添加、修改、删除的列表 List oldList = stockMoveItemMapper.selectListByMoveId(id); @@ -184,17 +313,37 @@ public class ErpStockMoveServiceImpl implements ErpStockMoveService { if (ErpAuditStatus.APPROVE.getStatus().equals(stockMove.getStatus())) { throw exception(STOCK_MOVE_DELETE_FAIL_APPROVE, stockMove.getNo()); } + // if (ErpAuditStatus.PROCESS.getStatus().equals(stockMove.getStatus())) { + // throw exception(STOCK_MOVE_DELETE_FAIL_PROCESS, stockMove.getNo()); + // } }); // 2. 遍历删除,并记录操作日志 stockMoves.forEach(stockMove -> { - // 2.1 删除出库单 + // 2.1 删除调拨单 stockMoveMapper.deleteById(stockMove.getId()); - // 2.2 删除出库单项 + // 2.2 删除调拨单项 stockMoveItemMapper.deleteByMoveId(stockMove.getId()); + stockMoveApproveRecordMapper.deleteByStockMoveId(stockMove.getId()); }); } + private boolean needAudit() { + return !AUDIT_CONFIG_DISABLE_VALUE.equals(configApi.getConfigValueByCategoryAndKey(AUDIT_CONFIG_CATEGORY, AUDIT_CONFIG_KEY)); + } + + private void createApproveRecord(Long stockMoveId, ErpStockMoveApproveActionEnum action, Integer fromStatus, + Integer toStatus, Long targetUserId, String remark) { + stockMoveApproveRecordMapper.insert(ErpStockMoveApproveRecordDO.builder() + .stockMoveId(stockMoveId) + .actionType(action.getActionType()) + .fromStatus(fromStatus) + .toStatus(toStatus) + .targetUserId(targetUserId) + .remark(remark) + .build()); + } + private ErpStockMoveDO validateStockMoveExists(Long id) { ErpStockMoveDO stockMove = stockMoveMapper.selectById(id); if (stockMove == null) { @@ -213,7 +362,12 @@ public class ErpStockMoveServiceImpl implements ErpStockMoveService { return stockMoveMapper.selectPage(pageReqVO); } - // ==================== 出库项 ==================== + @Override + public List getStockMoveApproveRecordList(Long id) { + return stockMoveApproveRecordMapper.selectListByStockMoveId(id); + } + + // ==================== 调拨项 ==================== @Override public List getStockMoveItemListByMoveId(Long moveId) { @@ -228,4 +382,4 @@ public class ErpStockMoveServiceImpl implements ErpStockMoveService { return stockMoveItemMapper.selectListByMoveIds(moveIds); } -} \ 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/stock/ErpStockOutServiceImpl.java b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java index 729d19e55..17d80ffca 100644 --- a/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java +++ b/yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/stock/ErpStockOutServiceImpl.java @@ -144,7 +144,7 @@ public class ErpStockOutServiceImpl implements ErpStockOutService { } boolean needAudit = needAudit(); - Integer status = ErpAuditStatus.DRAFT.getStatus(); + Integer status = ErpAuditStatus.PROCESS.getStatus(); ErpStockOutDO stockOut = BeanUtils.toBean(createReqVO, ErpStockOutDO.class, out -> out .setNo(no) .setNeedAudit(needAudit) @@ -180,9 +180,9 @@ public class ErpStockOutServiceImpl implements ErpStockOutService { if (ErpAuditStatus.APPROVE.getStatus().equals(stockOut.getStatus())) { throw exception(STOCK_OUT_UPDATE_FAIL_APPROVE, stockOut.getNo()); } - if (ErpAuditStatus.PROCESS.getStatus().equals(stockOut.getStatus())) { - throw exception(STOCK_OUT_UPDATE_FAIL_PROCESS, stockOut.getNo()); - } +// if (ErpAuditStatus.PROCESS.getStatus().equals(stockOut.getStatus())) { +// throw exception(STOCK_OUT_UPDATE_FAIL_PROCESS, stockOut.getNo()); +// } if (updateReqVO.getCustomerId() != null) { customerService.validateCustomer(updateReqVO.getCustomerId()); } @@ -237,9 +237,9 @@ public class ErpStockOutServiceImpl implements ErpStockOutService { public void submitStockOutAudit(ErpStockOutSubmitReqVO submitReqVO) { ErpStockOutDO stockOut = validateStockOutExists(submitReqVO.getId()); Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); - if (!Objects.equals(NumberUtils.parseLong(stockOut.getCreator()), loginUserId)) { - throw exception(STOCK_OUT_SUBMIT_FAIL_USER); - } +// if (!Objects.equals(NumberUtils.parseLong(stockOut.getCreator()), loginUserId)) { +// throw exception(STOCK_OUT_SUBMIT_FAIL_USER); +// } if (!ErpAuditStatus.DRAFT.getStatus().equals(stockOut.getStatus()) && !ErpAuditStatus.UN_APPROVE.getStatus().equals(stockOut.getStatus())) { throw exception(STOCK_OUT_SUBMIT_FAIL_STATUS); @@ -267,11 +267,12 @@ public class ErpStockOutServiceImpl implements ErpStockOutService { // if (!ErpAuditStatus.PROCESS.getStatus().equals(stockOut.getStatus())) { // throw exception(STOCK_OUT_AUDIT_FAIL_STATUS); // } + Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); Integer fromStatus = stockOut.getStatus(); if (!needAudit()) { int updateCount = stockOutMapper.updateByIdAndStatus(stockOut.getId(), fromStatus, - new ErpStockOutDO().setNeedAudit(false).setStatus(ErpAuditStatus.APPROVE.getStatus())); + new ErpStockOutDO().setNeedAudit(false).setStatus(ErpAuditStatus.APPROVE.getStatus()).setAuditUserId(loginUserId)); if (updateCount == 0) { throw exception(STOCK_OUT_AUDIT_FAIL_STATUS); } @@ -283,12 +284,11 @@ public class ErpStockOutServiceImpl implements ErpStockOutService { return; } - Long loginUserId = SecurityFrameworkUtils.getLoginUserId(); boolean adminCanSubmit = permissionApi.hasAnyRoles(loginUserId, RoleCodeEnum.SUPER_ADMIN.getCode()); - if (!Objects.equals(stockOut.getAuditUserId(), loginUserId) && !adminCanSubmit) { - throw exception(STOCK_OUT_AUDIT_FAIL_USER); - } +// if (!Objects.equals(stockOut.getAuditUserId(), loginUserId) && !adminCanSubmit) { +// throw exception(STOCK_OUT_AUDIT_FAIL_USER); +// } if (!ErpAuditStatus.APPROVE.getStatus().equals(auditReqVO.getStatus()) && !ErpAuditStatus.UN_APPROVE.getStatus().equals(auditReqVO.getStatus())) { @@ -296,7 +296,7 @@ public class ErpStockOutServiceImpl implements ErpStockOutService { } int updateCount = stockOutMapper.updateByIdAndStatus(stockOut.getId(), fromStatus, - new ErpStockOutDO().setNeedAudit(true).setStatus(auditReqVO.getStatus())); + new ErpStockOutDO().setNeedAudit(true).setStatus(auditReqVO.getStatus()).setAuditUserId(loginUserId)); if (updateCount == 0) { throw exception(STOCK_OUT_AUDIT_FAIL_STATUS); } @@ -322,9 +322,9 @@ public class ErpStockOutServiceImpl implements ErpStockOutService { if (ErpAuditStatus.APPROVE.getStatus().equals(stockOut.getStatus())) { throw exception(STOCK_OUT_DELETE_FAIL_APPROVE, stockOut.getNo()); } - if (ErpAuditStatus.PROCESS.getStatus().equals(stockOut.getStatus())) { - throw exception(STOCK_OUT_DELETE_FAIL_PROCESS, stockOut.getNo()); - } +// if (ErpAuditStatus.PROCESS.getStatus().equals(stockOut.getStatus())) { +// throw exception(STOCK_OUT_DELETE_FAIL_PROCESS, stockOut.getNo()); +// } }); stockOuts.forEach(stockOut -> { stockOutMapper.deleteById(stockOut.getId());