diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transfer/vo/MesWmTransferSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transfer/vo/MesWmTransferSaveReqVO.java index cf3d395..64025c1 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transfer/vo/MesWmTransferSaveReqVO.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/transfer/vo/MesWmTransferSaveReqVO.java @@ -5,6 +5,8 @@ import lombok.Data; import java.time.LocalDateTime; +import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED; + @Schema(description = "管理后台 - MES 转移单 Save Request VO") @Data public class MesWmTransferSaveReqVO { @@ -12,16 +14,17 @@ public class MesWmTransferSaveReqVO { @Schema(description = "编号", example = "1") private Long id; - @Schema(description = "转移单编号", example = "TR2026020001") + // TODO @AI:validator 参数校验需要添加 + @Schema(description = "转移单编号", requiredMode = REQUIRED, example = "TR2026020001") private String code; - @Schema(description = "转移单名称", example = "钢板转移单") + @Schema(description = "转移单名称", requiredMode = REQUIRED, example = "钢板转移单") private String name; - @Schema(description = "转移单类型", example = "1") + @Schema(description = "转移单类型", requiredMode = REQUIRED, example = "1") private Integer type; - @Schema(description = "是否配送", example = "true") + @Schema(description = "是否配送", requiredMode = REQUIRED, example = "true") private Boolean deliveryFlag; @Schema(description = "收货人", example = "张三") @@ -39,15 +42,9 @@ public class MesWmTransferSaveReqVO { @Schema(description = "运输单号", example = "SF123456789") private String shippingNumber; - @Schema(description = "是否已确认", example = "false") - private Boolean confirmFlag; - - @Schema(description = "转移日期") + @Schema(description = "转移日期", requiredMode = REQUIRED) private LocalDateTime transferDate; - @Schema(description = "单据状态", example = "0") - private Integer status; - @Schema(description = "备注", example = "备注信息") private String remark; diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/transfer/MesWmTransferDetailDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/transfer/MesWmTransferDetailDO.java index 61a679f..b8c3b44 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/transfer/MesWmTransferDetailDO.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/transfer/MesWmTransferDetailDO.java @@ -2,6 +2,9 @@ package cn.iocoder.yudao.module.mes.dal.dataobject.wm.transfer; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; @@ -57,17 +60,22 @@ public class MesWmTransferDetailDO extends BaseDO { */ private Long batchId; - // TODO @AI:需要 @ /** * 移入仓库编号 + * + * 关联 {@link MesWmWarehouseDO#getId()} */ private Long toWarehouseId; /** * 移入库区编号 + * + * 关联 {@link MesWmWarehouseLocationDO#getId()} */ private Long toLocationId; /** * 移入库位编号 + * + * 关联 {@link MesWmWarehouseAreaDO#getId()} */ private Long toAreaId; diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/transfer/MesWmTransferLineDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/transfer/MesWmTransferLineDO.java index 59fa528..5bf09a9 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/transfer/MesWmTransferLineDO.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/transfer/MesWmTransferLineDO.java @@ -2,6 +2,9 @@ package cn.iocoder.yudao.module.mes.dal.dataobject.wm.transfer; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; @@ -54,17 +57,22 @@ public class MesWmTransferLineDO extends BaseDO { */ private Long batchId; - // TODO @AI:需要 @ /** * 移出仓库编号 + * + * 关联 {@link MesWmWarehouseDO#getId()} */ private Long fromWarehouseId; /** * 移出库区编号 + * + * 关联 {@link MesWmWarehouseLocationDO#getId()} */ private Long fromLocationId; /** * 移出库位编号 + * + * 关联 {@link MesWmWarehouseAreaDO#getId()} */ private Long fromAreaId; diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java index 27baef2..d6c8d52 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java @@ -403,6 +403,8 @@ public interface ErrorCodeConstants { ErrorCode WM_TRANSFER_NOT_CONFIRMED = new ErrorCode(1_040_710_004, "只有待确认状态的转移单才可执行确认"); ErrorCode WM_TRANSFER_NOT_UNEXECUTE = new ErrorCode(1_040_710_005, "只有待执行状态的转移单才可完成"); ErrorCode WM_TRANSFER_ALREADY_FINISHED = new ErrorCode(1_040_710_006, "转移单已完成或已取消,无法继续操作"); + ErrorCode WM_TRANSFER_NO_LINE = new ErrorCode(1_040_710_007, "转移单至少需要一条行数据"); + ErrorCode WM_TRANSFER_DETAIL_QUANTITY_MISMATCH = new ErrorCode(1_040_710_008, "转移单行数量与明细数量不一致"); ErrorCode WM_TRANSFER_LINE_NOT_EXISTS = new ErrorCode(1_040_710_100, "转移单行不存在"); ErrorCode WM_TRANSFER_DETAIL_NOT_EXISTS = new ErrorCode(1_040_710_200, "调拨明细不存在"); diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmTransferStatusEnum.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmTransferStatusEnum.java index eb690fe..988ee73 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmTransferStatusEnum.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmTransferStatusEnum.java @@ -1,7 +1,9 @@ package cn.iocoder.yudao.module.mes.enums.wm; import cn.iocoder.yudao.framework.common.core.ArrayValuable; +import cn.iocoder.yudao.module.mes.controller.admin.wm.transfer.vo.MesWmTransferSaveReqVO; import cn.iocoder.yudao.module.mes.enums.MesOrderStatusConstants; +import cn.iocoder.yudao.module.mes.service.wm.transfer.MesWmTransferService; import lombok.AllArgsConstructor; import lombok.Getter; @@ -16,29 +18,40 @@ import java.util.Arrays; @AllArgsConstructor public enum MesWmTransferStatusEnum implements ArrayValuable { - // TODO @AI:/Users/yunai/Java/yudao-all-in-one/ruoyi-vue-pro/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmOutsourceReceiptStatusEnum.java,增加 “对应方法” /** * 草稿 + * + * 对应方法:{@link MesWmTransferService#createTransfer(MesWmTransferSaveReqVO)} */ PREPARE(MesOrderStatusConstants.PREPARE, "草稿"), /** * 待确认(仅配送模式) + * + * 对应方法:{@link MesWmTransferService#submitTransfer(Long)} */ UNCONFIRMED(MesOrderStatusConstants.CONFIRMED, "待确认"), /** * 待上架 + * + * 对应方法:{@link MesWmTransferService#submitTransfer(Long)}、{@link MesWmTransferService#confirmTransfer(Long)} */ UNSTOCK(MesOrderStatusConstants.APPROVING, "待上架"), /** * 待执行 + * + * 对应方法:调拨明细维护完成后进入待执行状态 */ UNEXECUTE(MesOrderStatusConstants.APPROVED, "待执行"), /** * 已完成 + * + * 对应方法:{@link MesWmTransferService#finishTransfer(Long)} */ FINISHED(MesOrderStatusConstants.FINISHED, "已完成"), /** * 已取消 + * + * 对应方法:{@link MesWmTransferService#cancelTransfer(Long)} */ CANCELED(MesOrderStatusConstants.CANCELLED, "已取消"); diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transfer/MesWmTransferServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transfer/MesWmTransferServiceImpl.java index 1708480..7b28184 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transfer/MesWmTransferServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/transfer/MesWmTransferServiceImpl.java @@ -1,17 +1,26 @@ package cn.iocoder.yudao.module.mes.service.wm.transfer; +import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockFreezeReqVO; import cn.iocoder.yudao.module.mes.controller.admin.wm.transfer.vo.MesWmTransferPageReqVO; import cn.iocoder.yudao.module.mes.controller.admin.wm.transfer.vo.MesWmTransferSaveReqVO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.transfer.MesWmTransferDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.transfer.MesWmTransferDetailDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.transfer.MesWmTransferLineDO; import cn.iocoder.yudao.module.mes.dal.mysql.wm.transfer.MesWmTransferMapper; import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransferStatusEnum; -import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransferTypeEnum; +import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; +import java.math.BigDecimal; +import java.util.List; + import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; @@ -25,11 +34,12 @@ public class MesWmTransferServiceImpl implements MesWmTransferService { @Resource private MesWmTransferMapper transferMapper; - // TODO @AI:MesWmTransferLineService、MesWmTransferDetailService 类不存在; @Resource private MesWmTransferLineService transferLineService; @Resource private MesWmTransferDetailService transferDetailService; + @Resource + private MesWmMaterialStockService materialStockService; @Override public Long createTransfer(MesWmTransferSaveReqVO createReqVO) { @@ -55,8 +65,8 @@ public class MesWmTransferServiceImpl implements MesWmTransferService { transferMapper.updateById(updateObj); } - // TODO @AI:少了事务; @Override + @Transactional(rollbackFor = Exception.class) public void deleteTransfer(Long id) { // 校验存在 + 草稿状态 validateTransferExistsAndDraft(id); @@ -79,23 +89,29 @@ public class MesWmTransferServiceImpl implements MesWmTransferService { } @Override + @Transactional(rollbackFor = Exception.class) public void submitTransfer(Long id) { // 校验存在 + 草稿状态 MesWmTransferDO transfer = validateTransferExistsAndDraft(id); + List lines = transferLineService.getTransferLineListByTransferId(id); + if (CollUtil.isEmpty(lines)) { + throw exception(WM_TRANSFER_NO_LINE); + } - // TODO @芋艿:这里的逻辑对齐不对;需要再次看看; - // 根据转移单类型设置状态 - // 内部调拨:草稿 -> 待上架 - // 外部调拨:草稿 -> 待确认 - if (MesWmTransferTypeEnum.INNER.getType().equals(transfer.getType())) { - transfer.setStatus(MesWmTransferStatusEnum.UNSTOCK.getStatus()); + // 先按是否配送决定是否进入待确认,并冻结来源库存 + // TODO @AI:!Boolean.TRUE.equals 改成 FALSE 平判断,减少取反。 + if (Boolean.TRUE.equals(transfer.getDeliveryFlag()) && !Boolean.TRUE.equals(transfer.getConfirmFlag())) { + transfer.setStatus(MesWmTransferStatusEnum.UNCONFIRMED.getStatus()).setConfirmFlag(false); + // TODO @AI:这个是不是应该 lineservice 里; + freezeTransferLineStocks(lines, true); } else { - transfer.setStatus(MesWmTransferStatusEnum.UNCONFIRMED.getStatus()); + transfer.setStatus(MesWmTransferStatusEnum.UNSTOCK.getStatus()); } transferMapper.updateById(transfer); } @Override + @Transactional(rollbackFor = Exception.class) public void confirmTransfer(Long id) { // 校验存在 + 待确认状态 MesWmTransferDO transfer = validateTransferExistsAndConfirm(id); @@ -107,9 +123,22 @@ public class MesWmTransferServiceImpl implements MesWmTransferService { } @Override + @Transactional(rollbackFor = Exception.class) public void finishTransfer(Long id) { // 校验存在 + 待执行状态 MesWmTransferDO transfer = validateTransferExistsAndUnexecute(id); + List lines = transferLineService.getTransferLineListByTransferId(id); + if (CollUtil.isEmpty(lines)) { + throw exception(WM_TRANSFER_NO_LINE); + } + + // 校验每行明细数量之和等于行数量 + validateTransferDetailQuantity(lines); + + // 配送模式下,执行完成后解除来源库存冻结 + if (Boolean.TRUE.equals(transfer.getDeliveryFlag())) { + freezeTransferLineStocks(lines, false); + } // TODO: 执行库存转移逻辑 @@ -119,9 +148,17 @@ public class MesWmTransferServiceImpl implements MesWmTransferService { } @Override + @Transactional(rollbackFor = Exception.class) public void cancelTransfer(Long id) { // 校验存在 + 非已完成/已取消状态 MesWmTransferDO transfer = validateTransferExistsAndNotFinished(id); + // TODO @AI:这个逻辑不需要,只是取消主的。 + if (Boolean.TRUE.equals(transfer.getDeliveryFlag()) + && (MesWmTransferStatusEnum.UNCONFIRMED.getStatus().equals(transfer.getStatus()) + || MesWmTransferStatusEnum.UNEXECUTE.getStatus().equals(transfer.getStatus()))) { + List lines = transferLineService.getTransferLineListByTransferId(id); + freezeTransferLineStocks(lines, false); + } // 更新状态 -> 已取消 transfer.setStatus(MesWmTransferStatusEnum.CANCELED.getStatus()); @@ -131,7 +168,6 @@ public class MesWmTransferServiceImpl implements MesWmTransferService { @Override public MesWmTransferDO validateTransferEditable(Long id) { MesWmTransferDO transfer = transferMapper.selectById(id); - // TODO @AI:错误码缺少;是不是少了 WM_ if (transfer == null) { throw exception(WM_TRANSFER_NOT_EXISTS); } @@ -203,4 +239,31 @@ public class MesWmTransferServiceImpl implements MesWmTransferService { return transfer; } + // TODO @AI:参考别的模块,不用独立方法,直接写在 UNEXECUTE 变更里里;。目前还少一个操作; UNEXECUTE(MesOrderStatusConstants.APPROVED, "待执行"), 你看看别的模块; + private void validateTransferDetailQuantity(List lines) { + for (MesWmTransferLineDO line : lines) { + List details = transferDetailService.getTransferDetailListByLineId(line.getId()); + BigDecimal totalDetailQty = CollectionUtils.getSumValue(details, + MesWmTransferDetailDO::getQuantity, BigDecimal::add, BigDecimal.ZERO); + if (line.getQuantity() != null && totalDetailQty.compareTo(line.getQuantity()) != 0) { + throw exception(WM_TRANSFER_DETAIL_QUANTITY_MISMATCH); + } + } + } + + private void freezeTransferLineStocks(List lines, boolean frozen) { + if (CollUtil.isEmpty(lines)) { + return; + } + for (MesWmTransferLineDO line : lines) { + if (line.getMaterialStockId() == null) { + continue; + } + MesWmMaterialStockFreezeReqVO freezeReqVO = new MesWmMaterialStockFreezeReqVO(); + freezeReqVO.setId(line.getMaterialStockId()); + freezeReqVO.setFrozen(frozen); + materialStockService.updateMaterialStockFrozen(freezeReqVO); + } + } + }