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 极卷库任务模块
}
}