| | |
| | | { |
| | | 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"]; |
| | | |
| | | /// <summary> |
| | | /// 出入库申请。 |
| | | /// 极卷库出入库申请 |
| | | /// </summary> |
| | | public async Task<AGVResponse> ApplyInOutAsync(ApplyInOutDto applyInOutDto) |
| | | { |
| | |
| | | if (validationMessage != null) |
| | | return response.Error(validationMessage); |
| | | |
| | | var existingTask = await BaseDal.QueryFirstAsync(x => x.PalletCode == applyInOutDto.TrayNumber); |
| | | var existingTask = await BaseDal.QueryFirstAsync(x => x.PalletCode == applyInOutDto.TrayNumber || x.OrderNo == applyInOutDto.TaskId); |
| | | if (existingTask != null) |
| | | return response.Error($"WMS已有当前任务,不可重复下发,任务号:{applyInOutDto.TaskId}"); |
| | | |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 手动出库完成反馈给AGV。 |
| | | /// 手动出库完成反馈给AGV |
| | | /// </summary> |
| | | public async Task<WebResponseContent> OutTaskComplete(OutTaskCompleteDto outTaskCompleteDto) |
| | | { |
| | |
| | | return response.Error(httpResponse?.Msg ?? "AGV接口调用异常"); |
| | | |
| | | if (!httpResponse.Code) |
| | | return response.Error(string.IsNullOrWhiteSpace(httpResponse.Msg) ? "AGV接口调用失败" : httpResponse.Msg); |
| | | return response.Error(string.IsNullOrWhiteSpace(httpResponse.Msg) ? "AGV接口调用失败" : httpResponse.Msg); |
| | | |
| | | var syncResult = await CompleteLocalOutboundAfterAgvAckAsync(task); |
| | | return syncResult.Status ? response.OK(httpResponse.Msg) : syncResult; |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 输送线申请进入。 |
| | | /// 输送线申请进入 |
| | | /// </summary> |
| | | public async Task<AGVResponse> ApplyEnterAsync(ApplyEnterDto applyEnterDto) |
| | | { |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 取放货完成。 |
| | | /// 取放货完成 |
| | | /// </summary> |
| | | public async Task<AGVResponse> TaskCompleteAsync(TaskCompleteDto taskCompleteDto) |
| | | { |
| | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 任务取消。 |
| | | /// 任务取消 |
| | | /// </summary> |
| | | public async Task<AGVResponse> TaskCancelAsync(TaskCancelDto taskCancelDto) |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | #region 参数验证 |
| | | private static string? ValidateApplyInOutRequest(ApplyInOutDto dto) |
| | | { |
| | | if (dto == null) return "请求参数不能为空"; |
| | |
| | | if (string.IsNullOrWhiteSpace(dto.TaskId)) return "任务号不能为空"; |
| | | return null; |
| | | } |
| | | #endregion 参数验证 |
| | | |
| | | #region 具体实现 |
| | | // 出入库共用创建任务 |
| | | private Dt_Task BuildAgvTask(ApplyInOutDto dto) |
| | | { |
| | | var task = new Dt_Task |
| | |
| | | return task; |
| | | } |
| | | |
| | | // 构建返回AGV出入库请求体 |
| | | private AGVDataDto BuildAgvDataDto(Dt_Task task, ApplyInOutDto dto) |
| | | { |
| | | return new AGVDataDto |
| | |
| | | }; |
| | | } |
| | | |
| | | // 入库创建 |
| | | private async Task<AGVResponse?> CreateAgvInboundTaskAsync(Dt_Task task, ApplyInOutDto dto) |
| | | { |
| | | AGVResponse response = new AGVResponse(); |
| | |
| | | return addResult ? null : response.Error("入库任务创建失败"); |
| | | } |
| | | |
| | | // 出库创建 |
| | | private async Task<AGVResponse?> CreateAgvOutboundTaskAsync(Dt_Task task, ApplyInOutDto dto) |
| | | { |
| | | AGVResponse response = new AGVResponse(); |
| | |
| | | if (stockInfo == null) |
| | | return response.Error($"未找到托盘{dto.TrayNumber}的库存信息"); |
| | | |
| | | if (stockInfo.WarehouseId != dto.YinYang) |
| | | return response.Error($"托盘{dto.TrayNumber}不属于当前{(dto.YinYang == 1 ? "阴极" : "阳极")}"); |
| | | //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); |
| | | var locationInfo = await _locationInfoService.GetLocationInfo(stockInfo.LocationCode); |
| | | if (locationInfo == null) |
| | | return response.Error($"未找到托盘{stockInfo.LocationCode}的货位信息"); |
| | | |
| | |
| | | task.SourceAddress = stockInfo.LocationCode; |
| | | task.CurrentAddress = stockInfo.LocationCode; |
| | | task.TargetAddress = dto.YinYang == 1 ? "D10020" : "D10090"; |
| | | |
| | | var wmsTaskDto = _mapper.Map<WMSTaskDTO>(task); |
| | | var taskList = new List<WMSTaskDTO> { wmsTaskDto }; |
| | | var requestBody = JsonSerializer.Serialize(taskList); |
| | | |
| | | var httpResponse = _httpClientHelper.Post<WebResponseContent>(WCS_ReceiveTask, requestBody); |
| | | if (httpResponse == null || httpResponse.Data == null || !httpResponse.Data.Status) |
| | | return response.Error(httpResponse?.Data?.Message ?? "下发WCS失败"); |
| | | |
| | | stockInfo.StockStatus = (int)StockStatusEmun.出库锁定; |
| | | locationInfo.LocationStatus = (int)LocationStatusEnum.InStockLock; |
| | |
| | | _unitOfWorkManage.RollbackTran(); |
| | | return response.Error("出库任务创建失败"); |
| | | } |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | |
| | | |
| | | return null; |
| | | } |
| | | |
| | | private async Task<WebResponseContent> 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; |
| | | task.TaskStatus = (int)TaskOutStatusEnum.Line_OutFinish; |
| | | |
| | | _unitOfWorkManage.BeginTran(); |
| | | var deleteTaskResult = BaseDal.DeleteData(task); |
| | | var updateLocationResult = _locationInfoService.UpdateData(locationInfo); |
| | | var deleteStockResult = _stockInfoService.DeleteData(stockInfo); |
| | | if (!deleteTaskResult || !updateLocationResult.Status || !deleteStockResult.Status) |
| | | var updateResult = BaseDal.UpdateData(task); |
| | | if (!updateResult) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | return WebResponseContent.Instance.Error("AGV完成回传后,本地任务/库存/货位更新失败"); |
| | | return WebResponseContent.Instance.Error("AGV完成回传后,任务更新失败"); |
| | | } |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | |
| | | |
| | | 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; |
| | | if (dto.InOut == 1) |
| | | { |
| | | var hasExecutingOutTask = BaseDal.QueryFirst(x => x.TaskType == (int)TaskOutboundTypeEnum.Outbound |
| | | && x.TargetAddress == task.SourceAddress |
| | | && (x.TaskStatus == (int)TaskOutStatusEnum.SC_OutExecuting |
| | | || x.TaskStatus == (int)TaskOutStatusEnum.Line_OutExecuting)); |
| | | |
| | | // 如果没有正在执行的出库任务,则允许入库 |
| | | return hasExecutingOutTask == null; |
| | | } |
| | | else |
| | | { |
| | | return task.TaskType == (int)TaskOutboundTypeEnum.Outbound |
| | | && task.TaskStatus == (int)TaskStatusEnum.Line_Finish; |
| | | } |
| | | } |
| | | |
| | | // WCS入库完成 |
| | | private async Task<WebResponseContent> CompleteAgvInboundTaskAsync(CreateTaskDto taskDto) |
| | | { |
| | | WebResponseContent response = new WebResponseContent(); |
| | | var task = await BaseDal.QueryFirstAsync(x => x.PalletType == taskDto.PalletType); |
| | | if (task == null) |
| | | return response.Error($"没有当前托盘{taskDto.PalletType}入库任务"); |
| | | |
| | | var stockInfo = await _stockInfoService.GetStockInfoAsync(task.PalletCode); |
| | | if (stockInfo == null) |
| | | return response.Error($"未找到托盘{task.PalletCode}的库存信息"); |
| | | |
| | | var locationInfo = await _locationInfoService.GetLocationInfoAsync(task.TargetAddress); |
| | | if (locationInfo == null) |
| | | return response.Error($"未找到货位{task.TargetAddress}的信息"); |
| | | |
| | | if (locationInfo.LocationStatus == (int)LocationStatusEnum.InStock) |
| | | return response.Error($"当前货位{locationInfo.LocationStatus}状态不是空闲状态,无法入库"); |
| | | |
| | | // 更新货位状态为占用 |
| | | locationInfo.LocationStatus = (int)LocationStatusEnum.InStock; |
| | | task.TaskStatus = (int)TaskInStatusEnum.InFinish; |
| | | stockInfo.StockStatus = (int)StockStatusEmun.入库完成; |
| | | _unitOfWorkManage.BeginTran(); |
| | | var addStockResult = _stockInfoService.UpdateData(stockInfo); |
| | | var updateLocationResult = _locationInfoService.UpdateData(locationInfo); |
| | | BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.自动完成 : OperateTypeEnum.人工完成); |
| | | |
| | | if (!addStockResult.Status || !updateLocationResult.Status) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | return response.Error("入库完成后,添加库存或货位更新失败"); |
| | | } |
| | | |
| | | _unitOfWorkManage.CommitTran(); |
| | | return response.OK(); |
| | | } |
| | | |
| | | // AGV出库完成 |
| | | private async Task<AGVResponse> CompleteAgvOutboundTaskAsync(Dt_Task task) |
| | | { |
| | | AGVResponse response = new AGVResponse(); |
| | |
| | | |
| | | _unitOfWorkManage.BeginTran(); |
| | | var deleteStockResult = _stockInfoService.DeleteData(stockInfo); |
| | | var updateLocationResult = await _locationInfoService.UpdateLocationInfoAsync(locationInfo); |
| | | var updateLocationResult = _locationInfoService.UpdateData(locationInfo); |
| | | BaseDal.DeleteAndMoveIntoHty(task, App.User.UserId == 0 ? OperateTypeEnum.自动完成 : OperateTypeEnum.人工完成); |
| | | if (!deleteStockResult.Status || !updateLocationResult) |
| | | if (!deleteStockResult.Status || !updateLocationResult.Status) |
| | | { |
| | | _unitOfWorkManage.RollbackTran(); |
| | | return response.Error("出库完成后,本地库存或货位更新失败"); |
| | |
| | | return response.OK(); |
| | | } |
| | | |
| | | // AGV已放货,准备输送线入库 |
| | | private async Task<AGVResponse> CompleteAgvInboundTaskAsync(Dt_Task task) |
| | | { |
| | | AGVResponse response = new AGVResponse(); |
| | |
| | | |
| | | task.TargetAddress = availableLocation.LocationCode; |
| | | |
| | | var wcsTaskDto = _mapper.Map<WCSTaskDTO>(task); |
| | | var httpResponse = _httpClientHelper.Post<WebResponseContent>(WCS_ReceiveTask, JsonSerializer.Serialize(wcsTaskDto)); |
| | | var wmsTaskDto = _mapper.Map<WMSTaskDTO>(task); |
| | | var taskList = new List<WMSTaskDTO> { wmsTaskDto }; |
| | | var requestBody = JsonSerializer.Serialize(taskList); |
| | | |
| | | var httpResponse = _httpClientHelper.Post<WebResponseContent>(WCS_ReceiveTask, requestBody); |
| | | if (httpResponse == null || httpResponse.Data == null || !httpResponse.Data.Status) |
| | | return response.Error(httpResponse?.Data?.Message ?? "下发WCS失败"); |
| | | |
| | | task.TaskStatus = (int)TaskStatusEnum.Line_Executing; |
| | | task.TaskStatus = (int)TaskInStatusEnum.Line_InExecuting; |
| | | task.Dispatchertime = DateTime.Now; |
| | | |
| | | var locationInfo = await _locationInfoService.GetLocationInfoAsync(task.TargetAddress); |
| | |
| | | |
| | | if (locationInfo.LocationStatus != (int)LocationStatusEnum.Free) |
| | | return response.Error($"当前货位{locationInfo.LocationStatus}状态信息错误"); |
| | | |
| | | var existingStock = await _stockInfoService.GetStockInfoAsync(task.PalletCode); |
| | | if (existingStock != null) |
| | | return response.Error($"托盘{task.PalletCode}的库存信息已存在,请勿重复入库"); |
| | | |
| | | Dt_StockInfo stockInfo = new Dt_StockInfo |
| | | { |
| | |
| | | return response.OK(); |
| | | } |
| | | |
| | | // AGV入库取消 |
| | | private AGVResponse CancelAgvInboundTask(Dt_Task task) |
| | | { |
| | | AGVResponse response = new AGVResponse(); |
| | |
| | | return response.OK(); |
| | | } |
| | | |
| | | |
| | | // AGV出库取消 |
| | | private async Task<AGVResponse> CancelAgvOutboundTaskAsync(Dt_Task task) |
| | | { |
| | | AGVResponse response = new AGVResponse(); |
| | |
| | | return response.OK(); |
| | | } |
| | | |
| | | #endregion 极卷库任务模块 |
| | | #endregion 具体实现 |
| | | } |
| | | } |
| | | } |