yuan
2 天以前 6f0df10fdd0e55e5ed3e31b1720efd25e2bf02fb
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
package com.ruoyi.technology.service.impl;
 
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.basic.mapper.ProductModelMapper;
import com.ruoyi.basic.pojo.ProductModel;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.technology.bean.dto.TechnologyBomStructureDto;
import com.ruoyi.technology.bean.vo.TechnologyBomStructureVo;
import com.ruoyi.technology.mapper.TechnologyBomMapper;
import com.ruoyi.technology.mapper.TechnologyBomStructureMapper;
import com.ruoyi.technology.mapper.TechnologyOperationMapper;
import com.ruoyi.technology.pojo.TechnologyBom;
import com.ruoyi.technology.pojo.TechnologyBomStructure;
import com.ruoyi.technology.service.TechnologyBomStructureService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
 
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
 
@Service
@RequiredArgsConstructor
public class TechnologyBomStructureServiceImpl extends ServiceImpl<TechnologyBomStructureMapper, TechnologyBomStructure> implements TechnologyBomStructureService {
 
    private final TechnologyBomStructureMapper technologyBomStructureMapper;
    private final TechnologyBomMapper technologyBomMapper;
    private final ProductModelMapper productModelMapper;
    private final TechnologyOperationMapper technologyOperationMapper;
 
    /**
     * 全量同步 BOM 的扁平物料明细:一行只表示“某个物料规格在某道工序被消耗”。
     * 不再有父子层级、单位用量、需求数量和单位配置。
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addTechnologyBomStructure(TechnologyBomStructureDto dto) {
        Long bomId = dto.getBomId();
        if (bomId == null) {
            throw new ServiceException("BOM ID不能为空");
        }
        TechnologyBom bom = technologyBomMapper.selectById(bomId);
        if (bom == null) {
            throw new ServiceException("BOM不存在");
        }
 
        List<TechnologyBomStructureDto> detailList = dto.getDetailList() == null
                ? Collections.emptyList()
                : dto.getDetailList();
 
        List<TechnologyBomStructure> dbList = this.list(new LambdaQueryWrapper<TechnologyBomStructure>()
                .eq(TechnologyBomStructure::getBomId, bomId));
        Set<Long> dbIds = new HashSet<>();
        for (TechnologyBomStructure dbItem : dbList) {
            dbIds.add(dbItem.getId());
        }
 
        Set<Long> submittedIds = new HashSet<>();
        Set<String> relationKeys = new HashSet<>();
        List<TechnologyBomStructure> insertList = new ArrayList<>();
        List<TechnologyBomStructure> updateList = new ArrayList<>();
 
        for (TechnologyBomStructureDto item : detailList) {
            Long productModelId = item.getProductModelId();
            Long operationId = item.getOperationId();
            validateMaterial(bom, productModelId);
            validateOperation(operationId);
            if (!relationKeys.add(productModelId + "#" + operationId)) {
                throw new ServiceException("同一物料规格在同一工序下不能重复配置");
            }
 
            TechnologyBomStructure entity = new TechnologyBomStructure();
            entity.setBomId(bomId);
            entity.setProductModelId(productModelId);
            entity.setOperationId(operationId);
            // 扁平 BOM 不再使用层级和数量语义,历史列统一置空。
            entity.setParentId(null);
            entity.setUnitQuantity(null);
            entity.setDemandedQuantity(null);
            entity.setUnit(null);
 
            if (item.getId() == null) {
                insertList.add(entity);
            } else {
                if (!dbIds.contains(item.getId())) {
                    throw new ServiceException("BOM物料明细不存在或不属于当前BOM");
                }
                entity.setId(item.getId());
                submittedIds.add(item.getId());
                updateList.add(entity);
            }
        }
 
        Set<Long> deleteIds = new HashSet<>(dbIds);
        deleteIds.removeAll(submittedIds);
        if (!deleteIds.isEmpty()) {
            this.removeByIds(deleteIds);
        }
        if (!updateList.isEmpty()) {
            this.updateBatchById(updateList);
        }
        if (!insertList.isEmpty()) {
            this.saveBatch(insertList);
        }
        return true;
    }
 
    /**
     * 根据BOM查询扁平物料明细,按稳定顺序返回。
     */
    @Override
    public List<TechnologyBomStructureVo> listByBomId(Long bomId) {
        if (bomId == null) {
            return new ArrayList<>();
        }
        return technologyBomStructureMapper.listByBomId(bomId);
    }
 
    /**
     * 校验物料规格:必须存在,且不能是 BOM 自身的成品规格。
     */
    private void validateMaterial(TechnologyBom bom, Long productModelId) {
        if (productModelId == null) {
            throw new ServiceException("请选择物料规格");
        }
        ProductModel productModel = productModelMapper.selectById(productModelId);
        if (productModel == null) {
            throw new ServiceException("物料规格不存在");
        }
        if (productModelId.equals(bom.getProductModelId())) {
            throw new ServiceException("成品规格不能作为自身的物料");
        }
    }
 
    /**
     * 校验消耗工序必填且存在。
     */
    private void validateOperation(Long operationId) {
        if (operationId == null) {
            throw new ServiceException("请选择消耗工序");
        }
        if (technologyOperationMapper.selectById(operationId) == null) {
            throw new ServiceException("消耗工序不存在");
        }
    }
}