| | |
| | | import com.baomidou.mybatisplus.mapper.EntityWrapper; |
| | | import com.core.common.Cools; |
| | | import com.core.exception.CoolException; |
| | | import com.zy.asrs.entity.WrkDetl; |
| | | import com.zy.asrs.entity.WrkMast; |
| | | import com.zy.asrs.mapper.OrderDetlMapper; |
| | | import com.zy.asrs.mapper.OrderMapper; |
| | | import com.zy.asrs.mapper.WrkMastMapper; |
| | | import com.zy.asrs.entity.*; |
| | | import com.zy.asrs.mapper.*; |
| | | import com.zy.asrs.service.ApiLogService; |
| | | import com.zy.asrs.service.WorkService; |
| | | import com.zy.asrs.service.WrkDetlService; |
| | | import com.zy.asrs.utils.Utils; |
| | | import com.zy.common.constant.MesConstant; |
| | | import com.zy.common.model.StartupDto; |
| | | import com.zy.common.properties.SlaveProperties; |
| | | import com.zy.common.service.CommonService; |
| | | import com.zy.common.utils.HttpHandler; |
| | | import com.zy.system.entity.Config; |
| | | import com.zy.system.mapper.ConfigMapper; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import javax.annotation.Resource; |
| | | import java.util.Date; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | |
| | | */ |
| | | @Slf4j |
| | | @Service |
| | | @Transactional |
| | | public class GhjtHandler { |
| | | |
| | | @Resource |
| | |
| | | @Resource |
| | | private OrderDetlMapper orderDetlMapper; |
| | | |
| | | @Transactional |
| | | @Resource |
| | | private LocDetlMapper locDetlMapper; |
| | | |
| | | @Resource |
| | | private LocMastMapper locMastMapper; |
| | | |
| | | @Resource |
| | | private WorkService workService; |
| | | |
| | | @Resource |
| | | private ConfigMapper configMapper; |
| | | |
| | | @Autowired |
| | | private SlaveProperties slaveProperties; |
| | | |
| | | @Resource |
| | | private CommonService commonService; |
| | | |
| | | // 堆垛机对应一楼出库站点 |
| | | private static final int[] oneFloorOutSite = new int[]{0,3002,3003,3006,3008,3009,3012}; |
| | | |
| | | public void startCkrwPushGwcs(WrkMast wrkMast) { |
| | | |
| | | // 获取请求头 |
| | |
| | | } else if (wrkMast.getIoType() == 3) { |
| | | // 修改工作主档状态 |
| | | wrkMast.setWrkSts(15L); |
| | | wrkMast.setModiTime(new Date()); |
| | | } else if(wrkMast.getIoType() == 12) { // 跨巷道转移 |
| | | wrkMast.setWrkSts(1L); // 状态改为1.生成入库id |
| | | wrkMast.setModiTime(new Date()); |
| | | } |
| | | wrkMastMapper.updateById(wrkMast); |
| | |
| | | } else if (wrkMast.getIoType() == 103 && (wrkMast.getStaNo() == 3077 || wrkMast.getStaNo() == 3106)) { // 两箱出一箱,需桁架理货 |
| | | // 都要先去理货 |
| | | flag = 2; |
| | | // if (wrkDetls.size() == 1) { // 一卷贴标出库 |
| | | // flag = 4; |
| | | // } else { // 多卷直接出库 |
| | | // |
| | | // } |
| | | } |
| | | return flag; |
| | | } |
| | | |
| | | /** |
| | | * 自动备货处理 |
| | | */ |
| | | public void autoStockUpHandler(List<String> list,int columnNum) { |
| | | |
| | | // 根据包装组号获取所在库位 |
| | | List<LocDetl> locDetls = locDetlMapper.selectLocNoByGroupNo(list); |
| | | if (locDetls.isEmpty()) { |
| | | return; |
| | | } |
| | | // 相同则合并,一个库位两个包装组号 |
| | | Map<String,List<String>> map = new HashMap<>(); |
| | | for(LocDetl locDetl : locDetls) { |
| | | List<String> brand = map.get(locDetl.getLocNo()); |
| | | if (brand == null) { |
| | | map.put(locDetl.getLocNo(),new ArrayList<String>(){{add(locDetl.getBrand());}}); |
| | | } else { |
| | | brand.add(locDetl.getBrand()); |
| | | map.put(locDetl.getLocNo(),brand); |
| | | } |
| | | } |
| | | |
| | | // 遍历堆垛机并且判断是否存在任务 |
| | | for (int i = 1; i <= 6; i++) { |
| | | // 要备货的库位 |
| | | String sourceLocNo = null; |
| | | // 备货目标库位 |
| | | String staLocNo = null; |
| | | Integer wrkCount = wrkMastMapper.selectCount(new EntityWrapper<WrkMast>().eq("crn_no", i)); |
| | | if(wrkCount > 0) { |
| | | log.warn("{}号堆垛机已存在任务",i); |
| | | continue; |
| | | } |
| | | // 根据堆垛机号查询到对应的深库位和浅库位 深库位4*n-3和4*n 浅库位4*n-2和4*n-1 |
| | | int s1 = 4*i-3; |
| | | int s2 = 4*i; |
| | | int q1 = 4 * i - 2; |
| | | int q2 = 4 * i -1; |
| | | |
| | | // 根据堆垛机号获取一个浅库位 |
| | | for(String key : map.keySet()) { |
| | | int row = Integer.parseInt(key.substring(0, 2)); |
| | | if (row == q1 || row == q2) { |
| | | sourceLocNo = key; |
| | | break; |
| | | } |
| | | } |
| | | // 浅库位没有则找一个深库位 |
| | | if (sourceLocNo == null) { |
| | | for(String key : map.keySet()) { |
| | | int row = Integer.parseInt(key.substring(0, 2)); |
| | | if (row == s1 || row == s2) { |
| | | sourceLocNo = key; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | // 没有找到源库位 |
| | | if (sourceLocNo == null) { |
| | | log.warn("没有找到源库位,堆垛机:{}",i); |
| | | continue; |
| | | } |
| | | // 寻找一个备货的目标库位,先深后浅 |
| | | List<LocMast> locMasts1 = locMastMapper.selectList(new EntityWrapper<LocMast>().eq("loc_sts", "O").eq("crn_no", i).in("row1", s1, s2) |
| | | .le("bay1", columnNum)); |
| | | if (locMasts1.isEmpty()) { |
| | | // 深库位为空了,取浅库位 |
| | | List<LocMast> locMasts2 = locMastMapper.selectList(new EntityWrapper<LocMast>().eq("loc_sts", "O").eq("crn_no", i).in("row1", q1, q2) |
| | | .le("bay1", columnNum)); |
| | | if (!locMasts2.isEmpty()) { |
| | | staLocNo = locMasts2.get(0).getLocNo(); |
| | | } |
| | | } else { |
| | | staLocNo = locMasts1.get(0).getLocNo(); |
| | | } |
| | | |
| | | if(staLocNo == null) { |
| | | log.warn("{}号堆垛机备货区满了",i); |
| | | continue; |
| | | } |
| | | |
| | | // 备货的源库位,目标库位都获取到了,生成移库任务 |
| | | workService.locMove(sourceLocNo,staLocNo,29L); |
| | | |
| | | // 订单明细改成备货中,在任务完成时候改成备货完成,并判断整个订单是否完成 |
| | | orderDetlMapper.updateOrderDetlStatusByPackageNo(map.get(sourceLocNo), 1); |
| | | |
| | | // 移除已生成备货库位 |
| | | map.remove(sourceLocNo); |
| | | } |
| | | |
| | | } |
| | | |
| | | public void autoMoveLoc(List<OrderDetl> orderDetlList) { |
| | | |
| | | // 判断是否已经有执行的移库任务 |
| | | Integer count = wrkMastMapper.selectCount(new EntityWrapper<WrkMast>().in("io_type", 11, 12)); |
| | | if (count > 0) { |
| | | return; |
| | | } |
| | | |
| | | OrderDetl detl = null; // 要移库的明细 |
| | | String staLoc = null; // 移库目标库位 |
| | | |
| | | // 从待移库位列表中先浅后深获取一个待移库位 |
| | | Optional<OrderDetl> any = orderDetlList.stream().filter(orderDetl -> Utils.isShallowLoc(slaveProperties,orderDetl.getSpecs())).findAny(); |
| | | |
| | | if (any.isPresent()){ |
| | | detl = any.get(); |
| | | } |
| | | // 剩下的应该都是深库位,获取第一个 |
| | | if (detl == null) { |
| | | detl = orderDetlList.get(0); |
| | | // 对应浅库位有货,在堆垛机出库的时候会检测到,在那里生成移库任务 |
| | | } |
| | | |
| | | // 获取备货区配置 |
| | | Config config = configMapper.selectConfigByCode("auto_stock_up"); |
| | | if (config == null) { |
| | | return; |
| | | } |
| | | // 备货取是前几列 |
| | | int bay1 = Integer.parseInt(config.getValue()); |
| | | // 指定的目标库位 |
| | | String model = detl.getModel(); |
| | | |
| | | // 指定目标库位 |
| | | if (!Cools.isEmpty(model)) { |
| | | // 目标库位是深库位 |
| | | if (Utils.isDeepLoc(slaveProperties,model)) { |
| | | // 目标库位 |
| | | LocMast locMast2 = locMastMapper.selectById(model); |
| | | if (locMast2 == null || !locMast2.getLocSts().equals("O")) { |
| | | log.error("指定的目标库位【{}】状不为空", model); |
| | | return; |
| | | } |
| | | // 获取到对应浅库位 |
| | | String shallowLoc = Utils.getShallowLoc(slaveProperties, model); |
| | | LocMast locMast = locMastMapper.selectById(shallowLoc); |
| | | // 浅库位有货 |
| | | if (locMast.getLocSts().equals("F") || locMast.getLocSts().equals("D")) { |
| | | log.error("选择的深库位【{}】,但是浅库位【{}】有货", model, locMast.getLocNo()); |
| | | return; |
| | | } |
| | | // 避开备货区 |
| | | if (Utils.getBay(model) <= bay1) { |
| | | log.error("指定的目标库位【{}】在备货区,不能转移", model); |
| | | return; |
| | | } |
| | | } |
| | | // 深库位检测通过,或者是浅库位 |
| | | staLoc = model; |
| | | } else if ( detl.getBeBatch() != null) { // 指定目标巷道 |
| | | // 目标巷道 |
| | | Integer beBatch = detl.getBeBatch(); |
| | | // 从巷道里面先深后浅取一个空库位,不要占用备货区 |
| | | List<LocMast> locMasts = locMastMapper.selectList(new EntityWrapper<LocMast>().eq("crn_no", beBatch).eq("loc_sts", "O").gt("bay1", bay1)); |
| | | if (locMasts.isEmpty()) { |
| | | log.error("指定巷道【{}】没有能移库的空库位了",beBatch); |
| | | return; |
| | | } |
| | | // 先过滤出深库位 |
| | | Optional<LocMast> a = locMasts.stream().filter(locMast -> Utils.isDeepLoc(slaveProperties,locMast.getLocNo())).findAny(); |
| | | if (a.isPresent()){ |
| | | staLoc = a.get().getLocNo(); |
| | | // 获取到对应浅库位 |
| | | String shallowLoc = Utils.getShallowLoc(slaveProperties, staLoc); |
| | | LocMast locMast = locMastMapper.selectById(shallowLoc); |
| | | // 浅库位有货 |
| | | if (locMast.getLocSts().equals("F") || locMast.getLocSts().equals("D")) { |
| | | log.error("指定的目标巷道深库位【{}】,但是浅库位【{}】有货",staLoc,locMast.getLocNo()); |
| | | return; |
| | | } |
| | | } |
| | | // 深库位没有则取浅库位 |
| | | if (staLoc == null) { |
| | | staLoc = locMasts.get(0).getLocNo(); |
| | | } |
| | | } else { |
| | | log.error("目标库位或目标巷道有误:{}",detl); |
| | | return; |
| | | } |
| | | |
| | | // 生成跨巷道移库任务 |
| | | workService.autoLocMove(detl.getOrderNo(),detl.getSpecs(),staLoc,29L); |
| | | |
| | | // 更新单据明细移库状态为移库中 |
| | | detl.setDanger(1); |
| | | if (detl.getBeBatch() != null) { |
| | | detl.setModel(staLoc); // 补充目标库位 |
| | | } |
| | | orderDetlMapper.updateById(detl); |
| | | // 更新单据状态为2处理中 |
| | | orderMapper.updatePendingSettleByOrderNo(detl.getOrderNo(),2L); |
| | | } |
| | | |
| | | /** |
| | | * 给指定桁架生成理货任务,按规则寻找到能理货的两个库位 |
| | | * 1.能理货的都是一箱一卷的 |
| | | * 2.规则:木箱型号相同-管芯类型相同-实测宽幅相同-生箔厚度相同-分切下料时间相近 |
| | | */ |
| | | public void autoTallyGoods(int flag) { |
| | | |
| | | // 获取备货区配置 |
| | | Config config = configMapper.selectConfigByCode("auto_stock_up"); |
| | | if (config == null) { |
| | | throw new CoolException("理货获取备货区配置错误!!!"); |
| | | } |
| | | // 前几列是备货区 |
| | | int columnNum = Integer.parseInt(config.getValue()); |
| | | |
| | | // 寻找一箱一卷的,没有理货的,不在备货区的物料明细 |
| | | List<LocDetl> tallyGoosList = locDetlMapper.selectTallyGoosList(columnNum); |
| | | |
| | | // 寻找满足理货条件的两个木箱 |
| | | LocDetl leftLocDetl = null; |
| | | LocDetl rightLocDetl = null; |
| | | for (int i = 0; i < tallyGoosList.size(); i++) { |
| | | leftLocDetl = tallyGoosList.get(i); |
| | | for (int j = i + 1; j < tallyGoosList.size(); j++) { |
| | | LocDetl tempLocDetl = tallyGoosList.get(j); |
| | | if (leftLocDetl.getColor().equals(tempLocDetl.getColor()) && leftLocDetl.getManu().equals(tempLocDetl.getManu()) && |
| | | leftLocDetl.getSku().equals(tempLocDetl.getSku()) && leftLocDetl.getItemNum().equals(tempLocDetl.getItemNum())) { |
| | | rightLocDetl = tempLocDetl; |
| | | break; |
| | | } |
| | | } |
| | | if (rightLocDetl != null) { |
| | | break; |
| | | } |
| | | } |
| | | |
| | | if (leftLocDetl == null || rightLocDetl == null) { |
| | | // log.warn("没有找到两个能理货的木箱"); |
| | | return; |
| | | } |
| | | |
| | | // 找到的两个木箱刚好在一个托盘上,直接更改理货状态为2 |
| | | if (leftLocDetl.getLocNo().equals(rightLocDetl.getLocNo())) { |
| | | locDetlMapper.updateLhStsByLocNo(leftLocDetl.getLocNo(), 2); |
| | | } else { |
| | | |
| | | // 判断是去哪套桁架的哪个站点 t0组盘点,t1左换盘点,t2右换盘点 |
| | | int t0 = 3046, t1 = 3045, t2 = 3044; |
| | | if (flag == 2) { |
| | | t0 = 3042; |
| | | t1 = 3041; |
| | | t2 = 3040; |
| | | } |
| | | |
| | | // 生成空闲理货任务 |
| | | WrkDetl wrkDetl1 = tallyGoodsGenerate(t1, leftLocDetl); |
| | | WrkDetl wrkDetl2 = tallyGoodsGenerate(t2, rightLocDetl); |
| | | |
| | | Date now = new Date(); |
| | | |
| | | // 寻找一个空库位 |
| | | StartupDto dto = commonService.getLocNo(1, t0, null, 0); |
| | | // 生成组盘入库任务 |
| | | WrkMast wrkMast = new WrkMast(); |
| | | wrkMast.setWrkNo(dto.getWorkNo()); |
| | | wrkMast.setIoTime(now); |
| | | wrkMast.setWrkSts(1L); // 工作状态 |
| | | wrkMast.setIoType(1); // 入出库类型 |
| | | wrkMast.setIoPri(13D); // 优先级:13 |
| | | wrkMast.setCrnNo(dto.getCrnNo()); |
| | | wrkMast.setSourceStaNo(dto.getSourceStaNo()); // 源站 |
| | | wrkMast.setStaNo(dto.getStaNo()); // 目标站 |
| | | wrkMast.setSourceLocNo(""); // 源库位 |
| | | wrkMast.setLocNo(dto.getLocNo()); |
| | | wrkMast.setFullPlt("Y"); // 满板:Y |
| | | wrkMast.setPicking("N"); // 拣料 |
| | | wrkMast.setExitMk("N"); // 退出 |
| | | wrkMast.setEmptyMk("N"); // 空板 |
| | | wrkMast.setLinkMis("N"); |
| | | wrkMast.setBarcode(""); // zwcs执行入库时更新托盘码 |
| | | wrkMast.setAppeUser(29L); // 操作人员 root |
| | | wrkMast.setAppeTime(now); |
| | | wrkMast.setModiUser(29L); |
| | | wrkMast.setModiTime(now); |
| | | if (wrkMastMapper.insert(wrkMast) != 1) { |
| | | throw new CoolException("空闲理货组盘保存工作档失败,详情:" + wrkMast); |
| | | } |
| | | |
| | | // 生成工作明细 |
| | | wrkDetl1.setWrkNo(wrkMast.getWrkNo()); |
| | | wrkDetl1.setOrigin("左"); // 固定拆到左边 |
| | | wrkDetl1.setDeadWarn(2); // 已理货标识 |
| | | wrkDetl2.setWrkNo(wrkMast.getWrkNo()); |
| | | wrkDetl2.setOrigin("右"); |
| | | wrkDetl2.setDeadWarn(2); |
| | | wrkDetlService.insert(wrkDetl1); // 入库完成时更新托盘码 |
| | | wrkDetlService.insert(wrkDetl2); |
| | | |
| | | // 更新目标库位状态 |
| | | LocMast locMast = locMastMapper.selectById(dto.getLocNo()); |
| | | locMast.setLocSts("S"); |
| | | locMastMapper.updateById(locMast); // 入库完成时更新托盘码 |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 生成空闲理货到换盘桁架的任务 |
| | | * |
| | | * @param site 换盘点 |
| | | * @param locDetl 库存明细 |
| | | */ |
| | | private WrkDetl tallyGoodsGenerate(int site, LocDetl locDetl) { |
| | | |
| | | // 判断库位状态 |
| | | LocMast locMast = locMastMapper.selectById(locDetl.getLocNo()); |
| | | if (!locMast.getLocSts().equals("F")) { |
| | | throw new CoolException("理货库位状态有误,不为F,库位号:" + locMast.getLocNo()); |
| | | } |
| | | |
| | | Date now = new Date(); |
| | | |
| | | // 生成工作档 |
| | | WrkMast wrkMast = new WrkMast(); |
| | | // 获取工作号 |
| | | int workNo = commonService.getWorkNo(5); |
| | | wrkMast.setWrkNo(workNo); |
| | | wrkMast.setIoTime(now); |
| | | wrkMast.setWrkSts(11L); // 工作状态:11.生成出库ID |
| | | wrkMast.setIoType(109); // 入出库状态 109.空闲理货 |
| | | wrkMast.setIoPri(13D); // 优先级:13 |
| | | wrkMast.setCrnNo(locMast.getCrnNo()); |
| | | wrkMast.setSourceStaNo(oneFloorOutSite[locMast.getCrnNo()]); // 源站 |
| | | wrkMast.setStaNo(site); // 目标站 |
| | | wrkMast.setSourceLocNo(locDetl.getLocNo()); // 源库位 |
| | | wrkMast.setFullPlt("Y"); // 满板:Y |
| | | wrkMast.setPicking("N"); // 拣料 |
| | | wrkMast.setExitMk("N"); // 退出 |
| | | wrkMast.setEmptyMk("N"); // 空板 |
| | | wrkMast.setLinkMis("N"); |
| | | wrkMast.setSheetNo("0"); |
| | | wrkMast.setBarcode(locDetl.getZpallet()); |
| | | wrkMast.setAppeUser(29L); // 操作人员 root |
| | | wrkMast.setAppeTime(now); |
| | | wrkMast.setModiUser(29L); |
| | | wrkMast.setModiTime(now); |
| | | if (wrkMastMapper.insert(wrkMast) != 1) { |
| | | throw new CoolException("空闲理货保存工作档失败,详情:" + wrkMast); |
| | | } |
| | | |
| | | // 生成工作明细 |
| | | WrkDetl wrkDetl = new WrkDetl(); |
| | | wrkDetl.sync(locDetl); |
| | | wrkDetl.setWrkNo(workNo); |
| | | wrkDetl.setIoTime(now); |
| | | wrkDetl.setAppeTime(now); |
| | | wrkDetl.setAppeUser(29L); |
| | | wrkDetl.setModiTime(now); |
| | | wrkDetl.setModiUser(29L); |
| | | if (!wrkDetlService.insert(wrkDetl)) { |
| | | throw new CoolException("空闲理货保存工作档明细失败,详情:" + wrkDetl); |
| | | } |
| | | |
| | | // 修改出库状态 |
| | | locMast.setLocSts("R"); |
| | | locMast.setModiUser(29L); |
| | | locMast.setModiTime(now); |
| | | if (locMastMapper.updateById(locMast) != 1) { |
| | | throw new CoolException("空闲理货预约库位状态失败,库位号:" + locMast.getLocNo()); |
| | | } |
| | | |
| | | // 更新库存明细为理货中 |
| | | locDetlMapper.updateLhStsByLocNo(locDetl.getLocNo(), 1); |
| | | |
| | | return wrkDetl; |
| | | } |
| | | |
| | | } |