9 天以前 67c5d3ea86cfaad45c0150b96949dbcb6729b4d0
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
package cn.iocoder.yudao.module.mes.service.wm.stockreserve;
 
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.stockreserve.MesWmStockReserveDO;
import cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstock.MesWmMaterialStockMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.wm.stockreserve.MesWmStockReserveMapper;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmStockReserveStatusEnum;
import cn.iocoder.yudao.module.mes.service.wm.materialstock.MesWmMaterialStockService;
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 java.math.BigDecimal;
import java.util.List;
 
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
 
/**
 * MES 库存占用 Service 实现类
 */
@Service
@Validated
@Slf4j
public class MesWmStockReserveServiceImpl implements MesWmStockReserveService {
 
    @Resource
    private MesWmStockReserveMapper stockReserveMapper;
 
    @Resource
    private MesWmMaterialStockMapper materialStockMapper;
 
    @Resource
    private MesWmMaterialStockService materialStockService;
 
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createReserve(Long materialStockId, Integer bizType, Long bizId, String bizCode, Long bizLineId, Long itemId, BigDecimal quantity) {
        // 1. 校验库存记录存在
        MesWmMaterialStockDO stock = materialStockService.getMaterialStock(materialStockId);
        if (stock == null) {
            throw exception(WM_MATERIAL_STOCK_NOT_EXISTS);
        }
 
        // 2. 校验可用量充足(在库数量 - 冻结数量 - 已占用量 >= 本次占用数量)
        BigDecimal availableQty = stock.getQuantity()
                .subtract(stock.getFrozenQuantity() != null ? stock.getFrozenQuantity() : BigDecimal.ZERO)
                .subtract(stock.getReservedQuantity() != null ? stock.getReservedQuantity() : BigDecimal.ZERO);
        if (availableQty.compareTo(quantity) < 0) {
            throw exception(WM_MATERIAL_STOCK_INSUFFICIENT);
        }
 
        // 3. 创建占用记录
        MesWmStockReserveDO reserve = MesWmStockReserveDO.builder()
                .materialStockId(materialStockId)
                .bizType(bizType)
                .bizId(bizId)
                .bizCode(bizCode)
                .bizLineId(bizLineId)
                .itemId(itemId)
                .quantity(quantity)
                .status(MesWmStockReserveStatusEnum.RESERVING.getStatus())
                .build();
        stockReserveMapper.insert(reserve);
 
        // 4. 更新库存占用量字段(累加)
        int updatedRows = materialStockMapper.updateReservedQuantity(materialStockId, quantity, true);
        if (updatedRows == 0) {
            throw exception(WM_MATERIAL_STOCK_INSUFFICIENT);
        }
 
        log.info("[createReserve] 创建库存占用成功,materialStockId={}, bizType={}, bizId={}, quantity={}",
                materialStockId, bizType, bizId, quantity);
    }
 
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createReserveBatch(List<ReserveInfo> reserves) {
        if (CollUtil.isEmpty(reserves)) {
            return;
        }
        for (ReserveInfo reserve : reserves) {
            createReserve(reserve.materialStockId(), reserve.bizType(), reserve.bizId(),
                    reserve.bizCode(), reserve.bizLineId(), reserve.itemId(), reserve.quantity());
        }
    }
 
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void releaseReserve(Integer bizType, Long bizId) {
        // 1. 查询占用中的记录
        List<MesWmStockReserveDO> reserveList = stockReserveMapper.selectReservingListByBiz(bizType, bizId);
        if (CollUtil.isEmpty(reserveList)) {
            log.warn("[releaseReserve] 未找到占用记录,bizType={}, bizId={}", bizType, bizId);
            return;
        }
 
        // 2. 更新占用记录状态为已释放,并扣减库存占用量字段
        for (MesWmStockReserveDO reserve : reserveList) {
            // 2.1 更新占用记录状态
            stockReserveMapper.updateById(new MesWmStockReserveDO()
                    .setId(reserve.getId())
                    .setStatus(MesWmStockReserveStatusEnum.RELEASED.getStatus()));
 
            // 2.2 扣减库存占用量(负数表示减少)
            materialStockMapper.updateReservedQuantity(reserve.getMaterialStockId(), reserve.getQuantity().negate(), false);
        }
 
        log.info("[releaseReserve] 释放库存占用成功,bizType={}, bizId={}, count={}", bizType, bizId, reserveList.size());
    }
 
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void confirmReserveToOutbound(Integer bizType, Long bizId) {
        // 1. 查询占用中的记录
        List<MesWmStockReserveDO> reserveList = stockReserveMapper.selectReservingListByBiz(bizType, bizId);
        if (CollUtil.isEmpty(reserveList)) {
            log.warn("[confirmReserveToOutbound] 未找到占用记录,bizType={}, bizId={}", bizType, bizId);
            return;
        }
 
        // 2. 更新占用记录状态为已出库,并扣减库存占用量字段
        for (MesWmStockReserveDO reserve : reserveList) {
            // 2.1 更新占用记录状态
            stockReserveMapper.updateById(new MesWmStockReserveDO()
                    .setId(reserve.getId())
                    .setStatus(MesWmStockReserveStatusEnum.OUTBOUND.getStatus()));
 
            // 2.2 扣减库存占用量(负数表示减少)
            materialStockMapper.updateReservedQuantity(reserve.getMaterialStockId(), reserve.getQuantity().negate(), false);
        }
 
        log.info("[confirmReserveToOutbound] 确认占用转出库成功,bizType={}, bizId={}, count={}", bizType, bizId, reserveList.size());
    }
 
    @Override
    public List<MesWmStockReserveDO> getReserveListByBiz(Integer bizType, Long bizId) {
        return stockReserveMapper.selectListByBiz(bizType, bizId);
    }
 
    @Override
    public BigDecimal sumReservedQuantity(Long itemId, Long warehouseId) {
        if (warehouseId != null) {
            return stockReserveMapper.sumReservedQuantityByItemAndWarehouse(itemId, warehouseId);
        }
        return stockReserveMapper.sumReservedQuantityByItem(itemId);
    }
 
}