package cn.iocoder.yudao.module.wms.service.inventory;
|
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.module.wms.api.inventory.dto.*;
|
import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.WmsInventoryReservePageReqVO;
|
import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryReserveDO;
|
import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryTransactionDO;
|
import cn.iocoder.yudao.module.wms.dal.mysql.inventory.WmsInventoryReserveMapper;
|
import cn.iocoder.yudao.module.wms.dal.mysql.inventory.WmsInventoryTransactionMapper;
|
import cn.iocoder.yudao.module.wms.enums.inventory.WmsReserveStatusEnum;
|
import cn.iocoder.yudao.module.wms.enums.inventory.WmsTransactionTypeEnum;
|
import cn.iocoder.yudao.module.wms.service.inventory.dto.WmsInventoryChangeReqDTO;
|
import jakarta.annotation.Resource;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.validation.annotation.Validated;
|
|
import java.math.BigDecimal;
|
import java.time.LocalDateTime;
|
import java.time.format.DateTimeFormatter;
|
import java.util.List;
|
import java.util.UUID;
|
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.*;
|
|
/**
|
* WMS 库存预留 Service 实现类
|
*
|
* @author 芋道源码
|
*/
|
@Service
|
@Validated
|
@Slf4j
|
public class WmsInventoryReserveServiceImpl implements WmsInventoryReserveService {
|
|
@Resource
|
private WmsInventoryReserveMapper reserveMapper;
|
|
@Resource
|
private WmsInventoryTransactionMapper transactionMapper;
|
|
@Resource
|
private WmsInventoryService inventoryService;
|
|
@Resource
|
private WmsInventoryTransactionService transactionService;
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public String createReserve(WmsReserveReqDTO reqDTO) {
|
// 1. 校验可用库存
|
BigDecimal availableQuantity = inventoryService.getAvailableQuantity(reqDTO.getSkuId(), reqDTO.getWarehouseId());
|
if (availableQuantity.compareTo(reqDTO.getQuantity()) < 0) {
|
throw exception(INVENTORY_QUANTITY_NOT_ENOUGH_FOR_RESERVE,
|
reqDTO.getSkuId(), reqDTO.getWarehouseId(), availableQuantity, reqDTO.getQuantity());
|
}
|
|
// 2. 生成预留单号
|
String reserveNo = generateReserveNo();
|
|
// 3. 创建预留记录
|
WmsInventoryReserveDO reserve = BeanUtils.toBean(reqDTO, WmsInventoryReserveDO.class);
|
reserve.setReserveNo(reserveNo);
|
reserve.setReserveQuantity(reqDTO.getQuantity());
|
reserve.setUsedQuantity(BigDecimal.ZERO);
|
reserve.setStatus(WmsReserveStatusEnum.RESERVED.getStatus());
|
reserveMapper.insert(reserve);
|
|
// 4. 记录事务流水
|
transactionService.createTransaction(buildReserveTransaction(reserve, reqDTO.getQuantity()));
|
|
return reserveNo;
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void releaseReserve(String reserveNo) {
|
// 1. 查询预留记录
|
WmsInventoryReserveDO reserve = reserveMapper.selectByReserveNo(reserveNo);
|
if (reserve == null) {
|
throw exception(INVENTORY_RESERVE_NOT_EXISTS);
|
}
|
// 1.1 校验状态:只有预留中或部分使用状态可释放
|
if (reserve.getStatus() != WmsReserveStatusEnum.RESERVED.getStatus()
|
&& reserve.getStatus() != WmsReserveStatusEnum.PARTIAL_USED.getStatus()) {
|
throw exception(INVENTORY_RESERVE_STATUS_INVALID);
|
}
|
|
// 2. 计算释放数量
|
BigDecimal releaseQuantity = reserve.getReserveQuantity().subtract(reserve.getUsedQuantity());
|
|
// 3. 更新预留状态
|
reserve.setStatus(WmsReserveStatusEnum.RELEASED.getStatus());
|
reserveMapper.updateById(reserve);
|
|
// 4. 记录事务流水(释放为负数)
|
transactionService.createTransaction(buildReleaseTransaction(reserve, releaseQuantity.negate()));
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void useReserve(WmsUseReserveReqDTO reqDTO) {
|
// 1. 查询预留记录
|
WmsInventoryReserveDO reserve = reserveMapper.selectByReserveNo(reqDTO.getReserveNo());
|
if (reserve == null) {
|
throw exception(INVENTORY_RESERVE_NOT_EXISTS);
|
}
|
// 1.1 校验状态
|
if (reserve.getStatus() != WmsReserveStatusEnum.RESERVED.getStatus()
|
&& reserve.getStatus() != WmsReserveStatusEnum.PARTIAL_USED.getStatus()) {
|
throw exception(INVENTORY_RESERVE_STATUS_INVALID);
|
}
|
|
// 2. 计算剩余可使用数量
|
BigDecimal remainQuantity = reserve.getReserveQuantity().subtract(reserve.getUsedQuantity());
|
if (reqDTO.getQuantity().compareTo(remainQuantity) > 0) {
|
throw exception(INVENTORY_RESERVE_QUANTITY_NOT_ENOUGH, reqDTO.getReserveNo(), remainQuantity, reqDTO.getQuantity());
|
}
|
|
// 3. 更新已使用数量和状态
|
BigDecimal newUsedQuantity = reserve.getUsedQuantity().add(reqDTO.getQuantity());
|
reserve.setUsedQuantity(newUsedQuantity);
|
if (newUsedQuantity.compareTo(reserve.getReserveQuantity()) == 0) {
|
reserve.setStatus(WmsReserveStatusEnum.USED.getStatus());
|
} else {
|
reserve.setStatus(WmsReserveStatusEnum.PARTIAL_USED.getStatus());
|
}
|
reserveMapper.updateById(reserve);
|
}
|
|
@Override
|
public List<WmsInventoryReserveDO> getReserveListByBiz(Integer bizType, Long bizId) {
|
return reserveMapper.selectListByBiz(bizType, bizId);
|
}
|
|
@Override
|
public PageResult<WmsInventoryReserveDO> getReservePage(WmsInventoryReservePageReqVO reqVO) {
|
return reserveMapper.selectPage(reqVO);
|
}
|
|
@Override
|
public WmsInventoryReserveDO getReserve(Long id) {
|
return reserveMapper.selectById(id);
|
}
|
|
@Override
|
public BigDecimal getReserveQuantity(Long skuId, Long warehouseId) {
|
return reserveMapper.selectReserveQuantity(skuId, warehouseId);
|
}
|
|
/**
|
* 生成预留单号
|
*/
|
private String generateReserveNo() {
|
return "RES" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"))
|
+ UUID.randomUUID().toString().substring(0, 8).toUpperCase();
|
}
|
|
/**
|
* 构建预留事务流水
|
*/
|
private WmsInventoryTransactionDO buildReserveTransaction(WmsInventoryReserveDO reserve, BigDecimal quantity) {
|
return WmsInventoryTransactionDO.builder()
|
.transactionNo(generateTransactionNo())
|
.transactionType(WmsTransactionTypeEnum.RESERVE.getType())
|
.bizType(reserve.getBizType())
|
.bizId(reserve.getBizId())
|
.bizNo(reserve.getBizNo())
|
.skuId(reserve.getSkuId())
|
.warehouseId(reserve.getWarehouseId())
|
.quantity(quantity)
|
.reserveId(reserve.getId())
|
.reserveNo(reserve.getReserveNo())
|
.transactionTime(LocalDateTime.now())
|
.remark(reserve.getRemark())
|
.build();
|
}
|
|
/**
|
* 构建释放事务流水
|
*/
|
private WmsInventoryTransactionDO buildReleaseTransaction(WmsInventoryReserveDO reserve, BigDecimal quantity) {
|
return WmsInventoryTransactionDO.builder()
|
.transactionNo(generateTransactionNo())
|
.transactionType(WmsTransactionTypeEnum.RELEASE.getType())
|
.bizType(reserve.getBizType())
|
.bizId(reserve.getBizId())
|
.bizNo(reserve.getBizNo())
|
.skuId(reserve.getSkuId())
|
.warehouseId(reserve.getWarehouseId())
|
.quantity(quantity)
|
.reserveId(reserve.getId())
|
.reserveNo(reserve.getReserveNo())
|
.transactionTime(LocalDateTime.now())
|
.remark("释放预留")
|
.build();
|
}
|
|
/**
|
* 生成事务流水号
|
*/
|
private String generateTransactionNo() {
|
return "TRX" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))
|
+ UUID.randomUUID().toString().substring(0, 6).toUpperCase();
|
}
|
|
}
|