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<MoveLibraryBoxDTO> 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<MoveLibraryBoxDTO> moveLibraryBoxDTOList, Long id) {
|
Long itemCount = packagingItemMapper.getPackagingItemCountByPackagingId(id);
|
//校验SQL查询结果
|
if (moveLibraryBoxDTOList.size() != itemCount) {
|
return R.failed("实际明细行数=" + moveLibraryBoxDTOList.size() + "->不等于SQL关联查询明细行数=" + itemCount);
|
}
|
//校验box明细行是否都存在到达库位号且到达库位为成品库位
|
List<MoveLibraryBoxDTO> 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<MoveLibraryBoxDTO> 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<MoveLibraryBoxDTO> moveLibraryBoxDTOListFilter = moveLibraryBoxDTOList.stream().filter(o -> StringUtils.isNotBlank(o.getStartLocationNoIfs()) && StringUtils.isNotBlank(o.getArriveLocationNoIfs())).collect(Collectors.toList());
|
//将list按照零件号进行分组,去除IFS启用批次管理为true的数据
|
Map<Long, List<MoveLibraryBoxDTO>> map = moveLibraryBoxDTOListFilter.stream().filter(x -> !x.getLotTrackingIfs()).collect(Collectors.groupingBy(MoveLibraryBoxDTO::getPartId));
|
List<MoveLibraryBoxDTO> ifsList = new ArrayList<>();
|
for (Map.Entry<Long, List<MoveLibraryBoxDTO>> entry : map.entrySet()) {
|
List<MoveLibraryBoxDTO> 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<MoveLibraryBoxDTO> 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<IfsMoveLibraryDTO.DataBean> 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<MoveLibraryBoxDTO> moveLibraryBoxDTOList) {
|
List<MoveLibraryBoxDTO> 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<MoveLibraryBoxDTO> 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<IfsMoveLibraryDTO.DataBean> 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.<FeederCertificate>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());
|
}
|
}
|
}
|