package com.chinaztt.mes.warehouse.util; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.BooleanUtil; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.StringUtils; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.chinaztt.ifs.api.feign.IfsFeignClient; import com.chinaztt.mes.basic.entity.Part; import com.chinaztt.mes.basic.mapper.PartMapper; import com.chinaztt.mes.warehouse.dto.IfsMoveLibraryDTO; import com.chinaztt.mes.warehouse.dto.MoveLibraryBoxDTO; import com.chinaztt.mes.warehouse.entity.FeederCertificate; import com.chinaztt.mes.warehouse.entity.Packaging; import com.chinaztt.mes.warehouse.entity.Stock; import com.chinaztt.mes.warehouse.entity.StockConfigBean; import com.chinaztt.mes.warehouse.mapper.FeederCertificateMapper; import com.chinaztt.mes.warehouse.mapper.PackagingItemMapper; import com.chinaztt.mes.warehouse.mapper.PackagingMapper; import com.chinaztt.mes.warehouse.mapper.StockMapper; import com.chinaztt.mes.warehouse.state.constant.LocationTypeStringValues; import com.chinaztt.mes.warehouse.state.escort.constant.EscortEvents; import com.chinaztt.ztt.admin.api.feign.RemoteParamService; import com.chinaztt.ztt.common.core.constant.SecurityConstants; import com.chinaztt.ztt.common.core.util.R; import com.google.gson.Gson; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.math.BigDecimal; import java.util.*; import java.util.stream.Collectors; /** * @Description : 仓库管理工具类 * @ClassName : WareHouseUtils * @Author : sll * @Date: 2022-06-02 22:04 */ @Service public class WareHouseUtils { @Resource private PackagingMapper packagingMapper; @Resource private PackagingItemMapper packagingItemMapper; @Resource private StockUtils stockUtils; @Resource private StockConfigBean stockConfigBean; @Resource private IfsFeignClient ifsFeignClient; @Resource private RemoteParamService remoteParamService; public static final String CONTRACT = "IFS_DOMAIN"; @Resource private PartMapper partMapper; @Resource private StockMapper stockMapper; @Resource private FeederCertificateMapper feederMapper; /** * 根据包装主表记录行id获取包装确认状态 * * @param id * @return */ public Boolean isPackConfirm(Long id) { Packaging packaging = packagingMapper.selectById(id); if (packaging == null) { throw new RuntimeException("包装主表id=" + id + "->异常->数据库无匹配记录"); } else { return packaging.getIsConfirm(); } } /** * 校验mes库位映射ifs库位的对称性 * * @param moveLibraryBoxDTOList * @return false:不对称;true:对称 */ public Boolean isLocationMapSym(List moveLibraryBoxDTOList) { for (MoveLibraryBoxDTO moveLibraryBoxDTO : moveLibraryBoxDTOList) { if (StringUtils.isBlank(moveLibraryBoxDTO.getStartLocationNoIfs()) ^ StringUtils.isBlank(moveLibraryBoxDTO.getArriveLocationNoIfs())) { return false; } } return true; } /** * 校验MoveLibraryBoxDTO * * @param moveLibraryBoxDTOList * @param id * @return */ public R checkMoveLibraryBox(List moveLibraryBoxDTOList, Long id) { Long itemCount = packagingItemMapper.getPackagingItemCountByPackagingId(id); //校验SQL查询结果 if (moveLibraryBoxDTOList.size() != itemCount) { return R.failed("实际明细行数=" + moveLibraryBoxDTOList.size() + "->不等于SQL关联查询明细行数=" + itemCount); } //校验box明细行是否都存在到达库位号且到达库位为成品库位 List moveLibraryBoxDTOListFilter = moveLibraryBoxDTOList.stream().filter(o -> StringUtils.isBlank(o.getArriveLocationNo()) || !o.getArriveLocationType().equals(LocationTypeStringValues.FINISHLOCATIONCODE)).collect(Collectors.toList()); if (CollectionUtil.isNotEmpty(moveLibraryBoxDTOListFilter)) { return R.failed("包装明细存在记录行未指定[到达库位]"); } //校验box明细行是否都存在出发库位号且出发库位是否是合格品库位 moveLibraryBoxDTOListFilter = moveLibraryBoxDTOList.stream().filter(o -> StringUtils.isBlank(o.getStartLocationNo()) || !o.getStartLocationType().equals(LocationTypeStringValues.PRODOUTQUALIFIELDLOCATIONCODE)).collect(Collectors.toList()); if (CollectionUtil.isNotEmpty(moveLibraryBoxDTOListFilter)) { return R.failed("包装明细存在记录行在实时库位中未找到[出发库位]或[出发库位]为非[产出合格品库位]"); } //校验库位的对称性 if (!isLocationMapSym(moveLibraryBoxDTOList)) { return R.failed("mes库位映射ifs库位不对称"); } return R.ok(); } /** * 包装模块确认/取消确认后的移库 * * @param moveLibraryBoxDTOList * @param escortEvents COMPLETE:确认;CANCEL:取消确认 * @param packagingId 包装主表id */ public void packagingMoveLibrary(List moveLibraryBoxDTOList, EscortEvents escortEvents, Long packagingId) { //1.mes移库 for (MoveLibraryBoxDTO moveLibraryBoxDTO : moveLibraryBoxDTOList) { switch (escortEvents) { case COMPLETE: stockUtils.localMove(moveLibraryBoxDTO.getPartId(), moveLibraryBoxDTO.getSystemNo(), moveLibraryBoxDTO.getBatchNo(), moveLibraryBoxDTO.getMoveQty(), moveLibraryBoxDTO.getStartLocationId(), moveLibraryBoxDTO.getArriveLocationId()); break; case CANCEL: stockUtils.localMove(moveLibraryBoxDTO.getPartId(), moveLibraryBoxDTO.getSystemNo(), moveLibraryBoxDTO.getBatchNo(), moveLibraryBoxDTO.getMoveQty(), moveLibraryBoxDTO.getArriveLocationId(), moveLibraryBoxDTO.getStartLocationId()); break; default: throw new RuntimeException("操作码" + escortEvents.name() + "->异常"); } } //2.ifs移库 List moveLibraryBoxDTOListFilter = moveLibraryBoxDTOList.stream().filter(o -> StringUtils.isNotBlank(o.getStartLocationNoIfs()) && StringUtils.isNotBlank(o.getArriveLocationNoIfs())).collect(Collectors.toList()); //将list按照零件号进行分组,去除IFS启用批次管理为true的数据 Map> map = moveLibraryBoxDTOListFilter.stream().filter(x -> !x.getLotTrackingIfs()).collect(Collectors.groupingBy(MoveLibraryBoxDTO::getPartId)); List ifsList = new ArrayList<>(); for (Map.Entry> entry : map.entrySet()) { List moveLibraryBoxDTOByGroupList = entry.getValue(); //汇总相同零件号的移库数量 BigDecimal moveQtySum = moveLibraryBoxDTOByGroupList.stream().filter(x -> x.getMoveQty() != null).map(MoveLibraryBoxDTO::getMoveQty).reduce(BigDecimal.ZERO, BigDecimal::add); MoveLibraryBoxDTO ifsDTO = new MoveLibraryBoxDTO(); BeanUtils.copyProperties(moveLibraryBoxDTOByGroupList.get(0), ifsDTO); ifsDTO.setMoveQty(moveQtySum); ifsList.add(ifsDTO); } //筛选出IFS启用批次管理为true的数据 List lotTrackingIfsList = moveLibraryBoxDTOListFilter.stream().filter(MoveLibraryBoxDTO::getLotTrackingIfs).collect(Collectors.toList()); ifsList.addAll(lotTrackingIfsList); if (CollectionUtil.isNotEmpty(ifsList)) { //拼接inAttr IfsMoveLibraryDTO ifsMoveLibraryDTO = new IfsMoveLibraryDTO(); //ifsMoveLibraryDTO.setRECORD_ID(packagingMapper.getPackingById(packagingId).getNo()); List dataBeanList = new ArrayList<>();//批量标识 for (MoveLibraryBoxDTO moveLibraryBoxDTO : ifsList) { // 工序库存不进行IFS移库 Stock stock = stockMapper.selectById(moveLibraryBoxDTO.getStockId()); if (BooleanUtil.isTrue(stock.getOperationStockStatus())) { continue; } IfsMoveLibraryDTO.DataBean batchInfo = new IfsMoveLibraryDTO.DataBean(); batchInfo.setPART_NO(moveLibraryBoxDTO.getPartNo());//零件号 batchInfo.setLOT_BATCH_NO(moveLibraryBoxDTO.getIfsBatchNo());//ifs批次号 batchInfo.setMOVE_QTY(moveLibraryBoxDTO.getMoveQty());//移库数量 //batchInfo.setSERIAL_NO("*");//序列号 batchInfo.setENG_CHG_LEVEL(moveLibraryBoxDTO.getEngChgLevel());//版本号 //判断是否启用批次管理 if (moveLibraryBoxDTO.getLotTrackingIfs() != null && moveLibraryBoxDTO.getLotTrackingIfs()) { batchInfo.setWAIV_DEV_REJ_NO(moveLibraryBoxDTO.getBatchNo());//wdr号(存mes的sn号) } else { batchInfo.setWAIV_DEV_REJ_NO("*");//wdr号 batchInfo.setLOT_BATCH_NO("*"); } switch (escortEvents) { case COMPLETE: batchInfo.setLOCATION_NO(moveLibraryBoxDTO.getStartLocationNoIfs());//ifs出发库位号 batchInfo.setTO_LOCATION_NO(moveLibraryBoxDTO.getArriveLocationNoIfs());//ifs到达库位号 break; case CANCEL: batchInfo.setLOCATION_NO(moveLibraryBoxDTO.getArriveLocationNoIfs());//ifs出发库位号 batchInfo.setTO_LOCATION_NO(moveLibraryBoxDTO.getStartLocationNoIfs());//ifs到达库位号 break; } String contract = remoteParamService.getByKey(CONTRACT, SecurityConstants.FROM_IN).getData();//从系统参数中获取ifs域 //batchInfo.setTO_CONTRACT(stockConfigBean.getRegion());//目标域 // 因为现在多个 mes库位可能对应一个 ifs库位 所以 执行移库操作之前需要判断一下库位是否相同 // xcg 20230413 if (StrUtil.equals(batchInfo.getLOCATION_NO(), batchInfo.getTO_LOCATION_NO())) { continue; } batchInfo.setTO_CONTRACT(contract);//目标域 dataBeanList.add(batchInfo); } if (CollectionUtils.isEmpty(dataBeanList)){ return; } ifsMoveLibraryDTO.setBATCH_INFO(dataBeanList); Gson gson = new Gson(); String jsonstr = gson.toJson(ifsMoveLibraryDTO); JSONObject jsonObject = JSONObject.parseObject(jsonstr);//解决序列化时自动将大写转小写问题 R res = ifsFeignClient.importMovePartStd(jsonObject, true); if (res.getCode() != 0) { throw new RuntimeException("ifs库存件移库失败->ifs报错信息=" + res.getMsg()); } } } /** * 移库(通用) * * @param moveLibraryBoxDTOList */ public void moveLibrary(List moveLibraryBoxDTOList) { List moveLibraryBoxDTOList_tmp = moveLibraryBoxDTOList.stream().filter(o -> StringUtils.isBlank(o.getPlanningMethod())).collect(Collectors.toList()); if (CollectionUtil.isNotEmpty(moveLibraryBoxDTOList_tmp)) { throw new RuntimeException("存在零件无[计划方法]->无法进行移库"); } //1.mes移库 for (MoveLibraryBoxDTO moveLibraryBoxDTO : moveLibraryBoxDTOList) { stockUtils.localMove(moveLibraryBoxDTO.getPartId(), moveLibraryBoxDTO.getSystemNo(), moveLibraryBoxDTO.getBatchNo(), moveLibraryBoxDTO.getMoveQty(), moveLibraryBoxDTO.getStartLocationId(), moveLibraryBoxDTO.getArriveLocationId()); } //2.ifs移库 List moveLibraryBoxDTOListFilter = moveLibraryBoxDTOList.stream().filter(o -> StringUtils.isNotBlank(o.getStartLocationNoIfs()) && StringUtils.isNotBlank(o.getArriveLocationNoIfs()) && !o.getPlanningMethod().equals("K")).collect(Collectors.toList()); if (CollectionUtil.isNotEmpty(moveLibraryBoxDTOListFilter)) { //拼接inAttr IfsMoveLibraryDTO ifsMoveLibraryDTO = new IfsMoveLibraryDTO(); ifsMoveLibraryDTO.setRECORD_ID(UUID.randomUUID().toString()); List dataBeanList = new ArrayList<>();//批量标识 for (MoveLibraryBoxDTO moveLibraryBoxDTO : moveLibraryBoxDTOListFilter) { // 工序库存不进行移库 Stock stock = stockMapper.selectById(moveLibraryBoxDTO.getStockId()); if (BooleanUtil.isTrue(stock.getOperationStockStatus())) { continue; } IfsMoveLibraryDTO.DataBean batchInfo = new IfsMoveLibraryDTO.DataBean(); batchInfo.setPART_NO(moveLibraryBoxDTO.getPartNo());//零件号 batchInfo.setLOT_BATCH_NO(moveLibraryBoxDTO.getIfsBatchNo());//ifs批次号 batchInfo.setMOVE_QTY(moveLibraryBoxDTO.getMoveQty());//移库数量 //batchInfo.setSERIAL_NO("*");//序列号 batchInfo.setENG_CHG_LEVEL(moveLibraryBoxDTO.getEngChgLevel());//版本号 //batchInfo.setWAIV_DEV_REJ_NO("*");//wdr号 Part part = partMapper.selectById(moveLibraryBoxDTO.getPartId()); //判断是否启用批次管理 if (part.getLotTrackingIfs() != null && part.getLotTrackingIfs()) { FeederCertificate feederCertificate = feederMapper.selectOne(Wrappers.lambdaQuery().eq(FeederCertificate::getSn, moveLibraryBoxDTO.getBatchNo())); if (null != feederCertificate) { batchInfo.setWAIV_DEV_REJ_NO(org.apache.commons.lang3.StringUtils.isNotBlank(feederCertificate.getExaminerAfter()) ? feederCertificate.getExaminerAfter() : feederCertificate.getExaminer()); } else { batchInfo.setWAIV_DEV_REJ_NO(moveLibraryBoxDTO.getBatchNo());//wdr号(把mes的sn号放里面) } } else { batchInfo.setWAIV_DEV_REJ_NO("*");//wdr号 } batchInfo.setLOCATION_NO(moveLibraryBoxDTO.getStartLocationNoIfs());//ifs出发库位号 batchInfo.setTO_LOCATION_NO(moveLibraryBoxDTO.getArriveLocationNoIfs());//ifs到达库位号 batchInfo.setTO_CONTRACT(stockConfigBean.getRegion());//目标域 // 因为现在多个 mes库位可能对应一个 ifs库位 所以 执行移库操作之前需要判断一下库位是否相同 // xcg 20230413 if (StrUtil.equals(batchInfo.getLOCATION_NO(), batchInfo.getTO_LOCATION_NO())) { continue; } dataBeanList.add(batchInfo); } if (CollectionUtil.isEmpty(dataBeanList)) { return; } ifsMoveLibraryDTO.setBATCH_INFO(dataBeanList); Gson gson = new Gson(); String jsonstr = gson.toJson(ifsMoveLibraryDTO); JSONObject jsonObject = JSONObject.parseObject(jsonstr);//解决序列化时自动将大写转小写问题 R res = ifsFeignClient.importMovePartStd(jsonObject, true); if (res.getCode() != 0) { throw new RuntimeException("{" + moveLibraryBoxDTOListFilter.get(0).getBatchNo() + "}IFS与MES库存不一致"); } } } /** * 精准查询ifs库存(零件号、批次号、wdr号) * * @param partNo 零件号 * @param batchNo 批次号 * @param wdr wdr号 * @return */ public R getIfsStockPrecise(String partNo, String batchNo, String wdr) { if (StringUtils.isBlank(partNo) || StringUtils.isBlank(batchNo) || StringUtils.isBlank(wdr)) { throw new RuntimeException("零件号&&批次号&&wdr号传参不可为空"); } JSONObject jsonObject = new JSONObject(); jsonObject.put("PART_NO", partNo); jsonObject.put("QUANTITY_FLAG", ">0"); jsonObject.put("LOT_BATCH_NO", batchNo); jsonObject.put("WDR_NO", wdr); R result = ifsFeignClient.queryInventoryInfoStd(jsonObject, true); if (result.getCode() == 0) { JSONObject data = (JSONObject) JSON.toJSON(result.getData()); JSONArray array = new JSONArray(); for (int i = 0; i < data.getJSONArray("LIST_INFO").size(); i++) { if (data.getJSONArray("LIST_INFO").getJSONObject(i).getBigDecimal("QTY_AVAILABLE").compareTo(BigDecimal.ZERO) > 0) { array.add(data.getJSONArray("LIST_INFO").getJSONObject(i)); } } return R.ok(array, "OK"); } else { throw new RuntimeException(result.getMsg()); } } }