云
6 天以前 fd1efdba56dbf07943b82c971694579af034fc5a
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
package cn.iocoder.yudao.module.mes.service.wm.scrap;
 
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi;
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.scrap.MesWmScrapSaleDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.scrap.MesWmScrapSaleLineDO;
import cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstock.MesWmMaterialStockMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.wm.scrap.MesWmScrapReceiptMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.wm.scrap.MesWmScrapSaleLineMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.wm.scrap.MesWmScrapSaleMapper;
import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants;
import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransactionTypeEnum;
import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService;
import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.Comparator;
import java.util.Objects;
import java.util.Map;
 
@Service
public class MesWmScrapSaleService {
    public static final String PROCESS_KEY = "wm_scrap_sale_finance";
    @Resource private MesWmScrapSaleMapper saleMapper;
    @Resource private MesWmScrapSaleLineMapper lineMapper;
    @Resource private MesWmScrapReceiptMapper receiptMapper;
    @Resource private MesWmMaterialStockMapper stockMapper;
    @Resource private MesWmTransactionService transactionService;
    @Resource private BpmProcessInstanceApi processApi;
 
    @Transactional(rollbackFor = Exception.class)
    public void submit(Long id, Long userId) {
        MesWmScrapSaleDO sale = saleMapper.lockById(id);
        if (sale == null || !Objects.equals(sale.getStatus(), 0)) throw new ServiceException(400, "仅草稿可提交审批");
        var lines = lineMapper.selectBySaleId(id);
        if (lines.isEmpty()) throw new ServiceException(400, "出售单没有明细");
        // 财务审核不可被全局免审批绕过。
        if (processApi.isGlobalAutoApprove()) throw new ServiceException(400, "全局免审批已开启,废料出售必须经过财务审核");
        MesWmScrapSaleDO update = new MesWmScrapSaleDO();
        update.setId(id);
        update.setStatus(1);
        saleMapper.updateById(update);
        String processId = processApi.createProcessInstance(userId, new BpmProcessInstanceCreateReqDTO()
                .setProcessDefinitionKey(PROCESS_KEY).setBusinessKey(String.valueOf(id))
                .setVariables(Map.of("saleCode", sale.getCode(), "buyer", sale.getBuyer(),
                        "totalAmount", lines.stream().map(line -> line.getQuantity().multiply(line.getUnitPrice()))
                                .reduce(BigDecimal.ZERO, BigDecimal::add))));
        MesWmScrapSaleDO processUpdate = new MesWmScrapSaleDO();
        processUpdate.setId(id);
        processUpdate.setProcessInstanceId(processId);
        saleMapper.updateById(processUpdate);
    }
 
    @Transactional(rollbackFor = Exception.class)
    public void onApproval(Long id, String processId, Integer status) {
        MesWmScrapSaleDO sale = saleMapper.lockById(id);
        if (sale == null || !Objects.equals(sale.getStatus(), 1)) return;
        if (sale.getProcessInstanceId() != null && !sale.getProcessInstanceId().equals(processId)) return;
        if (Objects.equals(status, BpmProcessInstanceStatusEnum.APPROVE.getStatus())) {
            var lines = lineMapper.selectBySaleId(id);
            lines.sort(Comparator.comparing(MesWmScrapSaleLineDO::getMaterialStockId));
            for (MesWmScrapSaleLineDO line : lines) {
                var stock = stockMapper.lockById(line.getMaterialStockId());
                if (stock == null || receiptMapper.countByStockId(line.getMaterialStockId()) == 0)
                    throw new ServiceException(400, "废料库存不存在或已变动");
                BigDecimal available = zero(stock.getQuantity()).subtract(zero(stock.getFrozenQuantity())).subtract(zero(stock.getReservedQuantity()));
                if (available.compareTo(line.getQuantity()) < 0) throw new ServiceException(400, "废料可用库存不足,无法出库");
                Long transactionId = transactionService.createTransaction(new MesWmTransactionSaveReqDTO()
                        .setType(MesWmTransactionTypeEnum.OUT.getType()).setBizType(MesBizTypeConstants.WM_SCRAP_SALE)
                        .setBizId(id).setBizCode(sale.getCode()).setBizLineId(line.getId())
                        .setMaterialStockId(stock.getId()).setItemId(stock.getItemId()).setQuantity(line.getQuantity().negate())
                        .setWarehouseId(stock.getWarehouseId()).setLocationId(stock.getLocationId()).setAreaId(stock.getAreaId())
                        .setBatchId(stock.getBatchId()).setBatchCode(stock.getBatchCode()));
                MesWmScrapSaleLineDO updateLine = new MesWmScrapSaleLineDO();
                updateLine.setId(line.getId());
                updateLine.setTransactionId(transactionId);
                lineMapper.updateById(updateLine);
            }
            setStatus(id, 2);
        } else if (Objects.equals(status, BpmProcessInstanceStatusEnum.REJECT.getStatus())) {
            setStatus(id, 3);
        } else if (Objects.equals(status, BpmProcessInstanceStatusEnum.CANCEL.getStatus())) {
            setStatus(id, 4);
        }
    }
 
    private void setStatus(Long id, int status) {
        MesWmScrapSaleDO update = new MesWmScrapSaleDO();
        update.setId(id);
        update.setStatus(status);
        saleMapper.updateById(update);
    }
    private BigDecimal zero(BigDecimal value) { return value == null ? BigDecimal.ZERO : value; }
}