Files
ww-jst/wmsjst/JSMachine.WMS.Business/Common/ServiceImpl/CommonService.cs
T
2026-09-02 16:31:50 +08:00

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());
}
}
}