新火炬后端单体项目初始化代码
cuilei
2 天以前 32863d68c09f45cd501fd3db59c7f13e57130fe4
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
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
package org.jeecg.modules.mes.service.impl;
 
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.modules.base.entity.Factory;
import org.jeecg.modules.base.entity.LineSideWarehouse;
import org.jeecg.modules.base.entity.Shift;
import org.jeecg.modules.base.entity.ShiftGroup;
import org.jeecg.modules.base.service.IFactoryService;
import org.jeecg.modules.base.service.ILineSideWarehouseService;
import org.jeecg.modules.base.service.IShiftGroupService;
import org.jeecg.modules.base.service.IShiftService;
import org.jeecg.modules.lsw.entity.LswMaterial;
import org.jeecg.modules.lsw.entity.LswMaterialInbound;
import org.jeecg.modules.lsw.entity.LswMaterialInventory;
import org.jeecg.modules.lsw.enums.MaterialCategoryEnum;
import org.jeecg.modules.lsw.enums.MaterialInboundCategory;
import org.jeecg.modules.lsw.enums.MaterialInventoryStatusEnum;
import org.jeecg.modules.lsw.service.ILswMaterialInboundService;
import org.jeecg.modules.lsw.service.ILswMaterialInventoryService;
import org.jeecg.modules.lsw.service.ILswMaterialService;
import org.jeecg.modules.mes.entity.*;
import org.jeecg.modules.mes.enums.ReportCategoryEnum;
import org.jeecg.modules.mes.mapper.MesWorkReportingMapper;
import org.jeecg.modules.mes.service.*;
import org.jeecg.modules.mes.utils.CommonUtils;
import org.jeecg.modules.pms.entity.PmsMaterialProcess;
import org.jeecg.modules.pms.service.IPmsMaterialProcessService;
import org.jeecg.modules.pms.service.IPmsProcessBillMaterialsService;
import org.jeecg.modules.pms.vo.ProcessBillMaterialsDetailVo;
import org.jeecg.modules.qms.entity.InspectionPlan;
import org.jeecg.modules.qms.entity.InspectionPlanItem;
import org.jeecg.modules.qms.enums.PlanCategoryEnum;
import org.jeecg.modules.qms.service.IInspectionPlanItemService;
import org.jeecg.modules.qms.service.IInspectionPlanService;
import org.jeecg.modules.sap.request.OrderLoadRequest;
import org.jeecg.modules.sap.request.OrderReportRequest;
import org.jeecg.modules.sap.service.OrderLoadService;
import org.jeecg.modules.sap.service.OrderReportService;
import org.jeecg.modules.system.service.ISysBusinessCodeRuleService;
import org.springframework.beans.factory.annotation.Autowired;
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.time.temporal.ChronoField;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
 
/**
 * @Description: 工单报工
 * @Author: jeecg-boot
 * @Date:   2025-07-04
 * @Version: V1.0
 */
@Slf4j
@Service
public class MesWorkReportingServiceImpl extends ServiceImpl<MesWorkReportingMapper, MesWorkReporting> implements IMesWorkReportingService {
 
    @Autowired
    private IMesProductionWorkOrderService mesProductionWorkOrderService;
    @Autowired
    private IMesProductionOrderService mesProductionOrderService;
    @Autowired
    private ILswMaterialService lswMaterialService;
    @Autowired
    private IFactoryService factoryService;
    @Autowired
    private IShiftService shiftService;
    @Autowired
    private IShiftGroupService shiftGroupService;
    @Autowired
    private ILineSideWarehouseService lineSideWarehouseService;
    @Autowired
    private ILswMaterialInboundService lswMaterialInboundService;
    @Autowired
    private IMesMaterialLoadingService mesMaterialLoadingService;
    @Autowired
    private IPmsProcessBillMaterialsService pmsProcessBillMaterialsService;
    @Autowired
    private IPmsMaterialProcessService pmsMaterialProcessService;
    @Autowired
    private ISysBusinessCodeRuleService sysBusinessCodeRuleService;
    @Autowired
    private OrderReportService orderReportService;
    @Autowired
    private OrderLoadService orderLoadService;
    @Autowired
    private IInspectionPlanService inspectionPlanService;
    @Autowired
    private IInspectionPlanItemService inspectionPlanItemService;
    @Autowired
    private IMesMaterialConsumptionDetailService mesMaterialConsumptionDetailService;
    @Autowired
    private ILswMaterialInventoryService lswMaterialInventoryService;
 
    @Override
    public List<MesWorkReporting> queryWorkReportingByWorkOrderId(String workOrderId) {
        return baseMapper.queryWorkReportingByWorkOrderId(workOrderId);
    }
 
    @Override
    public List<MesWorkReporting> queryWorkReportingByOrderId(String orderId) {
        return baseMapper.queryWorkReportingByOrderId(orderId);
    }
 
    @Override
    @Transactional(rollbackFor = Exception.class)
    public MesWorkReporting addReporting(MesWorkReporting mesWorkReporting) {
        MesProductionWorkOrder workOrder = mesProductionWorkOrderService.getById(mesWorkReporting.getWorkOrderId());
        if (workOrder == null) {
            throw new JeecgBootException("工单不存在!");
        }
        LswMaterial material = lswMaterialService.list(new LambdaQueryWrapper<LswMaterial>()
                        .eq(LswMaterial::getMaterialNumber, workOrder.getMaterialNumber())
                        .eq(LswMaterial::getDelFlag, CommonConstant.DEL_FLAG_0)).stream()
                .findAny().orElse(null);
        if (material == null) {
            throw new JeecgBootException("物料不存在!");
        }
        MaterialCategoryEnum materialCategory = MaterialCategoryEnum.fromName(material.getMaterialCategory());
        if (materialCategory == null) {
            throw new JeecgBootException("未知的物料类型!");
        }
 
        LineSideWarehouse lineSideWarehouse = lineSideWarehouseService.list(new LambdaQueryWrapper<LineSideWarehouse>()
                        .eq(LineSideWarehouse::getFactoryId, mesWorkReporting.getFactoryId())
                        .eq(LineSideWarehouse::getDelFlag, CommonConstant.DEL_FLAG_0))
                .stream().findAny().orElse(null);
        if (lineSideWarehouse == null) {
            throw new JeecgBootException("线边仓库不存在!");
        }
 
        //生产批次号
        LocalDate today = LocalDate.now();
        String yearLastTwo = today.format(DateTimeFormatter.ofPattern("yy"));
        String dayOfYearStr = today.format(DateTimeFormatter.ofPattern("DDD"));
        ShiftGroup shiftGroup = shiftGroupService.getById(workOrder.getGroupId());
        int currentPallets = workOrder.getFinishedPallets() + 1;
        String batchNumber = yearLastTwo + dayOfYearStr + shiftGroup.getGroupCode() + currentPallets;
        mesWorkReporting.setBatchNumber(batchNumber)
                .setWorkOrderCode(workOrder.getWorkOrderCode())
                .setWarehouseId(lineSideWarehouse.getId())
                .setWarehouseCode(lineSideWarehouse.getWarehouseCode())
                .setReporter(Objects.requireNonNull(CommonUtils.getCurrentUser()).getUsername())
                .setReportTime(new Date());
        String date = today.format(DateTimeFormatter.ofPattern("yyMMdd"));
        Factory factory = factoryService.getById(mesWorkReporting.getFactoryId());
        workOrder.setFactoryCode(factory.getFactoryCode());
        List<MesMaterialConsumptionDetail> consumptionDetailList = CollectionUtil.newArrayList();
        switch (materialCategory) {
            case FINISHED_PRODUCT:
                //成品报工
                consumptionDetailList = productReport(mesWorkReporting, workOrder, lineSideWarehouse);
                //生成检验工单
                //generateInspectionOrder(mesWorkReporting, workOrder);
                //拼接成品报工托号
                String palletNumber4 = sysBusinessCodeRuleService.generateBusinessCodeSeq("WorkReportingPalletNumber4");
                String finishedPalletNumber = material.getMaterialNumber() + date + palletNumber4;
                mesWorkReporting.setPalletNumber(finishedPalletNumber).setReportType(ReportCategoryEnum.FINISHED.name());
                break;
            case INNER_FLANGE:
            case OUTER_FLANGE:
                //半成品(内法兰、外法兰)报工
                consumptionDetailList = productReport(mesWorkReporting, workOrder, lineSideWarehouse);
                //拼接半成品报工托号
                Shift shift = shiftService.getById(workOrder.getShiftId());
                String palletNumber6 = sysBusinessCodeRuleService.generateBusinessCodeSeq("WorkReportingPalletNumber6");
                String halfPalletNumber = factory.getFactoryCode() + material.getMaterialNumber() + date + shift.getShiftCode() + palletNumber6;
                mesWorkReporting.setPalletNumber(halfPalletNumber).setReportType(ReportCategoryEnum.HALF.name());
                break;
            case BLANK:
                //热处理报工
                consumptionDetailList = heatTreatmentReport(mesWorkReporting, workOrder, lineSideWarehouse);
                mesWorkReporting.setReportType(ReportCategoryEnum.HEATTREATMENT.name());
 
        }
        //新增报工记录
        save(mesWorkReporting);
        consumptionDetailList.forEach(i -> i.setReportingId(mesWorkReporting.getId()));
        //保存物料消耗明细
        mesMaterialConsumptionDetailService.saveBatch(consumptionDetailList);
        //更新排产工单
        MesProductionWorkOrder productionWorkUpdateOrder = new MesProductionWorkOrder()
                .setId(workOrder.getId())
                .setActualQuantity(workOrder.getActualQuantity().add(mesWorkReporting.getQuantity()))
                .setFinishedPallets(workOrder.getFinishedPallets() + 1);
        mesProductionWorkOrderService.updateById(productionWorkUpdateOrder);
        //返回报工记录,用于托标签打印
        return mesWorkReporting;
    }
 
    //热处理报工
    private List<MesMaterialConsumptionDetail> heatTreatmentReport(MesWorkReporting mesWorkReporting, MesProductionWorkOrder workOrder, LineSideWarehouse lineSideWarehouse) {
        //1、入库热处理毛坯到对应线边库,热处理前后物料编码不发生变化,只需要更新热处理标识,所以此处不能直接调用线边库的入库方法,需要直接更新物料库存信息中的热处理标识字段
        LswMaterialInventory materialInventory = lswMaterialInventoryService.list(new LambdaQueryWrapper<LswMaterialInventory>()
                .eq(LswMaterialInventory::getWarehouseId, lineSideWarehouse.getId())
                .eq(LswMaterialInventory::getInventoryStatus, MaterialInventoryStatusEnum.OUTBOUND.name())
                .eq(LswMaterialInventory::getHeatTreatmentFlag, CommonConstant.STATUS_0)
                .apply("EXISTS (SELECT 1 FROM lsw_material t WHERE t.id = lsw_material_inventory.material_id AND t.material_number = {0} " +
                        "AND t.del_flag = {1} AND t.material_status = {2})", workOrder.getMaterialNumber(), CommonConstant.DEL_FLAG_0, CommonConstant.STATUS_1))
                .stream().findFirst().orElse(null);
        if (materialInventory == null) {
            throw new JeecgBootException("线边库无该物料库存信息!");
        }
        if (materialInventory.getQuantity().compareTo(mesWorkReporting.getQuantity()) != 0) {
            throw new JeecgBootException("报工数量不符合整批次数量要求!");
        }
        materialInventory.setHeatTreatmentFlag(CommonConstant.STATUS_1);
        materialInventory.setInventoryStatus(MaterialInventoryStatusEnum.NORMAL.name());
        lswMaterialInventoryService.updateById(materialInventory);
        //2、更新该批次号得上料记录
        MesMaterialLoading materialLoading = mesMaterialLoadingService.list(new LambdaQueryWrapper<MesMaterialLoading>()
                        .eq(MesMaterialLoading::getFactoryId, workOrder.getFactoryId())
                        .eq(MesMaterialLoading::getWarehouseId, lineSideWarehouse.getId())
                        .eq(MesMaterialLoading::getMaterialNumber, workOrder.getMaterialNumber())
                        .eq(MesMaterialLoading::getBatchNumber, materialInventory.getBatchNumber()))
                        .stream().findFirst().orElse(null);
        if (materialLoading == null) {
            throw new JeecgBootException("未找到该批次号的上料记录!");
        }
        materialLoading.setRemainingQuantity(BigDecimal.ZERO);
        mesMaterialLoadingService.updateById(materialLoading);
        //热处理报工,批次号取库存的整批批次号
        mesWorkReporting.setBatchNumber(materialInventory.getBatchNumber());
        //3、记录消耗明细
        MesMaterialConsumptionDetail materialConsumptionDetail = new MesMaterialConsumptionDetail()
                .setWorkOrderId(workOrder.getId())
                .setFactoryId(workOrder.getFactoryId())
                .setLoadingId(materialLoading.getId())
                .setQuantity(mesWorkReporting.getQuantity());
        return Collections.singletonList(materialConsumptionDetail);
    }
 
    //半成品(内法兰、外法兰)、成品报工
    private List<MesMaterialConsumptionDetail> productReport(MesWorkReporting mesWorkReporting, MesProductionWorkOrder workOrder, LineSideWarehouse lineSideWarehouse) {
        //1、入库 半成品/成品 到对应线边库
        LswMaterialInbound materialInbound = new LswMaterialInbound()
                .setFactoryId(workOrder.getFactoryId())
                .setWarehouseId(lineSideWarehouse.getId())
                .setMaterialNumber(workOrder.getMaterialNumber())
                .setMaterialName(workOrder.getMaterialName())
                .setBatchNumber(mesWorkReporting.getBatchNumber())
                .setQuantity(mesWorkReporting.getQuantity())
                .setInboundCategory(MaterialInboundCategory.PRODUCTION_INBOUND.name())//生产下线
                .setOriginalCode(lineSideWarehouse.getWarehouseCode())
                .setOriginalName(lineSideWarehouse.getWarehouseName());
        lswMaterialInboundService.inboundMaterial(materialInbound);
        //2、扣减使用毛坯库存(更新上料记录)或半成品物料库存(内法兰、外法兰、小内圈、配件等),按照 产线id、库存地id、物料编码 查询上料记录,按照时间从早到晚排序,优先扣减早的上料记录(先进先出)
        //先查询物料 BOM
        Map<String, ProcessBillMaterialsDetailVo> processBillMaterialsDetailMap = pmsProcessBillMaterialsService
                .queryMaterialsDetailByOrderIdAndMaterialNumber(mesWorkReporting.getOrderId(), workOrder.getMaterialNumber()).stream()
                .collect(Collectors.toMap(ProcessBillMaterialsDetailVo::getMaterialNumber, v1 -> v1, (v1, v2) -> v1));
        //查询上料记录
        Map<String, List<MesMaterialLoading>> materialLoadingRecordMap = mesMaterialLoadingService.list(new LambdaQueryWrapper<MesMaterialLoading>()
                        .eq(MesMaterialLoading::getFactoryId, workOrder.getFactoryId())
                        .eq(MesMaterialLoading::getWarehouseId, lineSideWarehouse.getId())
                        .in(MesMaterialLoading::getMaterialNumber, processBillMaterialsDetailMap.keySet())
                        .gt(MesMaterialLoading::getRemainingQuantity, BigDecimal.ZERO)).stream()
                .sorted(Comparator.comparing(MesMaterialLoading::getCreateTime))
                .collect(Collectors.groupingBy(MesMaterialLoading::getMaterialNumber));
        List<MesMaterialLoading> materialLoadingRecordUpdateList = CollectionUtil.newArrayList();
        List<MesMaterialConsumptionDetail> consumptionDetailAddList = CollectionUtil.newArrayList();
        for (String materialNumber : processBillMaterialsDetailMap.keySet()) {
            List<MesMaterialLoading> materialLoadingRecordList = materialLoadingRecordMap.get(materialNumber);
            if (materialLoadingRecordList.isEmpty()) {
                throw new JeecgBootException("未查询到相应物料的上料记录!");
            }
            //计算物料扣减数量
            ProcessBillMaterialsDetailVo processBillMaterialsDetailVo = processBillMaterialsDetailMap.get(materialNumber);
            BigDecimal quantity = processBillMaterialsDetailVo.getPerQuantity().multiply(mesWorkReporting.getQuantity());
            //扣减上料数量并记录物料消耗明细
            for (MesMaterialLoading mesMaterialLoading : materialLoadingRecordList) {
                //记录物料消耗明细
                MesMaterialConsumptionDetail materialConsumptionDetail = new MesMaterialConsumptionDetail()
                        .setOrderId(mesWorkReporting.getOrderId())
                        .setWorkOrderId(workOrder.getId())
                        .setFactoryId(workOrder.getFactoryId())
                        .setLoadingId(mesMaterialLoading.getId());
                if (mesMaterialLoading.getRemainingQuantity().compareTo(quantity) >= 0) {
                    mesMaterialLoading.setRemainingQuantity(mesMaterialLoading.getRemainingQuantity().subtract(quantity));
                    materialConsumptionDetail.setQuantity(quantity);
                    break;
                } else {
                    quantity = quantity.subtract(mesMaterialLoading.getRemainingQuantity());
                    materialConsumptionDetail.setQuantity(mesMaterialLoading.getRemainingQuantity());
                    mesMaterialLoading.setRemainingQuantity(BigDecimal.ZERO);
                }
                consumptionDetailAddList.add(materialConsumptionDetail);
            }
            materialLoadingRecordUpdateList.addAll(materialLoadingRecordList);
        }
        //更新上料记录
        mesMaterialLoadingService.updateBatchById(materialLoadingRecordUpdateList);
        MesProductionOrder productionOrder = mesProductionOrderService.getById(mesWorkReporting.getOrderId());
        //3、调用SAP投料接口(消耗的物料) OrderLoadService
        for (String materialNumber : processBillMaterialsDetailMap.keySet()) {
            ProcessBillMaterialsDetailVo processBillMaterialsDetailVo = processBillMaterialsDetailMap.get(materialNumber);
            OrderLoadRequest loadRequest = new OrderLoadRequest()
                    .setOrderCode(productionOrder.getOrderCode())
                    .setFactoryCode(workOrder.getFactoryCode())
                    .setMaterialNumber(materialNumber)
                    .setWarehouseCode(lineSideWarehouse.getWarehouseCode())
                    .setQuantity(processBillMaterialsDetailVo.getPerQuantity().multiply(mesWorkReporting.getQuantity()))
                    .setBatchNumber(mesWorkReporting.getBatchNumber())
                    .setProductionUnit(processBillMaterialsDetailVo.getProductionUnit());
            try {
                orderLoadService.productionOrderLoad(loadRequest);
            } catch (Exception e) {
                log.error("SAP生产订单投料异常!", e);
            }
        }
        //4、调用SAP工序报工(根据生产订单id查询对应的物料工序(半成品是多个工序,成品只有一个工序),按照工序号从小到大依次挨个报工;目前考虑异步执行) OrderReportService
        List<PmsMaterialProcess> processList = pmsMaterialProcessService.list(new LambdaQueryWrapper<PmsMaterialProcess>()
                .eq(PmsMaterialProcess::getOrderId, mesWorkReporting.getOrderId())
                .orderByAsc(PmsMaterialProcess::getProcessCode));
        for (PmsMaterialProcess process : processList) {
            OrderReportRequest reportRequest = new OrderReportRequest()
                    .setOrderCode(productionOrder.getOrderCode())
                    .setFactoryCode(workOrder.getFactoryCode())
                    .setProcessCode(process.getProcessCode())
                    .setQualifiedQuantity(mesWorkReporting.getQuantity())
                    .setWarehouseCode(lineSideWarehouse.getWarehouseCode())
                    .setBatchNumber(mesWorkReporting.getBatchNumber());
            try {
                orderReportService.productionOrderReport(reportRequest);
            } catch (Exception e) {
                log.error("SAP工序报工异常!", e);
            }
        }
        return consumptionDetailAddList;
    }
 
    //根据检验方案生成检验工单
    private void generateInspectionOrder(MesWorkReporting mesWorkReporting, MesProductionWorkOrder workOrder) {
        //1.根据物料编码查询检验方案
        InspectionPlan inspectionPlan = inspectionPlanService.list(new LambdaQueryWrapper<InspectionPlan>()
                .eq(InspectionPlan::getMaterialNumber, workOrder.getMaterialNumber())
                .eq(InspectionPlan::getPlanCategory, PlanCategoryEnum.COMPLETION_INSPECTION.name())
                .eq(InspectionPlan::getPlanStatus, CommonConstant.STATUS_1)
                .eq(InspectionPlan::getDelFlag, CommonConstant.DEL_FLAG_0)).stream().findFirst().orElse(null);
        if (inspectionPlan == null) {
            throw new JeecgBootException("未找到该物料的检验方案!");
        }
        List<InspectionPlanItem> inspectionPlanItemList = inspectionPlanItemService.list(new LambdaQueryWrapper<InspectionPlanItem>()
                .eq(InspectionPlanItem::getPlanId, inspectionPlan.getId())
                .orderByAsc(InspectionPlanItem::getSorter));
        if (inspectionPlanItemList.isEmpty()) {
            throw new JeecgBootException("未找到该物料的检验方案检验项明细!");
        }
        //2.生成检验工单
        //todo 检验工单目前还没有生成代码,没有功能
    }
 
}