diff --git a/nflg-wms-admin/src/main/java/com/nflg/wms/admin/schedule/InventoryExpirationInspectionScheduledTask.java b/nflg-wms-admin/src/main/java/com/nflg/wms/admin/schedule/InventoryExpirationInspectionScheduledTask.java new file mode 100644 index 00000000..6f502eb6 --- /dev/null +++ b/nflg-wms-admin/src/main/java/com/nflg/wms/admin/schedule/InventoryExpirationInspectionScheduledTask.java @@ -0,0 +1,103 @@ +package com.nflg.wms.admin.schedule; + +import com.nflg.wms.admin.service.QmsService; +import com.nflg.wms.common.pojo.qo.InventoryDetectionApplyQO; +import com.nflg.wms.repository.entity.QmsQcMaterial; +import com.nflg.wms.repository.entity.WmsInventory; +import com.nflg.wms.repository.service.IQmsQcMaterialService; +import com.nflg.wms.repository.service.IWmsInventoryService; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 库存物料过期自动发起检测任务 + */ +@Slf4j +@Component +public class InventoryExpirationInspectionScheduledTask { + + @Resource + private IWmsInventoryService inventoryService; + + @Resource + private IQmsQcMaterialService qcMaterialService; + + @Resource + private QmsService qmsService; + + /** + * 每天凌晨1点检查库存物料是否过期 + */ + @Scheduled(cron = "0 0 1 * * ?") + public void applyExpiredInventoryInspection() { + LocalDateTime now = LocalDateTime.now(); + List inventories = inventoryService.lambdaQuery() + .gt(WmsInventory::getNum, BigDecimal.ZERO) + .isNotNull(WmsInventory::getCreateTime) + .eq(WmsInventory::getDetectionStatus, (short) 0) + .list(); + if (inventories.isEmpty()) { + log.info("库存物料过期检测任务执行完成:无待检查库存"); + return; + } + + Set materialNos = inventories.stream() + .map(WmsInventory::getMaterialNo) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + if (materialNos.isEmpty()) { + log.info("库存物料过期检测任务执行完成:待检查库存均无物料编号"); + return; + } + + Map materialMap = qcMaterialService.lambdaQuery() + .in(QmsQcMaterial::getMaterialNo, materialNos) + .orderByDesc(QmsQcMaterial::getId) + .list() + .stream() + .collect(Collectors.toMap(QmsQcMaterial::getMaterialNo, Function.identity(), (first, ignored) -> first)); + + int applied = 0; + int skipped = 0; + int failed = 0; + for (WmsInventory inventory : inventories) { + QmsQcMaterial material = materialMap.get(inventory.getMaterialNo()); + if (Objects.isNull(material) || Objects.isNull(material.getValidityPeriod())) { + skipped++; + continue; + } + + LocalDateTime expiredTime = inventory.getCreateTime().plusMonths(material.getValidityPeriod()); + if (!expiredTime.isBefore(now)) { + skipped++; + continue; + } + + InventoryDetectionApplyQO request = new InventoryDetectionApplyQO(); + request.setInventoryId(inventory.getId()); + request.setInspectionQty(inventory.getNum().intValue()); + request.setStorageDays(Math.max(1, (int) ChronoUnit.DAYS.between(inventory.getCreateTime(), now))); + try { + qmsService.pushInventoryInspection(request); + applied++; + } catch (Exception ex) { + failed++; + log.error("库存物料过期检测任务发起失败,库存ID:{}", inventory.getId(), ex); + } + } + log.info("库存物料过期检测任务执行完成:检查库存数={},发起检测数={},跳过数={},失败数={}", + inventories.size(), applied, skipped, failed); + } +} diff --git a/nflg-wms-admin/src/main/java/com/nflg/wms/admin/service/QmsService.java b/nflg-wms-admin/src/main/java/com/nflg/wms/admin/service/QmsService.java index 1272afcb..68f661b9 100644 --- a/nflg-wms-admin/src/main/java/com/nflg/wms/admin/service/QmsService.java +++ b/nflg-wms-admin/src/main/java/com/nflg/wms/admin/service/QmsService.java @@ -7,7 +7,9 @@ import com.nflg.wms.common.pojo.qo.ExternalInventoryInspectionApplyQO; import com.nflg.wms.common.pojo.qo.InventoryDetectionApplyQO; import com.nflg.wms.common.util.VUtil; import com.nflg.wms.repository.entity.WmsInventory; +import com.nflg.wms.repository.entity.WmsQrCodeMaster; import com.nflg.wms.repository.service.IWmsInventoryService; +import com.nflg.wms.repository.service.IWmsQrCodeMasterService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; @@ -20,6 +22,9 @@ import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Objects; @@ -27,12 +32,17 @@ import java.util.Objects; @Component public class QmsService { + private static final DateTimeFormatter INVENTORY_INSPECTION_REQUEST_NO_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMddHH"); + @Resource private RestTemplate restTemplate; @Resource private IWmsInventoryService inventoryService; + @Resource + private IWmsQrCodeMasterService qrCodeMasterService; + @Value("${qms.inspection.url:}") private String qmsUrl; @@ -58,9 +68,36 @@ public class QmsService { } public void pushInventoryInspection(InventoryDetectionApplyQO request) { - ExternalInventoryInspectionApplyQO apply = request.getApply(); - log.info("推送库存检测申请到QMS:申请参数={},二维码={}", - JSONUtil.toJsonStr(apply), JSONUtil.toJsonStr(request.getQrCodes())); + WmsInventory inventory = inventoryService.getById(request.getInventoryId()); + VUtil.trueThrowBusinessError(Objects.isNull(inventory)).throwMessage("未找到对应库存"); + VUtil.trueThrowBusinessError(Objects.equals(inventory.getDetectionStatus(), (short) 1)) + .throwMessage("该库存正在检测中,不能重复发起检测任务"); + VUtil.trueThrowBusinessError( + Objects.isNull(inventory.getNum()) + || BigDecimal.valueOf(request.getInspectionQty()).compareTo(inventory.getNum()) > 0 + ).throwMessage("检验数量不能大于库存数量"); + + ExternalInventoryInspectionApplyQO apply = new ExternalInventoryInspectionApplyQO(); + apply.setRequestNo(generateInventoryInspectionRequestNo(request.getInventoryId())); + apply.setMaterialNo(inventory.getMaterialNo()); + apply.setFactory(inventory.getFactoryNo()); + apply.setInspectionQty(request.getInspectionQty()); + apply.setWarehouse(inventory.getWarehouseNo()); + apply.setStorageLocation(inventory.getBinLocation()); + apply.setStorageDays(request.getStorageDays()); + + List qrCodes = qrCodeMasterService.lambdaQuery() + .select(WmsQrCodeMaster::getBarcodeCode) + .eq(WmsQrCodeMaster::getMaterialCode, apply.getMaterialNo()) + .eq(WmsQrCodeMaster::getFactoryCode, apply.getFactory()) + .eq(WmsQrCodeMaster::getStorageLocation, apply.getWarehouse()) + .eq(WmsQrCodeMaster::getBinLocation, apply.getStorageLocation()) + .list() + .stream() + .map(WmsQrCodeMaster::getBarcodeCode) + .toList(); + log.info("推送库存检测申请到QMS:申请参数={},关联二维码={}", + JSONUtil.toJsonStr(apply), JSONUtil.toJsonStr(qrCodes)); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); @@ -82,11 +119,12 @@ public class QmsService { boolean inventoryUpdated = inventoryService.lambdaUpdate() .set(WmsInventory::getDetectionStatus, (short) 1) .set(WmsInventory::getDetectionResults, null) - .eq(WmsInventory::getMaterialNo, apply.getMaterialNo()) - .eq(WmsInventory::getFactoryNo, apply.getFactory()) - .eq(WmsInventory::getWarehouseNo, apply.getWarehouse()) - .eq(WmsInventory::getBinLocation, apply.getStorageLocation()) + .eq(WmsInventory::getId, request.getInventoryId()) .update(); VUtil.trueThrowBusinessError(!inventoryUpdated).throwMessage("未找到对应库存,无法更新检测状态"); } + + private String generateInventoryInspectionRequestNo(Long inventoryId) { + return LocalDateTime.now().format(INVENTORY_INSPECTION_REQUEST_NO_FORMATTER) + inventoryId; + } } diff --git a/nflg-wms-common/src/main/java/com/nflg/wms/common/pojo/qo/InventoryDetectionApplyQO.java b/nflg-wms-common/src/main/java/com/nflg/wms/common/pojo/qo/InventoryDetectionApplyQO.java index 05d47cf9..dbda070a 100644 --- a/nflg-wms-common/src/main/java/com/nflg/wms/common/pojo/qo/InventoryDetectionApplyQO.java +++ b/nflg-wms-common/src/main/java/com/nflg/wms/common/pojo/qo/InventoryDetectionApplyQO.java @@ -1,11 +1,9 @@ package com.nflg.wms.common.pojo.qo; -import jakarta.validation.Valid; +import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotNull; import lombok.Data; -import java.util.List; - /** * WMS发起库存检测申请 */ @@ -13,14 +11,22 @@ import java.util.List; public class InventoryDetectionApplyQO { /** - * 库存检测申请参数 + * 库存ID */ - @Valid - @NotNull(message = "库存检测申请参数不能为空") - private ExternalInventoryInspectionApplyQO apply; + @NotNull(message = "库存ID不能为空") + private Long inventoryId; /** - * 物料二维码列表,允许为空;后续落库使用,本次仅预留 + * 检验数量 */ - private List qrCodes; + @NotNull(message = "检验数量不能为空") + @Min(value = 1, message = "检验数量必须大于0") + private Integer inspectionQty; + + /** + * 存储时长(单位:天) + */ + @NotNull(message = "存储时长不能为空") + @Min(value = 1, message = "存储时长必须大于0") + private Integer storageDays; }