/* * 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 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 ids) { List list = this.baseMapper.getInitialDetailsByIds(ids); if (list.isEmpty()) { throw new RuntimeException("没有可执行数据"); } Map 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 locationList = locationService.list(Wrappers.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.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 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 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 partList = partMapper.selectList(Wrappers.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 palletTransportsMaterialList = palletTransportsMaterialMapper.selectList(Wrappers.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 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.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 palletTransportsDetailList = baseMapper.selectList(Wrappers.lambdaQuery() .eq(PalletTransportsDetail::getTransportsId, transportsId)); boolean present = palletTransportsDetailList.stream() .allMatch(a->PalletTransportsDetailStateStringValues.SUBMITTED.equals(a.getState())); List palletTransportsMaterialList = palletTransportsMaterialMapper.selectList(Wrappers.lambdaQuery() .eq(PalletTransportsMaterial::getTransportsId, transportsId)); Set materialIdList = palletTransportsMaterialList.stream().map(PalletTransportsMaterial::getId).collect(Collectors.toSet()); Set 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); } } }