420 lines
18 KiB
C#
420 lines
18 KiB
C#
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
|
|
{
|
|
/// <summary>
|
|
/// RCS 回调业务,将外部 AGV 状态转换为本地任务、库存及报警状态。
|
|
/// </summary>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 给Rcs调用,获取AGV上报的任务状态
|
|
/// </summary>
|
|
/// <param name="callBackWmsParam"></param>
|
|
/// <returns></returns>
|
|
public async Task<RcsApiResult> 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<bool> 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<RcsApiResult> 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回调
|
|
|
|
|
|
/// <summary>
|
|
/// 解锁中区库位并绑定合格证
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
private async Task UnlockAndSetMiddleWarehouse(StorageRackDto storageRack)
|
|
{
|
|
if (storageRack.Transport != TransportEnum.MiddleOutArea)
|
|
return;
|
|
|
|
storageRack.IsLock = false;
|
|
await _storageRackService.EditSingalWithSpecificCols(storageRack, ["IsLock", "BarCode"]);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 更新AgvTask任务状态
|
|
/// </summary>
|
|
/// <param name="agvTask">库位编号</param>
|
|
/// <returns></returns>
|
|
private async Task<bool> 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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 清空起点库位上的物料信息
|
|
/// </summary>
|
|
/// <param name="agvTask"></param>
|
|
/// <returns></returns>
|
|
private async Task<bool> 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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 更新终点库位上的物料信息
|
|
/// </summary>
|
|
/// <param name="agvTask"></param>
|
|
/// <returns></returns>
|
|
private async Task<bool> 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
|
|
}
|
|
}
|