李林
2023-10-07 658d4927d468c47208fd012d9128b09249c07eff
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
/*
 *    Copyright (c) 2018-2025, ztt All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: ztt
 */
package com.chinaztt.mes.warehouse.service.impl;
 
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.chinaztt.mes.basic.dto.LocationIfsMoveDTO;
import com.chinaztt.mes.basic.entity.Location;
import com.chinaztt.mes.basic.entity.Part;
import com.chinaztt.mes.basic.mapper.PartMapper;
import com.chinaztt.mes.basic.service.LocationService;
import com.chinaztt.mes.warehouse.dto.PalletTransportsDetailDTO;
import com.chinaztt.mes.warehouse.dto.StockAddDTO;
import com.chinaztt.mes.warehouse.dto.StockDTO;
import com.chinaztt.mes.warehouse.entity.*;
import com.chinaztt.mes.warehouse.mapper.PalletTransportsDetailMapper;
import com.chinaztt.mes.warehouse.mapper.PalletTransportsMapper;
import com.chinaztt.mes.warehouse.mapper.PalletTransportsMaterialMapper;
import com.chinaztt.mes.warehouse.service.PalletTransportsDetailService;
import com.chinaztt.mes.warehouse.service.PalletTransportsMaterialService;
import com.chinaztt.mes.warehouse.service.StockService;
import com.chinaztt.mes.warehouse.state.constant.PalletTransportsState;
import com.chinaztt.mes.warehouse.state.pallettransportsdetail.PalletTransportsDetailStateStringValues;
import com.chinaztt.mes.warehouse.util.StockUtils;
import com.chinaztt.mes.warehouse.util.WareHouseUtils;
import com.chinaztt.ztt.common.core.util.R;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
 
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.stream.Collectors;
 
/**
 * 货盘运输任务移库明细表
 *
 * @author shz
 * @date 2022-05-24 17:17:26
 */
@Transactional(rollbackFor = Exception.class)
@Service
@AllArgsConstructor
public class PalletTransportsDetailServiceImpl extends ServiceImpl<PalletTransportsDetailMapper, PalletTransportsDetail> implements PalletTransportsDetailService {
 
    private LocationService locationService;
    private StockService stockService;
    private JoinStockOrderServiceImpl joinStockOrderService;
    private PalletTransportsMaterialMapper palletTransportsMaterialMapper;
    private PartMapper partMapper;
    private WareHouseUtils wareHouseUtils;
    private StockUtils stockUtils;
    private PalletTransportsMaterialService transportsMaterialService;
    private PalletTransportsMapper palletTransportsMapper;
    private PalletTransportsDetailMapper palletTransportsDetailMapper;
//    @Autowired
//    public PalletTransportsDetailServiceImpl(@Lazy PalletTransportsMaterialService palletTransportsMaterialService) {
//        this.palletTransportsMaterialService = palletTransportsMaterialService;
//    }
 
    @Override
    public synchronized void executeMoveLocation(List<Long> ids) {
        List<PalletTransportsDetailDTO> list = this.baseMapper.getInitialDetailsByIds(ids);
        if (list.isEmpty()) {
            throw new RuntimeException("没有可执行数据");
        }
 
 
 
        Map<String, Location> locationMap = new HashMap<>();
        // 判断至库位是否有值,是否绑定mes库位
        for (PalletTransportsDetailDTO check : list) {
            Part part = partMapper.selectById(check.getPartId());
            if(!part.getLotTrackingIfs()){
                if(!"*".equals(check.getWdr())){
                    throw new RuntimeException("零件号"+part.getPartNo()+"未启用批次管理,且wdr不为“*”");
                }
 
            }
            if (StringUtils.isBlank(check.getToIfsLocationNo())) {
                throw new RuntimeException(check.getPartNo() + "至库位为空");
            }
            List<Location> locationList = locationService.list(Wrappers.<Location>lambdaQuery()
                    .eq(Location::getIfsLocation, check.getToIfsLocationNo())
                    .isNotNull(Location::getTransportLocationNo)
                    .eq(Location::getLocStatus, 1).eq(Location::getActive, true));
            if (locationList.isEmpty()) {
                throw new RuntimeException("IFS库位:" + check.getToIfsLocationNo() + ",未找到MES库位对应的货盘运输库位");
            }
            // 根据货盘运输库位号找到原本对应的MES库位
            Location location = locationService.getOne(Wrappers.<Location>lambdaQuery()
                    .eq(Location::getLocNo, locationList.get(0).getTransportLocationNo())
                    .eq(Location::getLocStatus, 1).eq(Location::getActive, true));
            if (location == null) {
                throw new RuntimeException("货盘运输库位:" + locationList.get(0).getTransportLocationNo() + ",未找到MES库位");
            }
            locationMap.put(check.getToIfsLocationNo(), location);
        }
 
        // ifs移库
        LocationIfsMoveDTO moveDTO = new LocationIfsMoveDTO();
        moveDTO.setRECORD_ID(UUID.randomUUID().toString().replace("-", ""));
        List<LocationIfsMoveDTO.DataBean> dataBeans = new ArrayList<>();
        moveDTO.setBATCH_INFO(dataBeans);
 
        for (PalletTransportsDetailDTO detail : list) {
            Part part = partMapper.selectById(detail.getPartId());
            LocationIfsMoveDTO.DataBean bean = new LocationIfsMoveDTO.DataBean();
            bean.setPART_NO(detail.getPartNo());
            if (part.getLotTrackingIfs() != null && part.getLotTrackingIfs()) {
                bean.setLOT_BATCH_NO(detail.getBatchNo());
                bean.setWAIV_DEV_REJ_NO(detail.getWdr());
            } else {
                bean.setLOT_BATCH_NO("*");
                bean.setWAIV_DEV_REJ_NO("*");
            }
            bean.setMOVE_QTY(detail.getTransferQuantity());
            bean.setLOCATION_NO(detail.getFromIfsLocationNo());
            bean.setTO_LOCATION_NO(detail.getToIfsLocationNo());
            bean.setMOVE_COMMENT(detail.getTransportsNo());
            dataBeans.add(bean);
        }
 
        R response = locationService.moveIfsLocation(moveDTO);
        // ifs移库成功
        if (response.getCode() == 0) {
            UpdateWrapper<PalletTransportsDetail> updateWrapper = new UpdateWrapper<>();
            this.update(updateWrapper.lambda().in(PalletTransportsDetail::getId, list.stream().map(PalletTransportsDetail::getId).collect(Collectors.toList()))
                    .set(PalletTransportsDetail::getIfsRecordId, moveDTO.getRECORD_ID()).set(PalletTransportsDetail::getState, PalletTransportsDetailStateStringValues.SUBMITTED));
            //更改主表状态
            changeTransportsState(list.get(0).getTransportsId());
 
            // 物料入mes库
            for (PalletTransportsDetailDTO detail : list) {
                Location location = locationMap.get(detail.getToIfsLocationNo());
 
                StockDTO stockDTO = new StockDTO();
                stockDTO.setPartBatchNo(detail.getWdr());
                stockDTO.setPartNo(detail.getPartNo());
                stockDTO.setPartName(detail.getPartDesc());
                stockDTO.setLocationNo(location.getLocNo());
                stockDTO.setPartId(detail.getPartId());
                stockDTO.setLocationId(location.getId());
                stockDTO.setIfsBatchNo(detail.getBatchNo());
                stockDTO.setStockQuantity(detail.getTransferQuantity());
 
                StockAddDTO stockAdd = new StockAddDTO();
                stockAdd.setPartsId(stockDTO.getPartId());
                stockAdd.setNewLocationId(stockDTO.getLocationId());
                stockAdd.setNewPartBatchNo(stockDTO.getPartBatchNo());
                stockAdd.setReelNumber(stockDTO.getReelNumber());
 
                Stock newStock = stockUtils.query(stockAdd);
                stockUtils.updateById(newStock.getId(), stockDTO.getStockQuantity(), BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, null, "RECEIVE");
                // 更新ifs批次号
                Stock update = new Stock();
                update.setId(newStock.getId());
                update.setIfsBatchNo(detail.getBatchNo());
                // 货盘运输任务来的物料,是否工序库存都为false
                update.setOperationStockStatus(false);
                stockService.updateById(update);
                // 自动预留
                if (null != detail.getOperationTaskId()) {
                    joinStockOrderService.addJoinStock(detail.getOperationTaskId(), newStock, detail.getTransferQuantity());
                }
 
            }
        }
    }
 
 
    @Override
    public R checkScanPalletTransportsDetail(Long transportsId, String partNo, String batchNo, String wdr) {
        if (StringUtils.isBlank(partNo) || StringUtils.isBlank(Long.toString(transportsId)) || StringUtils.isBlank(batchNo) || StringUtils.isBlank(wdr)) {
            return R.failed("零件号||货盘运输主表id||ifs批次号||wdr号为空");
        }
        //根据零件号获取零件id
        List<Part> partList = partMapper.selectList(Wrappers.<Part>lambdaQuery().eq(Part::getPartNo, partNo));
        if (CollectionUtil.isEmpty(partList)) {
            return R.failed("零件号=" + partNo + "->mes无对应基础数据");
        } else if (partList.size() > 1) {
            return R.failed("零件号=" + partNo + "->mes中对应的基础数据存在多条");
        }
 
        //判断查询的零件号是否在对应的货盘运输物料需求计划明细中
        List<PalletTransportsMaterial> palletTransportsMaterialList = palletTransportsMaterialMapper.selectList(Wrappers.<PalletTransportsMaterial>lambdaQuery().eq(PalletTransportsMaterial::getTransportsId, transportsId).eq(PalletTransportsMaterial::getPartId, partList.get(0).getId()));
        if (CollectionUtil.isEmpty(palletTransportsMaterialList)) {
            return R.failed("零件号=" + partNo + "->不在此货盘运输任务物料需求列表中");
        }
 
        //调ifs库存查询接口
        R ifsres = wareHouseUtils.getIfsStockPrecise(partNo, batchNo, wdr);
        JSONArray array = (JSONArray) JSON.toJSON(ifsres.getData());
        BigDecimal qtyAvailable = new BigDecimal(BigInteger.ZERO);
        for (int i = 0; i < array.size(); i++) {
            qtyAvailable = qtyAvailable.add(array.getJSONObject(i).getBigDecimal("QTY_AVAILABLE"));//可用库存数量
        }
        return R.ok(array, qtyAvailable.toString());//将ifs可用库存数量:ifs库位号键值对及可用数量求和后返回
    }
 
    @Override
    public Boolean saveBatchDetails(List<PalletTransportsDetail> details) {
        transportsMaterialService.checkTransportsState(details.get(0).getTransportsId());
        // 设置初始状态,增加移库数量
        BigDecimal quantity = BigDecimal.ZERO;
        for (PalletTransportsDetail detail : details) {
            detail.setState(PalletTransportsDetailStateStringValues.INITIAL);
            quantity = quantity.add(detail.getTransferQuantity());
        }
        // 更新物料需求
        transportsMaterialService.calculateQuantity(details.get(0).getTransportsMaterialId(), quantity, true);
        // 更新是否存在明细状态
        PalletTransportsMaterial update = new PalletTransportsMaterial();
        update.setId(details.get(0).getTransportsMaterialId());
        update.setDetailExistState(true);
        transportsMaterialService.updateById(update);
 
        // 设置只库位
        PalletTransportsMaterial material = this.transportsMaterialService.getById(update.getId());
        if (StringUtils.isNotBlank(material.getToIfsLocationNo())) {
            details.forEach(p -> {
                p.setToIfsLocationNo(material.getToIfsLocationNo());
                p.setToIfsLocationName(material.getToIfsLocationName());
            });
        }
        return this.saveBatch(details);
    }
 
    @Override
    public R update(PalletTransportsDetail detail) {
        PalletTransportsDetail old = this.getById(detail.getId());
        if (old.getState().equals(PalletTransportsDetailStateStringValues.SUBMITTED)) {
            return R.failed("已执行数据无法更新");
        }
 
        if (detail.getTransferQuantity() != null && detail.getTransferQuantity().compareTo(old.getTransferQuantity()) != 0) {
            if (detail.getTransferQuantity().compareTo(old.getTransferQuantity()) > 0) {
                transportsMaterialService.calculateQuantity(old.getTransportsMaterialId(), detail.getTransferQuantity().subtract(old.getTransferQuantity()), true);
            } else {
                transportsMaterialService.calculateQuantity(old.getTransportsMaterialId(), old.getTransferQuantity().subtract(detail.getTransferQuantity()), false);
            }
        }
        this.updateById(detail);
        return R.ok();
    }
 
    @Override
    public R remove(Long id) {
        PalletTransportsDetail detail = this.getById(id);
        Long transportsId = detail.getTransportsId();
        if (detail.getState().equals(PalletTransportsDetailStateStringValues.SUBMITTED)) {
            return R.failed("已执行无法删除");
        }
        // 重新计算数量
        transportsMaterialService.calculateQuantity(detail.getTransportsMaterialId(), detail.getTransferQuantity(), false);
        // 最后一条记录改回状态
        int count = this.count(Wrappers.<PalletTransportsDetail>lambdaQuery().eq(PalletTransportsDetail::getTransportsMaterialId, detail.getTransportsMaterialId()));
        if (count == 1) {
            PalletTransportsMaterial update = new PalletTransportsMaterial();
            update.setId(detail.getTransportsMaterialId());
            update.setDetailExistState(false);
            this.transportsMaterialService.updateById(update);
        }
        this.removeById(id);
        changeTransportsState(transportsId);
        return R.ok();
    }
 
    @Override
    public R savePalletTransportsDetail(PalletTransportsDetail palletTransportsDetail) {
        if(StringUtils.isBlank(Long.toString(palletTransportsDetail.getTransportsId()))){
            return R.failed("货盘运输任务明细未绑定货盘运输物料需求计划行");//对PDA端的操作进行保险验证
        }
        transportsMaterialService.checkTransportsState(palletTransportsDetail.getTransportsId());
        palletTransportsDetail.setState(PalletTransportsDetailStateStringValues.INITIAL);
        return R.ok(save(palletTransportsDetail));
    }
 
 
    @Override
    public void changeTransportsState(Long transportsId){
        List<PalletTransportsDetail> palletTransportsDetailList = baseMapper.selectList(Wrappers.<PalletTransportsDetail>lambdaQuery()
                .eq(PalletTransportsDetail::getTransportsId, transportsId));
        boolean present = palletTransportsDetailList.stream()
                .allMatch(a->PalletTransportsDetailStateStringValues.SUBMITTED.equals(a.getState()));
        List<PalletTransportsMaterial> palletTransportsMaterialList = palletTransportsMaterialMapper.selectList(Wrappers.<PalletTransportsMaterial>lambdaQuery()
                .eq(PalletTransportsMaterial::getTransportsId, transportsId));
        Set<Long> materialIdList = palletTransportsMaterialList.stream().map(PalletTransportsMaterial::getId).collect(Collectors.toSet());
        Set<Long> detailMaterialIdList = palletTransportsDetailList.stream().map(PalletTransportsDetail::getTransportsMaterialId).collect(Collectors.toSet());
        Boolean flag = false;
        if(materialIdList.size()==detailMaterialIdList.size()){
            if(materialIdList.containsAll(detailMaterialIdList)){
                flag = true;
            }
        }
        if(present && flag){
            PalletTransports palletTransports = new PalletTransports();
            palletTransports.setId(transportsId);
            palletTransports.setState(PalletTransportsState.FINISHED.getCode());
            palletTransportsMapper.updateById(palletTransports);
        }
    }
}