using JSMachine.WMS.App.Dto; using JSMachine.WMS.App.Dto.Enum; using JSMachine.WMS.App.IService; using JSMachine.WMS.App.ServiceImpl; using JSMachine.WMS.Business.Common.IService; using JSMachine.WMS.Business.Common.Models; using JSMachine.WMS.Business.SSE; using JSMachine.WMS.Business.StockIn.IService; using JSMachine.WMS.Business.StockIn.ServiceImpl.Strategy; using JSMachine.WMS.Infrastructure.Helper; using JSMachine.WMS.PLC.ModbusImpl.Elevator.ModbusIO.Read; using JSMachine.WMS.PLC.ModbusImpl.Elevator.Model; using System.Diagnostics; namespace JSMachine.WMS.Business.Common.ServiceImpl { /// /// WMS 通用业务服务,协调 ERP 任务、库位和 AGV 任务, /// 负责中转区及提升机相关任务的生成。 /// public class CommonService : ICommonService { private IERPTaskService _erpTaskService; private IStorageRackService _storageRackService; private IAGVTaskService _agvTaskService; public CommonService( IERPTaskService erpTaskService, IStorageRackService storageRackService, IAGVTaskService agvTaskService) { _erpTaskService = erpTaskService; _storageRackService = storageRackService; _agvTaskService = agvTaskService; } /// /// 检查指定库位所在列是否存在锁定库位。 /// 该判断通过查询同列全部库位完成,任一库位被锁定即视为整列锁定。 /// /// 用于确定库位列的库位信息。 /// 同列存在锁定库位时返回 。 public async Task IsColLock(StorageRackDto storageRack) { List storageRacksThisCol = await _storageRackService .GetListByExpression(p => p.ReservoirAreaColumnId == storageRack.ReservoirAreaColumnId); if (storageRacksThisCol.IsNullOrEmpty()) return false; if (storageRacksThisCol.Any(p => p.IsLock)) return true; return false; } /// /// 跟据erp任务获取已经生成的agv任务列表(不包含已经取消的任务) /// /// /// public async Task> GetCreatedAgvTasksFromErpTask(ERPTaskDto erpTask, TaskTypeEnum taskType) { List agvTasks = await _agvTaskService .GetListByExpression(p => p.ErpTaskId == erpTask.Id && p.TaskType == taskType && p.TaskStatus != TaskStatusEnum.Cancelled && p.TaskStatus != TaskStatusEnum.Failed); agvTasks = agvTasks .GroupBy(p => p.BarCode) .Select(p => p.First()) .ToList(); return agvTasks; } /// /// 生成到中转区域的任务。指定起点,终点为中转区 /// /// /// public async Task CreateAgvTaskToTransferArea(StorageRackDto startPosition, TaskTypeEnum taskType, ERPTaskDto erpTask) { StorageRackDto endPosition = await _storageRackService.GetUsableTransferStorageRack(); if (endPosition == null) { LogHelper.Info("中转区域库位已满"); return false; } await CreateAndInsertAgvTask(new AgvTaskCreationParam { StartPosition = startPosition, EndPosition = endPosition, ErpTaskId = erpTask.Id, TaskType = taskType, StockOutWharf = erpTask.Transport, ErpUploadStatus = ErpUploadStatusEnum.Unnecessary }); return true; } /// /// 中转区作业调度 起点为中转区域 终点需计算 /// /// 要调度的中转区物料 /// public async Task CreateAgvTaskFromTransferArea(StorageRackDto startPosition, AGVTaskDto lastAgvTaskRelated, ERPTaskDto erpTask) { // 中转区任务按出库、入库、清理出库阻塞物的顺序生成;任一环节失败即停止后续调度。 bool bRet = await CreateTransferStockOutAgvTask(startPosition, lastAgvTaskRelated, erpTask); if (!bRet) return false; bRet = await CreateTransferStockInAgvTask(startPosition, lastAgvTaskRelated, erpTask); if (!bRet) return false; bRet = await CreateRemoveStockOutObstructionAgvTask(startPosition, lastAgvTaskRelated, erpTask); if (!bRet) return false; return true; } private async Task CreateTransferStockOutAgvTask( StorageRackDto startPosition, AGVTaskDto lastAgvTaskRelated, ERPTaskDto erpTask) { if (lastAgvTaskRelated.TaskType != TaskTypeEnum.TransferStockOut) return true; StorageRackDto elevator = await GetUsableElevator(FloorEnum.SecondFloor, 2); if (elevator == null) { LogHelper.Warn($"中转区出库业务 所有提升机出库库位均被WMS或者PLC锁定,erpTask {lastAgvTaskRelated.ErpTaskId} 无法生成AgvTask"); return false; } await CreateAndInsertAgvTask(new AgvTaskCreationParam { StartPosition = startPosition, EndPosition = elevator, ErpTaskId = erpTask.Id, TaskType = TaskTypeEnum.TransferStockOut, StockOutWharf = erpTask.Transport, ErpUploadStatus = ErpUploadStatusEnum.Unnecessary }); return true; } private async Task CreateTransferStockInAgvTask(StorageRackDto startPosition, AGVTaskDto lastAgvTaskRelated, ERPTaskDto erpTask) { if (lastAgvTaskRelated.TaskType != TaskTypeEnum.TransferStockIn) return true; IStockInStrategy stockInStrategy = StrategyFactory.CreateStockInStrategy( TransportEnum.TransitArea, FloorEnum.SecondFloor, startPosition.MateriaBatch); StorageRackDto endPosition = await stockInStrategy.CalCulateWarehouse(); if (endPosition == null) return false; await CreateAndInsertAgvTask(new AgvTaskCreationParam { StartPosition = startPosition, EndPosition = endPosition, ErpTaskId = erpTask.Id, TaskType = lastAgvTaskRelated.TaskType, ErpUploadStatus = (erpTask.TaskType == TaskTypeEnum.PdaIn || erpTask.TaskType == TaskTypeEnum.TailIn) ? ErpUploadStatusEnum.WaittingToUpload : ErpUploadStatusEnum.Unnecessary }); return true; } private async Task CreateRemoveStockOutObstructionAgvTask( StorageRackDto startPosition, AGVTaskDto lastAgvTaskRelated, ERPTaskDto erpTask) { if (lastAgvTaskRelated.TaskType != TaskTypeEnum.RemoveStockOutObstruction) return true; IStockInStrategy stockInStrategy = StrategyFactory.CreateStockInStrategy( TransportEnum.TransitArea, FloorEnum.SecondFloor, startPosition.MateriaBatch); StorageRackDto endPosition = await stockInStrategy.CalCulateWarehouse(); if (endPosition == null) return false; await CreateAndInsertAgvTask(new AgvTaskCreationParam { StartPosition = startPosition, EndPosition = endPosition, ErpTaskId = erpTask.Id, TaskType = lastAgvTaskRelated.TaskType, ErpUploadStatus = (erpTask.TaskType == TaskTypeEnum.PdaIn || erpTask.TaskType == TaskTypeEnum.TailIn) ? ErpUploadStatusEnum.WaittingToUpload : ErpUploadStatusEnum.Unnecessary }); return true; } /// /// 获取可用提升机库位 /// /// 楼层 /// 任务类型 1-入库 2-出库 /// public async Task GetUsableElevator(FloorEnum floor, int taskType) { List elevatorWarehouse = await _storageRackService.GetListByExpression(p => p.Transport == TransportEnum.Elevator && p.Floor == floor && !p.IsLock ); if (elevatorWarehouse.IsNullOrEmpty()) { return null; } List elevatorPlcStatuses = await ElevatorStatusRead.ReadAllElevatorStatus(); StorageRackDto elevator = null; foreach (StorageRackDto elvatorWarehouse in elevatorWarehouse) { int elevatorNo = elvatorWarehouse.StorageRackName.Contains("1号") ? 1 : 2; ElevatorPlcStatus elevatorPlcStatus = elevatorPlcStatuses.First(p => p.ElevatorNo == elevatorNo); //入库 if (taskType == 1) { if (elvatorWarehouse.ElevatorChannel == 1001 && elevatorPlcStatus.StockInPutdownChanelTwo || elvatorWarehouse.ElevatorChannel == 1011 && elevatorPlcStatus.StockInPutdownChanelOne) { elevator = elvatorWarehouse; break; } } //出库 if (taskType == 2) { if (elvatorWarehouse.ElevatorChannel == 2001 && elevatorPlcStatus.StockOutPutdownChanelTwo || elvatorWarehouse.ElevatorChannel == 2011 && elevatorPlcStatus.StockOutPutdownChanelOne) { elevator = elvatorWarehouse; break; } } } return elevator; } public async Task CreateAndInsertAgvTask(AgvTaskCreationParam agvTaskCreationParam) { AGVTaskDto agvTask = new() { ErpTaskId = agvTaskCreationParam.ErpTaskId, BarCode = agvTaskCreationParam.StartPosition.BarCode, OrderNo = agvTaskCreationParam.StartPosition.OrderNo, CustomName = agvTaskCreationParam.StartPosition.CustomName, MateriaName = agvTaskCreationParam.StartPosition.MateriaName, MateriaType = agvTaskCreationParam.StartPosition.MateriaType, MateriaNum = agvTaskCreationParam.StartPosition.MateriaNum, MateriaBatch = agvTaskCreationParam.StartPosition.MateriaBatch, MateriaCode = agvTaskCreationParam.StartPosition.MateriaCode, TaskType = agvTaskCreationParam.TaskType, TaskStatus = TaskStatusEnum.Initial, Priority = agvTaskCreationParam.TaskType == TaskTypeEnum.SaleOut ? PriorityEnum.High : PriorityEnum.Middle, Floor = agvTaskCreationParam.StartPosition.Floor, StartPositionCode = agvTaskCreationParam.StartPosition.StorageRackNo, EndPositionCode = agvTaskCreationParam.EndPosition.StorageRackNo, Transport = agvTaskCreationParam.StockOutWharf, ErpUploadStatus = agvTaskCreationParam.ErpUploadStatus }; await _storageRackService.Lock(agvTaskCreationParam.StartPosition); await _storageRackService.Lock(agvTaskCreationParam.EndPosition); await _agvTaskService.Add(agvTask); //发送广播通知前端网站刷新页面 SseEngine.BrodCast(agvTaskCreationParam.StartPosition.Floor.ToString()); } } }