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 receipt(WmsReceiptReqDTO reqDTO) { // 1. 构建库存变更请求 WmsInventoryChangeReqDTO changeReq = buildInventoryChangeReq(reqDTO); // 2. 执行入库变更 inventoryService.changeInventory(changeReq); // 3. 记录事务流水 List 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 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 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 reserve(WmsReserveReqDTO reqDTO) { return success(reserveService.createReserve(reqDTO)); } @Override @Transactional(rollbackFor = Exception.class) public CommonResult releaseReserve(String reserveNo) { reserveService.releaseReserve(reserveNo); return success(true); } @Override @Transactional(rollbackFor = Exception.class) public CommonResult useReserve(WmsUseReserveReqDTO reqDTO) { reserveService.useReserve(reqDTO); return success(true); } // ==================== 库存查询 ==================== @Override public CommonResult> getInventoryList(WmsInventoryQueryReqDTO reqDTO) { // 1. 查询库存 List inventories = inventoryMapper.selectListByQuery(reqDTO); // 2. 转换结果 List 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 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 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 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 buildReceiptTransactions(WmsReceiptReqDTO reqDTO) { List 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 buildShipmentTransactions(WmsShipmentReqDTO reqDTO) { List 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(); } }