package cn.iocoder.yudao.module.erp.service.stock; import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.erp.controller.admin.stock.vo.stock.ErpStockPageReqVO; import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpStockDO; import cn.iocoder.yudao.module.erp.dal.mysql.stock.ErpStockMapper; import cn.iocoder.yudao.module.erp.service.product.ErpProductService; import cn.iocoder.yudao.module.erp.service.stock.ErpWarehouseService; import cn.iocoder.yudao.module.mdm.api.item.MdmItemSkuApi; import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemSkuRespDTO; import cn.iocoder.yudao.module.wms.api.inventory.WmsInventoryApi; import cn.iocoder.yudao.module.wms.api.inventory.dto.WmsInventoryQueryReqDTO; import cn.iocoder.yudao.module.wms.api.inventory.dto.WmsInventoryRespDTO; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import java.math.BigDecimal; import java.util.List; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.*; /** * ERP 产品库存 Service 实现类 * * 改造说明:ERP 库存调用 WMS 库存 API * - productId 对应 MDM itemId * - 通过 MDM SKU API 获取物料的默认 SKU * - 库存操作调用 WMS Inventory API * * @author 芋道源码 */ @Service @Validated public class ErpStockServiceImpl implements ErpStockService { /** * 允许库存为负数 * TODO 芋艿:后续做成 db 配置 */ private static final Boolean NEGATIVE_STOCK_COUNT_ENABLE = false; @Resource private ErpProductService productService; @Resource private ErpWarehouseService warehouseService; @Resource private ErpStockMapper stockMapper; @Resource private WmsInventoryApi wmsInventoryApi; @Resource private MdmItemSkuApi mdmItemSkuApi; @Override public ErpStockDO getStock(Long id) { return stockMapper.selectById(id); } @Override public ErpStockDO getStock(Long productId, Long warehouseId) { // 通过 MDM 获取产品的默认 SKU,然后查询 WMS 库存 Long skuId = getDefaultSkuId(productId); if (skuId == null) { return null; } // 查询 WMS 库存 BigDecimal quantity = wmsInventoryApi.getAvailableQuantity(skuId, warehouseId).getCheckedData(); if (quantity == null || quantity.compareTo(BigDecimal.ZERO) == 0) { return null; } // 转换为 ERP Stock DO ErpStockDO stock = new ErpStockDO(); stock.setProductId(productId); stock.setWarehouseId(warehouseId); stock.setCount(quantity); return stock; } @Override public BigDecimal getStockCount(Long productId) { // 通过 MDM 获取产品的默认 SKU,然后查询 WMS 库存总量 Long skuId = getDefaultSkuId(productId); if (skuId == null) { return BigDecimal.ZERO; } // 查询该 SKU 在所有仓库的库存 WmsInventoryQueryReqDTO queryReq = new WmsInventoryQueryReqDTO(); queryReq.setSkuIds(List.of(skuId)); queryReq.setOnlyPositive(true); List inventories = wmsInventoryApi.getInventoryList(queryReq).getCheckedData(); if (CollUtil.isEmpty(inventories)) { return BigDecimal.ZERO; } return inventories.stream() .map(WmsInventoryRespDTO::getQuantity) .filter(q -> q != null) .reduce(BigDecimal.ZERO, BigDecimal::add); } @Override public PageResult getStockPage(ErpStockPageReqVO pageReqVO) { // 暂时保留原逻辑,后续可改为调用 WMS 分页 API return stockMapper.selectPage(pageReqVO); } @Override public BigDecimal updateStockCountIncrement(Long productId, Long warehouseId, BigDecimal count) { // 通过 MDM 获取产品的默认 SKU Long skuId = getDefaultSkuId(productId); if (skuId == null) { throw exception(STOCK_COUNT_NEGATIVE2, productService.getProduct(productId).getName(), warehouseService.getWarehouse(warehouseId).getName()); } // 查询当前库存 BigDecimal currentStock = wmsInventoryApi.getAvailableQuantity(skuId, warehouseId).getCheckedData(); if (currentStock == null) { currentStock = BigDecimal.ZERO; } // 校验库存是否充足(出库时) if (!NEGATIVE_STOCK_COUNT_ENABLE && count.compareTo(BigDecimal.ZERO) < 0) { BigDecimal afterStock = currentStock.add(count); if (afterStock.compareTo(BigDecimal.ZERO) < 0) { throw exception(STOCK_COUNT_NEGATIVE, productService.getProduct(productId).getName(), warehouseService.getWarehouse(warehouseId).getName(), currentStock, count.abs()); } } // TODO: 调用 WMS 库存变更 API(需要 WMS 提供 increment/decrement 方法) // 暂时保留原逻辑,使用本地库存表 ErpStockDO stock = stockMapper.selectByProductIdAndWarehouseId(productId, warehouseId); if (stock == null) { stock = new ErpStockDO() .setProductId(productId) .setWarehouseId(warehouseId) .setCount(BigDecimal.ZERO); stockMapper.insert(stock); } int updateCount = stockMapper.updateCountIncrement(stock.getId(), count, NEGATIVE_STOCK_COUNT_ENABLE); if (updateCount == 0) { throw exception(STOCK_COUNT_NEGATIVE2, productService.getProduct(productId).getName(), warehouseService.getWarehouse(warehouseId).getName()); } return stock.getCount().add(count); } /** * 获取产品的默认 SKU ID * ERP productId 对应 MDM itemId,默认使用第一个 SKU */ private Long getDefaultSkuId(Long productId) { if (productId == null) { return null; } List skuList = mdmItemSkuApi.getItemSkuListByItemId(productId).getCheckedData(); if (CollUtil.isEmpty(skuList)) { return null; } return skuList.get(0).getId(); } }