package com.ruoyi.ams.xuankuang.service; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.toolkit.IdWorker; import com.ruoyi.ams.asn.domain.WmsDocAsnDetails; import com.ruoyi.ams.asn.domain.WmsDocAsnHeader; import com.ruoyi.ams.asn.service.IWmsDocAsnDetailsService; import com.ruoyi.ams.asn.service.IWmsDocAsnHeaderService; import com.ruoyi.ams.business.IBusinessService; import com.ruoyi.ams.config.domain.dto.AgvCallDTO; import com.ruoyi.ams.config.domain.dto.AgvCallItemDTO; import com.ruoyi.ams.config.domain.dto.LotattDTO; import com.ruoyi.ams.inv.service.IInvLotLocIdService; import com.ruoyi.ams.order.domain.WmsDocOrderDetails; import com.ruoyi.ams.order.domain.WmsDocOrderHeader; import com.ruoyi.ams.order.service.IWmsDocOrderDetailsService; import com.ruoyi.ams.order.service.IWmsDocOrderHeaderService; import com.ruoyi.ams.task.service.IWcsTaskService; import com.ruoyi.ams.xuankuang.domain.form.AgvInTaskForm; import com.ruoyi.ams.xuankuang.domain.form.OutTaskForm; import com.ruoyi.ams.xuankuang.domain.vo.WcsResponseVo; import com.ruoyi.base.constant.Constant; import com.ruoyi.base.domain.BaseLocationInfo; import com.ruoyi.base.domain.BaseSku; import com.ruoyi.base.domain.vo.BaseLocationLotattDTO; import com.ruoyi.base.service.IBaseLocationInfoService; import com.ruoyi.base.service.IBaseSkuService; import com.ruoyi.base.utils.IdSequenceUtils; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.utils.StringUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; /** * @author Jwk * @version 1.0 * @date 2023/6/6 13:35 */ @Slf4j @Service public class AgvCallProxyService { @Autowired private IBusinessService iBusinessService; @Autowired BaseLocationInfoSubService baseLocationInfoSubService; @Autowired WmsDocAsnSubService wmsDocAsnSubService; @Autowired private IBaseSkuService iBaseSkuService; @Autowired private IdSequenceUtils idSequenceUtils; @Autowired private IWmsDocAsnHeaderService iWmsDocAsnHeaderService; @Autowired private IWmsDocAsnDetailsService iWmsDocAsnDetailsService; @Autowired private IWmsDocOrderHeaderService iWmsDocOrderHeaderService; @Autowired private IWmsDocOrderDetailsService iWmsDocOrderDetailsService; @Autowired private WmsDocOrderSubService wmsDocOrderSubService; @Autowired private WcsTaskSubService wcsTaskSubService; @Autowired private WmsToWcsApiService wmsToWcsApiService; @Autowired private IBaseLocationInfoService iBaseLocationInfoService; @Autowired private InvLotLocIdSubService invLotLocIdSubService; @Autowired private IWcsTaskService iWcsTaskService; @Autowired private IInvLotLocIdService invLotLocIdService; /** * 主方法:桶装入库 * @param palletNo 入库托盘号 * @param materialType 物料类型 丁胺黑药类型:5 * @param agvSourceLocationId agv的起始点位 * @param quantity 数量 */ @Transactional(rollbackFor = RuntimeException.class) public void bucketIntoStorage(String palletNo, String materialType, String agvSourceLocationId, Double quantity) { //1.预备参数设置 BaseSku baseSku = iBaseSkuService.selectSkuByMaterialType(materialType); Assert.isTrue(ObjectUtil.isNotNull(baseSku) && StringUtils.isNotBlank(baseSku.getSku()), "the materialType is illegal"); String asnNo = idSequenceUtils.generateId(Constant.ID_TYPE.ASNNO.getDesc()); Assert.isTrue(ObjectUtil.isNotNull(quantity) && quantity > 0, "quantity is illegal"); BigDecimal quantityDecimal = new BigDecimal(quantity); //2. 获取agv的库位,并创建agv的wcs任务 String agvTargetLocationId = String.valueOf(getAgvLocationId("bucketLocationIdList")); String agvTaskNo = IdWorker.getIdStr(); addWcsTask(agvTaskNo, agvSourceLocationId, agvTargetLocationId, asnNo, palletNo, Constant.TASK_STS.TASK_CREATE.getLongValue(), "AGV入库任务下发", Constant.TaskType.AGV.getDesc()); //3.入库单创建 WmsDocAsnHeader wmsDocAsnHeader = iWmsDocAsnHeaderService.createAsnHeader(asnNo, Constant.ASN_TYP.TZ.getValue(), Constant.ASN_STS.STS00.getValue()); WmsDocAsnDetails wmsDocAsnDetail = iWmsDocAsnDetailsService.createAsnDetail(asnNo, baseSku.getSku(), quantityDecimal); //4. 根据入库单进行agv的任务下发,通知wcs并生成wcs任务;agv的目标点则是wcs任务的起始点位 String taskNo = IdWorker.getIdStr(); WcsResponseVo wcsResponseVo = noticeBucketIntoLocTask(taskNo, agvTargetLocationId, asnNo, palletNo, materialType, quantity); if (!wcsResponseVo.isSuccess()) { wmsDocAsnHeader.setNotes(wcsResponseVo.getMessage()); iWmsDocAsnHeaderService.updateWmsDocAsnHeader(wmsDocAsnHeader); wcsTaskSubService.callBack(taskNo, Constant.TASK_STS.TASK_CANCEL.getValue(), null); } wmsDocAsnHeader.setAsnStatus(Constant.ASN_STS.STS10.getValue()); wmsDocAsnDetail.setLineStatus(Constant.ASN_STS.STS10.getValue()); iWmsDocAsnDetailsService.updateWmsDocAsnDetails(wmsDocAsnDetail); iWmsDocAsnHeaderService.updateWmsDocAsnHeader(wmsDocAsnHeader); } /** * 主方法:桶装出库 * @param materialType 物料类型,丁胺黑药默认传5 * @param targetLocationId 出库的最终目标库位 * @param quantity 数量 不能大于4 */ @Transactional(rollbackFor = RuntimeException.class) public void bucketOutOfStorage(String materialType, String targetLocationId, Double quantity) { //1.预备参数设置 BaseSku baseSku = iBaseSkuService.selectSkuByMaterialType(materialType); Assert.isTrue(ObjectUtil.isNotNull(baseSku) && StringUtils.isNotBlank(baseSku.getSku()), "the materialType is illegal"); String orderNo = idSequenceUtils.generateId(Constant.ID_TYPE.ORDERNO.getDesc()); Assert.isTrue(ObjectUtil.isNotNull(quantity) && quantity > 0, "quantity is illegal"); BigDecimal quantityDecimal = new BigDecimal(quantity); //2. 获取agv的库位,并创建agv的wcs任务 String agvSourceLocationId = String.valueOf(getAgvLocationId("bucketLocationIdList")); String agvTaskNo = IdWorker.getIdStr(); addWcsOutTask(agvTaskNo, agvSourceLocationId, targetLocationId, orderNo, Constant.TASK_STS.TASK_CREATE.getLongValue(), "AGV出库任务下发", Constant.TaskType.AGV.getDesc()); //3.出库单创建 WmsDocOrderHeader docOrderHeader = iWmsDocOrderHeaderService.createOrderHeader(orderNo, Constant.ORDER_TYP.TZ.getValue(), Constant.ORDER_STS.STS00.getValue(), baseSku.getSku()); WmsDocOrderDetails docOrderDetail = iWmsDocOrderDetailsService.createOrderDetail(orderNo, baseSku.getSku(), quantityDecimal); //4. 根据出库单进行出库任务下发,通知wcs并生成wcs任务;改变订单的状态 List baseLocationLotattList = wmsDocOrderSubService.addConfirmAllocationAuto(orderNo); List filteredBaseLocationLotattList = wmsDocOrderSubService.filterInv(baseLocationLotattList, orderNo); Assert.isTrue(CollectionUtil.isNotEmpty(filteredBaseLocationLotattList), "filteredBaseLocationLotattList is empty"); //int errorCount = 0; for (BaseLocationInfo baseLocationInfo : filteredBaseLocationLotattList){ //每个推荐的出库库存都创建一个wcs任务,agv的起始点则是wcs任务的目标点位 //通知wcs的桶装出库的任务 WcsResponseVo wcsResponseVo = noticeBucketOutLocTask(IdWorker.getIdStr(), agvSourceLocationId, orderNo, materialType, quantity, baseLocationInfo); if (!wcsResponseVo.isSuccess()) { //errorCount++; docOrderHeader.setRemark(wcsResponseVo.getMessage()); iWmsDocOrderHeaderService.updateWmsDocOrderHeader(docOrderHeader); } } //此处屏蔽的代码:代表只有在全部同步失败的情况下,不改变单头和明细的状态 //if(errorCount == filteredBaseLocationLotattList.size()) return; docOrderHeader.setOrderStatus(Constant.ASN_STS.STS10.getValue()); docOrderDetail.setLineStatus(Constant.ASN_STS.STS10.getValue()); iWmsDocOrderDetailsService.updateWmsDocOrderDetails(docOrderDetail); iWmsDocOrderHeaderService.updateWmsDocOrderHeader(docOrderHeader); } /** * 主方法:桶装越库 * @param palletNo 托盘号 * @param materialType 物料类型 丁胺黑药类型5 * @param sourceLocationId 起始库位 * @param targetLocationId 目标库位 * @param quantity 数量 不大于4 */ public void bucketCrossStorage(String palletNo, String materialType, String sourceLocationId, String targetLocationId, Double quantity) { //1.预备参数设置 Assert.isTrue(ObjectUtil.isNotNull(quantity) && quantity > 0, "quantity is illegal"); BaseSku baseSku = iBaseSkuService.selectBaseSkuByMaterialType(materialType); Assert.isTrue(ObjectUtil.isNotNull(baseSku) && StringUtils.isNotBlank(baseSku.getSku()), "the materialType is illegal"); BigDecimal quantityDecimal = new BigDecimal(quantity); //2.入库单创建 String asnNo = idSequenceUtils.generateId(Constant.ID_TYPE.ASNNO.getDesc()); iWmsDocAsnHeaderService.createAsnHeader(asnNo, Constant.ASN_TYP.TZ.getValue(), Constant.ASN_STS.STS40.getValue()); iWmsDocAsnDetailsService.createAsnDetail(asnNo, baseSku.getSku(), quantityDecimal); //3.出库单创建 String orderNo = idSequenceUtils.generateId(Constant.ID_TYPE.ORDERNO.getDesc()); iWmsDocOrderHeaderService.createOrderHeader(orderNo, Constant.ORDER_TYP.TZ.getValue(), Constant.ORDER_STS.STS40.getValue(), baseSku.getSku()); iWmsDocOrderDetailsService.createOrderDetail(orderNo, baseSku.getSku(), quantityDecimal); //2. 获取agv的库位,并创建agv的wcs任务 String agvTaskNo = IdWorker.getIdStr(); wcsTaskSubService.addCrossWcsTask(agvTaskNo, sourceLocationId, targetLocationId, asnNo, palletNo, orderNo, Constant.TASK_STS.TASK_WAIT.getLongValue(), "agv越库任务下发"); } /** * 桶装出库 * * @param locationFrom * @param locationTo * @return */ public AjaxResult barrelsOutOfStorage(String locationFrom, String locationTo, String palletNo, String wcsId) { AgvCallDTO agvCallDTO = new AgvCallDTO(); agvCallDTO.setLocationFrom(locationFrom); agvCallDTO.setLocationTo(locationTo); List agvCallItemDTOList = new ArrayList<>(); LotattDTO lotattDTO = new LotattDTO(); lotattDTO.setLotatt07(palletNo); lotattDTO.setLotatt08(wcsId); AgvCallItemDTO agvCallItemDTO = new AgvCallItemDTO(); agvCallItemDTO.setSku("C4H9O2PSSNH4"); // 丁铵黑药 agvCallItemDTO.setLotattDTO(lotattDTO); agvCallItemDTOList.add(agvCallItemDTO); agvCallDTO.setAgvCallItemDTOList(agvCallItemDTOList); return iBusinessService.agvCall(Constant.FLOW_CONFIG_ID.ONE.getValue(), agvCallDTO); } private WcsResponseVo noticeBucketOutLocTask(String taskNo, String bucketCacheLocationId, String orderNo, String materialType, Double quantity, BaseLocationInfo baseLocationInfo) { BaseSku baseSku = iBaseSkuService.selectSkuByMaterialType(materialType); Assert.isTrue(ObjectUtil.isNotNull(baseSku) && StringUtils.isNotBlank(baseSku.getSku()) , "baseSku is null"); //1.生成一个wcs任务 String locationInfoId = String.valueOf(baseLocationInfo.getId()); addWcsOutTask(taskNo, locationInfoId, bucketCacheLocationId, orderNo, 10L, "桶装料出库任务", Constant.TaskType.RGV.getDesc()); //修改出库出库存的traceId TODO invLotLocIdService.operateTraceIdByLocationId(locationInfoId, taskNo); //4.组装wcs任务请求参数并同步当前的wcs任务 OutTaskForm outTaskForm = assemblyOutTaskForm(taskNo, orderNo, baseSku.getSkuType(), materialType, quantity, baseLocationInfo); return wmsToWcsApiService.wmsOutTask(outTaskForm); } private AjaxResult addWcsTask(String taskNo, String locationFrom, String locationTo , String asnNo, String palletNo, Long state, String remake, String taskType) { return wcsTaskSubService.addWcsTask(taskNo, locationFrom, locationTo, asnNo, palletNo, StringUtils.EMPTY, state, remake, taskType); } private AjaxResult addWcsOutTask(String taskNo, String locationFrom, String locationTo, String orderNo, Long status, String remark, String taskType) { return wcsTaskSubService.addWcsOutTask(taskNo, locationFrom, locationTo , orderNo, StringUtils.EMPTY, StringUtils.EMPTY, status, remark, taskType); } private WcsResponseVo noticeBucketIntoLocTask(String taskNo, String bucketCacheLocationId, String asnNo, String palletNo, String materialType, Double quantity) { BaseSku baseSku = iBaseSkuService.selectBaseSkuByMaterialType(materialType); Assert.isTrue(ObjectUtil.isNotNull(baseSku), "baseSku is null"); // 1.推荐目标库位 BaseLocationInfo baseLocationInfo = baseLocationInfoSubService.recommendAReceiptLocation(baseSku.getSku()); Assert.isTrue(ObjectUtil.isNotNull(baseLocationInfo), "baseLocationLotatt is null"); // 2.桶装接驳位生成库存 invLotLocIdSubService.initInv(bucketCacheLocationId, baseSku.getSku(), palletNo, asnNo, taskNo, quantity); // 3.生成任务 addWcsTask(taskNo, bucketCacheLocationId , String.valueOf(baseLocationInfo.getId()), asnNo, palletNo, Constant.TASK_STS.TASK_PUBILSH.getLongValue(), "桶装料入库任务", Constant.TaskType.RGV.getDesc()); //4.同步当前的wcs任务 AgvInTaskForm agvInTaskForm = assemblyAgvInTaskForm(taskNo, asnNo, materialType, quantity, palletNo, baseLocationInfo); return wmsToWcsApiService.wmsAgvInTask(agvInTaskForm); } private OutTaskForm assemblyOutTaskForm(String taskNo, String orderNo, String skuType, String materialType, Double quantity, BaseLocationInfo baseLocationInfo) { OutTaskForm outTaskForm = new OutTaskForm(); outTaskForm.setDocNo(orderNo); outTaskForm.setTaskNo(taskNo); outTaskForm.setRow(Integer.valueOf(baseLocationInfo.getRowIndex())); outTaskForm.setCol(Integer.parseInt(baseLocationInfo.getRowNo())); outTaskForm.setFloor(Integer.parseInt(baseLocationInfo.getShiftNo())); outTaskForm.setPackageType(Integer.valueOf(skuType)); outTaskForm.setMaterial(Integer.valueOf(materialType)); outTaskForm.setTotal(quantity.intValue()); return outTaskForm; } private AgvInTaskForm assemblyAgvInTaskForm(String taskNo, String asnNo, String materialType, Double quantity, String palletNo, BaseLocationInfo baseLocationInfo) { AgvInTaskForm agvInTaskForm = new AgvInTaskForm(); agvInTaskForm.setTaskNo(taskNo); agvInTaskForm.setAgvId("1"); agvInTaskForm.setMaterial(Integer.valueOf(materialType)); agvInTaskForm.setDocNo(asnNo); agvInTaskForm.setNum(quantity.intValue()); agvInTaskForm.setPalletId(palletNo); agvInTaskForm.setRow(Integer.valueOf(baseLocationInfo.getRowIndex())); agvInTaskForm.setCol(Integer.valueOf(baseLocationInfo.getRowNo())); agvInTaskForm.setFloor(Integer.valueOf(baseLocationInfo.getShiftNo())); return agvInTaskForm; } private Long getAgvLocationId(String subSceneCode) { List bucketLocationIdList = iWcsTaskService.getBucketLocationIdList(subSceneCode); Assert.isTrue(CollectionUtil.isNotEmpty(bucketLocationIdList), "bucketLocationIdList is empty"); BaseLocationInfo agvTargetLocationInfo = iBaseLocationInfoService.selectBaseLocationInfoById(bucketLocationIdList.get(0)); return ObjectUtil.isNotNull(agvTargetLocationInfo) ? agvTargetLocationInfo.getId() : Constant.DRUM_CONNECTORS; } }