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<WmsInventoryRespDTO> 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<ErpStockDO> 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<MdmItemSkuRespDTO> skuList = mdmItemSkuApi.getItemSkuListByItemId(productId).getCheckedData();
|
if (CollUtil.isEmpty(skuList)) {
|
return null;
|
}
|
return skuList.get(0).getId();
|
}
|
|
}
|