using Mapster; using System.Text.Json; using WIDESEA_Common.LocationEnum; using WIDESEA_Common.StockEnum; using WIDESEA_Common.TaskEnum; using WIDESEA_Common.WareHouseEnum; using WIDESEA_Core; using WIDESEA_Core.Enums; using WIDESEA_Core.Helper; using WIDESEA_DTO.Task; using WIDESEA_Model.Models; namespace WIDESEA_TaskInfoService { public partial class TaskService { #region 极卷库任务模块 public string AGV_OutTaskComplete = WIDESEA_Core.Helper.AppSettings.Configuration["AGV_OutTaskComplete"]; public string WCS_ReceiveTask = WIDESEA_Core.Helper.AppSettings.Configuration["WCS_ReceiveTask"]; /// /// 出入库申请。 /// public async Task ApplyInOutAsync(ApplyInOutDto applyInOutDto) { AGVResponse response = new AGVResponse(); try { var validationMessage = ValidateApplyInOutRequest(applyInOutDto); if (validationMessage != null) return response.Error(validationMessage); var existingTask = await BaseDal.QueryFirstAsync(x => x.PalletCode == applyInOutDto.TrayNumber); if (existingTask != null) return response.Error($"WMS已有当前任务,不可重复下发,任务号:{applyInOutDto.TaskId}"); var task = BuildAgvTask(applyInOutDto); if (applyInOutDto.InOut == 1) { var inboundResult = await CreateAgvInboundTaskAsync(task, applyInOutDto); if (inboundResult != null) return inboundResult; } else { var outboundResult = await CreateAgvOutboundTaskAsync(task, applyInOutDto); if (outboundResult != null) return outboundResult; } return response.OK(BuildAgvDataDto(task, applyInOutDto)); } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); return response.Error($"WMS任务创建接口错误: {ex.Message}"); } } /// /// 手动出库完成反馈给AGV。 /// public async Task OutTaskComplete(OutTaskCompleteDto outTaskCompleteDto) { WebResponseContent response = new WebResponseContent(); try { var validationMessage = ValidateOutTaskCompleteRequest(outTaskCompleteDto); if (validationMessage != null) return response.Error(validationMessage); var task = await BaseDal.QueryFirstAsync(x => x.OrderNo == outTaskCompleteDto.TaskId); if (task == null) return response.Error("未找到任务信息"); outTaskCompleteDto.ReqTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); var httpResponse = _httpClientHelper.Post(AGV_OutTaskComplete, outTaskCompleteDto.ToJson()).Data; if (httpResponse == null || httpResponse.Data == null) return response.Error(httpResponse?.Msg ?? "AGV接口调用异常"); if (!httpResponse.Code) return response.Error(string.IsNullOrWhiteSpace(httpResponse.Msg) ? "AGV接口调用失败" : httpResponse.Msg); var syncResult = await CompleteLocalOutboundAfterAgvAckAsync(task); return syncResult.Status ? response.OK(httpResponse.Msg) : syncResult; } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); return response.Error($"WMS任务完成接口错误:{ex.Message}"); } } /// /// 输送线申请进入。 /// public async Task ApplyEnterAsync(ApplyEnterDto applyEnterDto) { AGVResponse response = new AGVResponse(); try { var validationMessage = ValidateApplyEnterRequest(applyEnterDto); if (validationMessage != null) return response.Error(validationMessage); var task = await BaseDal.QueryFirstAsync(x => x.OrderNo == applyEnterDto.TaskId); if (task == null) return response.Error($"未找到任务信息,任务号:{applyEnterDto.TaskId}"); if (CanApplyEnter(task, applyEnterDto)) return response.OK(); return response.Error($"输送线{applyEnterDto.DevId}当前繁忙,请稍后重试"); } catch (Exception ex) { return response.Error($"WMS输送线申请接口错误:{ex.Message}"); } } /// /// 取放货完成。 /// public async Task TaskCompleteAsync(TaskCompleteDto taskCompleteDto) { AGVResponse response = new AGVResponse(); try { var validationMessage = ValidateTaskCompleteRequest(taskCompleteDto); if (validationMessage != null) return response.Error(validationMessage); var task = await BaseDal.QueryFirstAsync(x => x.OrderNo == taskCompleteDto.TaskId); if (task == null) return response.Error($"未找到任务信息,任务号:{taskCompleteDto.TaskId}"); return taskCompleteDto.InOut == 2 ? await CompleteAgvOutboundTaskAsync(task) : await CompleteAgvInboundTaskAsync(task); } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); return response.Error($"WMS取放货完成接口错误:{ex.Message}"); } } /// /// 任务取消。 /// public async Task TaskCancelAsync(TaskCancelDto taskCancelDto) { AGVResponse response = new AGVResponse(); try { var validationMessage = ValidateTaskCancelRequest(taskCancelDto); if (validationMessage != null) return response.Error(validationMessage); var task = await BaseDal.QueryFirstAsync(x => x.OrderNo == taskCancelDto.TaskId); if (task == null) return response.OK(); if (task.TaskStatus == (int)TaskInStatusEnum.InNew) return CancelAgvInboundTask(task); if (task.TaskStatus == (int)TaskOutStatusEnum.OutNew) return await CancelAgvOutboundTaskAsync(task); return response.Error("任务已经在执行中,不可取消"); } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); return response.Error($"WMS任务取消接口错误:{ex.Message}"); } } private static string? ValidateApplyInOutRequest(ApplyInOutDto dto) { if (dto == null) return "请求参数不能为空"; if (string.IsNullOrWhiteSpace(dto.TrayNumber)) return "托盘号不能为空"; if (string.IsNullOrWhiteSpace(dto.TaskId)) return "任务号不能为空"; if (string.IsNullOrWhiteSpace(dto.MaterialType)) return "物料类型不能为空"; if (string.IsNullOrWhiteSpace(dto.MaterialName)) return "物料描述不能为空"; if (string.IsNullOrWhiteSpace(dto.ReqTime)) return "请求时间不能为空"; if (dto.Floor != 1 && dto.Floor != 2) return $"楼层段错误,必须为1(模切段)或2(卷绕段),当前值:{dto.Floor}"; if (dto.YinYang != 1 && dto.YinYang != 2) return $"阴阳极错误,必须为1(阴极)或2(阳极),当前值:{dto.YinYang}"; if (dto.InOut != 1 && dto.InOut != 2) return $"出入库类型错误,必须为1(入库)或2(出库),当前值:{dto.InOut}"; if (dto.InOut == 1 && (dto.Width == null || dto.Width <= 0)) return "入库时宽度不能为空且必须大于0"; if (dto.InOut == 1 && string.IsNullOrWhiteSpace(dto.Group)) return "入库时整托组别不能为空"; return null; } private static string? ValidateOutTaskCompleteRequest(OutTaskCompleteDto dto) { if (dto == null) return "请求参数不能为空"; if (string.IsNullOrWhiteSpace(dto.TaskId)) return "任务号不能为空"; if (string.IsNullOrWhiteSpace(dto.DevId)) return "出库口编号不能为空"; return null; } private static string? ValidateApplyEnterRequest(ApplyEnterDto dto) { if (dto == null) return "请求参数不能为空"; if (string.IsNullOrWhiteSpace(dto.DevId)) return "设备编号不能为空"; if (string.IsNullOrWhiteSpace(dto.TaskId)) return "任务号不能为空"; if (dto.InOut != 1 && dto.InOut != 2) return $"出入库类型错误,必须为1(入库)或2(出库),当前值:{dto.InOut}"; return null; } private static string? ValidateTaskCompleteRequest(TaskCompleteDto dto) { if (dto == null) return "请求参数不能为空"; if (string.IsNullOrWhiteSpace(dto.TaskId)) return "任务号不能为空"; if (string.IsNullOrWhiteSpace(dto.DevId)) return "设备编号不能为空"; if (dto.InOut != 1 && dto.InOut != 2) return $"出入库类型错误,必须为1(入库)或2(出库),当前值:{dto.InOut}"; return null; } private static string? ValidateTaskCancelRequest(TaskCancelDto dto) { if (dto == null) return "请求参数不能为空"; if (string.IsNullOrWhiteSpace(dto.TaskId)) return "任务号不能为空"; return null; } private Dt_Task BuildAgvTask(ApplyInOutDto dto) { var task = new Dt_Task { OrderNo = dto.TaskId, PalletCode = dto.TrayNumber, PalletType = dto.Floor, Grade = 1, Creater = "AGV", CreateDate = DateTime.Now, Remark = $"物料类型:{dto.MaterialType},物料描述:{dto.MaterialName}" }; if (dto.YinYang == 1) { task.Roadway = WarehouseEnum.FJ1.ToString(); task.WarehouseId = (int)WarehouseEnum.FJ1; task.SourceAddress = dto.InOut == 1 ? "D10010" : "D10020"; task.NextAddress = "D10080"; task.TargetAddress = "阴极卷库"; } else { task.Roadway = WarehouseEnum.ZJ1.ToString(); task.WarehouseId = (int)WarehouseEnum.ZJ1; task.SourceAddress = dto.InOut == 1 ? "D10100" : "D10090"; task.NextAddress = "D10160"; task.TargetAddress = "正极卷库"; } return task; } private AGVDataDto BuildAgvDataDto(Dt_Task task, ApplyInOutDto dto) { return new AGVDataDto { DevId = dto.InOut == 1 ? task.SourceAddress : task.TargetAddress, TrayNumber = task.PalletCode, Group = dto.Group, Width = dto.Width ?? 0, LabelNumber = dto.LabelNumber, ProductNo = dto.ProductNo, ProductName = dto.ProductName, Quantity = dto.Quantity, UomCode = dto.UomCode, ProductType = dto.ProductType, Equipment = dto.Equipment, ProductionDate = dto.ProductionDate, LowerLimitTime = dto.LowerLimitTime, WarningTime = dto.WarningTime, OverdueTime = dto.OverdueTime }; } private async Task CreateAgvInboundTaskAsync(Dt_Task task, ApplyInOutDto dto) { AGVResponse response = new AGVResponse(); var stockInfo = await _stockInfoService.GetStockInfoAsync(dto.TrayNumber); if (stockInfo != null) return response.Error($"当前托盘{dto.TrayNumber}已经入库了"); task.TaskType = (int)TaskInboundTypeEnum.Inbound; task.TaskStatus = (int)TaskInStatusEnum.InNew; task.CurrentAddress = task.SourceAddress; var addResult = await BaseDal.AddDataAsync(task) > 0; return addResult ? null : response.Error("入库任务创建失败"); } private async Task CreateAgvOutboundTaskAsync(Dt_Task task, ApplyInOutDto dto) { AGVResponse response = new AGVResponse(); var stockInfo = await _stockInfoService.GetStockInfoAsync(dto.TrayNumber); if (stockInfo == null) return response.Error($"未找到托盘{dto.TrayNumber}的库存信息"); if (stockInfo.WarehouseId != dto.YinYang) return response.Error($"托盘{dto.TrayNumber}不属于当前{(dto.YinYang == 1 ? "阴极" : "阳极")}"); if (stockInfo.StockStatus != (int)StockStatusEmun.入库完成) return response.Error($"托盘{dto.TrayNumber}正在移动中,请稍后!"); var locationInfo = await _locationInfoService.GetLocationInfoAsync(stockInfo.LocationCode); if (locationInfo == null) return response.Error($"未找到托盘{stockInfo.LocationCode}的货位信息"); if (locationInfo.LocationStatus != (int)LocationStatusEnum.InStock) return response.Error($"当前货位{locationInfo.LocationStatus}状态信息错误"); task.TaskType = (int)TaskOutboundTypeEnum.Outbound; task.TaskStatus = (int)TaskOutStatusEnum.OutNew; task.SourceAddress = stockInfo.LocationCode; task.CurrentAddress = stockInfo.LocationCode; task.TargetAddress = dto.YinYang == 1 ? "D10020" : "D10090"; stockInfo.StockStatus = (int)StockStatusEmun.出库锁定; locationInfo.LocationStatus = (int)LocationStatusEnum.InStockLock; _unitOfWorkManage.BeginTran(); var addTaskResult = await BaseDal.AddDataAsync(task) > 0; var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(locationInfo); var updateStockResult = await _stockInfoService.UpdateStockAsync(stockInfo); if (!addTaskResult || !updateLocationResult || !updateStockResult) { _unitOfWorkManage.RollbackTran(); return response.Error("出库任务创建失败"); } _unitOfWorkManage.CommitTran(); return null; } private async Task CompleteLocalOutboundAfterAgvAckAsync(Dt_Task task) { var stockInfo = await _stockInfoService.GetStockInfoAsync(task.PalletCode); if (stockInfo == null) return WebResponseContent.Instance.Error($"未找到托盘{task.PalletCode}的库存信息"); var locationInfo = await _locationInfoService.GetLocationInfoAsync(stockInfo.LocationCode); if (locationInfo == null) return WebResponseContent.Instance.Error($"未找到托盘{stockInfo.LocationCode}的货位信息"); if (stockInfo.StockStatus != (int)StockStatusEmun.出库锁定 || locationInfo.LocationStatus != (int)LocationStatusEnum.InStockLock) return WebResponseContent.Instance.Error($"当前库存{stockInfo.StockStatus}或者货位{locationInfo.LocationStatus}状态信息错误"); locationInfo.LocationStatus = (int)LocationStatusEnum.Free; _unitOfWorkManage.BeginTran(); var deleteTaskResult = BaseDal.DeleteData(task); var updateLocationResult = _locationInfoService.UpdateData(locationInfo); var deleteStockResult = _stockInfoService.DeleteData(stockInfo); if (!deleteTaskResult || !updateLocationResult.Status || !deleteStockResult.Status) { _unitOfWorkManage.RollbackTran(); return WebResponseContent.Instance.Error("AGV完成回传后,本地任务/库存/货位更新失败"); } _unitOfWorkManage.CommitTran(); return WebResponseContent.Instance.OK(); } private bool CanApplyEnter(Dt_Task task, ApplyEnterDto dto) { return dto.InOut == 1 ? task.TaskType == (int)TaskInboundTypeEnum.Inbound && task.TaskStatus == (int)TaskInStatusEnum.InNew : task.TaskType == (int)TaskOutboundTypeEnum.Outbound && task.TaskStatus == (int)TaskStatusEnum.Line_Finish; } private async Task CompleteAgvOutboundTaskAsync(Dt_Task task) { AGVResponse response = new AGVResponse(); var stockInfo = await _stockInfoService.GetStockInfoAsync(task.PalletCode); if (stockInfo == null) return response.Error($"未找到托盘{task.PalletCode}的库存信息"); var locationInfo = await _locationInfoService.GetLocationInfoAsync(stockInfo.LocationCode); if (locationInfo == null) return response.Error($"未找到托盘{stockInfo.LocationCode}的货位信息"); if (stockInfo.StockStatus != (int)StockStatusEmun.出库锁定 || locationInfo.LocationStatus != (int)LocationStatusEnum.InStockLock) return response.Error($"当前库存{stockInfo.StockStatus}或者货位{locationInfo.LocationStatus}状态信息错误"); locationInfo.LocationStatus = (int)LocationStatusEnum.Free; task.TaskStatus = (int)TaskOutStatusEnum.OutFinish; _unitOfWorkManage.BeginTran(); var deleteStockResult = _stockInfoService.DeleteData(stockInfo); var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(locationInfo); BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.自动完成 : OperateTypeEnum.人工完成); if (!deleteStockResult.Status || !updateLocationResult) { _unitOfWorkManage.RollbackTran(); return response.Error("出库完成后,本地库存或货位更新失败"); } _unitOfWorkManage.CommitTran(); return response.OK(); } private async Task CompleteAgvInboundTaskAsync(Dt_Task task) { AGVResponse response = new AGVResponse(); var availableLocation = await _locationInfoService.GetLocationInfo(task.Roadway); if (availableLocation == null) return response.Error("无可用的入库货位"); task.TargetAddress = availableLocation.LocationCode; var wcsTaskDto = _mapper.Map(task); var httpResponse = _httpClientHelper.Post(WCS_ReceiveTask, JsonSerializer.Serialize(wcsTaskDto)); if (httpResponse == null || httpResponse.Data == null || !httpResponse.Data.Status) return response.Error(httpResponse?.Data?.Message ?? "下发WCS失败"); task.TaskStatus = (int)TaskStatusEnum.Line_Executing; task.Dispatchertime = DateTime.Now; var locationInfo = await _locationInfoService.GetLocationInfoAsync(task.TargetAddress); if (locationInfo == null) return response.Error($"未找到托盘{task.TargetAddress}的货位信息"); if (locationInfo.LocationStatus != (int)LocationStatusEnum.Free) return response.Error($"当前货位{locationInfo.LocationStatus}状态信息错误"); Dt_StockInfo stockInfo = new Dt_StockInfo { PalletCode = task.PalletCode, StockStatus = (int)StockStatusEmun.入库确认, LocationCode = locationInfo.LocationCode, WarehouseId = task.WarehouseId, Creater = "AGV", CreateDate = DateTime.Now }; locationInfo.LocationStatus = (int)LocationStatusEnum.FreeLock; _unitOfWorkManage.BeginTran(); var updateTaskResult = BaseDal.UpdateData(task); var updateLocationResult = _locationInfoService.UpdateData(locationInfo); var addStockResult = _stockInfoService.AddData(stockInfo); if (!updateTaskResult || !updateLocationResult.Status || !addStockResult.Status) { _unitOfWorkManage.RollbackTran(); return response.Error("入库完成后,本地任务、库存或货位更新失败"); } _unitOfWorkManage.CommitTran(); return response.OK(); } private AGVResponse CancelAgvInboundTask(Dt_Task task) { AGVResponse response = new AGVResponse(); task.TaskStatus = (int)TaskInStatusEnum.InCancel; _unitOfWorkManage.BeginTran(); BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.自动完成 : OperateTypeEnum.人工完成); _unitOfWorkManage.CommitTran(); return response.OK(); } private async Task CancelAgvOutboundTaskAsync(Dt_Task task) { AGVResponse response = new AGVResponse(); var stockInfo = await _stockInfoService.GetStockInfoAsync(task.PalletCode); if (stockInfo == null) return response.Error($"未找到托盘{task.PalletCode}的库存信息"); var locationInfo = await _locationInfoService.GetLocationInfoAsync(stockInfo.LocationCode); if (locationInfo == null) return response.Error($"未找到托盘{stockInfo.LocationCode}的货位信息"); if (stockInfo.StockStatus != (int)StockStatusEmun.出库锁定 || locationInfo.LocationStatus != (int)LocationStatusEnum.InStockLock) return response.Error($"当前库存{stockInfo.StockStatus}或者货位{locationInfo.LocationStatus}状态信息错误"); stockInfo.StockStatus = (int)StockStatusEmun.入库完成; locationInfo.LocationStatus = (int)LocationStatusEnum.InStock; task.TaskStatus = (int)TaskOutStatusEnum.OutCancel; _unitOfWorkManage.BeginTran(); var updateLocationResult = _locationInfoService.UpdateData(locationInfo); var updateStockResult = _stockInfoService.UpdateData(stockInfo); BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.自动完成 : OperateTypeEnum.人工完成); if (!updateLocationResult.Status || !updateStockResult.Status) { _unitOfWorkManage.RollbackTran(); return response.Error("出库任务取消失败"); } _unitOfWorkManage.CommitTran(); return response.OK(); } #endregion 极卷库任务模块 } }