package cn.iocoder.yudao.module.wms.api.inventory;
|
|
import cn.hutool.core.collection.CollUtil;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.module.wms.api.inventory.dto.*;
|
import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryDO;
|
import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryTransactionDO;
|
import cn.iocoder.yudao.module.wms.dal.mysql.inventory.WmsInventoryMapper;
|
import cn.iocoder.yudao.module.wms.enums.inventory.WmsTransactionTypeEnum;
|
import cn.iocoder.yudao.module.wms.service.inventory.dto.WmsInventoryChangeReqDTO;
|
import cn.iocoder.yudao.module.wms.service.inventory.WmsInventoryReserveService;
|
import cn.iocoder.yudao.module.wms.service.inventory.WmsInventoryService;
|
import cn.iocoder.yudao.module.wms.service.inventory.WmsInventoryTransactionService;
|
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 org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RestController;
|
|
import java.math.BigDecimal;
|
import java.time.LocalDateTime;
|
import java.time.format.DateTimeFormatter;
|
import java.util.ArrayList;
|
import java.util.List;
|
import java.util.UUID;
|
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
|
/**
|
* WMS 库存操作 API 实现类
|
*
|
* @author 芋道源码
|
*/
|
@RestController
|
@RequestMapping(WmsInventoryApi.PREFIX)
|
@Service
|
@Validated
|
@Slf4j
|
public class WmsInventoryApiImpl implements WmsInventoryApi {
|
|
@Resource
|
private WmsInventoryService inventoryService;
|
|
@Resource
|
private WmsInventoryReserveService reserveService;
|
|
@Resource
|
private WmsInventoryTransactionService transactionService;
|
|
@Resource
|
private WmsInventoryMapper inventoryMapper;
|
|
// ==================== 入库操作 ====================
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public CommonResult<WmsReceiptResultDTO> receipt(WmsReceiptReqDTO reqDTO) {
|
// 1. 构建库存变更请求
|
WmsInventoryChangeReqDTO changeReq = buildInventoryChangeReq(reqDTO);
|
|
// 2. 执行入库变更
|
inventoryService.changeInventory(changeReq);
|
|
// 3. 记录事务流水
|
List<WmsInventoryTransactionDO> transactions = buildReceiptTransactions(reqDTO);
|
transactionService.createTransactionList(transactions);
|
|
// 4. 构建返回结果
|
WmsReceiptResultDTO result = new WmsReceiptResultDTO();
|
result.setReceiptOrderNo(generateReceiptNo());
|
result.setTotalQuantity(calculateTotalQuantity(reqDTO.getItems()));
|
return success(result);
|
}
|
|
// ==================== 出库操作 ====================
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public CommonResult<WmsShipmentResultDTO> shipment(WmsShipmentReqDTO reqDTO) {
|
// 1. 如果有预留单号,先使用预留
|
if (reqDTO.getReserveNo() != null) {
|
WmsUseReserveReqDTO useReq = new WmsUseReserveReqDTO();
|
useReq.setReserveNo(reqDTO.getReserveNo());
|
useReq.setQuantity(calculateTotalQuantity(reqDTO.getItems()));
|
reserveService.useReserve(useReq);
|
}
|
|
// 2. 构建库存变更请求(出库为负数)
|
WmsInventoryChangeReqDTO changeReq = buildShipmentChangeReq(reqDTO);
|
|
// 3. 执行出库变更
|
inventoryService.changeInventory(changeReq);
|
|
// 4. 记录事务流水
|
List<WmsInventoryTransactionDO> transactions = buildShipmentTransactions(reqDTO);
|
transactionService.createTransactionList(transactions);
|
|
// 5. 构建返回结果
|
WmsShipmentResultDTO result = new WmsShipmentResultDTO();
|
result.setShipmentOrderNo(generateShipmentNo());
|
result.setTotalQuantity(calculateTotalQuantity(reqDTO.getItems()));
|
return success(result);
|
}
|
|
// ==================== 库存预留 ====================
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public CommonResult<String> reserve(WmsReserveReqDTO reqDTO) {
|
return success(reserveService.createReserve(reqDTO));
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public CommonResult<Boolean> releaseReserve(String reserveNo) {
|
reserveService.releaseReserve(reserveNo);
|
return success(true);
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public CommonResult<Boolean> useReserve(WmsUseReserveReqDTO reqDTO) {
|
reserveService.useReserve(reqDTO);
|
return success(true);
|
}
|
|
// ==================== 库存查询 ====================
|
|
@Override
|
public CommonResult<List<WmsInventoryRespDTO>> getInventoryList(WmsInventoryQueryReqDTO reqDTO) {
|
// 1. 查询库存
|
List<WmsInventoryDO> inventories = inventoryMapper.selectListByQuery(reqDTO);
|
|
// 2. 转换结果
|
List<WmsInventoryRespDTO> results = new ArrayList<>();
|
for (WmsInventoryDO inventory : inventories) {
|
WmsInventoryRespDTO resp = BeanUtils.toBean(inventory, WmsInventoryRespDTO.class);
|
// 计算预留数量
|
BigDecimal reserveQuantity = reserveService.getReserveQuantity(
|
inventory.getSkuId(), inventory.getWarehouseId());
|
resp.setReserveQuantity(reserveQuantity);
|
resp.setAvailableQuantity(inventory.getQuantity().subtract(reserveQuantity));
|
results.add(resp);
|
}
|
return success(results);
|
}
|
|
@Override
|
public CommonResult<BigDecimal> getAvailableQuantity(Long skuId, Long warehouseId) {
|
return success(inventoryService.getAvailableQuantity(skuId, warehouseId));
|
}
|
|
// ==================== 私有方法 ====================
|
|
private WmsInventoryChangeReqDTO buildInventoryChangeReq(WmsReceiptReqDTO reqDTO) {
|
WmsInventoryChangeReqDTO changeReq = new WmsInventoryChangeReqDTO();
|
changeReq.setOrderType(reqDTO.getBizType());
|
changeReq.setOrderNo(reqDTO.getBizNo());
|
|
List<WmsInventoryChangeReqDTO.Item> items = new ArrayList<>();
|
for (WmsReceiptReqDTO.Item item : reqDTO.getItems()) {
|
WmsInventoryChangeReqDTO.Item changeItem = new WmsInventoryChangeReqDTO.Item();
|
changeItem.setSkuId(item.getSkuId());
|
changeItem.setWarehouseId(reqDTO.getWarehouseId());
|
changeItem.setQuantity(item.getQuantity()); // 入库为正数
|
changeItem.setPrice(item.getPrice());
|
changeItem.setRemark(item.getRemark());
|
items.add(changeItem);
|
}
|
changeReq.setItems(items);
|
return changeReq;
|
}
|
|
private WmsInventoryChangeReqDTO buildShipmentChangeReq(WmsShipmentReqDTO reqDTO) {
|
WmsInventoryChangeReqDTO changeReq = new WmsInventoryChangeReqDTO();
|
changeReq.setOrderType(reqDTO.getBizType());
|
changeReq.setOrderNo(reqDTO.getBizNo());
|
|
List<WmsInventoryChangeReqDTO.Item> items = new ArrayList<>();
|
for (WmsShipmentReqDTO.Item item : reqDTO.getItems()) {
|
WmsInventoryChangeReqDTO.Item changeItem = new WmsInventoryChangeReqDTO.Item();
|
changeItem.setSkuId(item.getSkuId());
|
changeItem.setWarehouseId(reqDTO.getWarehouseId());
|
changeItem.setQuantity(item.getQuantity().negate()); // 出库为负数
|
changeItem.setRemark(item.getRemark());
|
items.add(changeItem);
|
}
|
changeReq.setItems(items);
|
return changeReq;
|
}
|
|
private List<WmsInventoryTransactionDO> buildReceiptTransactions(WmsReceiptReqDTO reqDTO) {
|
List<WmsInventoryTransactionDO> transactions = new ArrayList<>();
|
for (WmsReceiptReqDTO.Item item : reqDTO.getItems()) {
|
WmsInventoryTransactionDO transaction = WmsInventoryTransactionDO.builder()
|
.transactionNo(generateTransactionNo())
|
.transactionType(WmsTransactionTypeEnum.RECEIPT.getType())
|
.bizType(reqDTO.getBizType())
|
.bizId(reqDTO.getBizId())
|
.bizNo(reqDTO.getBizNo())
|
.skuId(item.getSkuId())
|
.warehouseId(reqDTO.getWarehouseId())
|
.quantity(item.getQuantity())
|
.transactionTime(reqDTO.getReceiptTime() != null ? reqDTO.getReceiptTime() : LocalDateTime.now())
|
.remark(item.getRemark())
|
.build();
|
transactions.add(transaction);
|
}
|
return transactions;
|
}
|
|
private List<WmsInventoryTransactionDO> buildShipmentTransactions(WmsShipmentReqDTO reqDTO) {
|
List<WmsInventoryTransactionDO> transactions = new ArrayList<>();
|
for (WmsShipmentReqDTO.Item item : reqDTO.getItems()) {
|
WmsInventoryTransactionDO transaction = WmsInventoryTransactionDO.builder()
|
.transactionNo(generateTransactionNo())
|
.transactionType(WmsTransactionTypeEnum.SHIPMENT.getType())
|
.bizType(reqDTO.getBizType())
|
.bizId(reqDTO.getBizId())
|
.bizNo(reqDTO.getBizNo())
|
.skuId(item.getSkuId())
|
.warehouseId(reqDTO.getWarehouseId())
|
.quantity(item.getQuantity().negate())
|
.reserveNo(reqDTO.getReserveNo())
|
.transactionTime(reqDTO.getShipmentTime() != null ? reqDTO.getShipmentTime() : LocalDateTime.now())
|
.remark(item.getRemark())
|
.build();
|
transactions.add(transaction);
|
}
|
return transactions;
|
}
|
|
private BigDecimal calculateTotalQuantity(List<?> items) {
|
if (CollUtil.isEmpty(items)) {
|
return BigDecimal.ZERO;
|
}
|
BigDecimal total = BigDecimal.ZERO;
|
for (Object item : items) {
|
if (item instanceof WmsReceiptReqDTO.Item) {
|
total = total.add(((WmsReceiptReqDTO.Item) item).getQuantity());
|
} else if (item instanceof WmsShipmentReqDTO.Item) {
|
total = total.add(((WmsShipmentReqDTO.Item) item).getQuantity());
|
}
|
}
|
return total;
|
}
|
|
private String generateReceiptNo() {
|
return "RCPT" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))
|
+ UUID.randomUUID().toString().substring(0, 6).toUpperCase();
|
}
|
|
private String generateShipmentNo() {
|
return "SHIP" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))
|
+ UUID.randomUUID().toString().substring(0, 6).toUpperCase();
|
}
|
|
private String generateTransactionNo() {
|
return "TRX" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))
|
+ UUID.randomUUID().toString().substring(0, 6).toUpperCase();
|
}
|
|
}
|