302 lines
12 KiB
C#
302 lines
12 KiB
C#
using JSMachine.WMS.App.Dto;
|
|
using JSMachine.WMS.App.Dto.Enum;
|
|
using JSMachine.WMS.App.IService;
|
|
using JSMachine.WMS.App.ServiceImpl;
|
|
using JSMachine.WMS.Business.Common.IService;
|
|
using JSMachine.WMS.Business.Common.Models;
|
|
using JSMachine.WMS.Business.SSE;
|
|
using JSMachine.WMS.Business.StockIn.IService;
|
|
using JSMachine.WMS.Business.StockIn.ServiceImpl.Strategy;
|
|
using JSMachine.WMS.Infrastructure.Helper;
|
|
using JSMachine.WMS.PLC.ModbusImpl.Elevator.ModbusIO.Read;
|
|
using JSMachine.WMS.PLC.ModbusImpl.Elevator.Model;
|
|
using System.Diagnostics;
|
|
|
|
namespace JSMachine.WMS.Business.Common.ServiceImpl
|
|
{
|
|
/// <summary>
|
|
/// WMS 通用业务服务,协调 ERP 任务、库位和 AGV 任务,
|
|
/// 负责中转区及提升机相关任务的生成。
|
|
/// </summary>
|
|
public class CommonService : ICommonService
|
|
{
|
|
private IERPTaskService _erpTaskService;
|
|
private IStorageRackService _storageRackService;
|
|
private IAGVTaskService _agvTaskService;
|
|
public CommonService(
|
|
IERPTaskService erpTaskService,
|
|
IStorageRackService storageRackService,
|
|
IAGVTaskService agvTaskService)
|
|
{
|
|
_erpTaskService = erpTaskService;
|
|
_storageRackService = storageRackService;
|
|
_agvTaskService = agvTaskService;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 检查指定库位所在列是否存在锁定库位。
|
|
/// 该判断通过查询同列全部库位完成,任一库位被锁定即视为整列锁定。
|
|
/// </summary>
|
|
/// <param name="storageRack">用于确定库位列的库位信息。</param>
|
|
/// <returns>同列存在锁定库位时返回 <see langword="true"/>。</returns>
|
|
public async Task<bool> IsColLock(StorageRackDto storageRack)
|
|
{
|
|
List<StorageRackDto> storageRacksThisCol = await _storageRackService
|
|
.GetListByExpression(p => p.ReservoirAreaColumnId == storageRack.ReservoirAreaColumnId);
|
|
|
|
if (storageRacksThisCol.IsNullOrEmpty())
|
|
return false;
|
|
|
|
if (storageRacksThisCol.Any(p => p.IsLock))
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 跟据erp任务获取已经生成的agv任务列表(不包含已经取消的任务)
|
|
/// </summary>
|
|
/// <param name="materialBatch"></param>
|
|
/// <returns></returns>
|
|
public async Task<List<AGVTaskDto>> GetCreatedAgvTasksFromErpTask(ERPTaskDto erpTask, TaskTypeEnum taskType)
|
|
{
|
|
List<AGVTaskDto> agvTasks = await _agvTaskService
|
|
.GetListByExpression(p => p.ErpTaskId == erpTask.Id &&
|
|
p.TaskType == taskType &&
|
|
p.TaskStatus != TaskStatusEnum.Cancelled &&
|
|
p.TaskStatus != TaskStatusEnum.Failed);
|
|
|
|
agvTasks = agvTasks
|
|
.GroupBy(p => p.BarCode)
|
|
.Select(p => p.First())
|
|
.ToList();
|
|
|
|
return agvTasks;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 生成到中转区域的任务。指定起点,终点为中转区
|
|
/// </summary>
|
|
/// <param name="startPosition"></param>
|
|
/// <returns></returns>
|
|
public async Task<bool> CreateAgvTaskToTransferArea(StorageRackDto startPosition, TaskTypeEnum taskType, ERPTaskDto erpTask)
|
|
{
|
|
StorageRackDto endPosition = await _storageRackService.GetUsableTransferStorageRack();
|
|
|
|
if (endPosition == null)
|
|
{
|
|
LogHelper.Info("中转区域库位已满");
|
|
return false;
|
|
}
|
|
|
|
await CreateAndInsertAgvTask(new AgvTaskCreationParam
|
|
{
|
|
StartPosition = startPosition,
|
|
EndPosition = endPosition,
|
|
ErpTaskId = erpTask.Id,
|
|
TaskType = taskType,
|
|
StockOutWharf = erpTask.Transport,
|
|
ErpUploadStatus = ErpUploadStatusEnum.Unnecessary
|
|
});
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 中转区作业调度 起点为中转区域 终点需计算
|
|
/// </summary>
|
|
/// <param name="startPosition">要调度的中转区物料</param>
|
|
/// <returns></returns>
|
|
public async Task<bool> CreateAgvTaskFromTransferArea(StorageRackDto startPosition, AGVTaskDto lastAgvTaskRelated, ERPTaskDto erpTask)
|
|
{
|
|
// 中转区任务按出库、入库、清理出库阻塞物的顺序生成;任一环节失败即停止后续调度。
|
|
bool bRet = await CreateTransferStockOutAgvTask(startPosition, lastAgvTaskRelated, erpTask);
|
|
if (!bRet)
|
|
return false;
|
|
|
|
bRet = await CreateTransferStockInAgvTask(startPosition, lastAgvTaskRelated, erpTask);
|
|
if (!bRet)
|
|
return false;
|
|
|
|
bRet = await CreateRemoveStockOutObstructionAgvTask(startPosition, lastAgvTaskRelated, erpTask);
|
|
if (!bRet)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
private async Task<bool> CreateTransferStockOutAgvTask(
|
|
StorageRackDto startPosition,
|
|
AGVTaskDto lastAgvTaskRelated,
|
|
ERPTaskDto erpTask)
|
|
{
|
|
if (lastAgvTaskRelated.TaskType != TaskTypeEnum.TransferStockOut)
|
|
return true;
|
|
|
|
StorageRackDto elevator = await GetUsableElevator(FloorEnum.SecondFloor, 2);
|
|
|
|
if (elevator == null)
|
|
{
|
|
LogHelper.Warn($"中转区出库业务 所有提升机出库库位均被WMS或者PLC锁定,erpTask {lastAgvTaskRelated.ErpTaskId} 无法生成AgvTask");
|
|
return false;
|
|
}
|
|
|
|
await CreateAndInsertAgvTask(new AgvTaskCreationParam
|
|
{
|
|
StartPosition = startPosition,
|
|
EndPosition = elevator,
|
|
ErpTaskId = erpTask.Id,
|
|
TaskType = TaskTypeEnum.TransferStockOut,
|
|
StockOutWharf = erpTask.Transport,
|
|
ErpUploadStatus = ErpUploadStatusEnum.Unnecessary
|
|
});
|
|
return true;
|
|
}
|
|
|
|
private async Task<bool> CreateTransferStockInAgvTask(StorageRackDto startPosition, AGVTaskDto lastAgvTaskRelated, ERPTaskDto erpTask)
|
|
{
|
|
if (lastAgvTaskRelated.TaskType != TaskTypeEnum.TransferStockIn)
|
|
return true;
|
|
|
|
IStockInStrategy stockInStrategy = StrategyFactory.CreateStockInStrategy(
|
|
TransportEnum.TransitArea,
|
|
FloorEnum.SecondFloor,
|
|
startPosition.MateriaBatch);
|
|
|
|
StorageRackDto endPosition = await stockInStrategy.CalCulateWarehouse();
|
|
if (endPosition == null)
|
|
return false;
|
|
|
|
await CreateAndInsertAgvTask(new AgvTaskCreationParam
|
|
{
|
|
StartPosition = startPosition,
|
|
EndPosition = endPosition,
|
|
ErpTaskId = erpTask.Id,
|
|
TaskType = lastAgvTaskRelated.TaskType,
|
|
ErpUploadStatus =
|
|
(erpTask.TaskType == TaskTypeEnum.PdaIn || erpTask.TaskType == TaskTypeEnum.TailIn) ?
|
|
ErpUploadStatusEnum.WaittingToUpload :
|
|
ErpUploadStatusEnum.Unnecessary
|
|
});
|
|
return true;
|
|
}
|
|
private async Task<bool> CreateRemoveStockOutObstructionAgvTask(
|
|
StorageRackDto startPosition,
|
|
AGVTaskDto lastAgvTaskRelated,
|
|
ERPTaskDto erpTask)
|
|
{
|
|
if (lastAgvTaskRelated.TaskType != TaskTypeEnum.RemoveStockOutObstruction)
|
|
return true;
|
|
|
|
IStockInStrategy stockInStrategy = StrategyFactory.CreateStockInStrategy(
|
|
TransportEnum.TransitArea,
|
|
FloorEnum.SecondFloor,
|
|
startPosition.MateriaBatch);
|
|
|
|
StorageRackDto endPosition = await stockInStrategy.CalCulateWarehouse();
|
|
|
|
if (endPosition == null)
|
|
return false;
|
|
|
|
await CreateAndInsertAgvTask(new AgvTaskCreationParam
|
|
{
|
|
StartPosition = startPosition,
|
|
EndPosition = endPosition,
|
|
ErpTaskId = erpTask.Id,
|
|
TaskType = lastAgvTaskRelated.TaskType,
|
|
ErpUploadStatus =
|
|
(erpTask.TaskType == TaskTypeEnum.PdaIn || erpTask.TaskType == TaskTypeEnum.TailIn) ?
|
|
ErpUploadStatusEnum.WaittingToUpload :
|
|
ErpUploadStatusEnum.Unnecessary
|
|
});
|
|
|
|
return true;
|
|
}
|
|
/// <summary>
|
|
/// 获取可用提升机库位
|
|
/// </summary>
|
|
/// <param name="floor">楼层</param>
|
|
/// <param name="taskType">任务类型 1-入库 2-出库</param>
|
|
/// <returns></returns>
|
|
public async Task<StorageRackDto> GetUsableElevator(FloorEnum floor, int taskType)
|
|
{
|
|
List<StorageRackDto> elevatorWarehouse = await _storageRackService.GetListByExpression(p =>
|
|
p.Transport == TransportEnum.Elevator &&
|
|
p.Floor == floor &&
|
|
!p.IsLock
|
|
);
|
|
|
|
if (elevatorWarehouse.IsNullOrEmpty())
|
|
{
|
|
return null;
|
|
}
|
|
|
|
List<ElevatorPlcStatus> elevatorPlcStatuses = await ElevatorStatusRead.ReadAllElevatorStatus();
|
|
|
|
StorageRackDto elevator = null;
|
|
foreach (StorageRackDto elvatorWarehouse in elevatorWarehouse)
|
|
{
|
|
int elevatorNo = elvatorWarehouse.StorageRackName.Contains("1号") ? 1 : 2;
|
|
|
|
ElevatorPlcStatus elevatorPlcStatus = elevatorPlcStatuses.First(p => p.ElevatorNo == elevatorNo);
|
|
|
|
//入库
|
|
if (taskType == 1)
|
|
{
|
|
if (elvatorWarehouse.ElevatorChannel == 1001 && elevatorPlcStatus.StockInPutdownChanelTwo ||
|
|
elvatorWarehouse.ElevatorChannel == 1011 && elevatorPlcStatus.StockInPutdownChanelOne)
|
|
{
|
|
elevator = elvatorWarehouse;
|
|
break;
|
|
}
|
|
}
|
|
//出库
|
|
if (taskType == 2)
|
|
{
|
|
if (elvatorWarehouse.ElevatorChannel == 2001 && elevatorPlcStatus.StockOutPutdownChanelTwo ||
|
|
elvatorWarehouse.ElevatorChannel == 2011 && elevatorPlcStatus.StockOutPutdownChanelOne)
|
|
{
|
|
elevator = elvatorWarehouse;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return elevator;
|
|
}
|
|
|
|
public async Task CreateAndInsertAgvTask(AgvTaskCreationParam agvTaskCreationParam)
|
|
{
|
|
AGVTaskDto agvTask = new()
|
|
{
|
|
ErpTaskId = agvTaskCreationParam.ErpTaskId,
|
|
BarCode = agvTaskCreationParam.StartPosition.BarCode,
|
|
OrderNo = agvTaskCreationParam.StartPosition.OrderNo,
|
|
CustomName = agvTaskCreationParam.StartPosition.CustomName,
|
|
MateriaName = agvTaskCreationParam.StartPosition.MateriaName,
|
|
MateriaType = agvTaskCreationParam.StartPosition.MateriaType,
|
|
MateriaNum = agvTaskCreationParam.StartPosition.MateriaNum,
|
|
MateriaBatch = agvTaskCreationParam.StartPosition.MateriaBatch,
|
|
MateriaCode = agvTaskCreationParam.StartPosition.MateriaCode,
|
|
TaskType = agvTaskCreationParam.TaskType,
|
|
TaskStatus = TaskStatusEnum.Initial,
|
|
Priority = agvTaskCreationParam.TaskType == TaskTypeEnum.SaleOut ? PriorityEnum.High : PriorityEnum.Middle,
|
|
Floor = agvTaskCreationParam.StartPosition.Floor,
|
|
|
|
StartPositionCode = agvTaskCreationParam.StartPosition.StorageRackNo,
|
|
EndPositionCode = agvTaskCreationParam.EndPosition.StorageRackNo,
|
|
|
|
Transport = agvTaskCreationParam.StockOutWharf,
|
|
|
|
ErpUploadStatus = agvTaskCreationParam.ErpUploadStatus
|
|
};
|
|
|
|
await _storageRackService.Lock(agvTaskCreationParam.StartPosition);
|
|
await _storageRackService.Lock(agvTaskCreationParam.EndPosition);
|
|
await _agvTaskService.Add(agvTask);
|
|
|
|
//发送广播通知前端网站刷新页面
|
|
SseEngine.BrodCast(agvTaskCreationParam.StartPosition.Floor.ToString());
|
|
}
|
|
}
|
|
}
|