feat(inventory): 添加库存锁定检查功能
- 在 ApiResult 中新增 errorWithExtras 方法用于返回额外信息 - 新增 InventoryLockVO 数据传输对象 - 在 IWmsInventoryService 中添加 getLockList 方法查询锁定库存列表 - 修改 IWmsReturnRequestService 的 addPurchaseReturns 方法返回库存锁定信息 - 在多个控制器中添加 Redisson 分布式锁确保库存操作一致性 - 实现库存不足时返回锁定详情的功能 - 在数据库映射中添加 getLockList 查询方法 - 更新 STATE 枚举添加 OutOfStock 状态码 120 - 在多个出库和调拨流程中集成库存锁定检查逻辑
This commit is contained in:
parent
a021013ef2
commit
78dad56dbe
|
|
@ -15,6 +15,8 @@ import com.nflg.wms.admin.util.PdfGeneratorUtil;
|
||||||
import com.nflg.wms.admin.util.QRCodeUtil;
|
import com.nflg.wms.admin.util.QRCodeUtil;
|
||||||
import com.nflg.wms.admin.util.ThymeleafUtil;
|
import com.nflg.wms.admin.util.ThymeleafUtil;
|
||||||
import com.nflg.wms.common.constant.BarCodeProcessStage;
|
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.ApiResult;
|
||||||
import com.nflg.wms.common.pojo.PageData;
|
import com.nflg.wms.common.pojo.PageData;
|
||||||
import com.nflg.wms.common.pojo.document.OutMaterialScanRecord;
|
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.NotEmpty;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.redisson.api.RLock;
|
||||||
|
import org.redisson.api.RedissonClient;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
|
@ -39,6 +43,7 @@ import java.math.BigDecimal;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -76,15 +81,15 @@ public class OutAssistanceController extends BaseController {
|
||||||
@Resource
|
@Resource
|
||||||
private InventoryForOutRepository inventoryForOutRepository;
|
private InventoryForOutRepository inventoryForOutRepository;
|
||||||
|
|
||||||
@Resource
|
|
||||||
private IParamConfigService paramConfigService;
|
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private IWmsBomService bomService;
|
private IWmsBomService bomService;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private IWmsQrCodeMasterService qrCodeMasterService;
|
private IWmsQrCodeMasterService qrCodeMasterService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RedissonClient redissonClient;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询SAP领料订单数据
|
* 查询SAP领料订单数据
|
||||||
*/
|
*/
|
||||||
|
|
@ -328,6 +333,34 @@ public class OutAssistanceController extends BaseController {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
List<InventoryLockVO> 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);
|
outAssistanceItemService.updateBatchById(datas);
|
||||||
outAssistanceTicketItemService.saveBatch(ticketItems);
|
outAssistanceTicketItemService.saveBatch(ticketItems);
|
||||||
outAssistanceTicketService.save(ticket);
|
outAssistanceTicketService.save(ticket);
|
||||||
|
|
@ -498,8 +531,7 @@ public class OutAssistanceController extends BaseController {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
qrCodeMasterService.updateBarCode(qrCodeMasters);
|
qrCodeMasterService.updateBarCode(qrCodeMasters);
|
||||||
submitSap(order, ticket, records, outAssistanceItemService.getList(order.getId()), qrCodeMasters
|
submitSap(order, ticket, records, outAssistanceItemService.getList(order.getId()), qrCodeMasters);
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
List<OutAssistanceItemVO> items = outAssistanceTicketItemService.getList(qo.getId());
|
List<OutAssistanceItemVO> items = outAssistanceTicketItemService.getList(qo.getId());
|
||||||
items.forEach(it -> {
|
items.forEach(it -> {
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@ import com.nflg.wms.admin.util.PdfGeneratorUtil;
|
||||||
import com.nflg.wms.admin.util.QRCodeUtil;
|
import com.nflg.wms.admin.util.QRCodeUtil;
|
||||||
import com.nflg.wms.admin.util.ThymeleafUtil;
|
import com.nflg.wms.admin.util.ThymeleafUtil;
|
||||||
import com.nflg.wms.common.constant.BarCodeProcessStage;
|
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.ApiResult;
|
||||||
import com.nflg.wms.common.pojo.PageData;
|
import com.nflg.wms.common.pojo.PageData;
|
||||||
import com.nflg.wms.common.pojo.document.OutMaterialScanRecord;
|
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.NotEmpty;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.redisson.api.RLock;
|
||||||
|
import org.redisson.api.RedissonClient;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
|
@ -39,6 +43,7 @@ import java.math.BigDecimal;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -85,6 +90,9 @@ public class OutCostCenterController extends BaseController {
|
||||||
@Resource
|
@Resource
|
||||||
private IWmsQrCodeMasterService qrCodeMasterService;
|
private IWmsQrCodeMasterService qrCodeMasterService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RedissonClient redissonClient;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询SAP领料订单数据
|
* 查询SAP领料订单数据
|
||||||
*/
|
*/
|
||||||
|
|
@ -319,6 +327,34 @@ public class OutCostCenterController extends BaseController {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
List<InventoryLockVO> 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);
|
outCostcenterItemService.updateBatchById(datas);
|
||||||
outCostcenterTicketItemService.saveBatch(ticketItems);
|
outCostcenterTicketItemService.saveBatch(ticketItems);
|
||||||
outCostcenterTicketService.save(ticket);
|
outCostcenterTicketService.save(ticket);
|
||||||
|
|
|
||||||
|
|
@ -143,6 +143,7 @@ public class OutProduceController extends BaseController {
|
||||||
VUtil.trueThrowBusinessError(CollectionUtil.isNotEmpty(materialNos))
|
VUtil.trueThrowBusinessError(CollectionUtil.isNotEmpty(materialNos))
|
||||||
.throwMessage("以下物料的申请数量超出限制:" + StrUtil.join(",", materialNos));
|
.throwMessage("以下物料的申请数量超出限制:" + StrUtil.join(",", materialNos));
|
||||||
Map<String, List<Zwm3a07VO>> maps = datas.stream().collect(Collectors.groupingBy(Zwm3a07VO::getKey2));
|
Map<String, List<Zwm3a07VO>> maps = datas.stream().collect(Collectors.groupingBy(Zwm3a07VO::getKey2));
|
||||||
|
List<InventoryLockVO> lockVOS = new ArrayList<>();
|
||||||
maps.forEach((key, items) -> {
|
maps.forEach((key, items) -> {
|
||||||
WmsOutProduce order = Convert.convert(WmsOutProduce.class, items.get(0));
|
WmsOutProduce order = Convert.convert(WmsOutProduce.class, items.get(0));
|
||||||
order.setNo(serialNumberControllerService.generateSerialNumber(9));
|
order.setNo(serialNumberControllerService.generateSerialNumber(9));
|
||||||
|
|
@ -155,10 +156,16 @@ public class OutProduceController extends BaseController {
|
||||||
try {
|
try {
|
||||||
// 等待5秒获取锁,10秒后自动释放
|
// 等待5秒获取锁,10秒后自动释放
|
||||||
if (lock.tryLock(5, 10, TimeUnit.SECONDS)) {
|
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);
|
WmsOutProduceItem data = Convert.convert(WmsOutProduceItem.class, item);
|
||||||
data.setLockNum(item.getSqsl());
|
data.setLockNum(item.getSqsl());
|
||||||
data.setOrderId(order.getId());
|
data.setOrderId(order.getId());
|
||||||
outProduceItemService.save(data);
|
outProduceItemService.save(data);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new NflgException(STATE.BusinessError, "获取锁失败");
|
throw new NflgException(STATE.BusinessError, "获取锁失败");
|
||||||
}
|
}
|
||||||
|
|
@ -166,14 +173,17 @@ public class OutProduceController extends BaseController {
|
||||||
log.error("保存生产领料单出错", e);
|
log.error("保存生产领料单出错", e);
|
||||||
throw new NflgException(STATE.BusinessError, e.getMessage());
|
throw new NflgException(STATE.BusinessError, e.getMessage());
|
||||||
} finally {
|
} finally {
|
||||||
// 确保只释放自己持有的锁
|
|
||||||
if (lock.isHeldByCurrentThread()) {
|
if (lock.isHeldByCurrentThread()) {
|
||||||
lock.unlock();
|
lock.unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
if (CollectionUtil.isEmpty(lockVOS)) {
|
||||||
return ApiResult.success();
|
return ApiResult.success();
|
||||||
|
} else {
|
||||||
|
return ApiResult.errorWithExtras(STATE.OutOfStock, lockVOS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -192,6 +202,7 @@ public class OutProduceController extends BaseController {
|
||||||
// VUtil.trueThrowBusinessError(CollectionUtil.isNotEmpty(materialNos))
|
// VUtil.trueThrowBusinessError(CollectionUtil.isNotEmpty(materialNos))
|
||||||
// .throwMessage("以下物料的申请数量超出限制:" + StrUtil.join(",", materialNos));
|
// .throwMessage("以下物料的申请数量超出限制:" + StrUtil.join(",", materialNos));
|
||||||
Map<String, List<Zwm3a07VO>> maps = datas.stream().collect(Collectors.groupingBy(Zwm3a07VO::getKey2));
|
Map<String, List<Zwm3a07VO>> maps = datas.stream().collect(Collectors.groupingBy(Zwm3a07VO::getKey2));
|
||||||
|
List<InventoryLockVO> lockVOS = new ArrayList<>();
|
||||||
maps.forEach((key, items) -> {
|
maps.forEach((key, items) -> {
|
||||||
WmsOutProduce order = Convert.convert(WmsOutProduce.class, items.get(0));
|
WmsOutProduce order = Convert.convert(WmsOutProduce.class, items.get(0));
|
||||||
order.setNo(serialNumberControllerService.generateSerialNumber(9));
|
order.setNo(serialNumberControllerService.generateSerialNumber(9));
|
||||||
|
|
@ -200,13 +211,39 @@ public class OutProduceController extends BaseController {
|
||||||
order.setCreateTime(LocalDateTime.now());
|
order.setCreateTime(LocalDateTime.now());
|
||||||
outProduceService.save(order);
|
outProduceService.save(order);
|
||||||
items.forEach(item -> {
|
items.forEach(item -> {
|
||||||
|
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);
|
WmsOutProduceItem data = Convert.convert(WmsOutProduceItem.class, item);
|
||||||
data.setLockNum(BigDecimal.ZERO);
|
data.setLockNum(data.getSqsl());
|
||||||
data.setOrderId(order.getId());
|
data.setOrderId(order.getId());
|
||||||
outProduceItemService.save(data);
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
if (CollectionUtil.isEmpty(lockVOS)) {
|
||||||
return ApiResult.success();
|
return ApiResult.success();
|
||||||
|
} else {
|
||||||
|
return ApiResult.errorWithExtras(STATE.OutOfStock, lockVOS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import com.nflg.wms.admin.util.PdfGeneratorUtil;
|
||||||
import com.nflg.wms.admin.util.QRCodeUtil;
|
import com.nflg.wms.admin.util.QRCodeUtil;
|
||||||
import com.nflg.wms.admin.util.ThymeleafUtil;
|
import com.nflg.wms.admin.util.ThymeleafUtil;
|
||||||
import com.nflg.wms.common.constant.BarCodeProcessStage;
|
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.constant.UserType;
|
||||||
import com.nflg.wms.common.pojo.ApiResult;
|
import com.nflg.wms.common.pojo.ApiResult;
|
||||||
import com.nflg.wms.common.pojo.PageData;
|
import com.nflg.wms.common.pojo.PageData;
|
||||||
|
|
@ -127,8 +128,12 @@ public class PurchaseReturnController extends BaseController {
|
||||||
VUtil.trueThrowBusinessError(CollectionUtil.isEmpty(request))
|
VUtil.trueThrowBusinessError(CollectionUtil.isEmpty(request))
|
||||||
.throwMessage("申请数据不可以为空");
|
.throwMessage("申请数据不可以为空");
|
||||||
List<PurchaseReturnDTO> purchaseReturnDTOList = Convert.toList(PurchaseReturnDTO.class, request);
|
List<PurchaseReturnDTO> purchaseReturnDTOList = Convert.toList(PurchaseReturnDTO.class, request);
|
||||||
SaveApply(purchaseReturnDTOList, Short.valueOf("0"));
|
List<InventoryLockVO> inventoryLockVOS = SaveApply(purchaseReturnDTOList, Short.valueOf("0"));
|
||||||
|
if (CollectionUtil.isEmpty(inventoryLockVOS)) {
|
||||||
return ApiResult.success();
|
return ApiResult.success();
|
||||||
|
} else {
|
||||||
|
return ApiResult.errorWithExtras(STATE.OutOfStock, inventoryLockVOS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -285,7 +290,7 @@ public class PurchaseReturnController extends BaseController {
|
||||||
* 保存申请单
|
* 保存申请单
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private void SaveApply(List<PurchaseReturnDTO> purchaseReturnDTOList, Short dataSource) {
|
private List<InventoryLockVO> SaveApply(List<PurchaseReturnDTO> purchaseReturnDTOList, Short dataSource) {
|
||||||
//根据采购组编号、采购单编号、供应商id进行去除
|
//根据采购组编号、采购单编号、供应商id进行去除
|
||||||
List<String> disGroupCode = purchaseReturnDTOList.stream()
|
List<String> disGroupCode = purchaseReturnDTOList.stream()
|
||||||
.map(PurchaseReturnDTO::getGroupCode)
|
.map(PurchaseReturnDTO::getGroupCode)
|
||||||
|
|
@ -334,7 +339,7 @@ public class PurchaseReturnController extends BaseController {
|
||||||
returnRequestItems.add(returnRequestItem);
|
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) {
|
for (WmsQrCodeMaster qrCodeMaster : qrCodeMasters) {
|
||||||
qrCodeVOS.add(BarcodeValidation(qrCodeMaster));
|
qrCodeVOS.add(BarcodeValidation(qrCodeMaster));
|
||||||
}
|
}
|
||||||
|
List<InventoryLockVO> inventoryLockVOS = null;
|
||||||
if (CollectionUtil.isNotEmpty(qrCodeVOS)) {
|
if (CollectionUtil.isNotEmpty(qrCodeVOS)) {
|
||||||
List<PurchaseReturnDTO> purchaseReturnDTOList = new ArrayList<>();
|
List<PurchaseReturnDTO> purchaseReturnDTOList = new ArrayList<>();
|
||||||
for (QrCodeVO qrCodeVO : qrCodeVOS) {
|
for (QrCodeVO qrCodeVO : qrCodeVOS) {
|
||||||
|
|
@ -430,10 +436,14 @@ public class PurchaseReturnController extends BaseController {
|
||||||
);
|
);
|
||||||
purchaseReturnDTO.setGroupCode(groupCode);
|
purchaseReturnDTO.setGroupCode(groupCode);
|
||||||
}
|
}
|
||||||
SaveApply(purchaseReturnDTOList, Short.valueOf("1"));
|
inventoryLockVOS = SaveApply(purchaseReturnDTOList, Short.valueOf("1"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (CollectionUtil.isEmpty(inventoryLockVOS)) {
|
||||||
return ApiResult.success();
|
return ApiResult.success();
|
||||||
|
} else {
|
||||||
|
return ApiResult.errorWithExtras(STATE.OutOfStock, inventoryLockVOS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@ import com.nflg.wms.admin.service.BasdeSerialNumberControllerService;
|
||||||
import com.nflg.wms.admin.service.SapService;
|
import com.nflg.wms.admin.service.SapService;
|
||||||
import com.nflg.wms.admin.util.*;
|
import com.nflg.wms.admin.util.*;
|
||||||
import com.nflg.wms.common.constant.BarCodeProcessStage;
|
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.ApiResult;
|
||||||
import com.nflg.wms.common.pojo.PageData;
|
import com.nflg.wms.common.pojo.PageData;
|
||||||
import com.nflg.wms.common.pojo.document.InMaterialScanRecord;
|
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.NotEmpty;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.redisson.api.RLock;
|
||||||
|
import org.redisson.api.RedissonClient;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
|
@ -44,6 +48,7 @@ import java.math.BigDecimal;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -87,9 +92,6 @@ public class TransferCompanyController extends BaseController {
|
||||||
@Resource
|
@Resource
|
||||||
private InventoryForOutRepository inventoryForOutRepository;
|
private InventoryForOutRepository inventoryForOutRepository;
|
||||||
|
|
||||||
@Resource
|
|
||||||
private IParamConfigService paramConfigService;
|
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private IWmsWarehouseService warehouseService;
|
private IWmsWarehouseService warehouseService;
|
||||||
|
|
||||||
|
|
@ -99,6 +101,9 @@ public class TransferCompanyController extends BaseController {
|
||||||
@Resource
|
@Resource
|
||||||
private IWmsQrCodeMasterService qrCodeMasterService;
|
private IWmsQrCodeMasterService qrCodeMasterService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RedissonClient redissonClient;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询SAP订单数据
|
* 查询SAP订单数据
|
||||||
*/
|
*/
|
||||||
|
|
@ -124,6 +129,7 @@ public class TransferCompanyController extends BaseController {
|
||||||
VUtil.trueThrowBusinessError(CollectionUtil.isNotEmpty(materialNos))
|
VUtil.trueThrowBusinessError(CollectionUtil.isNotEmpty(materialNos))
|
||||||
.throwMessage("以下物料的申请数量超出限制:" + StrUtil.join(",", materialNos));
|
.throwMessage("以下物料的申请数量超出限制:" + StrUtil.join(",", materialNos));
|
||||||
Map<String, List<AllocationOrderDTO>> maps = datas.stream().collect(Collectors.groupingBy(AllocationOrderDTO::getGroup1));
|
Map<String, List<AllocationOrderDTO>> maps = datas.stream().collect(Collectors.groupingBy(AllocationOrderDTO::getGroup1));
|
||||||
|
List<InventoryLockVO> lockVOS = new ArrayList<>();
|
||||||
maps.forEach((key, items) -> {
|
maps.forEach((key, items) -> {
|
||||||
WmsTransferCompany order = Convert.convert(WmsTransferCompany.class, items.get(0));
|
WmsTransferCompany order = Convert.convert(WmsTransferCompany.class, items.get(0));
|
||||||
order.setNo(serialNumberControllerService.generateSerialNumber(22));
|
order.setNo(serialNumberControllerService.generateSerialNumber(22));
|
||||||
|
|
@ -131,16 +137,38 @@ public class TransferCompanyController extends BaseController {
|
||||||
order.setCreateTime(LocalDateTime.now());
|
order.setCreateTime(LocalDateTime.now());
|
||||||
transferCompanyService.save(order);
|
transferCompanyService.save(order);
|
||||||
items.forEach(item -> {
|
items.forEach(item -> {
|
||||||
BigDecimal max = inventoryService.getNumOne(item.getReswk(), item.getLgfsb1(), item.getMatnr());
|
RLock lock = redissonClient.getLock(StrUtil.format("lock:inventory:{}:{}:{}", item.getReswk(), item.getLgfsb1(), item.getMatnr()));
|
||||||
VUtil.trueThrowBusinessError(item.getNum().compareTo(max) > 0)
|
try {
|
||||||
.throwMessage("物料" + item.getMatnr() + "的申请数量超出库存限制");
|
// 等待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);
|
WmsTransferCompanyItem data = Convert.convert(WmsTransferCompanyItem.class, item);
|
||||||
data.setOrderId(order.getId());
|
data.setOrderId(order.getId());
|
||||||
data.setLeft(data.getNum());
|
data.setLeft(data.getNum());
|
||||||
transferCompanyItemService.save(data);
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
if (CollectionUtil.isEmpty(lockVOS)) {
|
||||||
return ApiResult.success();
|
return ApiResult.success();
|
||||||
|
} else {
|
||||||
|
return ApiResult.errorWithExtras(STATE.OutOfStock, lockVOS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,8 @@ import com.nflg.wms.admin.util.PdfGeneratorUtil;
|
||||||
import com.nflg.wms.admin.util.QRCodeUtil;
|
import com.nflg.wms.admin.util.QRCodeUtil;
|
||||||
import com.nflg.wms.admin.util.ThymeleafUtil;
|
import com.nflg.wms.admin.util.ThymeleafUtil;
|
||||||
import com.nflg.wms.common.constant.BarCodeProcessStage;
|
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.ApiResult;
|
||||||
import com.nflg.wms.common.pojo.PageData;
|
import com.nflg.wms.common.pojo.PageData;
|
||||||
import com.nflg.wms.common.pojo.document.InMaterialScanRecord;
|
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.NotEmpty;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.redisson.api.RLock;
|
||||||
|
import org.redisson.api.RedissonClient;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
|
@ -42,6 +46,7 @@ import java.math.BigDecimal;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -85,9 +90,6 @@ public class TransferFactoryController extends BaseController {
|
||||||
@Resource
|
@Resource
|
||||||
private InventoryForOutRepository inventoryForOutRepository;
|
private InventoryForOutRepository inventoryForOutRepository;
|
||||||
|
|
||||||
@Resource
|
|
||||||
private IParamConfigService paramConfigService;
|
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private IWmsBomService bomService;
|
private IWmsBomService bomService;
|
||||||
|
|
||||||
|
|
@ -97,6 +99,9 @@ public class TransferFactoryController extends BaseController {
|
||||||
@Resource
|
@Resource
|
||||||
private IWmsQrCodeMasterService qrCodeMasterService;
|
private IWmsQrCodeMasterService qrCodeMasterService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RedissonClient redissonClient;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询SAP领料订单数据
|
* 查询SAP领料订单数据
|
||||||
*/
|
*/
|
||||||
|
|
@ -122,6 +127,7 @@ public class TransferFactoryController extends BaseController {
|
||||||
VUtil.trueThrowBusinessError(CollectionUtil.isNotEmpty(materialNos))
|
VUtil.trueThrowBusinessError(CollectionUtil.isNotEmpty(materialNos))
|
||||||
.throwMessage("以下物料的申请数量超出限制:" + StrUtil.join(",", materialNos));
|
.throwMessage("以下物料的申请数量超出限制:" + StrUtil.join(",", materialNos));
|
||||||
Map<String, List<TransferOrderDTO>> maps = datas.stream().collect(Collectors.groupingBy(TransferOrderDTO::getGroup1));
|
Map<String, List<TransferOrderDTO>> maps = datas.stream().collect(Collectors.groupingBy(TransferOrderDTO::getGroup1));
|
||||||
|
List<InventoryLockVO> lockVOS = new ArrayList<>();
|
||||||
maps.forEach((key, items) -> {
|
maps.forEach((key, items) -> {
|
||||||
WmsTransferFactory order = Convert.convert(WmsTransferFactory.class, items.get(0));
|
WmsTransferFactory order = Convert.convert(WmsTransferFactory.class, items.get(0));
|
||||||
order.setNo(serialNumberControllerService.generateSerialNumber(18));
|
order.setNo(serialNumberControllerService.generateSerialNumber(18));
|
||||||
|
|
@ -129,16 +135,38 @@ public class TransferFactoryController extends BaseController {
|
||||||
order.setCreateTime(LocalDateTime.now());
|
order.setCreateTime(LocalDateTime.now());
|
||||||
transferFactoryService.save(order);
|
transferFactoryService.save(order);
|
||||||
items.forEach(item -> {
|
items.forEach(item -> {
|
||||||
BigDecimal max = inventoryService.getNumOne(item.getWerks(), item.getLgort(), item.getMatnr());
|
RLock lock = redissonClient.getLock(StrUtil.format("lock:inventory:{}:{}:{}", item.getWerks(), item.getLgort(), item.getMatnr()));
|
||||||
VUtil.trueThrowBusinessError(item.getNum().compareTo(max) > 0)
|
try {
|
||||||
.throwMessage("物料" + item.getMatnr() + "的申请数量超出库存限制");
|
// 等待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);
|
WmsTransferFactoryItem data = Convert.convert(WmsTransferFactoryItem.class, item);
|
||||||
data.setOrderId(order.getId());
|
data.setOrderId(order.getId());
|
||||||
data.setLeft(data.getNum());
|
data.setLeft(data.getNum());
|
||||||
transferFactoryItemService.save(data);
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
if (CollectionUtil.isEmpty(lockVOS)) {
|
||||||
return ApiResult.success();
|
return ApiResult.success();
|
||||||
|
} else {
|
||||||
|
return ApiResult.errorWithExtras(STATE.OutOfStock, lockVOS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,8 @@ public enum STATE {
|
||||||
RequestMethodError(116, "请求方式错误"),
|
RequestMethodError(116, "请求方式错误"),
|
||||||
InconsistentDataError(117, "需要用户确认"),
|
InconsistentDataError(117, "需要用户确认"),
|
||||||
NoOrderData(118, "订单不存在"),
|
NoOrderData(118, "订单不存在"),
|
||||||
SAPErr(119, "SAP错误");
|
SAPErr(119, "SAP错误"),
|
||||||
|
OutOfStock(120, "库存不足");
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final Integer state;
|
private final Integer state;
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,14 @@ public class ApiResult<T> implements Serializable {
|
||||||
return vo;
|
return vo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static <T> ApiResult<T> errorWithExtras(STATE state,Object extras) {
|
||||||
|
ApiResult<T> vo = new ApiResult<>();
|
||||||
|
vo.extras = extras;
|
||||||
|
vo.code = state.getState();
|
||||||
|
vo.type = state.getType();
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
public static <T> ApiResult<T> error(int state, String type, String msg) {
|
public static <T> ApiResult<T> error(int state, String type, String msg) {
|
||||||
ApiResult<T> vo = new ApiResult<T>();
|
ApiResult<T> vo = new ApiResult<T>();
|
||||||
vo.code = state;
|
vo.code = state;
|
||||||
|
|
@ -63,6 +71,7 @@ public class ApiResult<T> implements Serializable {
|
||||||
vo.type = STATE.Success.getType();
|
vo.type = STATE.Success.getType();
|
||||||
return vo;
|
return vo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> ApiResult<T> error(STATE code, String msg) {
|
public static <T> ApiResult<T> error(STATE code, String msg) {
|
||||||
return error(code.getState(), code.getType(), msg);
|
return error(code.getState(), code.getType(), msg);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -201,4 +201,11 @@ public class OutMaterialScanRecord {
|
||||||
public String getKey9() {
|
public String getKey9() {
|
||||||
return materialNo + "|" + getBatchNo() + "|" + this.getSerialNo() + "|" + this.getBinNo();
|
return materialNo + "|" + getBatchNo() + "|" + this.getSerialNo() + "|" + this.getBinNo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
private String key10;
|
||||||
|
|
||||||
|
public String getKey10() {
|
||||||
|
return materialNo + "|" + getFactoryNo() + "|" + this.getWarehouseNo();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -56,6 +56,12 @@
|
||||||
<groupId>org.springframework.security</groupId>
|
<groupId>org.springframework.security</groupId>
|
||||||
<artifactId>spring-security-crypto</artifactId>
|
<artifactId>spring-security-crypto</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.redisson</groupId>
|
||||||
|
<artifactId>redisson</artifactId>
|
||||||
|
<version>3.52.0</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.nflg.wms.common.pojo.dto.InventoryInDTO;
|
import com.nflg.wms.common.pojo.dto.InventoryInDTO;
|
||||||
import com.nflg.wms.common.pojo.qo.InventorySearchQO;
|
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.pojo.vo.InventoryVO;
|
||||||
import com.nflg.wms.repository.entity.WmsInventory;
|
import com.nflg.wms.repository.entity.WmsInventory;
|
||||||
|
|
||||||
|
|
@ -30,4 +31,6 @@ public interface WmsInventoryMapper extends BaseMapper<WmsInventory> {
|
||||||
BigDecimal getNumOne(String factoryNo, String warehouseNo, String materialNo);
|
BigDecimal getNumOne(String factoryNo, String warehouseNo, String materialNo);
|
||||||
|
|
||||||
BigDecimal getLockedNumOne(String factoryNo, String warehouseNo, String materialNo);
|
BigDecimal getLockedNumOne(String factoryNo, String warehouseNo, String materialNo);
|
||||||
|
|
||||||
|
List<InventoryLockVO> getLockList(String factoryNo, String warehouseNo, String materialNo);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.InventoryInDTO;
|
||||||
import com.nflg.wms.common.pojo.dto.InventoryOutDTO;
|
import com.nflg.wms.common.pojo.dto.InventoryOutDTO;
|
||||||
import com.nflg.wms.common.pojo.qo.InventorySearchQO;
|
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.pojo.vo.InventoryVO;
|
||||||
import com.nflg.wms.repository.entity.WmsInventory;
|
import com.nflg.wms.repository.entity.WmsInventory;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
|
|
@ -48,4 +49,6 @@ public interface IWmsInventoryService extends IService<WmsInventory> {
|
||||||
BigDecimal getNumOne(String factoryNo, String warehouseNo, String materialNo);
|
BigDecimal getNumOne(String factoryNo, String warehouseNo, String materialNo);
|
||||||
|
|
||||||
List<WmsInventory> getForOutFIFO(String factoryNo, String warehouseNo, Collection<String> materialNos);
|
List<WmsInventory> getForOutFIFO(String factoryNo, String warehouseNo, Collection<String> materialNos);
|
||||||
|
|
||||||
|
List<InventoryLockVO> getLockList(String factoryNo, String warehouseNo, String materialNo);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.qo.GoodsReceiptSearchQO;
|
||||||
import com.nflg.wms.common.pojo.vo.ApplyReturnRequestVO;
|
import com.nflg.wms.common.pojo.vo.ApplyReturnRequestVO;
|
||||||
import com.nflg.wms.common.pojo.vo.GoodsReceiptVO;
|
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.nflg.wms.repository.entity.WmsReturnRequest;
|
||||||
import com.baomidou.mybatisplus.extension.service.IService;
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
import com.nflg.wms.repository.entity.WmsReturnRequestItem;
|
import com.nflg.wms.repository.entity.WmsReturnRequestItem;
|
||||||
|
|
@ -25,7 +26,7 @@ import java.util.List;
|
||||||
*/
|
*/
|
||||||
public interface IWmsReturnRequestService extends IService<WmsReturnRequest> {
|
public interface IWmsReturnRequestService extends IService<WmsReturnRequest> {
|
||||||
|
|
||||||
void addPurchaseReturns(List<WmsReturnRequest> returnRequests, List<WmsReturnRequestItem> returnRequestItems);
|
List<InventoryLockVO> addPurchaseReturns(List<WmsReturnRequest> returnRequests, List<WmsReturnRequestItem> returnRequestItems);
|
||||||
|
|
||||||
IPage<GoodsReceiptVO> getGoodsReceipts(@Valid GoodsReceiptSearchQO request);
|
IPage<GoodsReceiptVO> getGoodsReceipts(@Valid GoodsReceiptSearchQO request);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.InventoryInDTO;
|
||||||
import com.nflg.wms.common.pojo.dto.InventoryOutDTO;
|
import com.nflg.wms.common.pojo.dto.InventoryOutDTO;
|
||||||
import com.nflg.wms.common.pojo.qo.InventorySearchQO;
|
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.pojo.vo.InventoryVO;
|
||||||
import com.nflg.wms.common.util.UserUtil;
|
import com.nflg.wms.common.util.UserUtil;
|
||||||
import com.nflg.wms.common.util.VUtil;
|
import com.nflg.wms.common.util.VUtil;
|
||||||
|
|
@ -194,4 +195,9 @@ public class WmsInventoryServiceImpl extends ServiceImpl<WmsInventoryMapper, Wms
|
||||||
.orderByAsc(WmsInventory::getId)
|
.orderByAsc(WmsInventory::getId)
|
||||||
.list();
|
.list();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<InventoryLockVO> getLockList(String factoryNo, String warehouseNo, String materialNo) {
|
||||||
|
return baseMapper.getLockList(factoryNo, warehouseNo, materialNo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,39 @@
|
||||||
package com.nflg.wms.repository.service.impl;
|
package com.nflg.wms.repository.service.impl;
|
||||||
|
|
||||||
import cn.hutool.core.collection.CollectionUtil;
|
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.Wrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.segments.MergeSegments;
|
import com.baomidou.mybatisplus.core.conditions.segments.MergeSegments;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
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.ApiResult;
|
||||||
import com.nflg.wms.common.pojo.PageData;
|
import com.nflg.wms.common.pojo.PageData;
|
||||||
import com.nflg.wms.common.pojo.qo.ApplyReturnRequestSearchQO;
|
import com.nflg.wms.common.pojo.qo.ApplyReturnRequestSearchQO;
|
||||||
import com.nflg.wms.common.pojo.qo.GoodsReceiptSearchQO;
|
import com.nflg.wms.common.pojo.qo.GoodsReceiptSearchQO;
|
||||||
import com.nflg.wms.common.pojo.vo.ApplyReturnRequestVO;
|
import com.nflg.wms.common.pojo.vo.ApplyReturnRequestVO;
|
||||||
import com.nflg.wms.common.pojo.vo.GoodsReceiptVO;
|
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.WmsReturnRequest;
|
||||||
import com.nflg.wms.repository.entity.WmsReturnRequestItem;
|
import com.nflg.wms.repository.entity.WmsReturnRequestItem;
|
||||||
import com.nflg.wms.repository.mapper.WmsReturnRequestMapper;
|
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.IWmsReturnRequestItemService;
|
||||||
import com.nflg.wms.repository.service.IWmsReturnRequestService;
|
import com.nflg.wms.repository.service.IWmsReturnRequestService;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
|
import org.redisson.api.RLock;
|
||||||
|
import org.redisson.api.RedissonClient;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
|
|
@ -38,15 +49,49 @@ public class WmsReturnRequestServiceImpl extends ServiceImpl<WmsReturnRequestMap
|
||||||
@Resource
|
@Resource
|
||||||
private IWmsReturnRequestItemService itemService;
|
private IWmsReturnRequestItemService itemService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private RedissonClient redissonClient;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private IWmsInventoryService inventoryService;
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
@Override
|
@Override
|
||||||
public void addPurchaseReturns(List<WmsReturnRequest> returnRequests, List<WmsReturnRequestItem> returnRequestItems) {
|
public List<InventoryLockVO> addPurchaseReturns(List<WmsReturnRequest> returnRequests, List<WmsReturnRequestItem> returnRequestItems) {
|
||||||
if (CollectionUtil.isNotEmpty(returnRequests)) {
|
if (CollectionUtil.isNotEmpty(returnRequests)) {
|
||||||
this.saveBatch(returnRequests);
|
this.saveBatch(returnRequests);
|
||||||
}
|
}
|
||||||
if (CollectionUtil.isNotEmpty(returnRequestItems)) {
|
if (CollectionUtil.isNotEmpty(returnRequestItems)) {
|
||||||
itemService.saveBatch(returnRequestItems);
|
List<InventoryLockVO> 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
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="getLockedNum" resultType="com.nflg.wms.common.pojo.dto.InventoryInDTO">
|
<select id="getLockedNum" resultType="com.nflg.wms.common.pojo.dto.InventoryInDTO">
|
||||||
SELECT material_no,num
|
SELECT material_no,sum(lock_num) as num
|
||||||
FROM v_inventory_lock
|
FROM v_inventory_lock
|
||||||
WHERE factory_no=#{factoryNo} AND warehouse_no=#{warehouseNo}
|
WHERE factory_no=#{factoryNo} AND warehouse_no=#{warehouseNo}
|
||||||
<if test="materialNos != null and materialNos.size() > 0">
|
<if test="materialNos != null and materialNos.size() > 0">
|
||||||
|
|
@ -48,18 +48,26 @@
|
||||||
#{item}
|
#{item}
|
||||||
</foreach>
|
</foreach>
|
||||||
</if>
|
</if>
|
||||||
|
group by material_no
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="getNumOne" resultType="java.math.BigDecimal">
|
<select id="getNumOne" resultType="java.math.BigDecimal">
|
||||||
SELECT SUM(num) num
|
SELECT SUM(num) as num
|
||||||
FROM wms_inventory
|
FROM wms_inventory
|
||||||
WHERE factory_no=#{factoryNo} AND warehouse_no=#{warehouseNo} AND material_no=#{materialNo}
|
WHERE factory_no=#{factoryNo} AND warehouse_no=#{warehouseNo} AND material_no=#{materialNo}
|
||||||
GROUP BY factory_no,warehouse_no,material_no
|
GROUP BY factory_no,warehouse_no,material_no
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="getLockedNumOne" resultType="java.math.BigDecimal">
|
<select id="getLockedNumOne" resultType="java.math.BigDecimal">
|
||||||
SELECT num
|
SELECT SUM(lock_num) as num
|
||||||
FROM v_inventory_lock
|
FROM v_inventory_lock
|
||||||
WHERE factory_no=#{factoryNo} AND warehouse_no=#{warehouseNo} AND material_no=#{materialNo}
|
WHERE factory_no=#{factoryNo} AND warehouse_no=#{warehouseNo} AND material_no=#{materialNo}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="getLockList" resultType="com.nflg.wms.common.pojo.vo.InventoryLockVO">
|
||||||
|
SELECT *
|
||||||
|
FROM v_inventory_lock
|
||||||
|
WHERE factory_no=#{factoryNo} AND warehouse_no=#{warehouseNo} AND material_no=#{materialNo}
|
||||||
|
ORDER BY id DESC
|
||||||
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue