Product_Wms/WcsMain/Business/CirculationTask/Stacker/ExeTaskDoubleFork.cs
2024-10-07 10:00:14 +08:00

456 lines
24 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using CirculateTool.Attribute;
using WcsMain.Business.CommonAction;
using WcsMain.Common;
using WcsMain.DataBase.Dao;
using WcsMain.DataBase.TableEntity;
using WcsMain.DataService;
using WcsMain.Enum.Stacker;
using WcsMain.EquipOperation.Convey;
using WcsMain.EquipOperation.Entity.Stacker;
using WcsMain.EquipOperation.Stacker;
using WcsMain.ExtendMethod;
namespace WcsMain.Business.CirculationTask.Stacker;
/// <summary>
/// 双货叉单深位执行堆垛机任务 ---- 卡特模式
/// </summary>
//[Circulation("双货叉单深位执行堆垛机任务")]
public class ExeTaskDoubleFork(
StackerOperation stackerOperation, AppWcsTaskDao wcsTaskDao, WCSTaskExecuteEvent wcsTaskEvent,
ConveyOperation conveyOperation, DataBaseData dataBaseData)
{
/// <summary>
/// 执行堆垛机任务
/// </summary>
/// <returns></returns>
[Circulation("执行堆垛机任务")]
public bool ExecuteStackerTask()
{
foreach (var stacker in CommonData.AppStackers.Open())
{
var stackerUseStatus = stackerOperation.StackerCanUse(stacker.StackerId, out int plcId, out int spare1);
if (stackerUseStatus == StackerUseStatusEnum.Free)
{
/* 空闲时正常执行任务 */
// 移库
bool exeMoveTask = ExecuteMoveTask(stacker.StackerId);
if (exeMoveTask) continue;
// 出库
bool exeOutTask = ExecuteOutTask(stacker.StackerId);
if (exeOutTask) continue;
// 入库
bool exeInTask = ExecuteInTask(stacker.StackerId);
if (exeInTask) continue;
// 拣选
//bool exePickTask = ExecutePickTask(stacker.StackerId);
//if (exePickTask) return;
}
if (stackerUseStatus == StackerUseStatusEnum.waitTask)
{
/* 重复入库时执行任务 */
bool exeDoubleInTask = ExecuteDoubleInTask(stacker.StackerId, plcId, 1);
if (exeDoubleInTask) continue;
exeDoubleInTask = ExecuteDoubleInTask(stacker.StackerId, spare1, 2);
if (exeDoubleInTask) continue;
}
}
return true;
}
/// <summary>
/// 执行堆垛机入库任务,若执行了任务则返回 true
/// </summary>
/// <param name="stackerId"></param>
/// <returns></returns>
private bool ExecuteInTask(int? stackerId)
{
if (stackerId == default) return false;
/* 检查入库站台是否允许取货 */
bool allowGetGoods = conveyOperation.AllowGetVehicle(stackerId.ToString());
if(!allowGetGoods) return false; // 入库站台不允许取货
/* 读取入库站台的条码 */
var codes = conveyOperation.ReadAreaConveyCode(stackerId.ToString());
if(codes == default || codes.Count != 2) return false;
/* 构造任务数据 */
bool isWriteTask = false; // 指示是否写入任务
for (int i = 0; i < 2; i++)
{
/* 校验货叉开启 */
string forkStatus = CommonData.AppStackers.First(f => f.StackerId == stackerId).ForkStatus ?? "";
if (forkStatus.Length <= i || forkStatus[i] != '1') continue; // 获取数据失败或者货叉未开启
var code = codes[i];
if (string.IsNullOrEmpty(code)) continue; // 检查条码是否为空
//ConsoleLog.Warning($"{stackerId} 号堆垛机,入库位置:{i + 1} 返回:{code}");
if (code == "NoRead") // 检查条码是否为 NoRead
{
/* 检查卸货站台是否允许卸货 */
bool allowSetGoods = conveyOperation.AllowSetVehicle(stackerId.ToString());
if (!allowSetGoods) continue; // 出库站台不允许取货
/* 生成一个直接卸货出去的任务 */
int? plcId = dataBaseData.GetNewPlcTaskId();
if(plcId == default || plcId == 0) continue;
StackerPlcTask errTask = StackerPlcTask.DefaultErrTask((int)plcId!, (int)stackerId!, i + 1);
string WriteTaskErrText = stackerOperation.WriteTask(errTask, i + 1);
if(string.IsNullOrEmpty(WriteTaskErrText)) // 写入成功
{
ConsoleLog.Success($"{stackerId} 号堆垛机,入库位置:{i + 1} 条码:{code},写入任务成功,{errTask}");
isWriteTask = true;
}
else
{
ConsoleLog.Warning($"【警告】{stackerId} 号堆垛机,入库位置:{i + 1} 条码:{code},写入任务失败,{errTask},异常信息:{WriteTaskErrText}");
}
continue;
}
var wcsTasks = wcsTaskDao.Select(new AppWcsTask { VehicleNo = code, TaskStatus = (int)WcsTaskStatusEnum.create });
if(wcsTasks == default) // 查询任务失败
{
ConsoleLog.Exception($"【警告】{stackerId} 号堆垛机,入库位置:{i + 1} 条码:{code} 查找任务失败,和数据库服务器连接中断");
continue;
}
if(wcsTasks.Count < 1) // 没有任务
{
/* 检查卸货站台是否允许卸货 */
bool allowSetGoods = conveyOperation.AllowSetVehicle(stackerId.ToString());
if (!allowSetGoods) continue; // 出库站台不允许取货
/* 生成一个直接卸货出去的任务 */
ConsoleLog.Warning($"【警告】{stackerId} 号堆垛机,入库位置:{i + 1} 条码:{code} 没有找到对应任务");
int? plcId = dataBaseData.GetNewPlcTaskId();
if (plcId == default || plcId == 0) continue;
StackerPlcTask errTask = StackerPlcTask.DefaultErrTask((int)plcId!, (int)stackerId!, i + 1, code.ToPlcVehicleNo());
string WriteTaskErrText = stackerOperation.WriteTask(errTask, i + 1);
if (string.IsNullOrEmpty(WriteTaskErrText)) // 写入成功
{
ConsoleLog.Success($"{stackerId} 号堆垛机,入库位置:{i + 1} 条码:{code},写入任务成功,{errTask}");
isWriteTask = true;
}
else
{
ConsoleLog.Warning($"【警告】{stackerId} 号堆垛机,入库位置:{i + 1} 条码:{code},写入任务失败,{errTask},异常信息:{WriteTaskErrText}");
}
continue;
}
var wcsTask = wcsTasks[0]; // 找出第一个任务
/* 校验终点是否正确 */
var destinationLocationInfo = CommonData.AppLocations.DetailWithWcsLocation(wcsTask.Destination);
if(destinationLocationInfo == default) // 任务终点错误,理论上此处不应该出现异常
{
/* 检查卸货站台是否允许卸货 */
bool allowSetGoods = conveyOperation.AllowSetVehicle(stackerId.ToString());
if (!allowSetGoods) continue; // 出库站台不允许取货
/* 生成一个直接卸货出去的任务 */
ConsoleLog.Warning($"【警告】{stackerId} 号堆垛机,入库位置:{i + 1} 条码:{code} 无法识别的入库库位");
int? plcId = dataBaseData.GetNewPlcTaskId();
if (plcId == default || plcId == 0) continue;
StackerPlcTask errTask = StackerPlcTask.DefaultErrTask((int)plcId!, (int)stackerId!, i + 1, code.ToPlcVehicleNo());
string WriteTaskErrText = stackerOperation.WriteTask(errTask, i + 1);
if (string.IsNullOrEmpty(WriteTaskErrText)) // 写入成功
{
ConsoleLog.Success($"{stackerId} 号堆垛机,入库位置:{i + 1} 条码:{code},写入任务成功,{errTask}");
wcsTaskEvent.ErrTaskEvent(wcsTask, "入库库位不正确");
isWriteTask = true;
}
else
{
ConsoleLog.Warning($"【警告】{stackerId} 号堆垛机,入库位置:{i + 1} 条码:{code},写入任务失败,{errTask},异常信息:{WriteTaskErrText}");
}
continue;
}
/* 判断冲突货位是否有任务 */
var runningWcsTasks = wcsTaskDao.QueryTaskWithWcsLocation(destinationLocationInfo.InterveneLocation);
if (runningWcsTasks == default) continue; // 查询失败
if(runningWcsTasks.Count > 0) continue; // 存在冲突点位,等待
/* 下发任务 */
StackerPlcTask stackerTask = wcsTask.ToStackerInTask((int)stackerId!, i + 1, destinationLocationInfo);
string WriteStackerTaskErrText = stackerOperation.WriteTask(stackerTask, i + 1);
if (string.IsNullOrEmpty(WriteStackerTaskErrText)) // 写入成功
{
ConsoleLog.Success($"{stackerId} 号堆垛机,入库位置:{i + 1} 条码:{code},写入任务成功,{stackerTask}");
wcsTaskEvent.StartTaskEvent(wcsTask); // 任务开始
isWriteTask = true;
}
else
{
ConsoleLog.Warning($"【警告】{stackerId} 号堆垛机,入库位置:{i + 1} 条码:{code},写入任务失败,{stackerTask},异常信息:{WriteStackerTaskErrText}");
}
}
if (isWriteTask)
{
string confirmResult = stackerOperation.WriteTaskConfirm(stackerId); // 写入任务确认
ConsoleLog.Info($"堆垛机:{stackerId} 入库任务写任务确认;信息:{(string.IsNullOrEmpty(confirmResult) ? "" : confirmResult)}");
Thread.Sleep(1000);
}
return isWriteTask;
}
/// <summary>
/// 执行堆垛机出库任务,若执行了任务则返回 true
/// </summary>
/// <param name="stackerId"></param>
/// <returns></returns>
public bool ExecuteOutTask(int? stackerId)
{
if (stackerId == default) return false;
/* 检查出库站台是否可以卸货 */
bool allowSetGoods = conveyOperation.AllowSetVehicle(stackerId.ToString());
if (!allowSetGoods) return false; // 出库站台不允许取货
var wcsTasks = wcsTaskDao.SelectOutTaskWithStacker((int)stackerId!);
if (wcsTasks == default)
{
ConsoleLog.Exception(string.Format("【异常】{0} 号堆垛机出库任务查询失败,与数据库连接异常", stackerId));
Thread.Sleep(5000);
return false;
}
if (wcsTasks.Count == 0) return false;
bool isWriteTask = false; // 指示是否写入任务
int writeTaskCount = 0; // 表示执行了多少条任务
for (int i = 0; i < wcsTasks.Count; i++)
{
if (writeTaskCount >= 2) break; // 最多执行两条
/* 校验货叉开启 */
string forkStatus = CommonData.AppStackers.First(f => f.StackerId == stackerId).ForkStatus ?? "";
if (forkStatus.Length <= i || forkStatus[i] != '1')
{
writeTaskCount ++;
continue; // 获取数据失败或者货叉未开启
}
var wcsTask = wcsTasks[i];
/* 校验起点是否正确 */
var originLocationInfo = CommonData.AppLocations.DetailWithWcsLocation(wcsTask.Origin);
if (originLocationInfo == default) // 任务起点错误,理论上此处不应该出现异常
{
ConsoleLog.Warning($"【警告】{stackerId} 号堆垛机,出库库位:{wcsTask.Origin} 条码:{wcsTask.VehicleNo} 无法识别的出库库位");
wcsTaskEvent.ErrTaskEvent(wcsTask, "出库的库位不正确");
continue;
}
/* 判断冲突货位是否有任务 */
var runningWcsTasks = wcsTaskDao.QueryTaskWithWcsLocation(originLocationInfo.InterveneLocation);
if (runningWcsTasks == default) continue; // 查询失败
if (runningWcsTasks.Count > 0) continue; // 存在冲突点位,等待
/* 下发任务 */
StackerPlcTask stackerTask = wcsTask.ToStackerOutTask((int)stackerId!, i + 1, originLocationInfo);
string WriteStackerTaskErrText = stackerOperation.WriteTask(stackerTask, i + 1);
if (string.IsNullOrEmpty(WriteStackerTaskErrText)) // 写入成功
{
ConsoleLog.Success($"{stackerId} 号堆垛机,出库位置:{i + 1} 条码:{wcsTask.VehicleNo},写入任务成功,{stackerTask}");
wcsTaskEvent.StartTaskEvent(wcsTask); // 任务开始
writeTaskCount++;
isWriteTask = true;
}
else
{
ConsoleLog.Warning($"【警告】{stackerId} 号堆垛机,出库位置:{i + 1} 条码:{wcsTask.VehicleNo},写入任务失败,{stackerTask},异常信息:{WriteStackerTaskErrText}");
}
}
if (isWriteTask)
{
string confirmResult = stackerOperation.WriteTaskConfirm(stackerId); // 写入任务确认
ConsoleLog.Info($"堆垛机:{stackerId}出库任务写任务确认;信息:{(string.IsNullOrEmpty(confirmResult) ? "" : confirmResult)}");
Thread.Sleep(1000);
}
return isWriteTask;
}
/// <summary>
/// 执行堆垛机拣选任务,若执行了任务则返回 true
/// </summary>
/// <param name="stackerId"></param>
/// <returns></returns>
public bool ExecutePickTask(int? stackerId)
{
if (stackerId == default) return false;
var wcsTasks = wcsTaskDao.SelectPickOutTaskWithStacker((int)stackerId!);
if (wcsTasks == default)
{
ConsoleLog.Error($"【异常】{stackerId} 号堆垛机拣选任务查询失败,与数据库连接异常");
Thread.Sleep(5000);
return false;
}
if (wcsTasks.Count == 0) return false;
var wcsTask = wcsTasks[0]; // 取第一条任务
/* 校验出库站台是否可以卸货 */
// TODO
/* 检验并返回起点终点信息 */
var originLocationInfo = CommonData.AppLocations.DetailWithWcsLocation(wcsTask.Origin);
var destinationLocationInfo = CommonData.AppLocations.DetailWithWcsLocation(wcsTask.Destination);
if (destinationLocationInfo == default || originLocationInfo == default) // 起点终点错误,直接标记错误
{
// 已经在接口内做了检查,按道理此处不会出错。直接返回异常,任务直接取消
ConsoleLog.Warning($"【警告】任务号:{wcsTask.TaskId}Plc任务号{wcsTask.PlcId} 无法执行,起点或者终点存在异常");
wcsTaskEvent.ErrTaskEvent(wcsTask, $"起点或者终点存在异常");
return false;
}
StackerPlcTask stackerTask = new()
{
StackerId = stackerId,
PlcId = wcsTask.PlcId,
TaskType = Convert.ToInt16(wcsTask.TaskType),
GetStand = 0,
InTunnelId = Convert.ToInt16(stackerId),
OutTunnelId = Convert.ToInt16(stackerId),
SetStand = 0,
GetQueue = Convert.ToInt16(originLocationInfo.Queue),
GetLine = Convert.ToInt16(originLocationInfo.Line),
GetLayer = Convert.ToInt16(originLocationInfo.Layer),
GetDeep = Convert.ToInt16(originLocationInfo.Depth),
SetQueue = Convert.ToInt16(destinationLocationInfo.Queue),
SetLine = Convert.ToInt16(destinationLocationInfo.Line),
SetLayer = Convert.ToInt16(destinationLocationInfo.Layer),
SetDeep = Convert.ToInt16(destinationLocationInfo.Depth),
Size = Convert.ToInt16(wcsTask.VehicleSize),
Weight = Convert.ToInt16(wcsTask.Weight),
Code = wcsTask.PlcVehicleNo ?? 0,
};
var writeStackerTaskErrText = stackerOperation.WriteTask(stackerTask);
if (string.IsNullOrEmpty(writeStackerTaskErrText))
{
ConsoleLog.Success($"堆垛机:{stackerId} 写入拣选任务成功,箱号:{wcsTask.VehicleNo}PlcId{wcsTask.PlcId}{wcsTask.Origin} => {wcsTask.Destination}");
wcsTaskEvent.StartTaskEvent(wcsTask);
return true;
}
else
{
ConsoleLog.Warning($"【警告】堆垛机:{stackerId} 写入拣选任务失败,箱号:{wcsTask.VehicleNo}PlcId{wcsTask.PlcId}{wcsTask.Origin} => {wcsTask.Destination},异常信息:{writeStackerTaskErrText}");
wcsTaskEvent.ErrTaskEvent(wcsTask, $"写入任务失败,异常信息:{writeStackerTaskErrText}");
}
return false;
}
/// <summary>
/// 执行堆垛机移库任务,若执行了任务则返回 true
/// </summary>
/// <param name="stackerId"></param>
/// <returns></returns>
public bool ExecuteMoveTask(int? stackerId)
{
if (stackerId == default) return false;
var wcsTasks = wcsTaskDao.SelectMoveTaskWithStacker((int)stackerId!);
if (wcsTasks == default)
{
ConsoleLog.Error($"【异常】{stackerId} 号堆垛机移库任务查询失败,与数据库连接异常");
Thread.Sleep(5000);
return false;
}
if (wcsTasks.Count == 0) return false;
bool isWriteTask = false; // 指示是否写入任务
int writeTaskCount = 0; // 表示执行了多少条任务
for (int i = 0; i < wcsTasks.Count; i++)
{
if (writeTaskCount >= 2) break; // 最多执行两条
/* 校验货叉开启 */
string forkStatus = CommonData.AppStackers.First(f => f.StackerId == stackerId).ForkStatus ?? "";
if (forkStatus.Length <= i || forkStatus[i] != '1')
{
writeTaskCount++;
continue; // 获取数据失败或者货叉未开启
}
var wcsTask = wcsTasks[i];
/* 校验起点是否正确 */
var originLocationInfo = CommonData.AppLocations.DetailWithWcsLocation(wcsTask.Origin);
var destinationLocationInfo = CommonData.AppLocations.DetailWithWcsLocation(wcsTask.Origin);
if (originLocationInfo == default || destinationLocationInfo == default) // 任务起点终点错误,理论上此处不应该出现异常
{
ConsoleLog.Warning($"【警告】{stackerId} 号堆垛机,移库库位:{wcsTask.Origin} 条码:{wcsTask.VehicleNo} 无法识别的库位");
wcsTaskEvent.ErrTaskEvent(wcsTask, "移库的库位不正确");
continue;
}
/* 判断冲突货位是否有任务,起点终点都要判断 */
var runningWcsTasks = wcsTaskDao.QueryTaskWithWcsLocation(destinationLocationInfo.InterveneLocation, originLocationInfo.InterveneLocation);
if (runningWcsTasks == default) continue; // 查询失败
if (runningWcsTasks.Count > 0) continue; // 存在冲突点位,等待
/* 下发任务 */
StackerPlcTask stackerTask = wcsTask.ToStackerMoveTask((int)stackerId!, originLocationInfo, destinationLocationInfo);
string WriteStackerTaskErrText = stackerOperation.WriteTask(stackerTask, i + 1);
if (string.IsNullOrEmpty(WriteStackerTaskErrText)) // 写入成功
{
ConsoleLog.Success($"{stackerId} 号堆垛机,移库位置:{i + 1} 条码:{wcsTask.VehicleNo},写入任务成功,{stackerTask}");
wcsTaskEvent.StartTaskEvent(wcsTask); // 任务开始
writeTaskCount++;
isWriteTask = true;
}
else
{
ConsoleLog.Warning($"【警告】{stackerId} 号堆垛机,移库位置:{i + 1} 条码:{wcsTask.VehicleNo},写入任务失败,{stackerTask},异常信息:{WriteStackerTaskErrText}");
}
}
if (isWriteTask)
{
string confirmResult = stackerOperation.WriteTaskConfirm(stackerId); // 写入任务确认
ConsoleLog.Info($"堆垛机:{stackerId}移库任务写任务确认;信息:{(string.IsNullOrEmpty(confirmResult) ? "" : confirmResult)}");
Thread.Sleep(1000);
}
return isWriteTask;
}
/// <summary>
/// 执行重复入库新任务若执行了返回true
/// </summary>
/// <param name="stackerId"></param>
/// <param name="plcId"></param>
/// <param name="forkId">货叉编号</param>
/// <returns></returns>
public bool ExecuteDoubleInTask(int? stackerId, int plcId, int forkId)
{
if (stackerId == default || plcId == 0) return false;
/* 查找这个PlcId对应的wms任务 */
List<AppWcsTask>? doubleInTasks = wcsTaskDao.Select(new AppWcsTask { PlcId = plcId });
if (doubleInTasks == default)
{
ConsoleLog.Error($"【异常】{stackerId} 号堆垛机重复入库任务检验失败,与数据库连接异常");
Thread.Sleep(5000);
return false;
}
if (doubleInTasks.Count == 0) return false; // 找不到对应的PlcId的任务
var doubleTask = doubleInTasks[0];
/* 判断这个任务是否出现卸货位置有货 */
if(doubleTask.TaskStatus != (int)WcsTaskStatusEnum.doubleIn) { return false; } // 没有重复入库不执行下面方法
/* 查找这个任务的新任务 */
List<AppWcsTask>? newTasks = wcsTaskDao.Select(new AppWcsTask { TaskId = doubleTask.TaskId, TaskType = (int)WcsTaskTypeEnum.newTaskForDoubleIn, TaskStatus = (int)WcsTaskStatusEnum.create });
if (newTasks == default)
{
ConsoleLog.Error($"【异常】{stackerId} 号堆垛机重复入库任务新任务查询失败,与数据库连接异常");
Thread.Sleep(5000);
return false;
}
if (newTasks.Count == 0) return false;
var newTask = newTasks[0];
var destinationLocationInfo = CommonData.AppLocations.DetailWithWcsLocation(newTask.Destination);
if (destinationLocationInfo == default) // 终点错误,直接标记错误
{
// 已经在接口内做了检查,按道理此处不会出错。直接返回异常,任务直接取消
ConsoleLog.Warning($"【警告】任务号:{newTask.TaskId}Plc任务号{newTask.PlcId} 无法执行,新终点存在异常");
wcsTaskEvent.ErrTaskEvent(newTask, $"新终点存在异常");
return false;
}
/* 判断冲突货位是否有任务 */
var runningWcsTasks = wcsTaskDao.QueryTaskWithWcsLocation(destinationLocationInfo.InterveneLocation);
if (runningWcsTasks == default) return false; // 查询失败
if (runningWcsTasks.Count > 0) return false; // 存在冲突点位,等待
/* 下发任务 */
StackerPlcTask stackerTask = newTask.ToStackerInTask((int)stackerId!, forkId, destinationLocationInfo);
var writeStackerTaskErrText = stackerOperation.WriteTask(stackerTask);
if (string.IsNullOrEmpty(writeStackerTaskErrText))
{
ConsoleLog.Success($"堆垛机:{stackerId} 写入重复入库新任务成功,箱号:{newTask.VehicleNo}PlcId{newTask.PlcId};新目的地:{newTask.Destination}");
wcsTaskEvent.StartTaskEvent(newTask);
return true;
}
else
{
ConsoleLog.Warning($"【警告】堆垛机:{stackerId} 写入重复入库新任务失败,箱号:{newTask.VehicleNo}PlcId{newTask.PlcId};新目的地:{newTask.Destination},异常信息:{writeStackerTaskErrText}");
wcsTaskEvent.ErrTaskEvent(newTask, $"写入任务失败,异常信息:{writeStackerTaskErrText}");
}
return false;
}
}