diff --git a/nflg-wms-admin/src/main/java/com/nflg/wms/admin/controller/OutAssistanceController.java b/nflg-wms-admin/src/main/java/com/nflg/wms/admin/controller/OutAssistanceController.java index 4533efd0..0b5f027e 100644 --- a/nflg-wms-admin/src/main/java/com/nflg/wms/admin/controller/OutAssistanceController.java +++ b/nflg-wms-admin/src/main/java/com/nflg/wms/admin/controller/OutAssistanceController.java @@ -15,6 +15,8 @@ import com.nflg.wms.admin.util.PdfGeneratorUtil; import com.nflg.wms.admin.util.QRCodeUtil; import com.nflg.wms.admin.util.ThymeleafUtil; import com.nflg.wms.common.constant.BarCodeProcessStage; +import com.nflg.wms.common.constant.STATE; +import com.nflg.wms.common.exception.NflgException; import com.nflg.wms.common.pojo.ApiResult; import com.nflg.wms.common.pojo.PageData; import com.nflg.wms.common.pojo.document.OutMaterialScanRecord; @@ -32,6 +34,8 @@ import jakarta.validation.Valid; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.extern.slf4j.Slf4j; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; @@ -39,6 +43,7 @@ import java.math.BigDecimal; import java.time.Instant; import java.time.LocalDateTime; import java.util.*; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; /** @@ -76,15 +81,15 @@ public class OutAssistanceController extends BaseController { @Resource private InventoryForOutRepository inventoryForOutRepository; - @Resource - private IParamConfigService paramConfigService; - @Resource private IWmsBomService bomService; @Resource private IWmsQrCodeMasterService qrCodeMasterService; + @Resource + private RedissonClient redissonClient; + /** * 查询SAP领料订单数据 */ @@ -328,6 +333,34 @@ public class OutAssistanceController extends BaseController { }); } }); + List lockVOS = new ArrayList<>(); + records.stream() + .collect(Collectors.groupingBy(OutMaterialScanRecord::getKey10)) + .forEach((key, vs) -> { + OutMaterialScanRecord info = vs.get(0); + BigDecimal lockNum = vs.stream().map(OutMaterialScanRecord::getNum).reduce(BigDecimal.ZERO, BigDecimal::add); + RLock lock = redissonClient.getLock(StrUtil.format("lock:inventory:{}:{}:{}", info.getFactoryNo(), info.getWarehouseNo(), info.getMaterialNo())); + try { + // 等待5秒获取锁,10秒后自动释放 + if (lock.tryLock(5, 10, TimeUnit.SECONDS)) { + if (inventoryService.getNumOne(info.getFactoryNo(), info.getWarehouseNo(), info.getMaterialNo()).compareTo(lockNum) < 0) { + lockVOS.addAll(inventoryService.getLockList(info.getFactoryNo(), info.getWarehouseNo(), info.getMaterialNo())); + } + } else { + throw new NflgException(STATE.BusinessError, "获取锁失败"); + } + } catch (Exception e) { + log.error("保存生产领料单出错", e); + throw new NflgException(STATE.BusinessError, e.getMessage()); + } finally { + if (lock.isHeldByCurrentThread()) { + lock.unlock(); + } + } + }); + if (CollectionUtil.isNotEmpty(lockVOS)) { + return ApiResult.errorWithExtras(STATE.OutOfStock, lockVOS); + } outAssistanceItemService.updateBatchById(datas); outAssistanceTicketItemService.saveBatch(ticketItems); outAssistanceTicketService.save(ticket); @@ -468,38 +501,37 @@ public class OutAssistanceController extends BaseController { .in(WmsQrCodeMaster::getBarcodeCode, records.stream().map(OutMaterialScanRecord::getUniqNo).toList()) .list(); qrCodeMasters.forEach(p -> { - OutMaterialScanRecord record = records.stream() - .filter(r -> r.getUniqNo().equals(p.getBarcodeCode())) - .findFirst() - .get(); - p.setFactoryCode(record.getFactoryNo()); - p.setStorageLocation(record.getWarehouseNo()); - p.setBinLocation(record.getBinNo()); - p.setProcessStage(BarCodeProcessStage.OutBound.getState()); - p.setLastScanBy(UserUtil.getUserId()); - p.setLastScanByname(UserUtil.getUserName()); - p.setLastScanTime(LocalDateTime.now()); - if (p.getPackagingType() == 1) { - List children = qrCodeMasterService.lambdaQuery() - .eq(WmsQrCodeMaster::getParentBarcodeId, p.getId()) - .list(); - if (CollectionUtil.isNotEmpty(children)) { - children.forEach(c -> { - c.setProcessStage(p.getProcessStage()); - c.setFactoryCode(p.getFactoryCode()); - c.setStorageLocation(p.getStorageLocation()); - c.setBinLocation(p.getBinLocation()); - c.setProcessStage(p.getProcessStage()); - c.setLastScanBy(p.getLastScanBy()); - c.setLastScanByname(p.getLastScanByname()); - c.setLastScanTime(p.getLastScanTime()); - }); - } - } - }); + OutMaterialScanRecord record = records.stream() + .filter(r -> r.getUniqNo().equals(p.getBarcodeCode())) + .findFirst() + .get(); + p.setFactoryCode(record.getFactoryNo()); + p.setStorageLocation(record.getWarehouseNo()); + p.setBinLocation(record.getBinNo()); + p.setProcessStage(BarCodeProcessStage.OutBound.getState()); + p.setLastScanBy(UserUtil.getUserId()); + p.setLastScanByname(UserUtil.getUserName()); + p.setLastScanTime(LocalDateTime.now()); + if (p.getPackagingType() == 1) { + List children = qrCodeMasterService.lambdaQuery() + .eq(WmsQrCodeMaster::getParentBarcodeId, p.getId()) + .list(); + if (CollectionUtil.isNotEmpty(children)) { + children.forEach(c -> { + c.setProcessStage(p.getProcessStage()); + c.setFactoryCode(p.getFactoryCode()); + c.setStorageLocation(p.getStorageLocation()); + c.setBinLocation(p.getBinLocation()); + c.setProcessStage(p.getProcessStage()); + c.setLastScanBy(p.getLastScanBy()); + c.setLastScanByname(p.getLastScanByname()); + c.setLastScanTime(p.getLastScanTime()); + }); + } + } + }); qrCodeMasterService.updateBarCode(qrCodeMasters); - submitSap(order, ticket, records, outAssistanceItemService.getList(order.getId()), qrCodeMasters - ); + submitSap(order, ticket, records, outAssistanceItemService.getList(order.getId()), qrCodeMasters); } else { List items = outAssistanceTicketItemService.getList(qo.getId()); items.forEach(it -> { diff --git a/nflg-wms-admin/src/main/java/com/nflg/wms/admin/controller/OutCostCenterController.java b/nflg-wms-admin/src/main/java/com/nflg/wms/admin/controller/OutCostCenterController.java index b2b0106e..9de4ca0d 100644 --- a/nflg-wms-admin/src/main/java/com/nflg/wms/admin/controller/OutCostCenterController.java +++ b/nflg-wms-admin/src/main/java/com/nflg/wms/admin/controller/OutCostCenterController.java @@ -15,6 +15,8 @@ import com.nflg.wms.admin.util.PdfGeneratorUtil; import com.nflg.wms.admin.util.QRCodeUtil; import com.nflg.wms.admin.util.ThymeleafUtil; import com.nflg.wms.common.constant.BarCodeProcessStage; +import com.nflg.wms.common.constant.STATE; +import com.nflg.wms.common.exception.NflgException; import com.nflg.wms.common.pojo.ApiResult; import com.nflg.wms.common.pojo.PageData; import com.nflg.wms.common.pojo.document.OutMaterialScanRecord; @@ -32,6 +34,8 @@ import jakarta.validation.Valid; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.extern.slf4j.Slf4j; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; @@ -39,6 +43,7 @@ import java.math.BigDecimal; import java.time.Instant; import java.time.LocalDateTime; import java.util.*; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; /** @@ -85,6 +90,9 @@ public class OutCostCenterController extends BaseController { @Resource private IWmsQrCodeMasterService qrCodeMasterService; + @Resource + private RedissonClient redissonClient; + /** * 查询SAP领料订单数据 */ @@ -319,6 +327,34 @@ public class OutCostCenterController extends BaseController { }); } }); + List lockVOS = new ArrayList<>(); + records.stream() + .collect(Collectors.groupingBy(OutMaterialScanRecord::getKey10)) + .forEach((key, vs) -> { + OutMaterialScanRecord info = vs.get(0); + BigDecimal lockNum = vs.stream().map(OutMaterialScanRecord::getNum).reduce(BigDecimal.ZERO, BigDecimal::add); + RLock lock = redissonClient.getLock(StrUtil.format("lock:inventory:{}:{}:{}", info.getFactoryNo(), info.getWarehouseNo(), info.getMaterialNo())); + try { + // 等待5秒获取锁,10秒后自动释放 + if (lock.tryLock(5, 10, TimeUnit.SECONDS)) { + if (inventoryService.getNumOne(info.getFactoryNo(), info.getWarehouseNo(), info.getMaterialNo()).compareTo(lockNum) < 0) { + lockVOS.addAll(inventoryService.getLockList(info.getFactoryNo(), info.getWarehouseNo(), info.getMaterialNo())); + } + } else { + throw new NflgException(STATE.BusinessError, "获取锁失败"); + } + } catch (Exception e) { + log.error("保存生产领料单出错", e); + throw new NflgException(STATE.BusinessError, e.getMessage()); + } finally { + if (lock.isHeldByCurrentThread()) { + lock.unlock(); + } + } + }); + if (CollectionUtil.isNotEmpty(lockVOS)) { + return ApiResult.errorWithExtras(STATE.OutOfStock, lockVOS); + } outCostcenterItemService.updateBatchById(datas); outCostcenterTicketItemService.saveBatch(ticketItems); outCostcenterTicketService.save(ticket); diff --git a/nflg-wms-admin/src/main/java/com/nflg/wms/admin/controller/OutProduceController.java b/nflg-wms-admin/src/main/java/com/nflg/wms/admin/controller/OutProduceController.java index 74b8b391..b0c277f0 100644 --- a/nflg-wms-admin/src/main/java/com/nflg/wms/admin/controller/OutProduceController.java +++ b/nflg-wms-admin/src/main/java/com/nflg/wms/admin/controller/OutProduceController.java @@ -143,6 +143,7 @@ public class OutProduceController extends BaseController { VUtil.trueThrowBusinessError(CollectionUtil.isNotEmpty(materialNos)) .throwMessage("以下物料的申请数量超出限制:" + StrUtil.join(",", materialNos)); Map> maps = datas.stream().collect(Collectors.groupingBy(Zwm3a07VO::getKey2)); + List lockVOS = new ArrayList<>(); maps.forEach((key, items) -> { WmsOutProduce order = Convert.convert(WmsOutProduce.class, items.get(0)); order.setNo(serialNumberControllerService.generateSerialNumber(9)); @@ -155,10 +156,16 @@ public class OutProduceController extends BaseController { try { // 等待5秒获取锁,10秒后自动释放 if (lock.tryLock(5, 10, TimeUnit.SECONDS)) { - WmsOutProduceItem data = Convert.convert(WmsOutProduceItem.class, item); - data.setLockNum(item.getSqsl()); - data.setOrderId(order.getId()); - outProduceItemService.save(data); + if (inventoryService.getNumOne(item.getDwerk(), item.getLgort2(), item.getMatnr()) + .compareTo(item.getSqsl()) < 0 + ) { + lockVOS.addAll(inventoryService.getLockList(item.getDwerk(), item.getLgort2(), item.getMatnr())); + } else { + WmsOutProduceItem data = Convert.convert(WmsOutProduceItem.class, item); + data.setLockNum(item.getSqsl()); + data.setOrderId(order.getId()); + outProduceItemService.save(data); + } } else { throw new NflgException(STATE.BusinessError, "获取锁失败"); } @@ -166,14 +173,17 @@ public class OutProduceController extends BaseController { log.error("保存生产领料单出错", e); throw new NflgException(STATE.BusinessError, e.getMessage()); } finally { - // 确保只释放自己持有的锁 if (lock.isHeldByCurrentThread()) { lock.unlock(); } } }); }); - return ApiResult.success(); + if (CollectionUtil.isEmpty(lockVOS)) { + return ApiResult.success(); + } else { + return ApiResult.errorWithExtras(STATE.OutOfStock, lockVOS); + } } /** @@ -192,6 +202,7 @@ public class OutProduceController extends BaseController { // VUtil.trueThrowBusinessError(CollectionUtil.isNotEmpty(materialNos)) // .throwMessage("以下物料的申请数量超出限制:" + StrUtil.join(",", materialNos)); Map> maps = datas.stream().collect(Collectors.groupingBy(Zwm3a07VO::getKey2)); + List lockVOS = new ArrayList<>(); maps.forEach((key, items) -> { WmsOutProduce order = Convert.convert(WmsOutProduce.class, items.get(0)); order.setNo(serialNumberControllerService.generateSerialNumber(9)); @@ -200,13 +211,39 @@ public class OutProduceController extends BaseController { order.setCreateTime(LocalDateTime.now()); outProduceService.save(order); items.forEach(item -> { - WmsOutProduceItem data = Convert.convert(WmsOutProduceItem.class, item); - data.setLockNum(BigDecimal.ZERO); - data.setOrderId(order.getId()); - outProduceItemService.save(data); + RLock lock = redissonClient.getLock(StrUtil.format("lock:inventory:{}:{}:{}", item.getDwerk(), item.getLgort2(), item.getMatnr())); + try { + // 等待5秒获取锁,10秒后自动释放 + if (lock.tryLock(5, 10, TimeUnit.SECONDS)) { + if (inventoryService.getNumOne(item.getDwerk(), item.getLgort2(), item.getMatnr()) + .compareTo(item.getSqsl()) < 0 + ) { + lockVOS.addAll(inventoryService.getLockList(item.getDwerk(), item.getLgort2(), item.getMatnr())); + } else { + WmsOutProduceItem data = Convert.convert(WmsOutProduceItem.class, item); + data.setLockNum(data.getSqsl()); + data.setOrderId(order.getId()); + outProduceItemService.save(data); + } + } else { + throw new NflgException(STATE.BusinessError, "获取锁失败"); + } + } catch (Exception e) { + log.error("保存生产领料单出错", e); + throw new NflgException(STATE.BusinessError, e.getMessage()); + } finally { + // 确保只释放自己持有的锁 + if (lock.isHeldByCurrentThread()) { + lock.unlock(); + } + } }); }); - return ApiResult.success(); + if (CollectionUtil.isEmpty(lockVOS)) { + return ApiResult.success(); + } else { + return ApiResult.errorWithExtras(STATE.OutOfStock, lockVOS); + } } /** diff --git a/nflg-wms-admin/src/main/java/com/nflg/wms/admin/controller/PurchaseReturnController.java b/nflg-wms-admin/src/main/java/com/nflg/wms/admin/controller/PurchaseReturnController.java index 1e876b39..5a915a8c 100644 --- a/nflg-wms-admin/src/main/java/com/nflg/wms/admin/controller/PurchaseReturnController.java +++ b/nflg-wms-admin/src/main/java/com/nflg/wms/admin/controller/PurchaseReturnController.java @@ -14,6 +14,7 @@ import com.nflg.wms.admin.util.PdfGeneratorUtil; import com.nflg.wms.admin.util.QRCodeUtil; import com.nflg.wms.admin.util.ThymeleafUtil; import com.nflg.wms.common.constant.BarCodeProcessStage; +import com.nflg.wms.common.constant.STATE; import com.nflg.wms.common.constant.UserType; import com.nflg.wms.common.pojo.ApiResult; import com.nflg.wms.common.pojo.PageData; @@ -127,8 +128,12 @@ public class PurchaseReturnController extends BaseController { VUtil.trueThrowBusinessError(CollectionUtil.isEmpty(request)) .throwMessage("申请数据不可以为空"); List purchaseReturnDTOList = Convert.toList(PurchaseReturnDTO.class, request); - SaveApply(purchaseReturnDTOList, Short.valueOf("0")); - return ApiResult.success(); + List inventoryLockVOS = SaveApply(purchaseReturnDTOList, Short.valueOf("0")); + if (CollectionUtil.isEmpty(inventoryLockVOS)) { + return ApiResult.success(); + } else { + return ApiResult.errorWithExtras(STATE.OutOfStock, inventoryLockVOS); + } } /** @@ -171,7 +176,7 @@ public class PurchaseReturnController extends BaseController { .throwMessage("无效申请单"); User user = userService.getById(UserUtil.getUserId()); VUtil.trueThrowBusinessError(StrUtil.equals(user.getPurchasingGroup(), returnRequest.getPurchaseGroup())) - .throwMessage("无权限审核此单"); + .throwMessage("无权限审核此单"); // VUtil.trueThrowBusinessError(returnRequest.getApprovalStatus() == 1) // .throwMessage("此单已审核通过,不可以再此审核"); @@ -285,7 +290,7 @@ public class PurchaseReturnController extends BaseController { * 保存申请单 * @return */ - private void SaveApply(List purchaseReturnDTOList, Short dataSource) { + private List SaveApply(List purchaseReturnDTOList, Short dataSource) { //根据采购组编号、采购单编号、供应商id进行去除 List disGroupCode = purchaseReturnDTOList.stream() .map(PurchaseReturnDTO::getGroupCode) @@ -334,7 +339,7 @@ public class PurchaseReturnController extends BaseController { returnRequestItems.add(returnRequestItem); } } - returnRequestService.addPurchaseReturns(returnRequests, returnRequestItems); + return returnRequestService.addPurchaseReturns(returnRequests, returnRequestItems); } /** @@ -372,6 +377,7 @@ public class PurchaseReturnController extends BaseController { for (WmsQrCodeMaster qrCodeMaster : qrCodeMasters) { qrCodeVOS.add(BarcodeValidation(qrCodeMaster)); } + List inventoryLockVOS = null; if (CollectionUtil.isNotEmpty(qrCodeVOS)) { List purchaseReturnDTOList = new ArrayList<>(); for (QrCodeVO qrCodeVO : qrCodeVOS) { @@ -430,10 +436,14 @@ public class PurchaseReturnController extends BaseController { ); purchaseReturnDTO.setGroupCode(groupCode); } - SaveApply(purchaseReturnDTOList, Short.valueOf("1")); + inventoryLockVOS = SaveApply(purchaseReturnDTOList, Short.valueOf("1")); } } - return ApiResult.success(); + if (CollectionUtil.isEmpty(inventoryLockVOS)) { + return ApiResult.success(); + } else { + return ApiResult.errorWithExtras(STATE.OutOfStock, inventoryLockVOS); + } } @@ -463,8 +473,8 @@ public class PurchaseReturnController extends BaseController { public void exportTicket(HttpServletResponse response, @Valid @RequestParam @NotNull Long id) throws Exception { WmsReturnRequest order = returnRequestService.getById(id); VUtil.trueThrowBusinessError(Objects.isNull(order)).throwMessage("申请单不存在"); - VUtil.trueThrowBusinessError(order.getApprovalStatus()!=1).throwMessage("申请单未审核通过"); - UserSupplier supplier=userSupplierService.getByCode(order.getSupplierCode()); + VUtil.trueThrowBusinessError(order.getApprovalStatus() != 1).throwMessage("申请单未审核通过"); + UserSupplier supplier = userSupplierService.getByCode(order.getSupplierCode()); List list = returnRequestItemService.lambdaQuery() .eq(WmsReturnRequestItem::getApplicationId, id) .list(); diff --git a/nflg-wms-admin/src/main/java/com/nflg/wms/admin/controller/TransferCompanyController.java b/nflg-wms-admin/src/main/java/com/nflg/wms/admin/controller/TransferCompanyController.java index 2c750fa6..1b491545 100644 --- a/nflg-wms-admin/src/main/java/com/nflg/wms/admin/controller/TransferCompanyController.java +++ b/nflg-wms-admin/src/main/java/com/nflg/wms/admin/controller/TransferCompanyController.java @@ -17,6 +17,8 @@ import com.nflg.wms.admin.service.BasdeSerialNumberControllerService; import com.nflg.wms.admin.service.SapService; import com.nflg.wms.admin.util.*; import com.nflg.wms.common.constant.BarCodeProcessStage; +import com.nflg.wms.common.constant.STATE; +import com.nflg.wms.common.exception.NflgException; import com.nflg.wms.common.pojo.ApiResult; import com.nflg.wms.common.pojo.PageData; import com.nflg.wms.common.pojo.document.InMaterialScanRecord; @@ -37,6 +39,8 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.extern.slf4j.Slf4j; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; @@ -44,6 +48,7 @@ import java.math.BigDecimal; import java.time.Instant; import java.time.LocalDateTime; import java.util.*; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; /** @@ -87,9 +92,6 @@ public class TransferCompanyController extends BaseController { @Resource private InventoryForOutRepository inventoryForOutRepository; - @Resource - private IParamConfigService paramConfigService; - @Resource private IWmsWarehouseService warehouseService; @@ -99,6 +101,9 @@ public class TransferCompanyController extends BaseController { @Resource private IWmsQrCodeMasterService qrCodeMasterService; + @Resource + private RedissonClient redissonClient; + /** * 查询SAP订单数据 */ @@ -124,6 +129,7 @@ public class TransferCompanyController extends BaseController { VUtil.trueThrowBusinessError(CollectionUtil.isNotEmpty(materialNos)) .throwMessage("以下物料的申请数量超出限制:" + StrUtil.join(",", materialNos)); Map> maps = datas.stream().collect(Collectors.groupingBy(AllocationOrderDTO::getGroup1)); + List lockVOS = new ArrayList<>(); maps.forEach((key, items) -> { WmsTransferCompany order = Convert.convert(WmsTransferCompany.class, items.get(0)); order.setNo(serialNumberControllerService.generateSerialNumber(22)); @@ -131,16 +137,38 @@ public class TransferCompanyController extends BaseController { order.setCreateTime(LocalDateTime.now()); transferCompanyService.save(order); items.forEach(item -> { - BigDecimal max = inventoryService.getNumOne(item.getReswk(), item.getLgfsb1(), item.getMatnr()); - VUtil.trueThrowBusinessError(item.getNum().compareTo(max) > 0) - .throwMessage("物料" + item.getMatnr() + "的申请数量超出库存限制"); - WmsTransferCompanyItem data = Convert.convert(WmsTransferCompanyItem.class, item); - data.setOrderId(order.getId()); - data.setLeft(data.getNum()); - transferCompanyItemService.save(data); + RLock lock = redissonClient.getLock(StrUtil.format("lock:inventory:{}:{}:{}", item.getReswk(), item.getLgfsb1(), item.getMatnr())); + try { + // 等待5秒获取锁,10秒后自动释放 + if (lock.tryLock(5, 10, TimeUnit.SECONDS)) { + if (inventoryService.getNumOne(item.getReswk(), item.getLgfsb1(), item.getMatnr()) + .compareTo(item.getNum()) < 0 + ) { + lockVOS.addAll(inventoryService.getLockList(item.getReswk(), item.getLgfsb1(), item.getMatnr())); + } else { + WmsTransferCompanyItem data = Convert.convert(WmsTransferCompanyItem.class, item); + data.setOrderId(order.getId()); + data.setLeft(data.getNum()); + transferCompanyItemService.save(data); + } + } else { + throw new NflgException(STATE.BusinessError, "获取锁失败"); + } + } catch (Exception e) { + log.error("保存生产领料单出错", e); + throw new NflgException(STATE.BusinessError, e.getMessage()); + } finally { + if (lock.isHeldByCurrentThread()) { + lock.unlock(); + } + } }); }); - return ApiResult.success(); + if (CollectionUtil.isEmpty(lockVOS)) { + return ApiResult.success(); + } else { + return ApiResult.errorWithExtras(STATE.OutOfStock, lockVOS); + } } /** diff --git a/nflg-wms-admin/src/main/java/com/nflg/wms/admin/controller/TransferFactoryController.java b/nflg-wms-admin/src/main/java/com/nflg/wms/admin/controller/TransferFactoryController.java index 28aa07c8..8923a3d7 100644 --- a/nflg-wms-admin/src/main/java/com/nflg/wms/admin/controller/TransferFactoryController.java +++ b/nflg-wms-admin/src/main/java/com/nflg/wms/admin/controller/TransferFactoryController.java @@ -15,6 +15,8 @@ import com.nflg.wms.admin.util.PdfGeneratorUtil; import com.nflg.wms.admin.util.QRCodeUtil; import com.nflg.wms.admin.util.ThymeleafUtil; import com.nflg.wms.common.constant.BarCodeProcessStage; +import com.nflg.wms.common.constant.STATE; +import com.nflg.wms.common.exception.NflgException; import com.nflg.wms.common.pojo.ApiResult; import com.nflg.wms.common.pojo.PageData; import com.nflg.wms.common.pojo.document.InMaterialScanRecord; @@ -35,6 +37,8 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.extern.slf4j.Slf4j; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; @@ -42,6 +46,7 @@ import java.math.BigDecimal; import java.time.Instant; import java.time.LocalDateTime; import java.util.*; +import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; /** @@ -85,9 +90,6 @@ public class TransferFactoryController extends BaseController { @Resource private InventoryForOutRepository inventoryForOutRepository; - @Resource - private IParamConfigService paramConfigService; - @Resource private IWmsBomService bomService; @@ -97,6 +99,9 @@ public class TransferFactoryController extends BaseController { @Resource private IWmsQrCodeMasterService qrCodeMasterService; + @Resource + private RedissonClient redissonClient; + /** * 查询SAP领料订单数据 */ @@ -122,6 +127,7 @@ public class TransferFactoryController extends BaseController { VUtil.trueThrowBusinessError(CollectionUtil.isNotEmpty(materialNos)) .throwMessage("以下物料的申请数量超出限制:" + StrUtil.join(",", materialNos)); Map> maps = datas.stream().collect(Collectors.groupingBy(TransferOrderDTO::getGroup1)); + List lockVOS = new ArrayList<>(); maps.forEach((key, items) -> { WmsTransferFactory order = Convert.convert(WmsTransferFactory.class, items.get(0)); order.setNo(serialNumberControllerService.generateSerialNumber(18)); @@ -129,16 +135,38 @@ public class TransferFactoryController extends BaseController { order.setCreateTime(LocalDateTime.now()); transferFactoryService.save(order); items.forEach(item -> { - BigDecimal max = inventoryService.getNumOne(item.getWerks(), item.getLgort(), item.getMatnr()); - VUtil.trueThrowBusinessError(item.getNum().compareTo(max) > 0) - .throwMessage("物料" + item.getMatnr() + "的申请数量超出库存限制"); - WmsTransferFactoryItem data = Convert.convert(WmsTransferFactoryItem.class, item); - data.setOrderId(order.getId()); - data.setLeft(data.getNum()); - transferFactoryItemService.save(data); + RLock lock = redissonClient.getLock(StrUtil.format("lock:inventory:{}:{}:{}", item.getWerks(), item.getLgort(), item.getMatnr())); + try { + // 等待5秒获取锁,10秒后自动释放 + if (lock.tryLock(5, 10, TimeUnit.SECONDS)) { + if (inventoryService.getNumOne(item.getWerks(), item.getLgort(), item.getMatnr()) + .compareTo(item.getNum()) < 0 + ) { + lockVOS.addAll(inventoryService.getLockList(item.getWerks(), item.getLgort(), item.getMatnr())); + } else { + WmsTransferFactoryItem data = Convert.convert(WmsTransferFactoryItem.class, item); + data.setOrderId(order.getId()); + data.setLeft(data.getNum()); + transferFactoryItemService.save(data); + } + } else { + throw new NflgException(STATE.BusinessError, "获取锁失败"); + } + } catch (Exception e) { + log.error("保存生产领料单出错", e); + throw new NflgException(STATE.BusinessError, e.getMessage()); + } finally { + if (lock.isHeldByCurrentThread()) { + lock.unlock(); + } + } }); }); - return ApiResult.success(); + if (CollectionUtil.isEmpty(lockVOS)) { + return ApiResult.success(); + } else { + return ApiResult.errorWithExtras(STATE.OutOfStock, lockVOS); + } } /** diff --git a/nflg-wms-common/src/main/java/com/nflg/wms/common/constant/STATE.java b/nflg-wms-common/src/main/java/com/nflg/wms/common/constant/STATE.java index 64e6068e..4d5f6a28 100644 --- a/nflg-wms-common/src/main/java/com/nflg/wms/common/constant/STATE.java +++ b/nflg-wms-common/src/main/java/com/nflg/wms/common/constant/STATE.java @@ -26,7 +26,8 @@ public enum STATE { RequestMethodError(116, "请求方式错误"), InconsistentDataError(117, "需要用户确认"), NoOrderData(118, "订单不存在"), - SAPErr(119, "SAP错误"); + SAPErr(119, "SAP错误"), + OutOfStock(120, "库存不足"); @Getter private final Integer state; diff --git a/nflg-wms-common/src/main/java/com/nflg/wms/common/pojo/ApiResult.java b/nflg-wms-common/src/main/java/com/nflg/wms/common/pojo/ApiResult.java index 6173c8dd..b36564cb 100644 --- a/nflg-wms-common/src/main/java/com/nflg/wms/common/pojo/ApiResult.java +++ b/nflg-wms-common/src/main/java/com/nflg/wms/common/pojo/ApiResult.java @@ -27,16 +27,16 @@ public class ApiResult implements Serializable { ApiResult vo = new ApiResult<>(); vo.result = value; vo.code = STATE.Success.getState(); - vo.type=STATE.Success.getType(); + vo.type = STATE.Success.getType(); return vo; } - public static ApiResult error(int state,String msg,T value) { + public static ApiResult error(int state, String msg, T value) { ApiResult vo = new ApiResult<>(); vo.result = value; vo.code = state; vo.type = msg; - vo.message=msg; + vo.message = msg; return vo; } @@ -49,7 +49,15 @@ public class ApiResult implements Serializable { return vo; } - public static ApiResult error(int state, String type,String msg) { + public static ApiResult errorWithExtras(STATE state,Object extras) { + ApiResult vo = new ApiResult<>(); + vo.extras = extras; + vo.code = state.getState(); + vo.type = state.getType(); + return vo; + } + + public static ApiResult error(int state, String type, String msg) { ApiResult vo = new ApiResult(); vo.code = state; vo.type = type; @@ -63,12 +71,13 @@ public class ApiResult implements Serializable { vo.type = STATE.Success.getType(); return vo; } + public static ApiResult error(STATE code, String msg) { - return error(code.getState(),code.getType(), msg); + return error(code.getState(), code.getType(), msg); } public static ApiResult error(String msg) { - return error(STATE.Error.getState(),STATE.Error.getType(), msg); + return error(STATE.Error.getState(), STATE.Error.getType(), msg); } public static ApiResult error(STATE code) { @@ -92,7 +101,7 @@ public class ApiResult implements Serializable { return vo; } - public static ApiResult> success(IPage page, Function converter) { + public static ApiResult> success(IPage page, Function converter) { ApiResult> vo = new ApiResult<>(); PageData pageData = new PageData<>(); pageData.setPage((int) page.getCurrent()); diff --git a/nflg-wms-common/src/main/java/com/nflg/wms/common/pojo/document/OutMaterialScanRecord.java b/nflg-wms-common/src/main/java/com/nflg/wms/common/pojo/document/OutMaterialScanRecord.java index 65b880b5..bb63c1b5 100644 --- a/nflg-wms-common/src/main/java/com/nflg/wms/common/pojo/document/OutMaterialScanRecord.java +++ b/nflg-wms-common/src/main/java/com/nflg/wms/common/pojo/document/OutMaterialScanRecord.java @@ -201,4 +201,11 @@ public class OutMaterialScanRecord { public String getKey9() { return materialNo + "|" + getBatchNo() + "|" + this.getSerialNo() + "|" + this.getBinNo(); } + + @Transient + private String key10; + + public String getKey10() { + return materialNo + "|" + getFactoryNo() + "|" + this.getWarehouseNo(); + } } diff --git a/nflg-wms-common/src/main/java/com/nflg/wms/common/pojo/vo/InventoryLockVO.java b/nflg-wms-common/src/main/java/com/nflg/wms/common/pojo/vo/InventoryLockVO.java new file mode 100644 index 00000000..96a192f7 --- /dev/null +++ b/nflg-wms-common/src/main/java/com/nflg/wms/common/pojo/vo/InventoryLockVO.java @@ -0,0 +1,39 @@ +package com.nflg.wms.common.pojo.vo; + +import lombok.Data; + +import java.math.BigDecimal; + +@Data +public class InventoryLockVO { + + /** + * 订单类型 + */ + private String type; + + /** + * 订单编号 + */ + private String no; + + /** + * 工厂编号 + */ + private String factoryNo; + + /** + * 仓库编号 + */ + private String warehouseNo; + + /** + * 物料编号 + */ + private String materialNo; + + /** + * 锁定数量 + */ + private BigDecimal lockNum; +} diff --git a/nflg-wms-repository/pom.xml b/nflg-wms-repository/pom.xml index 2c5fd037..e407b220 100644 --- a/nflg-wms-repository/pom.xml +++ b/nflg-wms-repository/pom.xml @@ -56,6 +56,12 @@ org.springframework.security spring-security-crypto + + org.redisson + redisson + 3.52.0 + compile + diff --git a/nflg-wms-repository/src/main/java/com/nflg/wms/repository/mapper/WmsInventoryMapper.java b/nflg-wms-repository/src/main/java/com/nflg/wms/repository/mapper/WmsInventoryMapper.java index 708ca4a6..cf80fc0b 100644 --- a/nflg-wms-repository/src/main/java/com/nflg/wms/repository/mapper/WmsInventoryMapper.java +++ b/nflg-wms-repository/src/main/java/com/nflg/wms/repository/mapper/WmsInventoryMapper.java @@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.nflg.wms.common.pojo.dto.InventoryInDTO; import com.nflg.wms.common.pojo.qo.InventorySearchQO; +import com.nflg.wms.common.pojo.vo.InventoryLockVO; import com.nflg.wms.common.pojo.vo.InventoryVO; import com.nflg.wms.repository.entity.WmsInventory; @@ -30,4 +31,6 @@ public interface WmsInventoryMapper extends BaseMapper { BigDecimal getNumOne(String factoryNo, String warehouseNo, String materialNo); BigDecimal getLockedNumOne(String factoryNo, String warehouseNo, String materialNo); + + List getLockList(String factoryNo, String warehouseNo, String materialNo); } diff --git a/nflg-wms-repository/src/main/java/com/nflg/wms/repository/service/IWmsInventoryService.java b/nflg-wms-repository/src/main/java/com/nflg/wms/repository/service/IWmsInventoryService.java index c88193c4..f32eacdb 100644 --- a/nflg-wms-repository/src/main/java/com/nflg/wms/repository/service/IWmsInventoryService.java +++ b/nflg-wms-repository/src/main/java/com/nflg/wms/repository/service/IWmsInventoryService.java @@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.extension.service.IService; import com.nflg.wms.common.pojo.dto.InventoryInDTO; import com.nflg.wms.common.pojo.dto.InventoryOutDTO; import com.nflg.wms.common.pojo.qo.InventorySearchQO; +import com.nflg.wms.common.pojo.vo.InventoryLockVO; import com.nflg.wms.common.pojo.vo.InventoryVO; import com.nflg.wms.repository.entity.WmsInventory; import jakarta.validation.Valid; @@ -48,4 +49,6 @@ public interface IWmsInventoryService extends IService { BigDecimal getNumOne(String factoryNo, String warehouseNo, String materialNo); List getForOutFIFO(String factoryNo, String warehouseNo, Collection materialNos); + + List getLockList(String factoryNo, String warehouseNo, String materialNo); } diff --git a/nflg-wms-repository/src/main/java/com/nflg/wms/repository/service/IWmsReturnRequestService.java b/nflg-wms-repository/src/main/java/com/nflg/wms/repository/service/IWmsReturnRequestService.java index 133cf30f..d892f3b6 100644 --- a/nflg-wms-repository/src/main/java/com/nflg/wms/repository/service/IWmsReturnRequestService.java +++ b/nflg-wms-repository/src/main/java/com/nflg/wms/repository/service/IWmsReturnRequestService.java @@ -7,6 +7,7 @@ import com.nflg.wms.common.pojo.qo.ApplyReturnRequestSearchQO; import com.nflg.wms.common.pojo.qo.GoodsReceiptSearchQO; import com.nflg.wms.common.pojo.vo.ApplyReturnRequestVO; import com.nflg.wms.common.pojo.vo.GoodsReceiptVO; +import com.nflg.wms.common.pojo.vo.InventoryLockVO; import com.nflg.wms.repository.entity.WmsReturnRequest; import com.baomidou.mybatisplus.extension.service.IService; import com.nflg.wms.repository.entity.WmsReturnRequestItem; @@ -25,7 +26,7 @@ import java.util.List; */ public interface IWmsReturnRequestService extends IService { - void addPurchaseReturns(List returnRequests, List returnRequestItems); + List addPurchaseReturns(List returnRequests, List returnRequestItems); IPage getGoodsReceipts(@Valid GoodsReceiptSearchQO request); diff --git a/nflg-wms-repository/src/main/java/com/nflg/wms/repository/service/impl/WmsInventoryServiceImpl.java b/nflg-wms-repository/src/main/java/com/nflg/wms/repository/service/impl/WmsInventoryServiceImpl.java index 936b8d22..3ab7cd1b 100644 --- a/nflg-wms-repository/src/main/java/com/nflg/wms/repository/service/impl/WmsInventoryServiceImpl.java +++ b/nflg-wms-repository/src/main/java/com/nflg/wms/repository/service/impl/WmsInventoryServiceImpl.java @@ -11,6 +11,7 @@ import com.nflg.wms.common.exception.NflgException; import com.nflg.wms.common.pojo.dto.InventoryInDTO; import com.nflg.wms.common.pojo.dto.InventoryOutDTO; import com.nflg.wms.common.pojo.qo.InventorySearchQO; +import com.nflg.wms.common.pojo.vo.InventoryLockVO; import com.nflg.wms.common.pojo.vo.InventoryVO; import com.nflg.wms.common.util.UserUtil; import com.nflg.wms.common.util.VUtil; @@ -194,4 +195,9 @@ public class WmsInventoryServiceImpl extends ServiceImpl getLockList(String factoryNo, String warehouseNo, String materialNo) { + return baseMapper.getLockList(factoryNo, warehouseNo, materialNo); + } } diff --git a/nflg-wms-repository/src/main/java/com/nflg/wms/repository/service/impl/WmsReturnRequestServiceImpl.java b/nflg-wms-repository/src/main/java/com/nflg/wms/repository/service/impl/WmsReturnRequestServiceImpl.java index c26b17fe..67afdb20 100644 --- a/nflg-wms-repository/src/main/java/com/nflg/wms/repository/service/impl/WmsReturnRequestServiceImpl.java +++ b/nflg-wms-repository/src/main/java/com/nflg/wms/repository/service/impl/WmsReturnRequestServiceImpl.java @@ -1,28 +1,39 @@ package com.nflg.wms.repository.service.impl; import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.segments.MergeSegments; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.nflg.wms.common.constant.STATE; +import com.nflg.wms.common.exception.NflgException; import com.nflg.wms.common.pojo.ApiResult; import com.nflg.wms.common.pojo.PageData; import com.nflg.wms.common.pojo.qo.ApplyReturnRequestSearchQO; import com.nflg.wms.common.pojo.qo.GoodsReceiptSearchQO; import com.nflg.wms.common.pojo.vo.ApplyReturnRequestVO; import com.nflg.wms.common.pojo.vo.GoodsReceiptVO; +import com.nflg.wms.common.pojo.vo.InventoryLockVO; +import com.nflg.wms.repository.entity.WmsOutProduceItem; import com.nflg.wms.repository.entity.WmsReturnRequest; import com.nflg.wms.repository.entity.WmsReturnRequestItem; import com.nflg.wms.repository.mapper.WmsReturnRequestMapper; +import com.nflg.wms.repository.service.IWmsInventoryService; import com.nflg.wms.repository.service.IWmsReturnRequestItemService; import com.nflg.wms.repository.service.IWmsReturnRequestService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import jakarta.annotation.Resource; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.ArrayList; import java.util.List; +import java.util.concurrent.TimeUnit; /** *

@@ -38,15 +49,49 @@ public class WmsReturnRequestServiceImpl extends ServiceImpl returnRequests, List returnRequestItems) { + public List addPurchaseReturns(List returnRequests, List returnRequestItems) { if (CollectionUtil.isNotEmpty(returnRequests)) { this.saveBatch(returnRequests); } if (CollectionUtil.isNotEmpty(returnRequestItems)) { - itemService.saveBatch(returnRequestItems); + List lockVOS = new ArrayList<>(); + returnRequestItems.forEach(item->{ + RLock lock = redissonClient.getLock(StrUtil.format("lock:inventory:{}:{}:{}", item.getFactoryCode(), item.getStorageLocation(), item.getMaterialCode())); + try { + // 等待5秒获取锁,10秒后自动释放 + if (lock.tryLock(5, 10, TimeUnit.SECONDS)) { + if (inventoryService.getNumOne(item.getFactoryCode(), item.getStorageLocation(), item.getMaterialCode()) + .compareTo(item.getLeft()) < 0 + ) { + lockVOS.addAll(inventoryService.getLockList(item.getFactoryCode(), item.getStorageLocation(), item.getMaterialCode())); + } else { + itemService.save(item); + } + } else { + throw new NflgException(STATE.BusinessError, "获取锁失败"); + } + } catch (Exception e) { + log.error("保存生产领料单出错", e); + throw new NflgException(STATE.BusinessError, e.getMessage()); + } finally { + if (lock.isHeldByCurrentThread()) { + lock.unlock(); + } + } + }); + if (CollectionUtil.isNotEmpty(lockVOS)) { + return lockVOS; + } } + return null; } @Override diff --git a/nflg-wms-repository/src/main/resources/mapper/WmsInventoryMapper.xml b/nflg-wms-repository/src/main/resources/mapper/WmsInventoryMapper.xml index 7a47fadc..b6a587df 100644 --- a/nflg-wms-repository/src/main/resources/mapper/WmsInventoryMapper.xml +++ b/nflg-wms-repository/src/main/resources/mapper/WmsInventoryMapper.xml @@ -39,7 +39,7 @@ + +