|
|
|
|
@ -1,11 +1,18 @@
|
|
|
|
|
package cn.iocoder.yudao.module.erp.service.bitwms;
|
|
|
|
|
|
|
|
|
|
import cn.hutool.core.collection.CollUtil;
|
|
|
|
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
|
|
|
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
|
|
|
|
import cn.iocoder.yudao.module.common.enums.CodeTypeEnum;
|
|
|
|
|
import cn.iocoder.yudao.module.common.enums.QrcodeBizTypeEnum;
|
|
|
|
|
import cn.iocoder.yudao.module.common.service.qrcordrecord.QrcodeRecordService;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.controller.admin.autocode.util.AutoCodeUtil;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsInboundReqVO;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsLabelRespVO;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsLocationStockPageReqVO;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsLocationStockRecordPageReqVO;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsLocationStockRecordRespVO;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsLocationStockRespVO;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsMoveReqVO;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsOutboundReqVO;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.controller.admin.bitwms.vo.BitWmsScanRespVO;
|
|
|
|
|
@ -16,9 +23,17 @@ import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.move.ErpStockMoveSa
|
|
|
|
|
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutAuditReqVO;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutSaveReqVO;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.out.ErpStockOutSaveReqVOItem;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.dal.dataobject.bitwms.BitWmsLocationStockDO;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.dal.dataobject.bitwms.BitWmsLocationStockRecordDO;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockInDO;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockMoveDO;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockOutDO;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.dal.dataobject.warehousearea.WarehouseAreaDO;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.dal.dataobject.warehouselocation.WarehouseLocationDO;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.dal.mysql.bitwms.BitWmsLocationStockMapper;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.dal.mysql.bitwms.BitWmsLocationStockRecordMapper;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductMapper;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.dal.mysql.warehouselocation.WarehouseLocationMapper;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus;
|
|
|
|
|
@ -26,7 +41,10 @@ import cn.iocoder.yudao.module.erp.service.product.ErpProductService;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.service.stock.ErpStockInService;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.service.stock.ErpStockMoveService;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.service.stock.ErpStockOutService;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.service.stock.ErpStockService;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.service.stock.ErpWarehouseService;
|
|
|
|
|
import cn.iocoder.yudao.module.erp.service.warehousearea.WarehouseAreaService;
|
|
|
|
|
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
|
|
|
|
|
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
|
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
import org.springframework.validation.annotation.Validated;
|
|
|
|
|
@ -36,8 +54,14 @@ import java.math.BigDecimal;
|
|
|
|
|
import java.io.UnsupportedEncodingException;
|
|
|
|
|
import java.time.LocalDateTime;
|
|
|
|
|
import java.util.Collections;
|
|
|
|
|
import java.util.HashSet;
|
|
|
|
|
import java.util.LinkedHashMap;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
import java.util.Set;
|
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
import java.util.regex.Matcher;
|
|
|
|
|
import java.util.regex.Pattern;
|
|
|
|
|
|
|
|
|
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
|
|
|
|
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.PRODUCT_CODE_NOT_EXISTS;
|
|
|
|
|
@ -60,6 +84,7 @@ public class BitWmsServiceImpl implements BitWmsService {
|
|
|
|
|
private static final String BIT_WAREHOUSE_LOCATION_CODE_RULE = "BIT_WAREHOUSE_LOCATION_CODE";
|
|
|
|
|
private static final int SAMPLE_PRINT_TEMPLATE_TYPE = 7;
|
|
|
|
|
private static final int LOCATION_PRINT_TEMPLATE_TYPE = 8;
|
|
|
|
|
private static final Pattern QRCODE_BIZ_KEY_PATTERN = Pattern.compile("^(.+)[-_](\\d+)$");
|
|
|
|
|
|
|
|
|
|
@Resource
|
|
|
|
|
private ErpProductService productService;
|
|
|
|
|
@ -74,11 +99,19 @@ public class BitWmsServiceImpl implements BitWmsService {
|
|
|
|
|
@Resource
|
|
|
|
|
private ErpStockMoveService stockMoveService;
|
|
|
|
|
@Resource
|
|
|
|
|
private ErpStockService stockService;
|
|
|
|
|
private ErpWarehouseService warehouseService;
|
|
|
|
|
@Resource
|
|
|
|
|
private WarehouseAreaService warehouseAreaService;
|
|
|
|
|
@Resource
|
|
|
|
|
private BitWmsLocationStockMapper locationStockMapper;
|
|
|
|
|
@Resource
|
|
|
|
|
private BitWmsLocationStockRecordMapper locationStockRecordMapper;
|
|
|
|
|
@Resource
|
|
|
|
|
private QrcodeRecordService qrcodeRecordService;
|
|
|
|
|
@Resource
|
|
|
|
|
private AutoCodeUtil autoCodeUtil;
|
|
|
|
|
@Resource
|
|
|
|
|
private AdminUserApi adminUserApi;
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
|
|
@ -111,6 +144,9 @@ public class BitWmsServiceImpl implements BitWmsService {
|
|
|
|
|
auditReqVO.setStatus(ErpAuditStatus.APPROVE.getStatus());
|
|
|
|
|
auditReqVO.setRemark(reqVO.getRemark() != null ? reqVO.getRemark() : "样品入库自动入库");
|
|
|
|
|
stockInService.auditStockIn(auditReqVO);
|
|
|
|
|
ErpStockInDO stockInDO = stockInService.getStockIn(id);
|
|
|
|
|
adjustLocationStock(product, location, reqVO.getCount(), "入库", SAMPLE_IN_TYPE, id,
|
|
|
|
|
stockInDO != null ? stockInDO.getNo() : null, reqVO.getRemark());
|
|
|
|
|
return id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -118,7 +154,10 @@ public class BitWmsServiceImpl implements BitWmsService {
|
|
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
|
|
public Long outbound(BitWmsOutboundReqVO reqVO) {
|
|
|
|
|
ErpProductRespVO product = validateBitSample(reqVO.getProductId());
|
|
|
|
|
validateStockEnough(reqVO.getProductId(), reqVO.getWarehouseId(), reqVO.getAreaId(), reqVO.getCount());
|
|
|
|
|
WarehouseLocationDO location = resolveOutboundLocation(reqVO);
|
|
|
|
|
Long warehouseId = location.getWarehouseId();
|
|
|
|
|
Long areaId = location.getAreaId();
|
|
|
|
|
validateLocationStockEnough(reqVO.getProductId(), location.getId(), reqVO.getCount());
|
|
|
|
|
|
|
|
|
|
ErpStockOutSaveReqVO stockOut = new ErpStockOutSaveReqVO();
|
|
|
|
|
stockOut.setOutType(SAMPLE_OUT_TYPE);
|
|
|
|
|
@ -127,8 +166,8 @@ public class BitWmsServiceImpl implements BitWmsService {
|
|
|
|
|
|
|
|
|
|
ErpStockOutSaveReqVOItem item = new ErpStockOutSaveReqVOItem();
|
|
|
|
|
item.setProductId(reqVO.getProductId());
|
|
|
|
|
item.setWarehouseId(reqVO.getWarehouseId());
|
|
|
|
|
item.setAreaId(reqVO.getAreaId());
|
|
|
|
|
item.setWarehouseId(warehouseId);
|
|
|
|
|
item.setAreaId(areaId);
|
|
|
|
|
item.setCount(reqVO.getCount());
|
|
|
|
|
item.setProductPrice(product.getPurchasePrice() != null ? product.getPurchasePrice() : BigDecimal.ZERO);
|
|
|
|
|
item.setRemark(reqVO.getRemark());
|
|
|
|
|
@ -139,6 +178,9 @@ public class BitWmsServiceImpl implements BitWmsService {
|
|
|
|
|
auditReqVO.setStatus(ErpAuditStatus.APPROVE.getStatus());
|
|
|
|
|
auditReqVO.setRemark(reqVO.getRemark() != null ? reqVO.getRemark() : "样品出库自动出库");
|
|
|
|
|
stockOutService.auditStockOut(auditReqVO);
|
|
|
|
|
ErpStockOutDO stockOutDO = stockOutService.getStockOut(id);
|
|
|
|
|
adjustLocationStock(product, location, reqVO.getCount().negate(), "出库", SAMPLE_OUT_TYPE, id,
|
|
|
|
|
stockOutDO != null ? stockOutDO.getNo() : null, buildOutboundRemark(reqVO.getOutReason(), reqVO.getRemark()));
|
|
|
|
|
return id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -146,7 +188,20 @@ public class BitWmsServiceImpl implements BitWmsService {
|
|
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
|
|
public Long move(BitWmsMoveReqVO reqVO) {
|
|
|
|
|
ErpProductRespVO product = validateBitSample(reqVO.getProductId());
|
|
|
|
|
validateStockEnough(reqVO.getProductId(), reqVO.getFromWarehouseId(), reqVO.getFromAreaId(), reqVO.getCount());
|
|
|
|
|
WarehouseLocationDO fromLocation = resolveLocation(reqVO.getFromLocationId());
|
|
|
|
|
WarehouseLocationDO toLocation = resolveLocation(reqVO.getToLocationId());
|
|
|
|
|
validateLocationStockEnough(reqVO.getProductId(), fromLocation.getId(), reqVO.getCount());
|
|
|
|
|
if (fromLocation.getId().equals(toLocation.getId())) {
|
|
|
|
|
throw exception(STOCK_COUNT_NEGATIVE2, reqVO.getProductId(), fromLocation.getId());
|
|
|
|
|
}
|
|
|
|
|
if (isSameWarehouseArea(fromLocation, toLocation)) {
|
|
|
|
|
String bizNo = buildLocationMoveNo();
|
|
|
|
|
Long recordId = adjustLocationStock(product, fromLocation, reqVO.getCount().negate(), "出库",
|
|
|
|
|
SAMPLE_MOVE_TYPE + "出", null, bizNo, reqVO.getRemark());
|
|
|
|
|
adjustLocationStock(product, toLocation, reqVO.getCount(), "入库", SAMPLE_MOVE_TYPE + "入", null,
|
|
|
|
|
bizNo, reqVO.getRemark());
|
|
|
|
|
return recordId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ErpStockMoveSaveReqVO stockMove = new ErpStockMoveSaveReqVO();
|
|
|
|
|
stockMove.setMoveTime(LocalDateTime.now());
|
|
|
|
|
@ -154,10 +209,10 @@ public class BitWmsServiceImpl implements BitWmsService {
|
|
|
|
|
|
|
|
|
|
ErpStockMoveSaveReqVO.Item item = new ErpStockMoveSaveReqVO.Item();
|
|
|
|
|
item.setProductId(reqVO.getProductId());
|
|
|
|
|
item.setFromWarehouseId(reqVO.getFromWarehouseId());
|
|
|
|
|
item.setFromAreaId(reqVO.getFromAreaId());
|
|
|
|
|
item.setToWarehouseId(reqVO.getToWarehouseId());
|
|
|
|
|
item.setToAreaId(reqVO.getToAreaId());
|
|
|
|
|
item.setFromWarehouseId(fromLocation.getWarehouseId());
|
|
|
|
|
item.setFromAreaId(fromLocation.getAreaId());
|
|
|
|
|
item.setToWarehouseId(toLocation.getWarehouseId());
|
|
|
|
|
item.setToAreaId(toLocation.getAreaId());
|
|
|
|
|
item.setCount(reqVO.getCount());
|
|
|
|
|
item.setProductPrice(product.getPurchasePrice() != null ? product.getPurchasePrice() : BigDecimal.ZERO);
|
|
|
|
|
item.setRemark(reqVO.getRemark());
|
|
|
|
|
@ -165,32 +220,106 @@ public class BitWmsServiceImpl implements BitWmsService {
|
|
|
|
|
|
|
|
|
|
Long id = stockMoveService.createStockMove(stockMove);
|
|
|
|
|
stockMoveService.updateStockMoveStatus(id, ErpAuditStatus.APPROVE.getStatus());
|
|
|
|
|
ErpStockMoveDO stockMoveDO = stockMoveService.getStockMove(id);
|
|
|
|
|
String bizNo = stockMoveDO != null ? stockMoveDO.getNo() : null;
|
|
|
|
|
adjustLocationStock(product, fromLocation, reqVO.getCount().negate(), "出库", SAMPLE_MOVE_TYPE + "出", id,
|
|
|
|
|
bizNo, reqVO.getRemark());
|
|
|
|
|
adjustLocationStock(product, toLocation, reqVO.getCount(), "入库", SAMPLE_MOVE_TYPE + "入", id,
|
|
|
|
|
bizNo, reqVO.getRemark());
|
|
|
|
|
return id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public BitWmsScanRespVO scan(String code) {
|
|
|
|
|
ErpProductDO product = productMapper.selectOne(ErpProductDO::getBarCode, code);
|
|
|
|
|
String scanCode = code != null ? code.trim() : "";
|
|
|
|
|
BitWmsScanRespVO qrcodeBizRespVO = scanByQrcodeBizKey(scanCode);
|
|
|
|
|
if (qrcodeBizRespVO != null) {
|
|
|
|
|
return qrcodeBizRespVO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ErpProductDO product = productMapper.selectOne(ErpProductDO::getBarCode, scanCode);
|
|
|
|
|
if (product != null && Boolean.TRUE.equals(product.getIsSample()) && BIT_BIZ_UNIT.equals(product.getBizUnit())) {
|
|
|
|
|
BitWmsScanRespVO respVO = new BitWmsScanRespVO();
|
|
|
|
|
respVO.setType(SAMPLE_TYPE);
|
|
|
|
|
respVO.setId(product.getId());
|
|
|
|
|
respVO.setCode(product.getBarCode());
|
|
|
|
|
respVO.setName(product.getName());
|
|
|
|
|
return respVO;
|
|
|
|
|
}
|
|
|
|
|
WarehouseLocationDO location = warehouseLocationMapper.selectByNo(code);
|
|
|
|
|
return buildSampleScanResp(product);
|
|
|
|
|
}
|
|
|
|
|
WarehouseLocationDO location = warehouseLocationMapper.selectByNo(scanCode);
|
|
|
|
|
if (location != null) {
|
|
|
|
|
BitWmsScanRespVO respVO = new BitWmsScanRespVO();
|
|
|
|
|
respVO.setType(LOCATION_TYPE);
|
|
|
|
|
respVO.setId(location.getId());
|
|
|
|
|
respVO.setCode(location.getCode());
|
|
|
|
|
respVO.setName(location.getName());
|
|
|
|
|
return respVO;
|
|
|
|
|
return buildLocationScanResp(location);
|
|
|
|
|
}
|
|
|
|
|
throw exception(PRODUCT_CODE_NOT_EXISTS);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private BitWmsScanRespVO scanByQrcodeBizKey(String code) {
|
|
|
|
|
Matcher matcher = QRCODE_BIZ_KEY_PATTERN.matcher(code);
|
|
|
|
|
if (!matcher.matches()) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
String bizType = matcher.group(1);
|
|
|
|
|
Long bizId = Long.valueOf(matcher.group(2));
|
|
|
|
|
if (QrcodeBizTypeEnum.PRODUCT.getCode().equalsIgnoreCase(bizType)) {
|
|
|
|
|
ErpProductDO product = productMapper.selectById(bizId);
|
|
|
|
|
if (product != null && Boolean.TRUE.equals(product.getIsSample()) && BIT_BIZ_UNIT.equals(product.getBizUnit())) {
|
|
|
|
|
return buildSampleScanResp(product);
|
|
|
|
|
}
|
|
|
|
|
throw exception(PRODUCT_CODE_NOT_EXISTS);
|
|
|
|
|
}
|
|
|
|
|
if (QrcodeBizTypeEnum.WAREHOUSE_LOCATION.getCode().equalsIgnoreCase(bizType)) {
|
|
|
|
|
WarehouseLocationDO location = warehouseLocationMapper.selectById(bizId);
|
|
|
|
|
if (location != null) {
|
|
|
|
|
return buildLocationScanResp(location);
|
|
|
|
|
}
|
|
|
|
|
throw exception(PRODUCT_CODE_NOT_EXISTS);
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private BitWmsScanRespVO buildSampleScanResp(ErpProductDO product) {
|
|
|
|
|
BitWmsScanRespVO respVO = new BitWmsScanRespVO();
|
|
|
|
|
respVO.setType(SAMPLE_TYPE);
|
|
|
|
|
respVO.setId(product.getId());
|
|
|
|
|
respVO.setCode(product.getBarCode());
|
|
|
|
|
respVO.setName(product.getName());
|
|
|
|
|
return respVO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private BitWmsScanRespVO buildLocationScanResp(WarehouseLocationDO location) {
|
|
|
|
|
BitWmsScanRespVO respVO = new BitWmsScanRespVO();
|
|
|
|
|
respVO.setType(LOCATION_TYPE);
|
|
|
|
|
respVO.setId(location.getId());
|
|
|
|
|
respVO.setCode(location.getCode());
|
|
|
|
|
respVO.setName(location.getName());
|
|
|
|
|
return respVO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public PageResult<BitWmsLocationStockRespVO> getLocationStockPage(BitWmsLocationStockPageReqVO pageReqVO) {
|
|
|
|
|
PageResult<BitWmsLocationStockDO> pageResult = locationStockMapper.selectPage(pageReqVO);
|
|
|
|
|
if (CollUtil.isEmpty(pageResult.getList())) {
|
|
|
|
|
return PageResult.empty(pageResult.getTotal());
|
|
|
|
|
}
|
|
|
|
|
LookupContext context = buildLookupContext(pageResult.getList(), null);
|
|
|
|
|
return BeanUtils.toBean(pageResult, BitWmsLocationStockRespVO.class,
|
|
|
|
|
stock -> fillLocationStockResp(stock, context));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public PageResult<BitWmsLocationStockRecordRespVO> getLocationStockRecordPage(BitWmsLocationStockRecordPageReqVO pageReqVO) {
|
|
|
|
|
PageResult<BitWmsLocationStockRecordDO> pageResult = locationStockRecordMapper.selectPage(pageReqVO);
|
|
|
|
|
if (CollUtil.isEmpty(pageResult.getList())) {
|
|
|
|
|
return PageResult.empty(pageResult.getTotal());
|
|
|
|
|
}
|
|
|
|
|
LookupContext context = buildLookupContext(null, pageResult.getList());
|
|
|
|
|
return BeanUtils.toBean(pageResult, BitWmsLocationStockRecordRespVO.class,
|
|
|
|
|
record -> fillLocationStockRecordResp(record, context));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public BigDecimal getLocationStockCount(Long productId, Long locationId) {
|
|
|
|
|
validateBitSample(productId);
|
|
|
|
|
resolveLocation(locationId);
|
|
|
|
|
BitWmsLocationStockDO stock = locationStockMapper.selectByProductIdAndLocationId(productId, locationId);
|
|
|
|
|
return stock != null && stock.getCount() != null ? stock.getCount() : BigDecimal.ZERO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public BitWmsLabelRespVO getSampleLabel(Long productId) {
|
|
|
|
|
ErpProductRespVO product = validateBitSample(productId);
|
|
|
|
|
@ -251,12 +380,180 @@ public class BitWmsServiceImpl implements BitWmsService {
|
|
|
|
|
return location;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void validateStockEnough(Long productId, Long warehouseId, Long areaId, BigDecimal count) {
|
|
|
|
|
ErpStockDO stock = stockService.getStock(productId, warehouseId, areaId);
|
|
|
|
|
private WarehouseLocationDO resolveOutboundLocation(BitWmsOutboundReqVO reqVO) {
|
|
|
|
|
return resolveLocation(reqVO.getLocationId());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private WarehouseLocationDO resolveLocation(Long locationId) {
|
|
|
|
|
WarehouseLocationDO location = warehouseLocationMapper.selectById(locationId);
|
|
|
|
|
if (location == null) {
|
|
|
|
|
throw exception(WAREHOUSE_LOCATION_NOT_EXISTS);
|
|
|
|
|
}
|
|
|
|
|
return location;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void validateLocationStockEnough(Long productId, Long locationId, BigDecimal count) {
|
|
|
|
|
BitWmsLocationStockDO stock = locationStockMapper.selectByProductIdAndLocationId(productId, locationId);
|
|
|
|
|
BigDecimal currentCount = stock != null && stock.getCount() != null ? stock.getCount() : BigDecimal.ZERO;
|
|
|
|
|
if (currentCount.compareTo(count) < 0) {
|
|
|
|
|
throw exception(STOCK_COUNT_NEGATIVE2, productId, warehouseId);
|
|
|
|
|
throw exception(STOCK_COUNT_NEGATIVE2, productId, locationId);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Long adjustLocationStock(ErpProductRespVO product, WarehouseLocationDO location, BigDecimal count,
|
|
|
|
|
String direction, String bizType, Long bizId, String bizNo, String remark) {
|
|
|
|
|
BitWmsLocationStockDO stock = locationStockMapper.selectByProductIdAndLocationId(product.getId(), location.getId());
|
|
|
|
|
if (stock == null) {
|
|
|
|
|
if (count.compareTo(BigDecimal.ZERO) < 0) {
|
|
|
|
|
throw exception(STOCK_COUNT_NEGATIVE2, product.getId(), location.getId());
|
|
|
|
|
}
|
|
|
|
|
stock = new BitWmsLocationStockDO()
|
|
|
|
|
.setProductId(product.getId())
|
|
|
|
|
.setWarehouseId(location.getWarehouseId())
|
|
|
|
|
.setAreaId(location.getAreaId())
|
|
|
|
|
.setLocationId(location.getId())
|
|
|
|
|
.setCount(count)
|
|
|
|
|
.setUnitId(product.getUnitId());
|
|
|
|
|
locationStockMapper.insert(stock);
|
|
|
|
|
} else {
|
|
|
|
|
int updated = locationStockMapper.updateCountIncrement(stock.getId(), count, false);
|
|
|
|
|
if (updated == 0 && count.compareTo(BigDecimal.ZERO) < 0) {
|
|
|
|
|
throw exception(STOCK_COUNT_NEGATIVE2, product.getId(), location.getId());
|
|
|
|
|
}
|
|
|
|
|
stock = locationStockMapper.selectById(stock.getId());
|
|
|
|
|
}
|
|
|
|
|
BitWmsLocationStockRecordDO record = new BitWmsLocationStockRecordDO()
|
|
|
|
|
.setProductId(product.getId())
|
|
|
|
|
.setWarehouseId(location.getWarehouseId())
|
|
|
|
|
.setAreaId(location.getAreaId())
|
|
|
|
|
.setLocationId(location.getId())
|
|
|
|
|
.setCount(count.abs())
|
|
|
|
|
.setTotalCount(stock.getCount())
|
|
|
|
|
.setUnitId(product.getUnitId())
|
|
|
|
|
.setBizDirection(direction)
|
|
|
|
|
.setBizType(bizType)
|
|
|
|
|
.setBizId(bizId)
|
|
|
|
|
.setBizNo(bizNo)
|
|
|
|
|
.setRemark(remark)
|
|
|
|
|
.setRecordTime(LocalDateTime.now());
|
|
|
|
|
locationStockRecordMapper.insert(record);
|
|
|
|
|
return record.getId();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean isSameWarehouseArea(WarehouseLocationDO fromLocation, WarehouseLocationDO toLocation) {
|
|
|
|
|
return fromLocation.getWarehouseId().equals(toLocation.getWarehouseId())
|
|
|
|
|
&& java.util.Objects.equals(fromLocation.getAreaId(), toLocation.getAreaId());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String buildLocationMoveNo() {
|
|
|
|
|
return "KWYK" + System.currentTimeMillis();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private LookupContext buildLookupContext(List<BitWmsLocationStockDO> stocks,
|
|
|
|
|
List<BitWmsLocationStockRecordDO> records) {
|
|
|
|
|
Set<Long> productIds = new HashSet<>();
|
|
|
|
|
Set<Long> warehouseIds = new HashSet<>();
|
|
|
|
|
Set<Long> areaIds = new HashSet<>();
|
|
|
|
|
Set<Long> locationIds = new HashSet<>();
|
|
|
|
|
Set<Long> creatorIds = new HashSet<>();
|
|
|
|
|
if (stocks != null) {
|
|
|
|
|
for (BitWmsLocationStockDO stock : stocks) {
|
|
|
|
|
collectCommonIds(productIds, warehouseIds, areaIds, locationIds,
|
|
|
|
|
stock.getProductId(), stock.getWarehouseId(), stock.getAreaId(), stock.getLocationId());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (records != null) {
|
|
|
|
|
for (BitWmsLocationStockRecordDO record : records) {
|
|
|
|
|
collectCommonIds(productIds, warehouseIds, areaIds, locationIds,
|
|
|
|
|
record.getProductId(), record.getWarehouseId(), record.getAreaId(), record.getLocationId());
|
|
|
|
|
if (record.getCreator() != null) {
|
|
|
|
|
creatorIds.add(Long.parseLong(record.getCreator()));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
LookupContext context = new LookupContext();
|
|
|
|
|
context.productMap = productIds.isEmpty() ? Collections.emptyMap() : productService.getProductVOMap(productIds);
|
|
|
|
|
context.warehouseMap = warehouseIds.isEmpty() ? Collections.emptyMap() : warehouseService.getWarehouseMap(warehouseIds);
|
|
|
|
|
context.areaMap = areaIds.isEmpty() ? Collections.emptyMap() : warehouseAreaService.getWarehouseAreaMap(areaIds);
|
|
|
|
|
context.locationMap = locationIds.isEmpty() ? Collections.emptyMap()
|
|
|
|
|
: warehouseLocationMapper.selectBatchIds(locationIds).stream()
|
|
|
|
|
.collect(Collectors.toMap(WarehouseLocationDO::getId, item -> item, (a, b) -> a));
|
|
|
|
|
context.userMap = creatorIds.isEmpty() ? Collections.emptyMap() : adminUserApi.getUserMap(creatorIds);
|
|
|
|
|
return context;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void collectCommonIds(Set<Long> productIds, Set<Long> warehouseIds, Set<Long> areaIds, Set<Long> locationIds,
|
|
|
|
|
Long productId, Long warehouseId, Long areaId, Long locationId) {
|
|
|
|
|
if (productId != null) {
|
|
|
|
|
productIds.add(productId);
|
|
|
|
|
}
|
|
|
|
|
if (warehouseId != null) {
|
|
|
|
|
warehouseIds.add(warehouseId);
|
|
|
|
|
}
|
|
|
|
|
if (areaId != null) {
|
|
|
|
|
areaIds.add(areaId);
|
|
|
|
|
}
|
|
|
|
|
if (locationId != null) {
|
|
|
|
|
locationIds.add(locationId);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void fillLocationStockResp(BitWmsLocationStockRespVO respVO, LookupContext context) {
|
|
|
|
|
ErpProductRespVO product = context.productMap.get(respVO.getProductId());
|
|
|
|
|
if (product != null) {
|
|
|
|
|
respVO.setProductName(product.getName());
|
|
|
|
|
respVO.setBarCode(product.getBarCode());
|
|
|
|
|
respVO.setSampleCategory(product.getSampleCategory());
|
|
|
|
|
respVO.setCustomerName(product.getCustomerName());
|
|
|
|
|
respVO.setUnitName(product.getUnitName());
|
|
|
|
|
}
|
|
|
|
|
fillLocationInfo(respVO.getWarehouseId(), respVO.getAreaId(), respVO.getLocationId(), context,
|
|
|
|
|
respVO::setWarehouseName, respVO::setAreaName, respVO::setLocationCode, respVO::setLocationName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void fillLocationStockRecordResp(BitWmsLocationStockRecordRespVO respVO, LookupContext context) {
|
|
|
|
|
ErpProductRespVO product = context.productMap.get(respVO.getProductId());
|
|
|
|
|
if (product != null) {
|
|
|
|
|
respVO.setProductName(product.getName());
|
|
|
|
|
respVO.setBarCode(product.getBarCode());
|
|
|
|
|
respVO.setUnitName(product.getUnitName());
|
|
|
|
|
}
|
|
|
|
|
fillLocationInfo(respVO.getWarehouseId(), respVO.getAreaId(), respVO.getLocationId(), context,
|
|
|
|
|
respVO::setWarehouseName, respVO::setAreaName, respVO::setLocationCode, respVO::setLocationName);
|
|
|
|
|
if (respVO.getCreator() != null) {
|
|
|
|
|
AdminUserRespDTO user = context.userMap.get(Long.parseLong(respVO.getCreator()));
|
|
|
|
|
if (user != null) {
|
|
|
|
|
respVO.setCreatorName(user.getNickname());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void fillLocationInfo(Long warehouseId, Long areaId, Long locationId, LookupContext context,
|
|
|
|
|
java.util.function.Consumer<String> warehouseSetter,
|
|
|
|
|
java.util.function.Consumer<String> areaSetter,
|
|
|
|
|
java.util.function.Consumer<String> locationCodeSetter,
|
|
|
|
|
java.util.function.Consumer<String> locationNameSetter) {
|
|
|
|
|
ErpWarehouseDO warehouse = context.warehouseMap.get(warehouseId);
|
|
|
|
|
if (warehouse != null) {
|
|
|
|
|
warehouseSetter.accept(warehouse.getName());
|
|
|
|
|
}
|
|
|
|
|
WarehouseAreaDO area = context.areaMap.get(areaId);
|
|
|
|
|
if (area != null) {
|
|
|
|
|
areaSetter.accept(area.getAreaName());
|
|
|
|
|
}
|
|
|
|
|
WarehouseLocationDO location = context.locationMap.get(locationId);
|
|
|
|
|
if (location != null) {
|
|
|
|
|
locationCodeSetter.accept(location.getCode());
|
|
|
|
|
locationNameSetter.accept(location.getName());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static class LookupContext {
|
|
|
|
|
private Map<Long, ErpProductRespVO> productMap;
|
|
|
|
|
private Map<Long, ErpWarehouseDO> warehouseMap;
|
|
|
|
|
private Map<Long, WarehouseAreaDO> areaMap;
|
|
|
|
|
private Map<Long, WarehouseLocationDO> locationMap;
|
|
|
|
|
private Map<Long, AdminUserRespDTO> userMap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String buildOutboundRemark(String outReason, String remark) {
|
|
|
|
|
|