zouyu
2023-11-16 f2597f5b7a8da61748f3bcc972450d409de93c18
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
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
package com.chinaztt.mes.quality.utils;
 
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.BooleanUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.chinaztt.mes.basic.entity.Location;
import com.chinaztt.mes.basic.entity.WorkstationLocation;
import com.chinaztt.mes.basic.mapper.LocationMapper;
import com.chinaztt.mes.basic.mapper.WorkstationLocationMapper;
import com.chinaztt.mes.common.numgen.NumberGenerator;
import com.chinaztt.mes.quality.dto.DockingIfsConditionActiveDTO;
import com.chinaztt.mes.quality.dto.TestReportDockingIfsConditionDTO;
import com.chinaztt.mes.quality.entity.Apply;
import com.chinaztt.mes.quality.entity.ApplyPart;
import com.chinaztt.mes.quality.entity.FinishedProdInspQtyChangeEvent;
import com.chinaztt.mes.quality.entity.Report;
import com.chinaztt.mes.quality.mapper.ApplyPartMapper;
import com.chinaztt.mes.quality.mapper.FinishedProdInspQtyChangeEventMapper;
import com.chinaztt.mes.quality.mapper.QualityMainIfsReportMapper;
import com.chinaztt.mes.quality.mapper.ReportMapper;
import com.chinaztt.mes.quality.service.impl.ApplyPartServiceImpl;
import com.chinaztt.mes.warehouse.entity.Stock;
import com.chinaztt.mes.warehouse.mapper.StockMapper;
import com.chinaztt.mes.warehouse.util.StockUtils;
import com.chinaztt.mes.warehouse.util.TransactionType;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
 
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
 
/**
 * @Author: cxf
 * @Date: 2021/06/01 16:00
 */
@Service
@AllArgsConstructor
public class ReportUtils {
    private NumberGenerator<Report> reportNumberGenerator;
    private ReportMapper reportMapper;
    private WorkstationLocationMapper workstationLocationMapper;
    private LocationMapper locationMapper;
    private QualityMainIfsReportMapper qualityMainIfsReportMapper;
    private ApplyPartMapper applyPartMapper;
    private StockUtils stockUtils;
    private StockMapper stockMapper;
    private FinishedProdInspQtyChangeEventMapper finishedProdInspQtyChangeEventMapper;
 
    public void checkReportNo(Report report) {
        if (StringUtils.isBlank(report.getReportNo())) {
            // 1. 自动生成编号
            report.setReportNo(reportNumberGenerator.generateNumberWithPrefix(Report.DIGIT, Report.PREFIX, Report::getReportNo));
        }
 
        // 2.判断是否重复(无论是自定义的编号,还是自动生成的编号都需经过编号校重)
        List<Report> repeatNos = reportMapper.selectList(Wrappers.<Report>query().lambda().eq(Report::getReportNo, report.getReportNo()).ne(Report::getId, report.getId()));
        if (CollectionUtil.isNotEmpty(repeatNos)) {
            throw new RuntimeException("编号重复");
        }
    }
 
    /**
     * 根据产出明细系统编号判断产出对应的工序是否是最后一道工序
     * @param systemNo 产出明细系统编号
     * @return true:是最后一道工序;false:非最后一道工序
     */
    public Boolean isProdOutLastOperationBySystemNo(String systemNo){
        List<Boolean> booleanList = reportMapper.isProdOutLastOperationBySystemNo(systemNo);
        if(CollectionUtil.isEmpty(booleanList)){
            throw new RuntimeException("根据产出系统编号=" + systemNo + "->缺少关联条件->无法判断是否是最后一道工序的产出");
        }else if(booleanList.size() > 1){
            throw new RuntimeException("根据产出系统编号=" + systemNo + "查询出多个工艺工序关系");
        }else{
            return booleanList.get(0);
        }
    }
 
    /**
     * 根据产出系统编号查询工单对应的ifs合格品接收库位
     * @param systemNo
     * @return
     */
    public String getIfsLocationArrivedBySystemNo(String systemNo){
        Long mesLocId = workstationLocationMapper.selectQualifiedLocationIdBySystemNo(systemNo);
        if(mesLocId == null){
            throw new RuntimeException("产出系统号=" + systemNo + "->对应工单无合格品库位id信息");
        }
        Location location = locationMapper.selectById(mesLocId);
        if(StringUtils.isBlank(location.getIfsLocation())){
            throw new RuntimeException("该工单对应的合格库位未匹配ifs库位");
        }else{
            return location.getIfsLocation();
        }
    }
 
    /**
     * 根据产出系统编号、汇报材料id获取检测汇报对接ifs条件结果
     * @param systemNo 产出系统编号
     * @param applyPartId 汇报材料id
     * @return
     */
    public TestReportDockingIfsConditionDTO getDockingIfsCondition(String systemNo,Long applyPartId){
        if(StringUtils.isBlank(systemNo)){
            throw new RuntimeException("根据产出系统编号获取对接ifs总条件结果状态->系统编号传参为空");
        }
 
        //1.报检类型为产出报检
        //2.汇报类型为非成品检&&非批次首检&&非首检&&非erp报检
        //3.产出物料需要检测
        //4.产出物料不是虚拟件
        //5.产出工序是工艺路线中最后一道工序
        DockingIfsConditionActiveDTO dockingIfsConditionActiveDTO = reportMapper.getDockingIfsConditionActive(applyPartId);
        if(dockingIfsConditionActiveDTO == null){
            throw new RuntimeException("根据产出系统编号获取对接ifs总条件结果状态->数据异常->无法获取结果");
        }
 
        if(dockingIfsConditionActiveDTO.getPlanningMethod() == null || dockingIfsConditionActiveDTO.getReportType() == null){
            throw new RuntimeException("根据产出系统编号获取对接ifs总条件结果状态->数据异常->无法获取检测汇报类型||无法获取零件计划方法");
        }
 
        TestReportDockingIfsConditionDTO testReportDockingIfsConditionDTO = new TestReportDockingIfsConditionDTO();
 
        // 找出所有检测规则
        List<String> rules = applyPartMapper.selectTestRulesBySystemNo(systemNo);
 
        // 如果单独做成品检
        if (rules.size() == 1 && dockingIfsConditionActiveDTO.getReportType().equals(Apply.PRODUCT_APPLY)) {
            // 获取是否为工序库存
            List<Boolean> operationStockStatus = applyPartMapper.selectStockOperationStatus(systemNo);
            // 如果是工序库存,不进行对接
            if (CollectionUtil.isNotEmpty(operationStockStatus) && BooleanUtil.isFalse(operationStockStatus.get(0))) {
                dockingIfsConditionActiveDTO.setMainSwitch(true);
            } else {
                dockingIfsConditionActiveDTO.setMainSwitch(false);
            }
        } else if(!dockingIfsConditionActiveDTO.getIsErp() && dockingIfsConditionActiveDTO.getInspection() && dockingIfsConditionActiveDTO.getIsLast()){
            if(dockingIfsConditionActiveDTO.getPlanningMethod().equals("K") || dockingIfsConditionActiveDTO.getPlanningMethod().equals("P")){
                dockingIfsConditionActiveDTO.setMainSwitch(false);
            }else if(dockingIfsConditionActiveDTO.getReportType().equals("00outputfirst")|| dockingIfsConditionActiveDTO.getReportType().equals("03erp")|| dockingIfsConditionActiveDTO.getReportType().equals("06finishedproduct")|| dockingIfsConditionActiveDTO.getReportType().equals("07batchfirst")){
                dockingIfsConditionActiveDTO.setMainSwitch(false);
            }else{
                dockingIfsConditionActiveDTO.setMainSwitch(true);
            }
        } else{
            dockingIfsConditionActiveDTO.setMainSwitch(false);
        }
 
        if(dockingIfsConditionActiveDTO.getMainSwitch() && !dockingIfsConditionActiveDTO.getProdOutIfsSync()){
            testReportDockingIfsConditionDTO.setIsShopOrderRec(true);//需要对接ifs车间订单接收
        }
        if(dockingIfsConditionActiveDTO.getMainSwitch() && dockingIfsConditionActiveDTO.getProdOutIfsSync()){
            testReportDockingIfsConditionDTO.setIsShopOrderCancelRec(true);//需要对接ifs车间订单取消接收
        }
 
        if(false){//取消通过工序报工关系对应表记录是否存在判断工序报工开关状态,改为直接通过总开关及车间订单中是否工序报工字段状态判断
            if(dockingIfsConditionActiveDTO.getMainSwitch() && !qualityMainIfsReportMapper.isAlReportOperationBySystemNo(applyPartId) && dockingIfsConditionActiveDTO.getIsReportOperation()){
                testReportDockingIfsConditionDTO.setIsReportOperation(true);//需要对接ifs工序报工
            }
 
            if(dockingIfsConditionActiveDTO.getMainSwitch() && qualityMainIfsReportMapper.isAlReportOperationBySystemNo(applyPartId) && dockingIfsConditionActiveDTO.getIsReportOperation()){
                testReportDockingIfsConditionDTO.setIsCancelReportOperation(true);//需要对接ifs取消工序报工
            }
        }
 
        if(dockingIfsConditionActiveDTO.getMainSwitch() && dockingIfsConditionActiveDTO.getIsReportOperation()){
            testReportDockingIfsConditionDTO.setIsReportOperation(true);//需要对接ifs工序报工
            testReportDockingIfsConditionDTO.setIsCancelReportOperation(true);//需要对接ifs取消工序报工
        }
 
        return testReportDockingIfsConditionDTO;//返回封装好的条件结果
    }
 
    /**
     * 根据产出系统编号、汇报材料id获取检测汇报对接ifs条件结果
     * @param systemNo 产出系统编号
     * @param applyPartId 汇报材料id
     * @return
     */
    public TestReportDockingIfsConditionDTO getDockingIfsConditionV2(String systemNo,Long applyPartId){
        if(StringUtils.isBlank(systemNo)){
            throw new RuntimeException("根据产出系统编号获取对接ifs总条件结果状态->系统编号传参为空");
        }
 
        //1.报检类型为产出报检
        //2.汇报类型为非成品检&&非批次首检&&非首检&&非erp报检
        //3.产出物料需要检测
        //4.产出物料不是虚拟件
        //5.产出工序是工艺路线中最后一道工序
        DockingIfsConditionActiveDTO dockingIfsConditionActiveDTO = reportMapper.getDockingIfsConditionActive(applyPartId);
        if(dockingIfsConditionActiveDTO == null){
            throw new RuntimeException("根据产出系统编号获取对接ifs总条件结果状态->数据异常->无法获取结果");
        }
 
        if(dockingIfsConditionActiveDTO.getPlanningMethod() == null || dockingIfsConditionActiveDTO.getReportType() == null){
            throw new RuntimeException("根据产出系统编号获取对接ifs总条件结果状态->数据异常->无法获取检测汇报类型||无法获取零件计划方法");
        }
 
        TestReportDockingIfsConditionDTO testReportDockingIfsConditionDTO = new TestReportDockingIfsConditionDTO();
 
        // 找出所有检测规则
        List<String> rules = applyPartMapper.selectTestRulesBySystemNo(systemNo);
 
        // 如果单独做成品检
        if (rules.size() == 1 && dockingIfsConditionActiveDTO.getReportType().equals(Apply.PRODUCT_APPLY)) {
            // 获取是否为工序库存
            List<Boolean> operationStockStatus = applyPartMapper.selectStockOperationStatus(systemNo);
            // 如果是工序库存,不进行对接
            if (CollectionUtil.isNotEmpty(operationStockStatus) && BooleanUtil.isFalse(operationStockStatus.get(0))) {
                dockingIfsConditionActiveDTO.setMainSwitch(true);
            } else {
                dockingIfsConditionActiveDTO.setMainSwitch(false);
            }
        } else if(!dockingIfsConditionActiveDTO.getIsErp() && dockingIfsConditionActiveDTO.getInspection() && dockingIfsConditionActiveDTO.getIsLast()){
            if(dockingIfsConditionActiveDTO.getPlanningMethod().equals("K") || dockingIfsConditionActiveDTO.getPlanningMethod().equals("P")){
                dockingIfsConditionActiveDTO.setMainSwitch(false);
            }else if(dockingIfsConditionActiveDTO.getReportType().equals("00outputfirst")|| dockingIfsConditionActiveDTO.getReportType().equals("03erp")|| dockingIfsConditionActiveDTO.getReportType().equals("07batchfirst")){
                dockingIfsConditionActiveDTO.setMainSwitch(false);
            }else{
                dockingIfsConditionActiveDTO.setMainSwitch(true);
            }
        } else{
            dockingIfsConditionActiveDTO.setMainSwitch(false);
        }
 
        if(dockingIfsConditionActiveDTO.getMainSwitch() && !dockingIfsConditionActiveDTO.getProdOutIfsSync()){
            testReportDockingIfsConditionDTO.setIsShopOrderRec(true);//需要对接ifs车间订单接收
        }
        if(dockingIfsConditionActiveDTO.getMainSwitch() && dockingIfsConditionActiveDTO.getProdOutIfsSync()){
            testReportDockingIfsConditionDTO.setIsShopOrderCancelRec(true);//需要对接ifs车间订单取消接收
        }
 
        if(false){//取消通过工序报工关系对应表记录是否存在判断工序报工开关状态,改为直接通过总开关及车间订单中是否工序报工字段状态判断
            if(dockingIfsConditionActiveDTO.getMainSwitch() && !qualityMainIfsReportMapper.isAlReportOperationBySystemNo(applyPartId) && dockingIfsConditionActiveDTO.getIsReportOperation()){
                testReportDockingIfsConditionDTO.setIsReportOperation(true);//需要对接ifs工序报工
            }
 
            if(dockingIfsConditionActiveDTO.getMainSwitch() && qualityMainIfsReportMapper.isAlReportOperationBySystemNo(applyPartId) && dockingIfsConditionActiveDTO.getIsReportOperation()){
                testReportDockingIfsConditionDTO.setIsCancelReportOperation(true);//需要对接ifs取消工序报工
            }
        }
 
        if(dockingIfsConditionActiveDTO.getMainSwitch() && dockingIfsConditionActiveDTO.getIsReportOperation()){
            testReportDockingIfsConditionDTO.setIsReportOperation(true);//需要对接ifs工序报工
            testReportDockingIfsConditionDTO.setIsCancelReportOperation(true);//需要对接ifs取消工序报工
        }
 
        return testReportDockingIfsConditionDTO;//返回封装好的条件结果
    }
 
    /**
     * 根据产出系统唯一编号移库(针对成品检)
     * @param systemNo 产出系统编号
     * @param lotBatchNo 批次号
     * @param qtyArrived 合格数量
     * @param unqualifiedArrived 不合格数量
     * @param dir 业务类型码
     * @param reportId 检测汇报id
     * @param applyPartId 汇报材料id
     */
    public void autoMoveStockFinishedProduct(String systemNo, String lotBatchNo, BigDecimal qtyArrived, BigDecimal unqualifiedArrived, BigDecimal scrapArrived, String dir, Long reportId,Long applyPartId,Long replacePartId){
        //根据系统唯一编号查出零件id
        Long partId = applyPartMapper.selectPartIdBySystemNo(systemNo);
        if (partId == null) {
            throw new RuntimeException("移库对象零件查无零件基础数据");
        }
        //根据产出系统唯一编号查出对应工作站的库位
        Long inspectionLocationId = workstationLocationMapper.selectBySystemNo(systemNo, WorkstationLocation.INSPECTION_LOCATION);//产出待检库位
        Long disqualifiedLocationId = workstationLocationMapper.selectBySystemNo(systemNo, WorkstationLocation.DISQUALIFIED_LOCATION);//产出不合格品库位
        //Long qualifiedLocationId = workstationLocationMapper.selectBySystemNo(systemNo, WorkstationLocation.QUALIFIED_LOCATION);
        // 获取成品待检库位
        Long toQualifiedLocationId = workstationLocationMapper.selectFinishToQualifiedLocationIdBySystemNo(systemNo);
        //合格库位取工单中库位(一个工作站可能会配置多个合格品库位)
        Long qualifiedLocationId = workstationLocationMapper.selectQualifiedLocationIdBySystemNo(systemNo);//合格品库位
        if (inspectionLocationId != null && disqualifiedLocationId != null && qualifiedLocationId != null) {
            //判断合格数量是否变更
            BigDecimal qtyChange = BigDecimal.ZERO;
            if (toQualifiedLocationId != null) {
                qtyChange =getQtyArrivedChange(partId, toQualifiedLocationId, systemNo, lotBatchNo, qtyArrived, dir,
                        reportId,
                        applyPartId);
            }else {
                qtyChange =getQtyArrivedChange(partId, qualifiedLocationId, systemNo, lotBatchNo, qtyArrived, dir,
                        reportId,
                        applyPartId);
            }
            switch(qtyChange.compareTo(BigDecimal.ZERO)){
                case 0:
                    // 合格数量没有变化,且配置了待检成品库,则移到合格库
                    if (null != toQualifiedLocationId) {
                        if (org.apache.commons.lang3.StringUtils.equals(dir, ApplyPartServiceImpl.MOVELIBRARY)) {
                            if (replacePartId != null) {
                                stockUtils.replaceMove(partId, systemNo, lotBatchNo, qtyArrived, toQualifiedLocationId,
                                        qualifiedLocationId, replacePartId);
                            } else {
                                stockUtils.localMove(partId, systemNo, lotBatchNo, qtyArrived, toQualifiedLocationId,
                                        qualifiedLocationId);
                            }
                        } else {
                            if (replacePartId != null) {
                                stockUtils.replaceMove(replacePartId, systemNo, lotBatchNo, qtyArrived, qualifiedLocationId,
                                        toQualifiedLocationId, partId);
                            } else {
                                stockUtils.localMove(partId, systemNo, lotBatchNo, qtyArrived, qualifiedLocationId,
                                        toQualifiedLocationId);
                            }
                        }
                    }
                    break;//合格数量没有变更
                case 1:
                    //将变更的数量有合格品库位移至不合格品库位
                    //合格数量变少
                case -1:
                    FinishedProdInspQtyChangeEvent finishedProdInspQtyChangeEvent = new FinishedProdInspQtyChangeEvent();
                    //合格数量变多
                    if(dir.equals(ApplyPartServiceImpl.MOVELIBRARY)){
                        if (null != toQualifiedLocationId) {
                            // 配置了待检成品库,合格数量发生变化,发生变化的数量为不合格数量,移入不合格库;剩余数量为合格数量,移入合格库
                            if (replacePartId != null) {
                                stockUtils.replaceMove(replacePartId, systemNo, lotBatchNo, qtyChange, toQualifiedLocationId,
                                        disqualifiedLocationId, partId);
                            } else {
                                stockUtils.localMove(partId, systemNo, lotBatchNo, qtyChange, toQualifiedLocationId,
                                        disqualifiedLocationId);
                            }
                            // 有合格数量
                            if (qtyArrived.compareTo(BigDecimal.ZERO) != 0) {
                                stockUtils.localMove(partId, systemNo, lotBatchNo, qtyArrived,
                                        toQualifiedLocationId, qualifiedLocationId);
                                finishedProdInspQtyChangeEvent.setReportId(reportId);
                                finishedProdInspQtyChangeEvent.setApplyPartId(applyPartId);
                                finishedProdInspQtyChangeEvent.setSystemNo(systemNo);
                                finishedProdInspQtyChangeEvent.setQtyChange(qtyArrived);
                                finishedProdInspQtyChangeEventMapper.insert(finishedProdInspQtyChangeEvent);
                            }
                        } else {
                            //将变更的数量由合格品库位移至不合格品库位
                            if (replacePartId != null) {
                                stockUtils.replaceMove(partId, systemNo, lotBatchNo, qtyChange, qualifiedLocationId,
                                        disqualifiedLocationId, replacePartId);
                            } else {
                                stockUtils.localMove(partId, systemNo, lotBatchNo, qtyChange, qualifiedLocationId,
                                        disqualifiedLocationId);
                            }
                        }
 
                        //创建合格数量变更事件记录
                        finishedProdInspQtyChangeEvent.setReportId(reportId);
                        finishedProdInspQtyChangeEvent.setApplyPartId(applyPartId);
                        finishedProdInspQtyChangeEvent.setSystemNo(systemNo);
                        finishedProdInspQtyChangeEvent.setQtyChange(qtyChange);
                        finishedProdInspQtyChangeEventMapper.insert(finishedProdInspQtyChangeEvent);
 
                    }else if(dir.equals(ApplyPartServiceImpl.UNMOVELIBRARY)){
                        // 配置了待检成品库,将原来提交时,移入合格库位和不合格库位的数量还原到待检成品库
                        if (null != toQualifiedLocationId) {
                            if (replacePartId != null) {
                                stockUtils.replaceMove(replacePartId, systemNo, lotBatchNo, qtyChange, disqualifiedLocationId,
                                        toQualifiedLocationId, partId);
                            } else {
                                stockUtils.localMove(partId, systemNo, lotBatchNo, qtyChange, disqualifiedLocationId,
                                        toQualifiedLocationId);
                            }
                            if (qtyArrived.compareTo(BigDecimal.ZERO) != 0) {
                                if (replacePartId != null) {
                                    stockUtils.replaceMove(replacePartId, systemNo, lotBatchNo, qtyArrived, qualifiedLocationId,
                                            toQualifiedLocationId, partId);
                                } else {
                                    stockUtils.localMove(partId, systemNo, lotBatchNo, qtyArrived, qualifiedLocationId,
                                            toQualifiedLocationId);
                                }
                            }
                        }else {
                            //将变更的数量由不合格品库位移至合格品库位
                            if (replacePartId != null) {
                                stockUtils.replaceMove(replacePartId, systemNo, lotBatchNo, qtyChange, disqualifiedLocationId,
                                        qualifiedLocationId, partId);
                            } else {
                                stockUtils.localMove(partId, systemNo, lotBatchNo, qtyChange, disqualifiedLocationId,
                                        qualifiedLocationId);
                            }
                        }
 
                        //删除合格数量变更事件记录
                        finishedProdInspQtyChangeEventMapper.delByGroupUniqueKey(reportId,applyPartId,systemNo);
                    }else{
                        throw new RuntimeException("移库方向码异常->异常码=" + dir);
                    }
                    break;
                default:
                    throw new RuntimeException("成品检移库->合格数量变更值与0比较发生异常");
            }
        }
    }
 
    public void autoMoveStockFinishedProductV2(ApplyPart applyPart, String dir){
        //根据系统唯一编号查出零件id
        Long partId = applyPart.getPartId();
        if (partId == null) {
            throw new RuntimeException("移库对象零件查无零件基础数据");
        }
        //根据产出系统唯一编号查出对应工作站的库位
        Long inspectionLocationId = workstationLocationMapper.selectBySystemNo(applyPart.getSystemNo(), WorkstationLocation.INSPECTION_LOCATION);//产出待检库位
        Long disqualifiedLocationId = workstationLocationMapper.selectBySystemNo(applyPart.getSystemNo(), WorkstationLocation.DISQUALIFIED_LOCATION);//产出不合格品库位
        //Long qualifiedLocationId = workstationLocationMapper.selectBySystemNo(systemNo, WorkstationLocation.QUALIFIED_LOCATION);
        // 获取成品待检库位
        Long toQualifiedLocationId = workstationLocationMapper.selectFinishToQualifiedLocationIdBySystemNo(applyPart.getSystemNo());
        //合格库位取工单中库位(一个工作站可能会配置多个合格品库位)
        Long qualifiedLocationId = workstationLocationMapper.selectQualifiedLocationIdBySystemNo(applyPart.getSystemNo());//合格品库
        // 如果存在源库位则使用源库位
        if (applyPart.getSourceLocationId() != null) {
            toQualifiedLocationId = applyPart.getSourceLocationId();
            disqualifiedLocationId = applyPart.getTargetUnqualifiedLocationId() == null ? -1 : applyPart.getTargetUnqualifiedLocationId();
            qualifiedLocationId = applyPart.getTargetQualifiedLocationId() == null ? -1 : applyPart.getTargetQualifiedLocationId();
        }
 
        if (toQualifiedLocationId != null && disqualifiedLocationId != null && qualifiedLocationId != null) {
            if(dir.equals(ApplyPartServiceImpl.MOVELIBRARY)){
                // 待检移合格
                if (new BigDecimal(applyPart.getQtyArrived()).compareTo(BigDecimal.ZERO) == 1) {
                    // 如果有替代件,则替代件移库
                    if (applyPart.getReplacePartId() != null) {
                        stockUtils.replaceMove(partId, applyPart.getSystemNo(), applyPart.getLotBatchNo(), new BigDecimal(applyPart.getQtyArrived()), toQualifiedLocationId, qualifiedLocationId, applyPart.getReplacePartId());
                    } else {
                        stockUtils.localMove(partId, applyPart.getSystemNo(), applyPart.getLotBatchNo(), new BigDecimal(applyPart.getQtyArrived()), toQualifiedLocationId, qualifiedLocationId);
                    }
                }
                // 待检移不合格
                if (new BigDecimal(applyPart.getUnqualifiedArrived()).compareTo(BigDecimal.ZERO) == 1) {
                    if (applyPart.getReplacePartId() != null) {
                        stockUtils.replaceMove(partId, applyPart.getSystemNo(), applyPart.getLotBatchNo(), new BigDecimal(applyPart.getUnqualifiedArrived()), toQualifiedLocationId, disqualifiedLocationId, applyPart.getReplacePartId());
                    } else {
                        stockUtils.localMove(partId, applyPart.getSystemNo(), applyPart.getLotBatchNo(), new BigDecimal(applyPart.getUnqualifiedArrived()), toQualifiedLocationId, disqualifiedLocationId);
                    }
                }
                // 报废库存发放
                if (applyPart.getScrapArrived() != null && applyPart.getScrapArrived().compareTo(BigDecimal.ZERO) > 0) {
                    Stock stock = stockMapper.selectOne(Wrappers.<Stock>lambdaQuery().eq(Stock::getPartId, partId)
                            .eq(Stock::getLocationId,toQualifiedLocationId)
                            .eq(Stock::getPartBatchNo,applyPart.getLotBatchNo())
                            .eq(Stock::getSystemNo,applyPart.getSystemNo()));
                    stockUtils.updateById(stock.getId(), applyPart.getScrapArrived().negate(), BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, null, TransactionType.SCRAP.getValue());
                }
            }else if(dir.equals(ApplyPartServiceImpl.UNMOVELIBRARY)){
                // 合格移待检
                if (new BigDecimal(applyPart.getQtyArrived()).compareTo(BigDecimal.ZERO) == 1) {
                    if (applyPart.getReplacePartId() != null) {
                        stockUtils.replaceMove(applyPart.getReplacePartId(), applyPart.getSystemNo(), applyPart.getLotBatchNo(), new BigDecimal(applyPart.getQtyArrived()), qualifiedLocationId, toQualifiedLocationId, partId);
                    } else {
                        stockUtils.localMove(partId, applyPart.getSystemNo(), applyPart.getLotBatchNo(), new BigDecimal(applyPart.getQtyArrived()), qualifiedLocationId, toQualifiedLocationId);
                    }
                }
                // 不合格移待检
                if (new BigDecimal(applyPart.getUnqualifiedArrived()).compareTo(BigDecimal.ZERO) == 1) {
                    if (applyPart.getReplacePartId() != null) {
                        stockUtils.replaceMove(applyPart.getReplacePartId(), applyPart.getSystemNo(), applyPart.getLotBatchNo(), new BigDecimal(applyPart.getUnqualifiedArrived()), disqualifiedLocationId, toQualifiedLocationId, partId);
                    } else {
                        stockUtils.localMove(partId, applyPart.getSystemNo(), applyPart.getLotBatchNo(), new BigDecimal(applyPart.getUnqualifiedArrived()), disqualifiedLocationId, toQualifiedLocationId);
                    }
                }
                // 报废库存撤回
                if (applyPart.getScrapArrived() != null && applyPart.getScrapArrived().compareTo(BigDecimal.ZERO) > 0) {
                    Stock stock = stockMapper.selectOne(Wrappers.<Stock>lambdaQuery().eq(Stock::getPartId, partId)
                            .eq(Stock::getLocationId,toQualifiedLocationId)
                            .eq(Stock::getPartBatchNo,applyPart.getLotBatchNo())
                            .eq(Stock::getSystemNo,applyPart.getSystemNo()));
                    stockUtils.updateById(stock.getId(), applyPart.getScrapArrived(), BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, null, TransactionType.CANCEL_SCRAP.getValue());
                }
            }else{
                throw new RuntimeException("移库方向码异常!异常码--" + dir);
            }
        } else {
            throw new RuntimeException("移库对象零件查无工作站库位缺失");
        }
    }
 
    /**
     * 获取合格数量在成品检及非成品检中的改变量
     * @param partId 零件id
     * @param qualifiedLocationId 合格品库位id
     * @param systemNo 产出系统编号
     * @param lotBatchNo 产出批次号
     * @param qtyArrived 当前检测合格数量
     * @param dir 业务类别代码
     * @param reportId 检测汇报id
     * @param applyPartId 汇报材料id
     * @return 返回当前库存中合格数量-当前检测中合格数量差
     */
    public BigDecimal getQtyArrivedChange(Long partId,Long qualifiedLocationId, String systemNo, String lotBatchNo, BigDecimal qtyArrived, String dir,Long reportId,Long applyPartId){
        if(dir.equals(ApplyPartServiceImpl.MOVELIBRARY)){
            List<Stock> stockList = stockMapper.selectList(Wrappers.<Stock>lambdaQuery().eq(Stock::getPartId,partId).eq(Stock::getSystemNo,systemNo).eq(Stock::getPartBatchNo,lotBatchNo).eq(Stock::getLocationId,qualifiedLocationId));
            if(stockList.size() == 0){
                throw new RuntimeException("成品检移库->产出系统编号=" + systemNo + "->移库对象不存在");
            }else if(stockList.size() > 1){
                throw new RuntimeException("成品检移库->零件id=" + partId + "->产出系统号=" + systemNo + "->批次号=" + lotBatchNo + "->库位id=" + qualifiedLocationId + "->唯一键重复");
            }else{
                return stockList.get(0).getStockQuantity().subtract(qtyArrived);//返回合格数量变更数量
            }
        }else if(dir.equals(ApplyPartServiceImpl.UNMOVELIBRARY)){
            //库存表在正向操作时已经被校正,逆向不能拿本身跟本身去比较差异,需要通过校正事件记录表中的数据去多校正进行逆向操作
            List<FinishedProdInspQtyChangeEvent> finishedProdInspQtyChangeEventList = finishedProdInspQtyChangeEventMapper.selectList(Wrappers.<FinishedProdInspQtyChangeEvent>lambdaQuery().eq(FinishedProdInspQtyChangeEvent::getReportId,reportId).eq(FinishedProdInspQtyChangeEvent::getApplyPartId,applyPartId).eq(FinishedProdInspQtyChangeEvent::getSystemNo,systemNo));
            if(CollectionUtils.isEmpty(finishedProdInspQtyChangeEventList)){
                return BigDecimal.ZERO;
            }else if(finishedProdInspQtyChangeEventList.size() > 1){
                throw new RuntimeException("数据异常->成品检合格数量改变事件记录表数据重复");
            }else{
                return finishedProdInspQtyChangeEventList.get(0).getQtyChange();//返回合格数量变更数量
            }
        }else{
            throw new RuntimeException("移库业务类别码=" + dir + "->非法");
        }
    }
 
    /**
     * 根据检测汇报id校验汇报明细的工序是否一致
     * @param reportId 检测汇报id
     */
    public void checkOperationNoIsSame(Long reportId){
        if(null != reportId){
            List<ApplyPart> applyPartList = applyPartMapper.selectListByReportId(reportId);
            HashSet<String> operationNos = new HashSet<>();
            if(CollectionUtils.isNotEmpty(applyPartList)){
                for(ApplyPart applyPart : applyPartList){
                    operationNos.add(applyPartMapper.selectOperationNoBySystemNo(applyPart.getSystemNo()));
                }
                if(null == operationNos){
                    throw new RuntimeException("系统数据异常 -> 工序编号获取失败");
                }else if(operationNos.size() != 1){
                    throw new RuntimeException("汇报零件工序不一致 -> " + operationNos.toString());
                }
                // 增加校验检测规则是否一致
                List<String> testRules = new ArrayList<>();
                for(ApplyPart applyPart : applyPartList){
                    List<String> rules = applyPartMapper.selectTestRulesBySystemNo(applyPart.getSystemNo());
                    if(CollectionUtils.isEmpty(testRules)){
                        testRules.addAll(rules);
                    }
                    if(!testRules.containsAll(rules)){
                        throw new RuntimeException("汇报零件检测规则不一致");
                    }
                }
            }
        }
    }
 
 
 
 
}