BusinessServiceImpl.java 56 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178
  1. package com.warewms.business.service.impl;
  2. import cn.hutool.core.util.NumberUtil;
  3. import cn.hutool.core.util.ObjectUtil;
  4. import com.baomidou.mybatisplus.core.toolkit.IdWorker;
  5. import com.warewms.business.domain.dto.AgvCallDTO;
  6. import com.warewms.business.domain.dto.AgvCallItem;
  7. import com.warewms.business.domain.dto.AgvCallItemDTO;
  8. import com.warewms.business.form.LineCallDetailsForm;
  9. import com.warewms.business.form.LineCallForm;
  10. import com.warewms.business.form.LineCallListFrom;
  11. import com.warewms.business.service.IBusinessService;
  12. import com.warewms.common.AmsConstant;
  13. import com.warewms.common.base.domain.AjaxResult;
  14. import com.warewms.common.constant.WmsConstant;
  15. import com.warewms.common.exception.ServiceException;
  16. import com.warewms.common.utils.redis.RedisCache;
  17. import com.warewms.common.utils.redis.RedisKey;
  18. import com.warewms.common.utils.uuid.SnowflakeIdWorker;
  19. import com.warewms.ndc.common.ByteUtil;
  20. import com.warewms.ndc.common.CRC16Util;
  21. import com.warewms.task.domain.AmsTask;
  22. import com.warewms.wms.asn.form.PaForm;
  23. import com.warewms.wms.asn.service.IWmsDocAsnHeaderService;
  24. import com.warewms.wms.base.dto.BaseLocationInfoSameColDTO;
  25. import com.warewms.wms.base.entity.BaseLocationInfo;
  26. import com.warewms.wms.base.entity.BaseLocationZone;
  27. import com.warewms.wms.base.mapper.BaseLocationInfoMapper;
  28. import com.warewms.wms.base.service.IBaseLocationInfoService;
  29. import com.warewms.wms.box.domain.WmsBoxInfo;
  30. import com.warewms.wms.box.service.IWmsBoxInfoService;
  31. import com.warewms.wms.flow.domain.AsnSoStrategy;
  32. import com.warewms.wms.flow.mapper.AsnSoStrategyMapper;
  33. import com.warewms.wms.flow.service.IFlowConfigHeaderService;
  34. import com.warewms.wms.flow.vo.FlowConfigHeaderVO;
  35. import com.warewms.wms.inv.domain.form.InvLotLocIdMoveForm;
  36. import com.warewms.wms.inv.domain.vo.InvLotLocIdLotattVO;
  37. import com.warewms.wms.inv.dto.LotattDTO;
  38. import com.warewms.wms.inv.service.IInvLotLocIdService;
  39. import com.warewms.wms.order.form.CheckOutInfoForm;
  40. import com.warewms.wms.task.domain.WcsTask;
  41. import com.warewms.wms.task.dto.WcsTaskLocationDTO;
  42. import com.warewms.wms.task.mapper.WcsTaskMapper;
  43. import com.warewms.wms.task.service.IWcsTaskService;
  44. import lombok.extern.slf4j.Slf4j;
  45. import org.apache.commons.lang3.StringUtils;
  46. import org.springframework.beans.BeanUtils;
  47. import org.springframework.beans.factory.annotation.Autowired;
  48. import org.springframework.stereotype.Service;
  49. import org.springframework.transaction.annotation.Propagation;
  50. import org.springframework.transaction.annotation.Transactional;
  51. import java.math.BigDecimal;
  52. import java.util.*;
  53. import java.util.stream.Collectors;
  54. @Slf4j
  55. @Service
  56. public class BusinessServiceImpl implements IBusinessService {
  57. @Autowired
  58. private IBusinessService businessService;
  59. @Autowired
  60. private IBaseLocationInfoService baseLocationInfoService;
  61. @Autowired
  62. private IInvLotLocIdService invLotLocIdService;
  63. @Autowired
  64. private WcsTaskMapper wcsTaskMapper;
  65. @Autowired
  66. private AsnSoStrategyMapper asnSoStrategyMapper;
  67. @Autowired
  68. private BaseLocationInfoMapper baseLocationInfoMapper;
  69. @Autowired
  70. private RedisCache redisCache;
  71. @Autowired
  72. private IWcsTaskService wcsTaskService;
  73. @Autowired
  74. private IAmsTaskService amsTaskService;
  75. @Autowired
  76. private IFlowConfigHeaderService flowConfigHeaderService;
  77. @Autowired
  78. private IWmsDocAsnHeaderService iWmsDocAsnHeaderService;
  79. @Autowired
  80. private IWmsBoxInfoService wmsBoxInfoService;
  81. public static int genIKey(String taskNo) {
  82. int res = CRC16Util.calcCrc16(ByteUtil.string2byteArray(taskNo));
  83. return res == 0 ? genIKey(NumberUtil.add(new BigDecimal(taskNo), BigDecimal.ONE).toString()) : res;
  84. }
  85. @Transactional
  86. @Override
  87. public AjaxResult agvCall(FlowConfigHeaderVO flowConfigHeaderVO, LineCallListFrom lform, LineCallForm lineCallForm
  88. , String asnNo, int orderRules, boolean superHighMark) {
  89. Map<String, AgvCallDTO> map = new HashMap<>();
  90. List<AgvCallDTO> list = new ArrayList<>();
  91. if (flowConfigHeaderVO.getFlowType().equals("ASN") && org.apache.commons.lang3.StringUtils.isEmpty(lform.getLocationFrom())) {
  92. return AjaxResult.error("入库任务必须选择起始库位");
  93. }
  94. if (flowConfigHeaderVO.getFlowType().equals("SO") && (lform.getQty() == null || lform.getQty().longValue() == 0)) {
  95. return AjaxResult.error("出库任务必须选择数量");
  96. }
  97. AgvCallDTO agvCallDTO;
  98. if (map.containsKey(lform.getLocationFrom() + "-" + lform.getLocationTo())) {
  99. agvCallDTO = map.get(lform.getLocationFrom() + "-" + lform.getLocationTo());
  100. } else {
  101. agvCallDTO = new AgvCallDTO();
  102. agvCallDTO.setWarehouseId(1L);//没用暂时写死
  103. agvCallDTO.setLocationFrom(lform.getLocationFrom());
  104. agvCallDTO.setLocationTo(lform.getLocationTo());
  105. agvCallDTO.setId(lform.getId());
  106. agvCallDTO.setPalletNo(lform.getPalletNo());
  107. agvCallDTO.setTaskType(lineCallForm.getFlowId().toString());
  108. agvCallDTO.setOrderNo(asnNo); // 入库单号
  109. agvCallDTO.setOrderRules(orderRules);
  110. }
  111. AgvCallItemDTO agvCallItemDTO = new AgvCallItemDTO();
  112. agvCallItemDTO.setWarehouseId(1L);
  113. agvCallItemDTO.setSku(lform.getSku());
  114. agvCallItemDTO.setQty(lform.getQty());
  115. agvCallItemDTO.setSupplier(lform.getSupplier());
  116. agvCallItemDTO.setWeight(lform.getWeight());
  117. agvCallItemDTO.setLocationFrom(lform.getLocationFrom());
  118. agvCallItemDTO.setLocationTo(lform.getLocationTo());
  119. agvCallItemDTO.setSuperHigh(superHighMark);
  120. agvCallDTO.getAgvCallItemDTOList().add(agvCallItemDTO);
  121. LotattDTO lotattDTO = new LotattDTO();
  122. List<LineCallDetailsForm> lineCallDetailsForms = lform.getLineCallDetailsFormList();
  123. if (lineCallDetailsForms != null && lineCallDetailsForms.size() > 0) {
  124. for (LineCallDetailsForm detailsForm : lineCallDetailsForms) {
  125. lotattDTO.setAttr(detailsForm.getLotattId(), detailsForm.getLotattValue());
  126. }
  127. }
  128. agvCallItemDTO.setLotattDTO(lotattDTO);
  129. map.put(lform.getLocationFrom() + "-" + lform.getLocationTo(), agvCallDTO);
  130. for (Map.Entry<String, AgvCallDTO> entry : map.entrySet()) {
  131. AgvCallDTO mapValue = entry.getValue();
  132. list.add(mapValue);
  133. }
  134. return businessService.agvCall(flowConfigHeaderVO, list);
  135. }
  136. @Transactional
  137. @Override
  138. public AjaxResult agvCall(AgvCallItem agvCallItem, Long flowId) {
  139. //查询所属流程
  140. FlowConfigHeaderVO flowConfigHeaderVO = flowConfigHeaderService.selectFlowConfigHeaderById(flowId);
  141. AgvCallItemDTO agvCallItemDTO = new AgvCallItemDTO();
  142. BeanUtils.copyProperties(agvCallItem, agvCallItemDTO);
  143. List<AgvCallDTO> list = new ArrayList<>();
  144. AgvCallDTO agvCallDTO = new AgvCallDTO();
  145. agvCallDTO.setWarehouseId(WmsConstant.WAREHOUSE_ID);
  146. agvCallDTO.setLocationFrom(agvCallItemDTO.getLocationFrom());
  147. agvCallDTO.setLocationTo(agvCallItemDTO.getLocationTo());
  148. agvCallItemDTO.setWarehouseId(WmsConstant.WAREHOUSE_ID);
  149. agvCallItemDTO.setFlowConfigHeaderVO(flowConfigHeaderVO);
  150. agvCallDTO.getAgvCallItemDTOList().add(agvCallItemDTO);
  151. list.add(agvCallDTO);
  152. return this.agvCall(flowConfigHeaderVO, list);
  153. }
  154. @Transactional
  155. @Override
  156. public AjaxResult agvCall(FlowConfigHeaderVO flowConfigHeaderVO, AgvCallDTO agvCallDTO) {
  157. List<AgvCallDTO> agvCallDTOList = new ArrayList<>();
  158. List<AgvCallItemDTO> callItemDTOList = new ArrayList<>();
  159. AgvCallItemDTO callItemDTO = new AgvCallItemDTO();
  160. callItemDTO.setLocationFrom(agvCallDTO.getLocationFrom());
  161. callItemDTO.setLocationTo(agvCallDTO.getLocationTo());
  162. callItemDTO.setWarehouseId(agvCallDTO.getWarehouseId());
  163. callItemDTO.setLotattDTO(new LotattDTO());
  164. callItemDTO.setExtParam(agvCallDTO.getExtParam());
  165. callItemDTOList.add(callItemDTO);
  166. agvCallDTO.setAgvCallItemDTOList(callItemDTOList);
  167. agvCallDTOList.add(agvCallDTO);
  168. return businessService.agvCall(flowConfigHeaderVO, agvCallDTOList);
  169. }
  170. @Transactional
  171. @Override
  172. public AjaxResult agvCall(FlowConfigHeaderVO flowConfigHeaderVO, List<AgvCallDTO> agvCallDTOList) {
  173. //唯一操作标识,用于redis标记。报错时根据该id进行删除
  174. Long token = SnowflakeIdWorker.generateId();
  175. try {
  176. //查询全局配置策略
  177. AsnSoStrategy asnSoStrategy = asnSoStrategyMapper.selectAsnSoStrategy();
  178. for (AgvCallDTO agvCallDTO : agvCallDTOList) {
  179. //如果是入库把起始库位相同的数据整合到一起生成库存记录
  180. BaseLocationInfo locationFrom = null;
  181. BaseLocationInfo locationTo = null;
  182. List<WcsTask> wcsTaskList = new ArrayList<>();
  183. String paramLocationFrom = agvCallDTO.getLocationFrom();
  184. String paramLocationTo = agvCallDTO.getLocationTo();
  185. List<String> zoneIdList = new ArrayList<>();
  186. if (StringUtils.isEmpty(paramLocationFrom)) {
  187. paramLocationFrom = flowConfigHeaderVO.getLocationFrom();
  188. }
  189. if (StringUtils.isEmpty(paramLocationTo)) {
  190. paramLocationTo = flowConfigHeaderVO.getLocationTo();
  191. }
  192. if (!StringUtils.isEmpty(flowConfigHeaderVO.getLocationFrom())) {
  193. zoneIdList = Arrays.stream(flowConfigHeaderVO.getLocationFrom().split(",")).collect(Collectors.toList());
  194. }
  195. if (flowConfigHeaderVO.getFlowType().equals("ASN")) {
  196. AgvCallItemDTO agvCall = agvCallDTO.getAgvCallItemDTOList().get(0);
  197. List<BaseLocationInfo> locationFromList = this.convertLocation(paramLocationFrom, agvCallDTO.getWarehouseId(), null);
  198. List<BaseLocationInfo> locationToList = null;
  199. //排序规则 普通入库回库先放在col_no小的位置 - 1,备货入库回库放在col_no大的位置 - 2
  200. if (agvCallDTO.getOrderRules() == 1) {
  201. locationToList = this.convertLocation(paramLocationTo, agvCallDTO.getWarehouseId(), "col_no + 0,shift_no + 0");
  202. } else {
  203. locationToList = this.convertLocation(paramLocationTo, agvCallDTO.getWarehouseId(), "col_no + 0 desc,shift_no + 0");
  204. }
  205. locationFrom = this.zoneLocationAllocation(locationFromList, "locationFrom", "ASN", asnSoStrategy, agvCall, token);
  206. locationTo = this.zoneLocationAllocation(locationFrom, locationToList, "locationTo", "ASN", asnSoStrategy, agvCall, token);
  207. //2.初始化库存
  208. // for (AgvCallItemDTO call : agvCallDTO.getAgvCallItemDTOList()) {
  209. // if (call.getLotattDTO() != null) {
  210. // invLotLocIdService.deleteInvLotLocIdById(locationFrom.getId());
  211. // invLotLocIdService.initInv(locationFrom.getId().toString(), call.getSku(), WmsConstant.CUSTOMER_ID, call.getQty(), call.getLotattDTO(), BigDecimal.ZERO);
  212. // }
  213. // }
  214. wcsTaskList.addAll(this.genTask(locationFrom, locationTo, flowConfigHeaderVO, agvCallDTO, token));
  215. } else if (flowConfigHeaderVO.getFlowType().equals("SO")) {
  216. AgvCallItemDTO agvCall = agvCallDTO.getAgvCallItemDTOList().get(0);
  217. List<BaseLocationInfo> locationToList = this.convertLocation(paramLocationTo, agvCallDTO.getWarehouseId(), null);
  218. List<BaseLocationInfo> locationFromList = this.convertLocation(paramLocationFrom, agvCallDTO.getWarehouseId(), null);
  219. /*HashMap<String, String> hashMap = JSON.parseObject(JSON.toJSONString(agvCall.getLotattDTO()), HashMap.class);
  220. List<BaseLocationInfo> locationFromList = baseLocationInfoMapper.selectSortedLocationLotattListByZoneIdListOrderBy(zoneIdList
  221. , agvCall.getWarehouseId(), hashMap, agvCall.getSku(), "inv.create_time");*/
  222. locationFrom = this.zoneLocationAllocation(locationFromList, "locationFrom", "SO", asnSoStrategy, agvCall, token);
  223. locationTo = this.zoneLocationAllocation(locationToList, "locationTo", "SO", asnSoStrategy, agvCall, token);
  224. wcsTaskList.addAll(this.genTask(locationFrom, locationTo, flowConfigHeaderVO, agvCallDTO, token));
  225. } else if (flowConfigHeaderVO.getFlowType().equals("MV")) {
  226. AgvCallItemDTO agvCall = agvCallDTO.getAgvCallItemDTOList().get(0);
  227. List<BaseLocationInfo> locationFromList = this.convertLocation(paramLocationFrom, agvCallDTO.getWarehouseId(), null);
  228. List<BaseLocationInfo> locationToList = this.convertLocation(paramLocationTo, agvCallDTO.getWarehouseId(), null);
  229. locationFrom = this.zoneLocationAllocation(locationFromList, "locationFrom", "MV", asnSoStrategy, agvCall, token);
  230. locationTo = this.zoneLocationAllocation(locationToList, "locationTo", "MV", asnSoStrategy, agvCall, token);
  231. //2.初始化库存
  232. for (AgvCallItemDTO call : agvCallDTO.getAgvCallItemDTOList()) {
  233. if (call.getLotattDTO() != null) {
  234. invLotLocIdService.deleteInvLotLocIdById(locationFrom.getId());
  235. invLotLocIdService.initInv(locationFrom.getId().toString(), call.getSku(), WmsConstant.CUSTOMER_ID, call.getQty(), call.getLotattDTO(), BigDecimal.ZERO);
  236. }
  237. }
  238. wcsTaskList.addAll(this.genTask(locationFrom, locationTo, flowConfigHeaderVO, agvCallDTO, token));
  239. }
  240. }
  241. return AjaxResult.success("任务下发成功");
  242. } catch (Exception e) {
  243. redisCache.unlockCacheObject(token); // 异常捕获的话就不能释放锁
  244. throw new ServiceException("agvCall任务下发失败:" + e.getMessage(), token);
  245. }
  246. }
  247. @Override
  248. public BaseLocationInfo zoneLocationAllocation(List<BaseLocationInfo> locationInfoList, String locationType, String type, AsnSoStrategy asnSoStrategy, AgvCallItemDTO agvCallDTO, Long token) {
  249. return zoneLocationAllocation(null, locationInfoList, locationType, type, asnSoStrategy, agvCallDTO, token);
  250. }
  251. @Override
  252. public BaseLocationInfo zoneLocationAllocation(BaseLocationInfo locationFrom, List<BaseLocationInfo> locationInfoList, String locationType, String type, AsnSoStrategy asnSoStrategy, AgvCallItemDTO agvCallDTO, Long token) {
  253. BaseLocationInfo locationInfo = null;
  254. if (type.equals("ASN")) {
  255. //入库
  256. if (locationType.equals("locationFrom")) {
  257. for (BaseLocationInfo b : locationInfoList) {
  258. if (!b.getStockStatus().equals("00")) {
  259. continue;
  260. }
  261. if (!redisCache.lockCacheObject(RedisKey.LOCK_LOCATION + b.getId(), b.getId().toString(), token)) {
  262. continue;
  263. }
  264. locationInfo = b;
  265. break;
  266. }
  267. if (locationInfo == null) {
  268. throw new ServiceException("入库起始库位没有可以分配的空库位", token);
  269. }
  270. } else {
  271. for (BaseLocationInfo b : locationInfoList) {
  272. if (!b.getStockStatus().equals("00") || !b.getIsEmpty().equals("Y") || redisCache.checkIsLock(RedisKey.LOCK_LOCATION + b.getId())) {
  273. continue;
  274. }
  275. // 根据起始库位判断目标是否可放
  276. Boolean canPut = checkLocCanPut(locationFrom, b, agvCallDTO.isSuperHigh());
  277. if (!canPut) {
  278. continue;
  279. }
  280. // AGV均匀任务
  281. int agvNo;
  282. // 推荐几号车做
  283. agvNo = recommendedWarehousingCarNumber();
  284. // 校验当前库位绑定的车号
  285. boolean iscan = checkCurrentLocationCarNumber(agvNo, b);
  286. if (!iscan) {
  287. continue;
  288. }
  289. if (!redisCache.lockCacheObject(RedisKey.LOCK_LOCATION + b.getId(), b.getId().toString(), token)) {
  290. continue;
  291. }
  292. locationInfo = b;
  293. break;
  294. }
  295. if (locationInfo == null) {
  296. // 如果没有可用库位,去掉AGV均匀任务判断
  297. for (BaseLocationInfo b : locationInfoList) {
  298. if (!b.getStockStatus().equals("00") || !b.getIsEmpty().equals("Y") || redisCache.checkIsLock(RedisKey.LOCK_LOCATION + b.getId())) {
  299. continue;
  300. }
  301. // 根据起始库位判断目标是否可放
  302. Boolean canPut = checkLocCanPut(locationFrom, b, agvCallDTO.isSuperHigh());
  303. if (!canPut) {
  304. continue;
  305. }
  306. if (!redisCache.lockCacheObject(RedisKey.LOCK_LOCATION + b.getId(), b.getId().toString(), token)) {
  307. continue;
  308. }
  309. locationInfo = b;
  310. break;
  311. }
  312. if (locationInfo == null) {
  313. throw new ServiceException("入库目标点没有可以分配的库位", token);
  314. }
  315. }
  316. }
  317. } else if (type.equals("SO")) {
  318. //起始库位
  319. if (locationType.equals("locationFrom")) {
  320. for (BaseLocationInfo b : locationInfoList) {
  321. if (!b.getStockStatus().equals("00") || !b.getIsEmpty().equals("N") || redisCache.checkIsLock(RedisKey.LOCK_LOCATION + b.getId())) {
  322. continue;
  323. }
  324. if (!redisCache.lockCacheObject(RedisKey.LOCK_LOCATION + b.getId(), b.getId().toString(), token)) {
  325. continue;
  326. }
  327. locationInfo = b;
  328. break;
  329. }
  330. if (locationInfo == null) {
  331. throw new ServiceException("出库起始点没有可以分配的库存!", token);
  332. }
  333. } else { //目标库位
  334. // 出库默认先不给分配目标库位 这里不能改 会破坏出库均匀任务
  335. // for (BaseLocationInfo b : locationInfoList) {
  336. // if (!b.getStockStatus().equals("00") || !b.getIsEmpty().equals("Y") || redisCache.checkIsLock(RedisKey.LOCK_LOCATION + b.getId())) {
  337. // continue;
  338. // }
  339. // if (!redisCache.lockCacheObject(RedisKey.LOCK_LOCATION + b.getId(), b.getId().toString(), token)) {
  340. // continue;
  341. // }
  342. // locationInfo = b;
  343. // break;
  344. // }
  345. // if (locationInfo == null) {
  346. // 出库没有可分配库位,不报错,返回空
  347. // throw new ServiceException("出库目标点没有可以分配的库位", token);
  348. // }
  349. }
  350. } else { //移库
  351. if (locationType.equals("locationFrom")) {
  352. for (BaseLocationInfo b : locationInfoList) {
  353. if (!b.getStockStatus().equals("00") || redisCache.checkIsLock(RedisKey.LOCK_LOCATION + b.getId())) {
  354. continue;
  355. }
  356. if (!redisCache.lockCacheObject(RedisKey.LOCK_LOCATION + b.getId(), b.getId().toString(), token)) {
  357. continue;
  358. }
  359. locationInfo = b;
  360. break;
  361. }
  362. //分配时是否需要做库位占用判断
  363. FlowConfigHeaderVO flowConfigHeaderVO = agvCallDTO.getFlowConfigHeaderVO();
  364. if (!StringUtils.isEmpty(flowConfigHeaderVO.getLocationFromStrategyFlag()) && flowConfigHeaderVO.getLocationFromStrategyFlag().equals("Y")) {
  365. } else {
  366. //如果未启用策略则进行判断
  367. if (locationInfo == null) {
  368. throw new ServiceException("移库没有可以分配的库位", token);
  369. }
  370. }
  371. } else {
  372. for (BaseLocationInfo b : locationInfoList) {
  373. if (!b.getStockStatus().equals("00") || !b.getIsEmpty().equals("Y") || redisCache.checkIsLock(RedisKey.LOCK_LOCATION + b.getId())) {
  374. continue;
  375. }
  376. if (!redisCache.lockCacheObject(RedisKey.LOCK_LOCATION + b.getId(), b.getId().toString(), token)) {
  377. continue;
  378. }
  379. locationInfo = b;
  380. break;
  381. }
  382. //分配时是否需要做库位占用判断
  383. FlowConfigHeaderVO flowConfigHeaderVO = agvCallDTO.getFlowConfigHeaderVO();
  384. if (!StringUtils.isEmpty(flowConfigHeaderVO.getLocationFromStrategyFlag()) && flowConfigHeaderVO.getLocationFromStrategyFlag().equals("Y")) {
  385. } else {
  386. //如果未启用策略则进行判断
  387. if (locationInfo == null) {
  388. throw new ServiceException("移库没有可以分配的库位", token);
  389. }
  390. }
  391. }
  392. }
  393. return locationInfo;
  394. }
  395. @Transactional
  396. @Override
  397. public AjaxResult doPaAndTask(PaForm paForm, FlowConfigHeaderVO flowConfigHeaderVO, LineCallListFrom lform, LineCallForm lineCallForm
  398. , boolean superHighMark) {
  399. // 上架
  400. String asnNo = "";
  401. //排序规则 普通入库回库先放在col_no小的位置 - 1,备货入库回库放在col_no大的位置 - 2
  402. int orderRules = 1;
  403. AjaxResult ajaxResult = iWmsDocAsnHeaderService.doPa(paForm);
  404. if (!ajaxResult.isSuccess()) {
  405. return ajaxResult;
  406. }
  407. asnNo = (String) ajaxResult.get("data");
  408. orderRules = (int) ajaxResult.get("orderRules");
  409. return businessService.agvCall(flowConfigHeaderVO, lform, lineCallForm, asnNo, orderRules, superHighMark);
  410. }
  411. /**
  412. * 校验当前库位车号
  413. *
  414. * @param agvNo
  415. * @param b
  416. * @return
  417. */
  418. private boolean checkCurrentLocationCarNumber(int agvNo, BaseLocationInfo b) {
  419. if (agvNo == 1) {
  420. if (!b.getFoldedTag().equals("1")) {
  421. return false;
  422. }
  423. } else if (agvNo == 2) {
  424. if (!b.getFoldedTag().equals("2")) {
  425. return false;
  426. }
  427. }
  428. return true;
  429. }
  430. /**
  431. * 推荐入库车号
  432. *
  433. * @return
  434. */
  435. private int recommendedWarehousingCarNumber() {
  436. if (redisCache.getCacheObject(RedisKey.AGV_TASK_CAR_NO) != null) {
  437. int carNo = redisCache.getCacheObject(RedisKey.AGV_TASK_CAR_NO);
  438. return carNo == 1 ? 2 : 1;
  439. }
  440. return 0;
  441. }
  442. public Boolean checkLocCanPut(BaseLocationInfo locationFrom, BaseLocationInfo locationTo, boolean isSuperHigh) {
  443. boolean con = false;
  444. // 永湖仓储区一层高度为1600,二层有4个点为1600,其他为2100
  445. // 入库和回库的时候,入库位IN-02-01(200)和回库位RET-01-01(500)没超高入库到1600的库位,超高了入库到2100
  446. // 入库和回库的时候,入库位IN-01-01和回库位RET-02-01入库到2100,超高不可入库
  447. if ((locationFrom.getLocationNo().equals("IN-02-01") || locationFrom.getLocationNo().equals("RET-01-01"))
  448. && !isSuperHigh) {
  449. if (locationTo.getShiftNo().equals("1")
  450. || (locationTo.getHeightLimit() != null && locationTo.getHeightLimit().compareTo(1600.0) == 0)) {
  451. con = true;
  452. }
  453. } else {
  454. if (!locationTo.getShiftNo().equals("1")
  455. && (locationTo.getHeightLimit() == null || locationTo.getHeightLimit().compareTo(1600.0) != 0)) {
  456. con = true;
  457. }
  458. }
  459. return con;
  460. }
  461. @Override
  462. public List<BaseLocationInfo> convertLocation(String locationNoOrZoneId, Long warehouseId, String orderBy) {
  463. List<BaseLocationInfo> locationInfoList = new ArrayList<>();
  464. if (!StringUtils.isEmpty(locationNoOrZoneId)) {
  465. String[] arr = locationNoOrZoneId.split(",");
  466. for (String obj : arr) {
  467. boolean isLocation = baseLocationInfoService.checkIsLocation(obj, warehouseId);
  468. if (isLocation) {
  469. BaseLocationInfo info = baseLocationInfoService.selectBaseLocationInfoByIdOrNo(obj, warehouseId);
  470. locationInfoList.add(info);
  471. } else {
  472. List<BaseLocationInfo> infoList = baseLocationInfoService.selectSortedLocatinListByZoneId(Long.parseLong(obj), warehouseId, orderBy);
  473. locationInfoList.addAll(infoList);
  474. }
  475. }
  476. }
  477. return locationInfoList;
  478. }
  479. @Override
  480. public List<WcsTask> genTask(BaseLocationInfo locationFrom, BaseLocationInfo locationTo, FlowConfigHeaderVO flowConfigHeaderVO, AgvCallDTO agvCallDTO, Long token) {
  481. if (flowConfigHeaderVO.getLocationFromStrategyFlag().equals("N") && ObjectUtil.isNull(locationFrom)) {
  482. throw new ServiceException("起始库位不能为空", token);
  483. }
  484. if (flowConfigHeaderVO.getLocationToStrategyFlag().equals("N") && ObjectUtil.isNull(locationTo)) {
  485. throw new ServiceException("目标库位不能为空", token);
  486. }
  487. List<WcsTask> wcsTaskList = new ArrayList<>();
  488. if (StringUtils.isNotBlank(flowConfigHeaderVO.getRootFlow())) return wcsTaskList;
  489. String taskNo = IdWorker.getIdStr();
  490. WcsTask wcsTask = new WcsTask();
  491. wcsTask.setTaskNo(taskNo);
  492. if (locationFrom != null) {
  493. wcsTask.setAreaFrom(locationFrom.getZoneId().toString());
  494. wcsTask.setLocationFrom(locationFrom.getId().toString());
  495. }
  496. if (locationTo != null) {
  497. wcsTask.setAreaTo(locationTo.getZoneId() + "");
  498. wcsTask.setLocationTo(locationTo.getId().toString());
  499. }
  500. wcsTask.setState(Long.parseLong(WmsConstant.TASK_STS.TASK9.getValue().toString()));
  501. wcsTask.setPriority(1L);
  502. wcsTask.setShopId(WmsConstant.WAREHOUSE_ID.toString());
  503. wcsTask.setCreateDate(new Date());
  504. wcsTask.setBusinessType(AmsConstant.TASK_BUSINESS_TYPE.TASK_01.getValue());
  505. wcsTask.setTaskType(WmsConstant.TASK_TYPE.FORWARD.getValue());
  506. wcsTask.setExt8(token.toString());
  507. wcsTask.setExt7(flowConfigHeaderVO.getId().toString());
  508. wcsTask.setExt6(agvCallDTO.getOrderNo());
  509. wcsTask.setExt5(agvCallDTO.getPalletNo());
  510. wcsTask.setExt4(agvCallDTO.getTaskType());// 任务类型
  511. wcsTask.setExtParam(agvCallDTO.getExtParam());
  512. wcsTaskList.add(wcsTask);
  513. businessService.addTask(wcsTask);
  514. return wcsTaskList;
  515. }
  516. @Transactional
  517. @Override
  518. public AjaxResult addTask(WcsTask wcsTask) {
  519. //锁定库位
  520. if (!StringUtils.isEmpty(wcsTask.getLocationFrom())) {
  521. baseLocationInfoService.updateLocationStockStatus(Long.parseLong(wcsTask.getLocationFrom()), WmsConstant.STOCK_STATUS.STOCK10.getValue());
  522. }
  523. if (!StringUtils.isEmpty(wcsTask.getLocationTo()) && !wcsTask.getLocationTo().equals("待分配")) {
  524. baseLocationInfoService.updateLocationStockStatus(Long.parseLong(wcsTask.getLocationTo()), WmsConstant.STOCK_STATUS.STOCK10.getValue());
  525. }
  526. Integer priority = 1;
  527. if (wcsTask.getTaskType().equals("OB")) {
  528. if (wcsTask.getPriority() == 99) {
  529. int current = wcsTaskMapper.selectCurrentPriority();
  530. priority = current - 100;
  531. } else {
  532. int current = wcsTaskMapper.selectCurrentPriority();
  533. priority = current + 10;
  534. }
  535. } else {
  536. //倒库任务顺序由原任务中间插入不需要获取
  537. priority = wcsTask.getPriority().intValue();
  538. }
  539. wcsTask.setPriority((long) priority);
  540. int result = wcsTaskMapper.insertWcsTask(wcsTask);
  541. if (result > 0) {
  542. return AjaxResult.success("任务生成成功");
  543. } else {
  544. throw new ServiceException("任务生成失败");
  545. }
  546. }
  547. @Override
  548. public AjaxResult addTaskList(List<WcsTask> wcsTaskList) {
  549. for (WcsTask wcsTask : wcsTaskList) {
  550. //锁定库位
  551. if (!StringUtils.isEmpty(wcsTask.getLocationFrom())) {
  552. baseLocationInfoService.updateLocationStockStatus(Long.parseLong(wcsTask.getLocationFrom()), WmsConstant.STOCK_STATUS.STOCK10.getValue());
  553. }
  554. if (!StringUtils.isEmpty(wcsTask.getLocationTo())) {
  555. baseLocationInfoService.updateLocationStockStatus(Long.parseLong(wcsTask.getLocationTo()), WmsConstant.STOCK_STATUS.STOCK10.getValue());
  556. }
  557. Integer priority = 1;
  558. if (!wcsTask.getTaskType().equals("OB")) {
  559. if (wcsTask.getPriority() == 99) {
  560. int current = wcsTaskMapper.selectCurrentPriority();
  561. priority = current - 100;
  562. } else {
  563. int current = wcsTaskMapper.selectCurrentPriority();
  564. priority = current + 10;
  565. }
  566. } else {
  567. //倒库任务顺序由原任务中间插入不需要获取
  568. priority = wcsTask.getPriority().intValue();
  569. }
  570. wcsTask.setPriority((long) priority);
  571. int result = wcsTaskMapper.insertWcsTask(wcsTask);
  572. if (result > 0) {
  573. return AjaxResult.success("任务生成成功");
  574. } else {
  575. throw new ServiceException("任务生成失败");
  576. }
  577. }
  578. return AjaxResult.success("");
  579. }
  580. @Override
  581. public AjaxResult sendTask(WcsTask wcsTask) {
  582. BaseLocationInfo locFrom = baseLocationInfoService.selectBaseLocationInfoByIdOrNo(wcsTask.getLocationFrom(), WmsConstant.WAREHOUSE_ID);
  583. BaseLocationInfo locTo = baseLocationInfoService.selectBaseLocationInfoByIdOrNo(wcsTask.getLocationTo(), WmsConstant.WAREHOUSE_ID);
  584. AmsTask amsTask = new AmsTask();
  585. amsTask.setTaskNo(wcsTask.getTaskNo());
  586. if (wcsTask.getBusinessType() == null || wcsTask.getBusinessType().equals("")) {
  587. amsTask.setBusinessType(AmsConstant.TASK_BUSINESS_TYPE.TASK_01.getValue());
  588. } else {
  589. amsTask.setBusinessType(wcsTask.getBusinessType());
  590. }
  591. amsTask.setIsDelete(0);
  592. amsTask.setAciAccept(0);
  593. amsTask.setIkey((long) genIKey(amsTask.getTaskNo()));
  594. amsTask.setPriority(10);
  595. // 充电任务直接传参数
  596. if (wcsTask.getBusinessType().equals(AmsConstant.TASK_BUSINESS_TYPE.TASK_POWER.getValue())) {
  597. amsTask.setStFrom(Integer.parseInt(wcsTask.getLocationFrom()));
  598. amsTask.setStTo(Integer.parseInt(wcsTask.getLocationTo()));
  599. } else {
  600. amsTask.setStFrom(locFrom.getAgvStation().intValue());
  601. amsTask.setStTo(locTo.getAgvStation().intValue());
  602. }
  603. amsTask.setExt1(wcsTask.getExt1());
  604. amsTask.setExt2(wcsTask.getExt2());
  605. amsTask.setExt3(wcsTask.getExt3());
  606. int result = amsTaskService.insertAmsTask(amsTask);
  607. if (result > 0) {
  608. //更新
  609. return AjaxResult.success("下发成功");
  610. } else {
  611. return AjaxResult.error("下发失败");
  612. }
  613. }
  614. @Override
  615. public AjaxResult sendTaskList(List<WcsTask> wcsTaskList) {
  616. return null;
  617. }
  618. @Transactional
  619. @Override
  620. public void autoSend() {
  621. List<WcsTask> wcsTaskList = wcsTaskService.selectWcsUnallocated(WmsConstant.WAREHOUSE_ID);
  622. if (wcsTaskList != null && wcsTaskList.size() > 0) {
  623. for (WcsTask wcsTask : wcsTaskList) {
  624. //如果是充电任务直接下发
  625. if (wcsTask.getBusinessType().equals(AmsConstant.TASK_BUSINESS_TYPE.TASK_POWER.getValue()) ||
  626. wcsTask.getBusinessType().equals(AmsConstant.TASK_BUSINESS_TYPE.TASK_m.getValue()) ||
  627. wcsTask.getBusinessType().equals(AmsConstant.TASK_BUSINESS_TYPE.TASK_74.getValue())
  628. ) {
  629. log.info("定时充电/盘点取消任务直接下发");
  630. sendTask(wcsTask);
  631. wcsTask.setState(2L);
  632. wcsTaskService.updateWcsTask(wcsTask);
  633. break;
  634. }
  635. // 出库任务分配目标库位
  636. if (StringUtils.isBlank(wcsTask.getLocationTo())) {
  637. // 出库均匀任务判断
  638. BaseLocationInfo baseLocationInfo = baseLocationInfoService.selectBaseLocationInfoByIdOrNo(wcsTask.getLocationFrom(), WmsConstant.WAREHOUSE_ID);
  639. String agvNo = baseLocationInfo.getFoldedTag(); // 车号
  640. boolean isCan = uniformOutboundTaskJudgment(agvNo);
  641. if (!isCan) {
  642. continue;
  643. }
  644. // 分配目标库位
  645. AjaxResult ajaxResult = allocateTargetLocation(wcsTask);
  646. if (!ajaxResult.isSuccess()) {
  647. continue;
  648. } else {
  649. BaseLocationInfo locationInfo = ajaxResult.getDataParseObject(BaseLocationInfo.class);
  650. wcsTask.setAreaTo(locationInfo.getZoneId().toString());
  651. wcsTask.setLocationTo(locationInfo.getId().toString());
  652. wcsTaskService.updateWcsTask(wcsTask);
  653. // 修改出库位置是哪台车在做
  654. BaseLocationInfo baseLocationInfoUpdate = new BaseLocationInfo();
  655. baseLocationInfoUpdate.setId(locationInfo.getId());
  656. baseLocationInfoUpdate.setFoldedTag(agvNo);
  657. baseLocationInfoUpdate.setStockStatus(WmsConstant.STOCK_STATUS.STOCK10.getValue());
  658. baseLocationInfoService.updateBaseLocationInfo(baseLocationInfoUpdate);
  659. }
  660. }
  661. //转发任务
  662. if (StringUtils.isNotEmpty(wcsTask.getTaskType())
  663. && wcsTask.getTaskType().equals(WmsConstant.TASK_TYPE.FORWARD.getValue())) {
  664. sendTask(wcsTask);
  665. wcsTask.setState(10L);
  666. wcsTaskService.updateWcsTask(wcsTask);
  667. break;
  668. }
  669. try {
  670. //任务下发判断
  671. businessService.taskDispatchStack(wcsTask);
  672. Thread.sleep(500);
  673. } catch (Exception e) {
  674. e.printStackTrace();
  675. }
  676. }
  677. }
  678. }
  679. /**
  680. * 出库均匀任务判断
  681. *
  682. * @return true 可以分配目标点 false 不可分配目标点
  683. */
  684. private boolean uniformOutboundTaskJudgment(String agvNo) {
  685. int lock = 0; // 占用
  686. int goods = 0; // 有货
  687. // 查出两个出库缓存位
  688. List<BaseLocationInfo> baseLocationInfos = baseLocationInfoService.selectLocatinListByZoneId(WmsConstant.ZONE_TYPE.ZONE_OUT.getValue());
  689. // 判断两个位置有几个任务占用
  690. List<BaseLocationInfo> baseLocationInfosLock
  691. = baseLocationInfos.stream()
  692. .filter(v -> v.getStockStatus().equals(WmsConstant.STOCK_STATUS.STOCK10.getValue()))
  693. .collect(Collectors.toList());
  694. lock = baseLocationInfosLock.size();
  695. // 如果两个都占用 返回false
  696. if (lock == 2) {
  697. return false;
  698. }
  699. // 判断两个位置有几个有货
  700. List<BaseLocationInfo> baseLocationInfosGoods
  701. = baseLocationInfos.stream()
  702. .filter(v -> v.getIsEmpty().equals(WmsConstant.IS_YES.N.name()))
  703. .collect(Collectors.toList());
  704. goods = baseLocationInfosGoods.size();
  705. // 如果两个都占用
  706. if (goods == 2) {
  707. return false;
  708. }
  709. // 如果没有占用
  710. if (lock == 0) {
  711. return true;
  712. }
  713. // 如果一个库位被占用
  714. BaseLocationInfo locationInfoLock = baseLocationInfosLock.get(0);
  715. String agvNoIng = locationInfoLock.getFoldedTag(); // 正在任务的车号
  716. return !agvNo.equals(agvNoIng);
  717. }
  718. /**
  719. * 分配出库目标库位
  720. * 目标库位为待分配
  721. *
  722. * @param wcsTask
  723. * @return
  724. */
  725. private AjaxResult allocateTargetLocation(WcsTask wcsTask) {
  726. List<BaseLocationInfo> locationToList = this.convertLocation(WmsConstant.ZONE_TYPE.ZONE_OUT.getValue().toString()
  727. , WmsConstant.WAREHOUSE_ID, null);
  728. BaseLocationInfo locationTo = this.zoneLocationAllocation(locationToList, Long.valueOf(wcsTask.getExt8()));
  729. if (locationTo == null) {
  730. return AjaxResult.error("");
  731. }
  732. return AjaxResult.success("", locationTo);
  733. }
  734. private BaseLocationInfo zoneLocationAllocation(List<BaseLocationInfo> locationInfoList, Long token) {
  735. BaseLocationInfo locationInfo = null;
  736. for (BaseLocationInfo b : locationInfoList) {
  737. if (!b.getStockStatus().equals("00") || !b.getIsEmpty().equals("Y") || redisCache.checkIsLock(RedisKey.LOCK_LOCATION + b.getId())) {
  738. continue;
  739. }
  740. if (!redisCache.lockCacheObject(RedisKey.LOCK_LOCATION + b.getId(), b.getId().toString(), token)) {
  741. continue;
  742. }
  743. locationInfo = b;
  744. break;
  745. }
  746. return locationInfo;
  747. }
  748. @Transactional
  749. @Override
  750. public boolean taskDispatchStack(WcsTask wcsTask) {
  751. /* boolean isSplit = taskService.taskSplit(wcsTask);
  752. //判断是否拆分如果拆分了直接跳过
  753. if(isSplit){
  754. return false;
  755. }*/
  756. //最后要执行的任务
  757. WcsTask currentTask = new WcsTask();
  758. //来源库位
  759. BaseLocationInfo basLocationInfoFrom = null;
  760. //目标区域
  761. BaseLocationZone basLocationZoneTo = null;
  762. //起始库位
  763. basLocationInfoFrom = baseLocationInfoService.selectBaseLocationInfoById(Long.parseLong(wcsTask.getLocationFrom()));
  764. //目标库位
  765. BaseLocationInfo locationInfoTo = baseLocationInfoService.selectBaseLocationInfoById(Long.parseLong(wcsTask.getLocationTo()));
  766. //TODO 前置任务未完成不进行下发
  767. if (businessService.taskDispatchCheck(wcsTask) == false) {
  768. return false;
  769. }
  770. if (basLocationInfoFrom != null) {
  771. if (basLocationInfoFrom.getIsEmpty().equals("Y")) {
  772. wcsTask.setRemark("起始库位为空无法进行任务");
  773. wcsTaskService.updateWcsTask(wcsTask);
  774. return false;
  775. }
  776. //起始库位巷道检测(起始库位检测是否同巷道)
  777. if (!StringUtils.isEmpty(basLocationInfoFrom.getColNo())) {
  778. List<BaseLocationInfo> locationInfoList = baseLocationInfoMapper.laneCheck(basLocationInfoFrom.getColNo(), "LANE_FROM", WmsConstant.WAREHOUSE_ID);
  779. if (locationInfoList != null && locationInfoList.size() > 0) {
  780. wcsTask.setRemark("起始库位同列或同巷道有车辆在任务中,等待其他任务完成");
  781. wcsTaskService.updateWcsTask(wcsTask);
  782. return false;
  783. }
  784. }
  785. }
  786. //起始库位是地堆需要判断是否有阻挡
  787. if (basLocationInfoFrom.getLocationType().equals("2")) {
  788. //判断队列中是否有阻挡在当前任务之前
  789. List<WcsTaskLocationDTO> locationDTOS = wcsTaskService.selectTaskByColNo(basLocationInfoFrom.getColNo(), basLocationInfoFrom.getColIndex(), basLocationInfoFrom.getZoneId(), null);
  790. if (locationDTOS.size() > 0) {
  791. wcsTask.setRemark("队列中有其他任务阻挡,让其他任务先执行");
  792. wcsTaskService.updateWcsTask(wcsTask);
  793. return false;
  794. }
  795. //判断出库库位前是否有阻挡
  796. List<BaseLocationInfo> beforeLoc = baseLocationInfoService.selectBeforeLocationByColNo(basLocationInfoFrom.getColNo(), basLocationInfoFrom.getColIndex());
  797. if (beforeLoc != null) {
  798. for (BaseLocationInfo b : beforeLoc) {
  799. //如果前面库位不为空,或者状态占用
  800. //TODO 去除已经在任务中的
  801. if (b.getIsEmpty().equals("N")) {
  802. wcsTask.setRemark("有阻挡物,任务无法执行");
  803. wcsTaskService.updateWcsTask(wcsTask);
  804. return false;
  805. }
  806. }
  807. }
  808. }
  809. currentTask = wcsTask;
  810. //目标库位如果是地堆需要判断是否有阻挡
  811. if (locationInfoTo != null && locationInfoTo.getLocationType().equals("2")) {
  812. List<BaseLocationInfo> beforeLoc = baseLocationInfoService.selectBeforeLocationByColNo(locationInfoTo.getColNo(), locationInfoTo.getColIndex());
  813. if (beforeLoc != null) {
  814. for (BaseLocationInfo b : beforeLoc) {
  815. //跳过起始库位
  816. if (b.getId().equals(locationInfoTo.getId())) {
  817. continue;
  818. }
  819. //如果前面库位不为空,或者状态占用
  820. //TODO 排除已经在任务中的
  821. if (b.getIsEmpty().equals("N")) {
  822. currentTask.setRemark("目标库位前方有阻挡1");
  823. currentTask.setUpdateDate(new Date());
  824. wcsTaskService.updateWcsTask(currentTask);
  825. return false;
  826. }
  827. }
  828. }
  829. List<WcsTaskLocationDTO> dtos = wcsTaskService.selectTaskByColNoAfter(locationInfoTo.getColNo(), locationInfoTo.getColIndex(), locationInfoTo.getZoneId(), null);
  830. if (dtos != null && dtos.size() > 0) {
  831. currentTask.setRemark("目标库位同列有未完成的任务");
  832. wcsTaskService.updateWcsTask(currentTask);
  833. return false;
  834. }
  835. }
  836. //查询是否有更里面的位置可以存放
  837. if (locationInfoTo != null) {
  838. if (locationInfoTo.getZoneId() != 10) {
  839. String locationtoTmp = "";
  840. List<BaseLocationInfoSameColDTO> b = baseLocationInfoService.selectSameColCanToLoc(locationInfoTo.getColNo(), locationInfoTo.getColIndex());
  841. for (BaseLocationInfoSameColDTO bt : b) {
  842. if (bt.getIsOb() == false) {
  843. locationtoTmp = bt.getId().toString();
  844. } else {
  845. break;
  846. }
  847. }
  848. if (!StringUtils.isEmpty(locationtoTmp)) {
  849. wcsTask.setLocationTo(locationtoTmp);
  850. wcsTaskService.updateWcsTask(wcsTask);
  851. //释放原库位
  852. locationInfoTo.setStockStatus("00");
  853. baseLocationInfoService.updateBaseLocationInfo(locationInfoTo);
  854. //占用新库位
  855. BaseLocationInfo newlocationInfoTo = baseLocationInfoService.selectBaseLocationInfoById(Long.parseLong(locationtoTmp));
  856. newlocationInfoTo.setStockStatus("10");
  857. baseLocationInfoService.updateBaseLocationInfo(newlocationInfoTo);
  858. }
  859. }
  860. }
  861. currentTask.setState(10L);
  862. currentTask.setRemark("");
  863. if (wcsTaskService.updateWcsTask(currentTask) > 0) {
  864. AjaxResult result = businessService.sendTask(currentTask);
  865. if ((int) result.get(AjaxResult.CODE_TAG) == 500) {
  866. throw new ServiceException("自动下发任务失败:" + result.get("msg"));
  867. }
  868. return true;
  869. } else {
  870. return false;
  871. }
  872. }
  873. @Override
  874. public boolean taskDispatchCheck(WcsTask wcsTask) {
  875. if (!StringUtils.isEmpty(wcsTask.getBeforeTask())) {
  876. List<WcsTask> taskFindBeforeRecord = wcsTaskMapper.selectBeforeTask(wcsTask.getBeforeTask());
  877. if (taskFindBeforeRecord != null && taskFindBeforeRecord.size() > 0) {
  878. //log.info("前置任务未完成主任务无法下发{}",wcsTask);
  879. wcsTask.setRemark("前置任务未完成主任务无法下发");
  880. wcsTaskService.updateWcsTask(wcsTask);
  881. return false;
  882. }
  883. }
  884. return true;
  885. }
  886. /**
  887. * 库存移动
  888. *
  889. * @param invLotLocIdMoveForm
  890. * @return
  891. */
  892. @Transactional
  893. @Override
  894. public AjaxResult move(InvLotLocIdMoveForm invLotLocIdMoveForm) {
  895. String locationFrom = invLotLocIdMoveForm.getLocationFrom();
  896. String locationTo = invLotLocIdMoveForm.getLocationTo();
  897. String reason = invLotLocIdMoveForm.getReason();
  898. String updateBy = invLotLocIdMoveForm.getUpdateBy();
  899. Long warehouseId = invLotLocIdMoveForm.getWarehouseId();
  900. BaseLocationInfo baseLocationFrom = null;
  901. BaseLocationInfo baseLocationTo = null;
  902. String palletNo;
  903. // 起始和目标库位
  904. baseLocationFrom = baseLocationInfoService.selectBaseLocationInfoByIdOrNo(locationFrom, warehouseId);
  905. if (baseLocationFrom.getZoneId().equals(WmsConstant.ZONE_TYPE.ZONE_VIRTUAL.getValue())) {
  906. return AjaxResult.error("起始库位虚拟库位不可移库!");
  907. }
  908. baseLocationTo = baseLocationInfoService.selectBaseLocationInfoByIdOrNo(locationTo, warehouseId);
  909. if (baseLocationTo.getZoneId().equals(WmsConstant.ZONE_TYPE.ZONE_VIRTUAL.getValue())) {
  910. // 如果起始库位是出库位 目标库位是线边 直接移动库存
  911. if (baseLocationFrom.getZoneId().equals(WmsConstant.ZONE_TYPE.ZONE_OUT.getValue())
  912. && baseLocationTo.getId().compareTo(WmsConstant.LOC_SORTATION02_CACHE) == 0) {
  913. return moveDirect(invLotLocIdMoveForm);
  914. }
  915. return AjaxResult.error("目标库位虚拟库位不可移库!");
  916. }
  917. // 如果起始区域位出库位 目标位回库位 直接移动库存
  918. if (baseLocationFrom.getZoneId().equals(WmsConstant.ZONE_TYPE.ZONE_OUT.getValue())
  919. && baseLocationTo.getZoneId().equals(WmsConstant.ZONE_TYPE.ZONE_RE.getValue())) {
  920. return moveDirect(invLotLocIdMoveForm);
  921. }
  922. // 验证起始库位
  923. Boolean isIdleFrom = baseLocationInfoService.verifyLocationIsIdle(locationFrom, warehouseId);
  924. if (!isIdleFrom) {
  925. return AjaxResult.error("起始库位需要空闲状态!");
  926. }
  927. // 验证目标库位
  928. Boolean isIdle = baseLocationInfoService.verifyLocationIsIdle(locationTo, warehouseId);
  929. if (!isIdle) {
  930. return AjaxResult.error("目标库位需要空闲状态!");
  931. }
  932. Boolean isInStock = baseLocationInfoService.verifyLocationIsInStock(locationTo, warehouseId);
  933. if (isInStock) {
  934. return AjaxResult.error("目标库位有货!");
  935. }
  936. // 验证起始库位必须有货
  937. List<InvLotLocIdLotattVO> invLotLocIdLotattVOList = invLotLocIdService.selectInvLocIdLotattByLocationId(baseLocationFrom.getId());
  938. if (invLotLocIdLotattVOList.size() == 0) {
  939. return AjaxResult.error("起始库位需要有库存!");
  940. }
  941. palletNo = invLotLocIdLotattVOList.get(0).getLotatt07();
  942. // 根据起始库位判断目标库位是否可以放置
  943. // Boolean canPut = iBusinessService.checkLocCanPut(baseLocationFrom, baseLocationTo);
  944. // if (!canPut) {
  945. // return AjaxResult.error("所选的目标库位超高!");
  946. // }
  947. // 下发移库任务
  948. String taskNo = System.currentTimeMillis() + "";
  949. WcsTask wcsTask = new WcsTask();
  950. wcsTask.setTaskNo(taskNo);
  951. if (locationFrom != null) {
  952. wcsTask.setAreaFrom(baseLocationFrom.getZoneId().toString());
  953. wcsTask.setLocationFrom(baseLocationFrom.getId().toString());
  954. }
  955. if (locationTo != null) {
  956. wcsTask.setAreaTo(baseLocationTo.getZoneId() + "");
  957. wcsTask.setLocationTo(baseLocationTo.getId().toString());
  958. }
  959. wcsTask.setState(9L);
  960. wcsTask.setPriority(1L);
  961. wcsTask.setShopId(WmsConstant.WAREHOUSE_ID.toString());
  962. wcsTask.setCreateDate(new Date());
  963. wcsTask.setBusinessType("01");
  964. wcsTask.setTaskType(WmsConstant.TASK_TYPE.FORWARD.getValue());
  965. wcsTask.setExt8("");
  966. wcsTask.setExt7("10"); // 任务类型 10代表移库
  967. wcsTask.setExt5(palletNo); // 托盘号
  968. addTask(wcsTask);
  969. // 锁定起始和目标库位任务状态
  970. baseLocationInfoService.lockLocationStockStatus(baseLocationFrom.getId(), baseLocationTo.getId()
  971. , warehouseId, updateBy);
  972. // 更新托盘绑定库位关系
  973. wmsBoxInfoService.updateLocationBind(palletNo, baseLocationTo.getId(), null);
  974. return AjaxResult.success("执行成功");
  975. }
  976. @Transactional
  977. @Override
  978. public AjaxResult moveDirect(InvLotLocIdMoveForm invLotLocIdMoveForm) {
  979. String locationFrom = invLotLocIdMoveForm.getLocationFrom();
  980. String locationTo = invLotLocIdMoveForm.getLocationTo();
  981. String reason = invLotLocIdMoveForm.getReason();
  982. String updateBy = invLotLocIdMoveForm.getUpdateBy();
  983. Long warehouseId = invLotLocIdMoveForm.getWarehouseId();
  984. BaseLocationInfo baseLocationFrom = null;
  985. BaseLocationInfo baseLocationTo = null;
  986. String palletNo;
  987. // 起始和目标库位
  988. baseLocationFrom = baseLocationInfoService.selectBaseLocationInfoByIdOrNo(locationFrom, warehouseId);
  989. if (baseLocationFrom.getZoneId().equals(WmsConstant.ZONE_TYPE.ZONE_VIRTUAL.getValue())) {
  990. return AjaxResult.error("起始库位不可为虚拟库位!");
  991. }
  992. baseLocationTo = baseLocationInfoService.selectBaseLocationInfoByIdOrNo(locationTo, warehouseId);
  993. if (baseLocationTo.getZoneId().equals(WmsConstant.ZONE_TYPE.ZONE_VIRTUAL.getValue())) {
  994. // 起始库位库存需要为备货库存才可以转移到虚拟库位
  995. boolean con = false;
  996. List<InvLotLocIdLotattVO> invLotLocIdLotattVOList = invLotLocIdService.selectInvLocIdLotattByLocationId(baseLocationFrom.getId());
  997. for (InvLotLocIdLotattVO invLotLocIdLotattVO : invLotLocIdLotattVOList) {
  998. if (com.warewms.common.utils.string.StringUtils.isNotEmpty(invLotLocIdLotattVO.getLotatt14())) {
  999. con = true;
  1000. }
  1001. }
  1002. if (!con) {
  1003. return AjaxResult.error("起始库位需要为备货库存才可以转移到虚拟区!");
  1004. }
  1005. }
  1006. // 验证起始库位
  1007. Boolean isIdleFrom = baseLocationInfoService.verifyLocationIsIdle(locationFrom, warehouseId);
  1008. if (!isIdleFrom) {
  1009. return AjaxResult.error("起始库位需要空闲状态!");
  1010. }
  1011. // 验证目标库位
  1012. Boolean isIdle = baseLocationInfoService.verifyLocationIsIdle(locationTo, warehouseId);
  1013. if (!isIdle) {
  1014. return AjaxResult.error("目标库位需要空闲状态!");
  1015. }
  1016. Boolean isInStock = baseLocationInfoService.verifyLocationIsInStock(locationTo, warehouseId);
  1017. if (isInStock
  1018. && !baseLocationTo.getZoneId().equals(WmsConstant.ZONE_TYPE.ZONE_VIRTUAL.getValue())) {
  1019. return AjaxResult.error("目标库位有货!");
  1020. }
  1021. // 验证起始库位必须有货
  1022. List<InvLotLocIdLotattVO> invLotLocIdLotattVOList = invLotLocIdService.selectInvLocIdLotattByLocationId(baseLocationFrom.getId());
  1023. if (invLotLocIdLotattVOList.size() == 0) {
  1024. return AjaxResult.error("起始库位需要有库存!");
  1025. }
  1026. palletNo = invLotLocIdLotattVOList.get(0).getLotatt07();
  1027. // 转移库存
  1028. int stockTransfer = invLotLocIdService.stockTransfer(baseLocationFrom.getId(), null, baseLocationTo.getId());
  1029. if (stockTransfer <= 0) {
  1030. return AjaxResult.success("库存转移失败!");
  1031. }
  1032. // 更新起始库位空闲无货
  1033. baseLocationInfoService.updateLocationIdleAndEmpty(baseLocationFrom.getId(), warehouseId, updateBy);
  1034. // 更新目标库位空闲有货
  1035. baseLocationInfoService.updateLocationIdleAndNoEmpty(baseLocationTo.getId(), warehouseId, updateBy);
  1036. // 更新托盘绑定库位关系
  1037. wmsBoxInfoService.updateLocationBind(palletNo, baseLocationTo.getId(), null);
  1038. return AjaxResult.success("操作成功!");
  1039. }
  1040. @Override
  1041. public AjaxResult movePalletTo(String palletNo, String locationTo, String isCallCar, String reason
  1042. , Long warehouseId, String updateBy) {
  1043. String locationFrom;
  1044. boolean callCar = false; // 是否叫车(不传默认不叫车)
  1045. if (com.warewms.common.utils.string.StringUtils.isEmpty(palletNo)) {
  1046. AjaxResult.error("托盘号不能为空!");
  1047. }
  1048. WmsBoxInfo wmsBoxInfo = wmsBoxInfoService.selectWmsBoxInfoByBoxNo(palletNo);
  1049. if (wmsBoxInfo == null) {
  1050. return AjaxResult.error("不存在对应托盘信息!" + palletNo);
  1051. }
  1052. locationFrom = wmsBoxInfo.getLocationId().toString();
  1053. if (com.warewms.common.utils.string.StringUtils.isNotEmpty(isCallCar)) {
  1054. callCar = isCallCar.equals(WmsConstant.IS_YES.Y.getValue());
  1055. }
  1056. // 执行库存移动
  1057. InvLotLocIdMoveForm moveForm = new InvLotLocIdMoveForm();
  1058. moveForm.setLocationFrom(locationFrom);
  1059. moveForm.setLocationTo(locationTo);
  1060. moveForm.setReason(reason);
  1061. moveForm.setWarehouseId(warehouseId);
  1062. moveForm.setUpdateBy(updateBy);
  1063. // 是否叫车
  1064. if (callCar) {
  1065. return this.move(moveForm);
  1066. }
  1067. return this.moveDirect(moveForm);
  1068. }
  1069. @Transactional(propagation = Propagation.REQUIRES_NEW)
  1070. @Override
  1071. public AjaxResult doCheckout(CheckOutInfoForm check) {
  1072. // String orderNo = check.getOrderNo();
  1073. String palletNo = check.getPalletNo();
  1074. // 验证出库单号
  1075. // WmsDocOrderHeader wmsDocOrderHeader = wmsDocOrderHeaderService.selectWmsDocOrderHeaderByErpNo(orderNo);
  1076. // if (wmsDocOrderHeader == null) {
  1077. // return AjaxResult.error("对应出库单号不存在!");
  1078. // }
  1079. //生成任务呼叫到接驳位
  1080. BaseLocationInfo baseLocationInfo = baseLocationInfoService.selectBaseLocationInfoByIdOrNo(check.getLocationNo(), WmsConstant.WAREHOUSE_ID);
  1081. FlowConfigHeaderVO flowConfigHeaderVO = flowConfigHeaderService.selectFlowConfigHeaderById((long) WmsConstant.FLOW_ID_SO);
  1082. AgvCallDTO agvCallDTO = new AgvCallDTO();
  1083. agvCallDTO.setId(flowConfigHeaderVO.getId());
  1084. agvCallDTO.setLocationFrom(baseLocationInfo.getId().toString());
  1085. agvCallDTO.setLocationTo(null);
  1086. agvCallDTO.setPalletNo(palletNo);
  1087. agvCallDTO.setWarehouseId(WmsConstant.WAREHOUSE_ID);
  1088. // 参数内容过长无法添加
  1089. agvCallDTO.setExtParam("");
  1090. agvCallDTO.setOrderNo(com.warewms.common.utils.string.StringUtils.EMPTY);
  1091. agvCallDTO.setTaskType(WmsConstant.FLOW_ID_SO + "");
  1092. AjaxResult result = businessService.agvCall(flowConfigHeaderVO, agvCallDTO);
  1093. if ((int) result.get(AjaxResult.CODE_TAG) == 500) {
  1094. throw new ServiceException("任务生成失败:" + result.getMsg() + ",库位:" + baseLocationInfo.getLocationNo());
  1095. }
  1096. return AjaxResult.success("操作成功");
  1097. }
  1098. }