using JSMachine.WMS.App.Dto; using JSMachine.WMS.App.Dto.Enum; using JSMachine.WMS.App.IService; using JSMachine.WMS.Business.RcsCallBack.IService; using JSMachine.WMS.Business.RcsCallBack.IService.StaePattern; using JSMachine.WMS.Business.RcsCallBack.IService.StrategyPattern; using JSMachine.WMS.Business.RcsCallBack.ServiceImpl.StatePattern; using JSMachine.WMS.Business.RcsCallBack.ServiceImpl.StrategyPatternImpl; using JSMachine.WMS.Common.Dto.Business; using JSMachine.WMS.Infrastructure.Helper; using JSMachine.WMS.RPC.RcsRPC.Dto; using JSMachine.WMS.RPC.RcsRPC.Dto.In; namespace JSMachine.WMS.Business.RcsCallBack.ServiceImpl { /// /// RCS 回调业务,将外部 AGV 状态转换为本地任务、库存及报警状态。 /// public class RcsCallBackService : IRcsCallBackService { private IAGVTaskService _agvTaskService; private IElevatorPlcQueueService _elevatorPlcQueueService; private IStorageRackService _storageRackService; private IERPTaskService _erptaskService; private IElevatorCountService _elevatorCountService; public RcsCallBackService( IAGVTaskService agvTaskService, IElevatorPlcQueueService elevatorPlcQueueService, IStorageRackService storageRackService, IERPTaskService erpTaskService, IElevatorCountService elevatorCountService) { _agvTaskService = agvTaskService; _elevatorPlcQueueService = elevatorPlcQueueService; _storageRackService = storageRackService; _erptaskService = erpTaskService; _elevatorCountService = elevatorCountService; } /// /// 给Rcs调用,获取AGV上报的任务状态 /// /// /// public async Task DealwithExcutionStatus(AgvExcutionInfo agvExcutionInfo, AGVTaskDto agvTask) { // 先处理失败和取消状态,再处理成功状态;各处理器根据回调状态自行决定是否生效。 //处理agv执行失败的回调,推送pda报警 await HandleFailed(agvExcutionInfo, agvTask); await HandleCanceled(agvExcutionInfo, agvTask); //处理agv执行成功的回调 RcsApiResult rcsApiResult = await HandleSuccess(agvExcutionInfo, agvTask); return rcsApiResult; } public async Task DealWithAlarmHandleResult(Guid agvTaskId) { AGVTaskDto agvTask = await _agvTaskService.GetSingalByExpression(p => p.Id == agvTaskId); if (agvTask == null) { LogHelper.Warn($"PDA上传的 {agvTaskId} 任务不存在,该任务告警可能已经处理?"); return true; } //模拟rcs回调,发送放货完成命令 await DealwithExcutionStatus(new AgvExcutionInfo { OrderId = agvTaskId.ToString(), Status = 23 }, agvTask); //处理完删除缓存中的报警信息 GlobalAgvTaskFailedAlarmInfo.RemoveAlarmInfo(agvTaskId); return true; } #region 处理入库rcs回调信息 private async Task HandleCanceled(AgvExcutionInfo agvExcutionInfo, AGVTaskDto agvTask) { if (agvExcutionInfo.Status != 3) return; agvTask.TaskStatus = TaskStatusEnum.Cancelled; await _agvTaskService.EditSingal(agvTask); //搬运的任务没有对应的erptask if (agvTask.TaskType != TaskTypeEnum.Carry) { ERPTaskDto erpTask = await _erptaskService.GetSingalByExpression(p => p.Id == agvTask.ErpTaskId); erpTask.TaskStatus = TaskStatusEnum.Cancelled; await _erptaskService.UpdateTaskStatus(erpTask); } } private async Task HandleFailed(AgvExcutionInfo agvExcutionInfo, AGVTaskDto agvTask) { if (agvExcutionInfo.Status != 7) return; //1.一楼 起点在入库库位,终点在提升机,人工搬运托盘到提升机入口,手动提交放货完成信号 //2.二楼 起点在提升机出口,终点在存储区库位,人工搬运托盘到库位,手动提交放货完成信号 //3.二楼 起点在入库区库位,终点在提升机入口,人工搬运托盘到提升机入口,手动提交放货完成信号 //4.一楼 起点在提升机,终点在出货码头,人工搬运托盘到出货码头,无需其他处理 await HandleStocInFirstFloor(agvExcutionInfo, agvTask); await HandleStocInSecondFloor(agvExcutionInfo, agvTask); await HandleStocOutSecondFloor(agvExcutionInfo, agvTask); await HandleStocOutFirstFloor(agvExcutionInfo, agvTask); } #region agv执行失败报警分任务处理 private async Task HandleStocInFirstFloor(AgvExcutionInfo agvExcutionInfo, AGVTaskDto agvTask) { if (!(agvTask.TaskType == TaskTypeEnum.PdaIn && agvTask.Floor == FloorEnum.FirstFloor)) return; StorageRackDto destWarehouse = await _storageRackService.GetSingalByExpression(p => p.StorageRackNo == agvTask.EndPositionCode); //终点在存储区,人工搬运获取到指定库位,完成后写放货完成 if (destWarehouse.Transport == TransportEnum.NormalArea) { string operatn = $"{agvExcutionInfo.DeviceNum}号小车报警,请将货物从车上取下搬运到 {destWarehouse.StorageRackName} " + $"库区的 {destWarehouse.StorageRackNo}库位上,完成后点击已处理按钮"; LogHelper.Warn(operatn); GlobalAgvTaskFailedAlarmInfo.AddAlarmInfo(new AgvTaskFailedAlarmInfo { AgvTaskId = agvTask.Id, Operation = operatn }); await UpdateErpTaskStatus(agvTask, TaskStatusEnum.Failed); } //终点在提升机入口,人工搬运获取到提升机入口,完成后写放货完成 if (destWarehouse.Transport == TransportEnum.Elevator) { string operatn = $"{agvExcutionInfo.DeviceNum}号小车报警,请将货物从车上(或库位{agvTask.StartPositionCode})搬运到 {destWarehouse.StorageRackName} 上," + $"完成后点击已处理按钮"; LogHelper.Warn($"任务 id {agvTask.Id} 操作信息:{operatn}"); GlobalAgvTaskFailedAlarmInfo.AddAlarmInfo(new AgvTaskFailedAlarmInfo { AgvTaskId = agvTask.Id, Operation = operatn }); } } private async Task HandleStocInSecondFloor(AgvExcutionInfo agvExcutionInfo, AGVTaskDto agvTask) { if (!(agvTask.TaskType == TaskTypeEnum.PdaIn && agvTask.Floor == FloorEnum.SecondFloor)) return; StorageRackDto startWarehouse = await _storageRackService.GetByStorageRackNo(agvTask.StartPositionCode); StorageRackDto destWarehouse = await _storageRackService.GetByStorageRackNo(agvTask.EndPositionCode); //终点在存储区,人工搬运获取到指定库位,完成后写放货完成 string operatn = $"{agvExcutionInfo.DeviceNum}号小车报警,请将货物从 {startWarehouse.StorageRackName} 搬运到 " + $"{destWarehouse.StorageRackNo}库位上,完成后点击已处理按钮"; LogHelper.Warn($"任务 id {agvTask.Id} 操作信息:{operatn}"); GlobalAgvTaskFailedAlarmInfo.AddAlarmInfo(new AgvTaskFailedAlarmInfo { AgvTaskId = agvTask.Id, Operation = operatn }); await UpdateErpTaskStatus(agvTask, TaskStatusEnum.Failed); } private async Task HandleStocOutSecondFloor(AgvExcutionInfo agvExcutionInfo, AGVTaskDto agvTask) { if (!(agvTask.TaskType == TaskTypeEnum.SaleOut && agvTask.Floor == FloorEnum.SecondFloor)) return; StorageRackDto destWarehouse = await _storageRackService.GetByStorageRackNo(agvTask.EndPositionCode); //终点在存储区,人工搬运获取到指定库位,完成后写放货完成 string operatn = $"{agvExcutionInfo.DeviceNum}号小车报警,请将货物从车上(或者{agvTask.StartPositionCode})放到 {destWarehouse.StorageRackNo} 上,完成后点击已处理按钮"; LogHelper.Warn($"任务 id {agvTask.Id} 操作信息:{operatn}"); GlobalAgvTaskFailedAlarmInfo.AddAlarmInfo(new AgvTaskFailedAlarmInfo { AgvTaskId = agvTask.Id, Operation = operatn }); } private async Task HandleStocOutFirstFloor(AgvExcutionInfo agvExcutionInfo, AGVTaskDto agvTask) { if (!(agvTask.TaskType == TaskTypeEnum.SaleOut && agvTask.Floor == FloorEnum.SecondFloor)) return; StorageRackDto startWarehouse = await _storageRackService.GetByStorageRackNo(agvTask.StartPositionCode); StorageRackDto destWarehouse = await _storageRackService.GetByStorageRackNo(agvTask.EndPositionCode); if (startWarehouse.Transport == TransportEnum.Elevator) { string operatn = $"{agvExcutionInfo.DeviceNum}号小车报警,请将货物从 {startWarehouse.StorageRackName} 搬运到 " + $"{(destWarehouse.Transport == TransportEnum.NorthArea ? "北出库码头" : "南出库码头")} " + $"的 {destWarehouse.StorageRackNo} 库位上,完成后点击已处理按钮"; LogHelper.Warn($"任务 id {agvTask.Id} 操作信息:{operatn}"); GlobalAgvTaskFailedAlarmInfo.AddAlarmInfo(new AgvTaskFailedAlarmInfo { AgvTaskId = agvTask.Id, Operation = operatn }); } if (startWarehouse.Transport == TransportEnum.NorthArea) { string operatn = $"{agvExcutionInfo.DeviceNum}号小车报警,请将货物从 " + $"{startWarehouse} 库位上搬运到北出库码头的" + $"{destWarehouse.StorageRackNo} 库位上,完成后点击已处理按钮"; LogHelper.Warn($"任务 id {agvTask.Id} 操作信息:{operatn}"); GlobalAgvTaskFailedAlarmInfo.AddAlarmInfo(new AgvTaskFailedAlarmInfo { AgvTaskId = agvTask.Id, Operation = operatn }); } if (startWarehouse.Transport == TransportEnum.SouthArea) { string operatn = $"{agvExcutionInfo.DeviceNum}号小车报警,请将货物从" + $"{startWarehouse} 库位搬运到南出库码头" + $"的 {destWarehouse.StorageRackNo} 库位上,完成后点击已处理按钮"; LogHelper.Warn($"任务 id {agvTask.Id} 操作信息:{operatn}"); GlobalAgvTaskFailedAlarmInfo.AddAlarmInfo(new AgvTaskFailedAlarmInfo { AgvTaskId = agvTask.Id, Operation = operatn }); } } #endregion private async Task HandleSuccess(AgvExcutionInfo agvExcutionInfo, AGVTaskDto agvTask) { if (!new int[] { 21, 23 }.Contains(agvExcutionInfo.Status)) { LogHelper.Warn("rcs回调状态不是21,23,不处理"); return new RcsApiResult { code = 1000 }; } StorageRackDto destWarehouse = await _storageRackService.GetSingalByExpression(p => p.StorageRackNo == agvTask.EndPositionCode); if (destWarehouse == null) { LogHelper.Error($"AgvTask终点库位 {agvTask.EndPositionCode} 不存在"); return new RcsApiResult { code = 1000 }; ; } IAgvTaskStateHandler handler = new RcsCallbackHandlerFactory().CreateHandler(agvExcutionInfo.Status, destWarehouse); if (handler == null) { LogHelper.Error("状态模式 没有匹配的模式可以处理"); return new RcsApiResult { code = 1000 }; } await handler.HandleAsync(agvExcutionInfo, agvTask, destWarehouse); return new RcsApiResult { code = 1000 }; } private async Task UpdateErpTaskStatus(AGVTaskDto agvTask, TaskStatusEnum taskStatus) { ERPTaskDto erpTask = await _erptaskService.GetSingalByExpression(p => p.Id == agvTask.ErpTaskId); erpTask.TaskStatus = taskStatus; //更新erp任务状态为完成 bool bRet = await _erptaskService.EditSingal(erpTask); LogHelper.Info($"更新erptask状态为 {taskStatus} ,数据库操作结果 {bRet}"); } #endregion #region 处理销售出库/生产退库,Rcs回调 /// /// 解锁中区库位并绑定合格证 /// /// private async Task UnlockAndSetMiddleWarehouse(StorageRackDto storageRack) { if (storageRack.Transport != TransportEnum.MiddleOutArea) return; storageRack.IsLock = false; await _storageRackService.EditSingalWithSpecificCols(storageRack, ["IsLock", "BarCode"]); } /// /// 更新AgvTask任务状态 /// /// 库位编号 /// private async Task UpdateAgvTaskStatus(AGVTaskDto agvTask) { var updateResult = false; if (agvTask != null) { updateResult = await _agvTaskService.EditSingal(agvTask); if (!updateResult) { LogHelper.Error($"销售出库:更新AgvTask {agvTask.Id} 的,完成状态失败"); } else { LogHelper.Info($"销售出库:更新AgvTask {agvTask.Id} 的,完成状态成功"); } } return updateResult; } /// /// 清空起点库位上的物料信息 /// /// /// private async Task ClearMateriaInfo(AGVTaskDto agvTask) { var clearResult = false; var typeMsg = ""; if (agvTask.TaskType == TaskTypeEnum.SaleOut) { typeMsg = "销售出库,"; } else if (agvTask.TaskType == TaskTypeEnum.Carry) { typeMsg = "搬运物料,"; } var clearWarehouse = await _storageRackService.GetSingalByExpression(p => p.StorageRackNo == agvTask.StartPositionCode); if (clearWarehouse != null) { clearWarehouse.MateriaBatch = ""; clearWarehouse.MateriaNum = 0; clearWarehouse.OrderNo = ""; clearWarehouse.MateriaName = ""; clearWarehouse.MateriaType = ""; clearWarehouse.MateriaCode = ""; clearWarehouse.BarCode = ""; clearWarehouse.IsLock = false; clearResult = await _storageRackService.EditSingal(clearWarehouse); if (!clearResult) { LogHelper.Error($"{typeMsg}清空库位{clearWarehouse.StorageRackNo}上的物料信息{clearWarehouse.MateriaCode}失败"); } else { LogHelper.Info($"{typeMsg}清空库位{clearWarehouse.StorageRackNo}上的物料信息{clearWarehouse.MateriaCode}成功"); } } else { LogHelper.Error($"{typeMsg}清空库位时,未查询到库位{agvTask.StartPositionCode}上的物料信息"); } return clearResult; } /// /// 更新终点库位上的物料信息 /// /// /// private async Task UpdateMateriaInfo(AGVTaskDto agvTask) { var updateResult = false; var updateWarehouse = await _storageRackService.GetSingalByExpression(p => p.StorageRackNo == agvTask.EndPositionCode); if (updateWarehouse != null) { updateWarehouse.MateriaBatch = agvTask.MateriaBatch; updateWarehouse.MateriaNum = agvTask.MateriaNum; updateWarehouse.OrderNo = agvTask.OrderNo; updateWarehouse.MateriaName = agvTask.MateriaName; updateWarehouse.MateriaType = agvTask.MateriaType; updateWarehouse.MateriaCode = agvTask.MateriaCode; updateWarehouse.BarCode = agvTask.BarCode; updateWarehouse.IsLock = false; updateResult = await _storageRackService.EditSingal(updateWarehouse); if (!updateResult) { LogHelper.Error($"销售出库:更新库位{updateWarehouse.StorageRackNo}上的物料信息{updateWarehouse.MateriaCode}失败"); } else { LogHelper.Info($"销售出库:更新库位{updateWarehouse.StorageRackNo}上的物料信息{updateWarehouse.MateriaCode}成功"); } } else { LogHelper.Error($"销售出库:更新库位时,未查询到库位{agvTask.EndPositionCode}上的物料信息"); } return updateResult; } #endregion } }