2026-06-29 940c8481d2fdcf51341db4ccd6fd6fcc2d43debb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
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();
    }
 
}