using JSMachine.WMS.App.Dto; using JSMachine.WMS.App.Dto.Enum; using JSMachine.WMS.App.IService; using JSMachine.WMS.Business.StockIn.IService; using JSMachine.WMS.Business.StockIn.ServiceImpl.Strategy; using JSMachine.WMS.Infrastructure.Helper; using JSMachine.WMS.PLC.ModbusImpl.Elevator.Util; using JSMachine.WMS.RPC.ErpRPC.Dto.In.XRBusinessResult; using JSMachine.WMS.RPC.ErpRPC.Dto.Out.XRBusinessResult; using JSMachine.WMS.RPC.ErpRPC.IService; using NPOI.OpenXmlFormats.Dml.Chart; namespace JSMachine.WMS.Business.StockIn.ServiceImpl { /// /// PDA入库业务类 /// public class StockInService : IStockInService { private IPaperStorageService _paperStorageService; private IStorageRackService _storageRackService; private IERPTaskService _erpTaskService; private IAGVTaskService _agvTaskService; private IElevatorPlcQueueService _elevatorPlcQueueService; public StockInService( IPaperStorageService paperStorageService, IStorageRackService storageRackService, IERPTaskService erpTaskService, IAGVTaskService agvTaskService, IElevatorPlcQueueService elevatorPlcQueueService ) { _paperStorageService = paperStorageService; _storageRackService = storageRackService; _erpTaskService = erpTaskService; _agvTaskService = agvTaskService; _elevatorPlcQueueService = elevatorPlcQueueService; } /// /// PDA入库 /// /// /// public async Task StockIn(PDAInParam stockInParam) { // 入库流程依次校验重复任务、物料和起点库位,再计算目标库位并创建任务。 //1.查询物料信息是否存在 //2.查询库位是否存在 //3.计算目标库位并锁定 //4.写入ErpTask表 bool existUnCompleteTask = await _erpTaskService.Exist(p => p.CreationTime > DateTime.Now.Date && (p.TaskType == TaskTypeEnum.PdaIn || p.TaskType==TaskTypeEnum.TailIn)&& (p.TaskStatus == TaskStatusEnum.Initial || p.TaskStatus == TaskStatusEnum.InExecution) && p.BarCode == stockInParam.BarCode); if (existUnCompleteTask) { LogHelper.Warn($"合格证号 {stockInParam.BarCode} 已有待入库的任务,请检查是否扫错"); return $"合格证号 {stockInParam.BarCode} 已有待入库的任务,请检查是否扫错"; } MateriaInfoDto materiaInfo = await CheckMaterialInfo(stockInParam.BarCode); if (materiaInfo == null) { string msg = $"未在ERP中查询到合格证号为 {stockInParam.BarCode} 的物料信息"; LogHelper.Warn(msg); return msg; } StorageRackDto startStoragRack = await _storageRackService.GetSingalByExpression(p => p.StorageRackNo == stockInParam.StorageRackNo && !p.IsDisabled); if (startStoragRack == null) { string msg = $"入库起点库位 {stockInParam.StorageRackNo} 不可用"; LogHelper.Warn(msg); return msg; } //如果是尾托回库,需要自动计算任务楼层 if (stockInParam.TaskType == TaskTypeEnum.TailIn) { AGVTaskDto outTask = await _agvTaskService.GetSingalByExpression(p => p.BarCode == stockInParam.BarCode && (p.TaskType == TaskTypeEnum.SaleOut || p.TaskType == TaskTypeEnum.TransferStockOut) && !p.StartPositionCode.Contains("TSJ"), p => p.CreationTime, SqlSugar.OrderByType.Desc); if (outTask == null) { string msg = $"合格证号 {stockInParam.BarCode} 批次 {materiaInfo.MateriaBatch} 没有对应的出库任务," + $"因此不知道该物料原来所属楼层,请人工将该货物放置到合适的库位上,然后使用pda更新物料信息"; LogHelper.Error(msg); return msg; } stockInParam.Floor = outTask.Floor; } //预先计算可用的库位(所有未禁用,空白库位-未完成的入库任务) int usableWarehouseCout = await _storageRackService.Count(p => p.Floor == stockInParam.Floor && p.Transport == TransportEnum.NormalArea && !p.IsDisabled); int unCompleteErpTaskCount = await _erpTaskService.Count(p => p.CreationTime > DateTime.Now.Date && (p.TaskType == TaskTypeEnum.PdaIn || p.TaskType == TaskTypeEnum.TailIn) && !(p.TaskStatus == TaskStatusEnum.Completed || p.TaskStatus == TaskStatusEnum.Cancelled) ); if (usableWarehouseCout- unCompleteErpTaskCount <=0) { string msg = $"没有空余库位,无法入库"; LogHelper.Warn(msg); return msg; } ERPTaskDto erpTask = CreateErpTask(stockInParam, materiaInfo); bool bRet = await _erpTaskService.Add(erpTask); if (!bRet) { string msg = $"数据库操作失败"; LogHelper.Warn(msg); return msg; } return string.Empty; } /// /// 从ERPTask生成AgvTask(pda入库) /// /// /// public async Task CreateAgvTaskFirstFloor(ERPTaskDto erpTask) { //1.入库到一楼寻找一楼库位 //2.入库到二楼寻找一楼提升机库位 StorageRackDto destWareHouse = await CalculateDestWarehouse(erpTask, erpTask.MateriaBatch, erpTask.Floor); if (destWareHouse == null) { return false; } AGVTaskDto agvTask = new() { ErpTaskId = erpTask.Id, BarCode = erpTask.BarCode, OrderNo = erpTask.OrderNo, CustomName = erpTask.CustomName, MateriaName = erpTask.MateriaName, MateriaType = erpTask.MateriaType, MateriaNum = erpTask.ErpOrderNum, MateriaBatch = erpTask.MateriaBatch, MateriaCode = erpTask.MateriaCode, TaskType = erpTask.TaskType, TaskStatus = TaskStatusEnum.Initial, Priority = PriorityEnum.High, Floor = FloorEnum.FirstFloor, StartPositionCode = erpTask.StorageRackNo, EndPositionCode = destWareHouse.StorageRackNo, ErpUploadStatus = destWareHouse.Transport == TransportEnum.Elevator ? ErpUploadStatusEnum.Unnecessary : ErpUploadStatusEnum.WaittingToUpload, Transport = TransportEnum.NormalArea }; destWareHouse.IsLock = true; await _storageRackService.Lock(destWareHouse); return await _agvTaskService.Add(agvTask); } private async Task CheckMaterialInfo(string barcode) { XRResultDto xRResult = await _paperStorageService.GetMateriaInfo(barcode); if (xRResult?.status == 200) return xRResult.data; return null; } /// /// 计算目标库位 /// /// /// private async Task CalculateDestWarehouse(ERPTaskDto erpTask, string materiaBatch, FloorEnum floor) { //1.入库到一楼寻找一楼库位 //2.入库到二楼寻找一楼提升机库位 if (floor == FloorEnum.FirstFloor) { IStockInStrategy stockInStrategy = StrategyFactory.CreateStockInStrategy(TransportEnum.ManualArea, floor, materiaBatch); StorageRackDto destWarehouse = await stockInStrategy.CalCulateWarehouse(); return destWarehouse; } StorageRackDto elevatorWarehouse = await ElevatorUtil.GetUsableElevatorChannel(erpTask.Id, FloorEnum.FirstFloor); return elevatorWarehouse; } private ERPTaskDto CreateErpTask(PDAInParam pdaInParam, MateriaInfoDto materiaInfoDto) { ERPTaskDto eRPTaskDto = new() { StorageRackNo = pdaInParam.StorageRackNo, OrderNo = materiaInfoDto.OrderNo, BarCode = materiaInfoDto.BarCode, MateriaName = materiaInfoDto.MateriaName, ErpOrderNum = pdaInParam.TaskType == TaskTypeEnum.PdaIn ? int.Parse(materiaInfoDto.MateriaNum) : pdaInParam.MertialNum, MateriaBatch = materiaInfoDto.MateriaBatch, MateriaCode = materiaInfoDto.MateriaCode, TaskStatus = TaskStatusEnum.Initial, TaskType = pdaInParam.TaskType, Floor = pdaInParam.Floor }; return eRPTaskDto; } } }