5 天以前 0d7d874912d0147376826b55667a1deb6547ed91
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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
package com.ruoyi.production.service.impl;
 
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.production.mapper.*;
import com.ruoyi.production.util.TaskPlanQuantityUtil;
import com.ruoyi.technology.mapper.*;
import com.ruoyi.production.pojo.*;
import com.ruoyi.production.service.ProductionOrderRoutingOperationService;
import com.ruoyi.production.service.ProductionProductMainService;
import com.ruoyi.technology.pojo.*;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
 
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
 
@Service
@Transactional(rollbackFor = Exception.class)
@RequiredArgsConstructor
public class ProductionOrderRoutingOperationServiceImpl extends ServiceImpl<ProductionOrderRoutingOperationMapper, ProductionOrderRoutingOperation>
        implements ProductionOrderRoutingOperationService {
 
    private final ProductionOrderRoutingOperationMapper productionOrderRoutingOperationMapper;
    private final ProductionOperationTaskMapper productionOperationTaskMapper;
    private final ProductionProductMainMapper productionProductMainMapper;
    private final ProductionProductMainService productionProductMainService;
    private final TechnologyOperationParamMapper technologyOperationParamMapper;
    private final TechnologyParamMapper technologyParamMapper;
    private final ProductionOrderRoutingOperationParamMapper productionOrderRoutingOperationParamMapper;
    private final ProductionOrderMapper productionOrderMapper;
    private final ProductionOrderRoutingMapper productionOrderRoutingMapper;
    private final ProductionOrderBomMapper productionOrderBomMapper;
    private final ProductionBomStructureMapper productionBomStructureMapper;
    private final TechnologyRoutingOperationMapper technologyRoutingOperationMapper;
 
    @Override
    public R addRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation) {
        // 新增工艺路线
        int insert = productionOrderRoutingOperationMapper.insert(productionOrderRoutingOperation);
        //工序关联的参数需要同步新增
        List<TechnologyOperationParam> technologyOperationParams = technologyOperationParamMapper.selectList(Wrappers.<TechnologyOperationParam>lambdaQuery()
                .eq(TechnologyOperationParam::getTechnologyOperationId, productionOrderRoutingOperation.getTechnologyOperationId()));
        // 参数与前置条件校验
        if (CollectionUtils.isNotEmpty(technologyOperationParams)){
            ArrayList<ProductionOrderRoutingOperationParam> productionOrderRoutingOperationParams = new ArrayList<>();
        // 遍历处理数据并组装结果
            for (TechnologyOperationParam technologyOperationParam : technologyOperationParams) {
                TechnologyParam technologyParam = technologyParamMapper.selectById(technologyOperationParam.getTechnologyParamId());
                ProductionOrderRoutingOperationParam productionOrderRoutingOperationParam = new ProductionOrderRoutingOperationParam();
                productionOrderRoutingOperationParam.setProductionOrderId(productionOrderRoutingOperation.getProductionOrderId());
                productionOrderRoutingOperationParam.setProductionOrderRoutingOperationId(productionOrderRoutingOperation.getId());
                productionOrderRoutingOperationParam.setParamCode(technologyParam.getParamCode());
                productionOrderRoutingOperationParam.setParamName(technologyParam.getParamName());
                productionOrderRoutingOperationParam.setParamType(technologyParam.getParamType());
                productionOrderRoutingOperationParam.setParamFormat(technologyParam.getParamFormat());
                productionOrderRoutingOperationParam.setUnit(technologyParam.getUnit());
                productionOrderRoutingOperationParam.setIsRequired(technologyParam.getIsRequired());
                productionOrderRoutingOperationParam.setRemark(technologyParam.getRemark());
                productionOrderRoutingOperationParam.setParamId(technologyParam.getId());
                productionOrderRoutingOperationParam.setTechnologyOperationId(productionOrderRoutingOperation.getTechnologyOperationId());
                productionOrderRoutingOperationParams.add(productionOrderRoutingOperationParam);
            }
            productionOrderRoutingOperationParamMapper.insert(productionOrderRoutingOperationParams);
        }
        String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        if (insert > 0) {
            ProductionOperationTask lastTask = productionOperationTaskMapper.selectOne(
                    Wrappers.<ProductionOperationTask>lambdaQuery()
                            .likeRight(ProductionOperationTask::getWorkOrderNo, "GD" + datePrefix)
                            .orderByDesc(ProductionOperationTask::getWorkOrderNo)
                            .last("limit 1"));
            int sequenceNumber = 1;
            if (lastTask != null && lastTask.getWorkOrderNo() != null) {
                String lastNo = lastTask.getWorkOrderNo();
                if (lastNo.startsWith("GD" + datePrefix)) {
                    String seqStr = lastNo.substring(("GD" + datePrefix).length());
                    try {
                        sequenceNumber = Integer.parseInt(seqStr) + 1;
                    } catch (NumberFormatException e) {
                        sequenceNumber = 1;
                    }
                }
            }
            String workOrderNoStr = "GD" + String.format("%s%03d", datePrefix, sequenceNumber);
            ProductionOperationTask productionOperationTask = new ProductionOperationTask();
            productionOperationTask.setProductionOrderRoutingOperationId(productionOrderRoutingOperation.getId());
            productionOperationTask.setProductionOrderId(productionOrderRoutingOperation.getProductionOrderId());
            productionOperationTask.setPlanQuantity(BigDecimal.ZERO);
            productionOperationTask.setCompleteQuantity(BigDecimal.ZERO);
            productionOperationTask.setWorkOrderNo(workOrderNoStr);
            productionOperationTask.setStatus(1);
            productionOperationTaskMapper.insert(productionOperationTask);
        }
        return R.ok();
    }
 
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R updateRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation) {
        Long operationId = productionOrderRoutingOperation.getId();
 
        // 更新工艺路线工序
        productionOrderRoutingOperationMapper.updateById(productionOrderRoutingOperation);
 
        // 重新查询完整记录(前端可能没有传递所有字段,如 productionOrderId)
        ProductionOrderRoutingOperation updatedOperation = productionOrderRoutingOperationMapper.selectById(operationId);
        if (updatedOperation == null) {
            throw new ServiceException("工艺路线工序不存在");
        }
 
        // 查询是否存在工单
        ProductionOperationTask productionOperationTask = productionOperationTaskMapper.selectOne(
                new LambdaQueryWrapper<ProductionOperationTask>()
                        .eq(ProductionOperationTask::getProductionOrderRoutingOperationId, operationId)
                        .last("limit 1"));
 
        // 根据是否需要生产进行处理
        Boolean isProduction = updatedOperation.getIsProduction();
 
        if (Boolean.TRUE.equals(isProduction)) {
            // 需要生产:检查工单是否存在,不存在则生成
            if (productionOperationTask == null) {
                ProductionOperationTask task = new ProductionOperationTask();
                task.setProductionOrderRoutingOperationId(updatedOperation.getId());
                task.setProductionOrderId(updatedOperation.getProductionOrderId());
                // 获取生产订单
                ProductionOrder productionOrder = productionOrderMapper.selectById(updatedOperation.getProductionOrderId());
                if (productionOrder == null) {
                    throw new ServiceException("生产订单不存在");
                }
 
                // 获取订单BOM
                ProductionOrderBom orderBom = productionOrderBomMapper.selectOne(
                        Wrappers.<ProductionOrderBom>lambdaQuery()
                                .eq(ProductionOrderBom::getProductionOrderId, productionOrder.getId()));
 
                // 确定根产品规格ID
                Long rootProductModelId = orderBom != null && orderBom.getProductModelId() != null
                        ? orderBom.getProductModelId()
                        : productionOrder.getProductModelId();
 
                // 获取BOM结构列表
                List<ProductionBomStructure> orderBomStructureList = orderBom == null || orderBom.getId() == null
                        ? Collections.emptyList()
                        : productionBomStructureMapper.selectList(
                        Wrappers.<ProductionBomStructure>lambdaQuery()
                                .eq(ProductionBomStructure::getProductionOrderBomId, orderBom.getId())
                                .orderByAsc(ProductionBomStructure::getId));
 
                // 构建工序需求量映射
                Map<String, BigDecimal> operationDemandedQuantityMap =
                        TaskPlanQuantityUtil.buildOperationDemandedQuantityMap(orderBomStructureList, rootProductModelId);
 
                // 获取工艺路线工序(用于计算计划数量)
                TechnologyRoutingOperation sourceOperation = technologyRoutingOperationMapper.selectById(
                        updatedOperation.getTechnologyRoutingOperationId());
                // 将原来的私有方法替换为调用工具类
                BigDecimal planQuantity = TaskPlanQuantityUtil.resolveTaskPlanQuantity(
                        sourceOperation,
                        operationDemandedQuantityMap,
                        productionOrder,
                        rootProductModelId);
                task.setPlanQuantity(planQuantity);
                task.setCompleteQuantity(BigDecimal.ZERO);
                task.setWorkOrderNo(generateNextTaskNo());
                task.setStatus(2);
                productionOperationTaskMapper.insert(task);
            }
        } else {
            // 不需要生产:检查工单是否存在
            if (productionOperationTask != null) {
                validateTaskCanRemove(productionOperationTask);
                // 没有报工,则删除工单
                productionOperationTaskMapper.deleteById(productionOperationTask.getId());
            }
        }
 
        return R.ok();
    }
 
    private void validateTaskCanRemove(ProductionOperationTask task) {
        if (task == null || task.getId() == null) {
            return;
        }
        if (defaultDecimal(task.getCompleteQuantity()).compareTo(BigDecimal.ZERO) > 0) {
            throw new ServiceException("工序已产生报工记录,无法根据 BOM 变更删除对应工序快照");
        }
        long reportCount = productionProductMainMapper.selectCount(
                Wrappers.<ProductionProductMain>lambdaQuery()
                        .eq(ProductionProductMain::getProductionOperationTaskId, task.getId()));
        if (reportCount > 0) {
            throw new ServiceException("工序已产生报工记录,无法根据 BOM 变更删除对应工单");
        }
    }
 
    private BigDecimal defaultDecimal(BigDecimal value) {
        return value == null ? BigDecimal.ZERO : value;
    }
 
    @Override
    public R deleteRouteItem(Long id) {
        // 删除工艺路线
        try {
        // 查询并准备业务数据
            ProductionOperationTask productionOperationTask = productionOperationTaskMapper.selectOne(
                    new LambdaQueryWrapper<ProductionOperationTask>()
                            .eq(ProductionOperationTask::getProductionOrderRoutingOperationId, id)
                            .last("limit 1"));
        // 参数与前置条件校验
            if (productionOperationTask == null) {
                throw new RuntimeException("删除失败:未找到关联的生产工单");
            }
            if (productionOperationTask.getCompleteQuantity() != null
                    && BigDecimal.ZERO.compareTo(productionOperationTask.getCompleteQuantity()) < 0) {
                throw new RuntimeException("删除失败:该工单已开始生产,请先删除生产报工");
            }
            List<ProductionProductMain> productionProductMains = productionProductMainMapper.selectList(
                    new LambdaQueryWrapper<ProductionProductMain>()
                            .eq(ProductionProductMain::getProductionOperationTaskId, productionOperationTask.getId()));
        // 遍历处理数据并组装结果
            for (ProductionProductMain main : productionProductMains) {
                productionProductMainService.removeProductMain(main.getId());
            }
            Long productionOrderId = productionOperationTask.getProductionOrderId();
            Long routingId = null;
            ProductionOrderRoutingOperation deleteItem = productionOrderRoutingOperationMapper.selectById(id);
            if (deleteItem != null) {
                routingId = deleteItem.getOrderRoutingId();
            }
            productionOperationTaskMapper.delete(new LambdaQueryWrapper<ProductionOperationTask>()
                    .eq(ProductionOperationTask::getProductionOrderRoutingOperationId, id));
            productionOrderRoutingOperationMapper.deleteById(id);
            if (routingId != null) {
                List<ProductionOrderRoutingOperation> operationList = productionOrderRoutingOperationMapper.selectList(
                        Wrappers.<ProductionOrderRoutingOperation>lambdaQuery()
                                .eq(ProductionOrderRoutingOperation::getOrderRoutingId, routingId)
                                .eq(ProductionOrderRoutingOperation::getProductionOrderId, productionOrderId)
                                .orderByAsc(ProductionOrderRoutingOperation::getDragSort));
                for (int i = 0; i < operationList.size(); i++) {
                    ProductionOrderRoutingOperation item = operationList.get(i);
                    if (!Integer.valueOf(i + 1).equals(item.getDragSort())) {
                        item.setDragSort(i + 1);
        // 持久化或输出处理结果
                        productionOrderRoutingOperationMapper.updateById(item);
                    }
                }
            }
            return R.ok();
        } catch (Exception e) {
            throw new RuntimeException("删除生产工艺路线失败:" + e.getMessage());
        }
    }
 
    @Override
    public int sortRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation) {
        // 排序工艺路线
        ProductionOrderRoutingOperation oldItem = productionOrderRoutingOperationMapper.selectById(productionOrderRoutingOperation.getId());
        List<ProductionOrderRoutingOperation> operationList = productionOrderRoutingOperationMapper.selectList(
                Wrappers.<ProductionOrderRoutingOperation>lambdaQuery()
                        .eq(ProductionOrderRoutingOperation::getOrderRoutingId, oldItem.getOrderRoutingId())
                        .orderByAsc(ProductionOrderRoutingOperation::getDragSort));
        Integer targetPosition = productionOrderRoutingOperation.getDragSort();
        if (targetPosition != null && targetPosition >= 1) {
            operationList.removeIf(item -> item.getId().equals(oldItem.getId()));
            operationList.add(targetPosition - 1, oldItem);
            for (int i = 0; i < operationList.size(); i++) {
                ProductionOrderRoutingOperation item = operationList.get(i);
                int dragSort = i + 1;
                if (!Integer.valueOf(dragSort).equals(item.getDragSort())) {
                    item.setDragSort(dragSort);
                    productionOrderRoutingOperationMapper.updateById(item);
                }
            }
            return 1;
        }
        return 0;
    }
 
    private String generateNextTaskNo() {
        // 生成下一个生产工单号
        String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String prefix = "GD" + datePrefix;
        ProductionOperationTask lastTask = productionOperationTaskMapper.selectOne(
                Wrappers.<ProductionOperationTask>lambdaQuery()
                        .likeRight(ProductionOperationTask::getWorkOrderNo, prefix)
                        .orderByDesc(ProductionOperationTask::getWorkOrderNo)
                        .last("limit 1"));
        int sequence = 1;
        if (lastTask != null && lastTask.getWorkOrderNo() != null && lastTask.getWorkOrderNo().startsWith(prefix)) {
            try {
                sequence = Integer.parseInt(lastTask.getWorkOrderNo().substring(prefix.length())) + 1;
            } catch (NumberFormatException ignored) {
                sequence = 1;
            }
        }
        return prefix + String.format("%03d", sequence);
    }
}