first commit
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace JSMachine.WMS.Job.Enum
|
||||
{
|
||||
/// <summary>
|
||||
/// 作业组(不同的系统应使用不同的作业组)
|
||||
/// </summary>
|
||||
public enum JobGroup
|
||||
{
|
||||
/// <summary>
|
||||
/// 进纸系统作业组
|
||||
/// </summary>
|
||||
PaperFeedGroup,
|
||||
/// <summary>
|
||||
/// 备纸系统作业组
|
||||
/// </summary>
|
||||
PaperPreparationGroup,
|
||||
/// <summary>
|
||||
/// 退纸系统作业组
|
||||
/// </summary>
|
||||
PaperReturnGroup,
|
||||
/// <summary>
|
||||
/// 原纸入库系统作业组
|
||||
/// </summary>
|
||||
PaperStorageGroup
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace JSMachine.WMS.Job.Enum
|
||||
{
|
||||
/// <summary>
|
||||
/// 作业调度类型
|
||||
/// </summary>
|
||||
public enum ScheduleType
|
||||
{
|
||||
/// <summary>
|
||||
/// 简单模式
|
||||
/// </summary>
|
||||
Simple,
|
||||
/// <summary>
|
||||
/// cron表达式
|
||||
/// </summary>
|
||||
Corn,
|
||||
/// <summary>
|
||||
/// 日历
|
||||
/// </summary>
|
||||
Calendar,
|
||||
/// <summary>
|
||||
/// XML配置文件
|
||||
/// </summary>
|
||||
XMLConfig,
|
||||
/// <summary>
|
||||
/// JSON配置文件
|
||||
/// </summary>
|
||||
JsonConfig,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<Platforms>AnyCPU;x64</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Event\**" />
|
||||
<EmbeddedResource Remove="Event\**" />
|
||||
<None Remove="Event\**" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Prism.Core" Version="8.1.97" />
|
||||
<PackageReference Include="Quartz" Version="3.3.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\JSMachine.WMS.Business\JSMachine.WMS.Business.csproj" />
|
||||
<ProjectReference Include="..\JSMachine.WMS.Common\JSMachine.WMS.Common.csproj" />
|
||||
<ProjectReference Include="..\JSMachine.WMS.Netty\JSMachine.WMS.Netty.csproj" />
|
||||
<ProjectReference Include="..\JSMachine.WMS.PLC\JSMachine.WMS.PLC.csproj" />
|
||||
<ProjectReference Include="..\JSMachine.WMS.RPC\JSMachine.WMS.RPC.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,88 @@
|
||||
using JSMachine.WMS.App.Dto;
|
||||
using JSMachine.WMS.App.Dto.Enum;
|
||||
using JSMachine.WMS.App.IService;
|
||||
using JSMachine.WMS.Infrastructure;
|
||||
using JSMachine.WMS.Infrastructure.Helper;
|
||||
using JSMachine.WMS.Job.Enum;
|
||||
using JSMachine.WMS.Job.JobAttributes;
|
||||
using JSMachine.WMS.RPC.ErpRPC.Dto.Out;
|
||||
using JSMachine.WMS.RPC.RcsRPC.Dto.In;
|
||||
using JSMachine.WMS.RPC.RcsRPC.IService;
|
||||
using Quartz;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace JSMachine.WMS.Job.Job
|
||||
{
|
||||
[DisallowConcurrentExecution]
|
||||
[PersistJobDataAfterExecution]
|
||||
[Job(Name = nameof(AgvTaskJob)
|
||||
, Group = nameof(AgvTaskJob) + "_Group"
|
||||
, Description = "Agv任务作业"
|
||||
, ScheduleType = ScheduleType.Simple
|
||||
, IntervalMilliSeconds = 1000
|
||||
, RepeatCount = 0
|
||||
, StartTimeStr = null)]
|
||||
/// <summary>
|
||||
/// 周期扫描待执行的 AGV 任务,并向 RCS 下发任务。
|
||||
/// 通过禁止并发执行,避免同一作业周期内重复领取待执行任务。
|
||||
/// </summary>
|
||||
public class AgvTaskJob : IJob
|
||||
{
|
||||
private static readonly IAGVTaskService AgvTaskService = GlobalServericeProvidor.GetService<IAGVTaskService>();
|
||||
private static readonly IRcsService IRcsService = GlobalServericeProvidor.GetService<IRcsService>();
|
||||
private static readonly IStorageRackService StorageRackService = GlobalServericeProvidor.GetService<IStorageRackService>();
|
||||
|
||||
/// <summary>
|
||||
/// 获取未锁定的初始任务,成功下发后更新任务状态;RCS 失败时保留初始状态,
|
||||
/// 由下一次调度继续尝试。
|
||||
/// </summary>
|
||||
/// <param name="context">Quartz 作业执行上下文。</param>
|
||||
public async Task Execute(IJobExecutionContext context)
|
||||
{
|
||||
AGVTaskDto agvTask = await AgvTaskService.GetSingalByExpression(p =>
|
||||
(p.TaskStatus == TaskStatusEnum.Initial) &&
|
||||
!p.IsLock);
|
||||
|
||||
if (agvTask == null)
|
||||
return;
|
||||
|
||||
StorageRackDto startWareHouse = await StorageRackService.GetByStorageRackNo(agvTask.StartPositionCode);
|
||||
|
||||
CreateTaskParam createTaskParam = new()
|
||||
{
|
||||
//从提升机出口取货和搬运要使用不同的模板
|
||||
modelProcessCode = startWareHouse.Transport == TransportEnum.Elevator ? "RK" : "cattleCarry4",
|
||||
orderId = agvTask.Id.ToString(),
|
||||
taskOrderDetail = new TaskOrderDetailDto
|
||||
{
|
||||
taskPath = $"{agvTask.StartPositionCode},{agvTask.EndPositionCode}"
|
||||
}
|
||||
};
|
||||
|
||||
// 只有 RCS 返回成功后才推进本地状态,防止本地记录与外部执行状态不一致。
|
||||
ApiReturnResult<bool> apiRet = await IRcsService.CreateTask(createTaskParam);
|
||||
if (apiRet.ResultCode == "200")
|
||||
{
|
||||
LogHelper.Info($"向Rcs下发Agv任务 {agvTask.Id} 成功,起点 {agvTask.StartPositionCode} 终点 {agvTask.EndPositionCode}");
|
||||
|
||||
agvTask.TaskStatus = TaskStatusEnum.InExecution;
|
||||
|
||||
bool bRet = await AgvTaskService.EditSingal(agvTask);
|
||||
if (!bRet)
|
||||
{
|
||||
LogHelper.Error($"更新AgvTask {agvTask.Id} 状态失败,稍后将重试一次");
|
||||
|
||||
await AgvTaskService.EditSingal(agvTask);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Error($"向Rcs下发Agv任务 {agvTask.Id} 失败,起点 {agvTask.StartPositionCode} 终点 {agvTask.EndPositionCode},原因 {apiRet.ErrorMsg}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
using JSMachine.WMS.App.IService;
|
||||
using JSMachine.WMS.Application.IService;
|
||||
using JSMachine.WMS.Infrastructure;
|
||||
using JSMachine.WMS.Job.Enum;
|
||||
using JSMachine.WMS.Job.JobAttributes;
|
||||
using Quartz;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace JSMachine.WMS.Job.Job
|
||||
{
|
||||
[DisallowConcurrentExecution]
|
||||
[PersistJobDataAfterExecution]
|
||||
[Job(Name = nameof(DataCleanJob)
|
||||
, Group = nameof(DataCleanJob) + "_Group"
|
||||
, Description = "过期数据清理任务"
|
||||
, ScheduleType = ScheduleType.Simple
|
||||
, IntervalMilliSeconds = 1000 * 3600 * 24
|
||||
, RepeatCount = 0
|
||||
, StartTimeStr = null)]
|
||||
/// <summary>
|
||||
/// 定期清理过期 ERP、AGV、操作日志、提升机计数和日志文件,避免历史数据无限增长。
|
||||
/// </summary>
|
||||
public class DataCleanJob : IJob
|
||||
{
|
||||
private static readonly IERPTaskService ERPTaskService = GlobalServericeProvidor.GetService<IERPTaskService>();
|
||||
private static readonly IAGVTaskService AgvTaskService = GlobalServericeProvidor.GetService<IAGVTaskService>();
|
||||
private static readonly IOperationLogService OperationLogService = GlobalServericeProvidor.GetService<IOperationLogService>();
|
||||
private static readonly IElevatorCountService ElevatorCountService = GlobalServericeProvidor.GetService<IElevatorCountService>();
|
||||
|
||||
|
||||
/// <summary>执行过期业务数据和日志文件清理。</summary>
|
||||
/// <param name="context">Quartz 作业上下文。</param>
|
||||
public async Task Execute(IJobExecutionContext context)
|
||||
{
|
||||
await ERPTaskService.DeleByExpression(p => p.CreationTime < DateTime.Now.AddMonths(-12));
|
||||
await AgvTaskService.DeleByExpression(p => p.CreationTime < DateTime.Now.AddMonths(-12));
|
||||
await OperationLogService.DeleByExpression(p => p.CreationTime < DateTime.Now.AddMonths(-12));
|
||||
await ElevatorCountService.DeleByExpression(p=> p.CreationTime < DateTime.Now.AddDays(-10));
|
||||
|
||||
DirectoryInfo dir = new(Path.Combine($"{AppDomain.CurrentDomain.BaseDirectory}", "logs"));
|
||||
if (dir.Exists)
|
||||
{
|
||||
FileSystemInfo[] fileInfos = dir.GetFileSystemInfos();
|
||||
foreach (var fileInfo in fileInfos)
|
||||
{
|
||||
if (fileInfo.CreationTime <= DateTime.Now.AddMonths(-12))
|
||||
fileInfo.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
using JSMachine.WMS.App.Dto;
|
||||
using JSMachine.WMS.App.Dto.Enum;
|
||||
using JSMachine.WMS.App.IService;
|
||||
using JSMachine.WMS.App.ServiceImpl;
|
||||
using JSMachine.WMS.Common.Cache;
|
||||
using JSMachine.WMS.Domain.Entity;
|
||||
using JSMachine.WMS.Infrastructure;
|
||||
using JSMachine.WMS.Infrastructure.Helper;
|
||||
using JSMachine.WMS.Job.Enum;
|
||||
using JSMachine.WMS.Job.JobAttributes;
|
||||
using JSMachine.WMS.PLC.ModbusImpl.Elevator.ModbusIO.Read;
|
||||
using JSMachine.WMS.PLC.ModbusImpl.Elevator.Model;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Newtonsoft.Json;
|
||||
using NLog;
|
||||
using Quartz;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Transactions;
|
||||
|
||||
namespace JSMachine.WMS.Job.Job
|
||||
{
|
||||
[DisallowConcurrentExecution]
|
||||
[PersistJobDataAfterExecution]
|
||||
[Job(Name = nameof(ElevatorJob)
|
||||
, Group = nameof(ElevatorJob) + "_Group"
|
||||
, Description = "提升机监控作业"
|
||||
, ScheduleType = ScheduleType.Simple
|
||||
, IntervalMilliSeconds = 500
|
||||
, RepeatCount = 0
|
||||
, StartTimeStr = null)]
|
||||
/// <summary>
|
||||
/// 周期读取提升机 PLC 状态,依据边沿信号处理取货、队列和计数业务。
|
||||
/// </summary>
|
||||
public class ElevatorJob : IJob
|
||||
{
|
||||
private static readonly IElevatorPlcQueueService ElevatorPlcQueueService = GlobalServericeProvidor.GetService<IElevatorPlcQueueService>();
|
||||
private static readonly IAGVTaskService AGVTaskService = GlobalServericeProvidor.GetService<IAGVTaskService>();
|
||||
private static readonly IStorageRackService StorageRackService = GlobalServericeProvidor.GetService<IStorageRackService>();
|
||||
private static readonly IElevatorCountService ElevatorCountService = GlobalServericeProvidor.GetService<IElevatorCountService>();
|
||||
|
||||
/// <summary>
|
||||
/// 1号提升机1号取货通道前一个允许取货状态
|
||||
/// </summary>
|
||||
private static bool PreElevatorOneChannelOneAllowPickUp = false;
|
||||
/// <summary>
|
||||
/// 1号提升机2号取货通道前一个允许取货状态
|
||||
/// </summary>
|
||||
private static bool PreElevatorOneChannelTwAollowPickUp = false;
|
||||
/// <summary>
|
||||
/// 2号提升机1号取货通道前一个允许取货状态
|
||||
/// </summary>
|
||||
private static bool PreElevatorTwoChannelOneAllowPickUp = false;
|
||||
/// <summary>
|
||||
/// 2号提升机2号取货通道前一个允许取货状态
|
||||
/// </summary>
|
||||
private static bool PreElevatorTwoChannelTwoAllowPickUp = false;
|
||||
|
||||
/// <summary>
|
||||
/// 执行一次提升机状态轮询,并处理新产生的取货信号。
|
||||
/// </summary>
|
||||
/// <param name="context">Quartz 作业上下文。</param>
|
||||
public async Task Execute(IJobExecutionContext context)
|
||||
{
|
||||
List<ElevatorPlcStatus> elevatorPlcStatuses = await ElevatorStatusRead.ReadAllElevatorStatus();
|
||||
|
||||
if (elevatorPlcStatuses.IsNullOrEmpty())
|
||||
{
|
||||
LogHelper.Warn($"入库:读取提升机PLC信号失败");
|
||||
return;
|
||||
}
|
||||
|
||||
ElevatorPlcStatus elevatorStatusOne = elevatorPlcStatuses.First(p => p.ElevatorNo == 1);
|
||||
ElevatorPlcStatus elevatorStatusTwo = elevatorPlcStatuses.First(p => p.ElevatorNo == 2);
|
||||
|
||||
if (!PreElevatorOneChannelOneAllowPickUp && elevatorStatusOne.StockInPickupChannelOne)
|
||||
{
|
||||
LogHelper.Warn("入库:1号提升机通道2014可以取货");
|
||||
|
||||
_ = ElevatorCountService.IncrementCount(1, 2014);
|
||||
|
||||
List<ElevatorPlcQueueDto> elevatorQueue = await ElevatorPlcQueueService
|
||||
.GetListByExpression(p =>
|
||||
p.ElevatorNo == 1 && p.ElevatorChannel == 1011,
|
||||
nameof(ElevatorPlcQueueDto.CreationTime),
|
||||
SqlSugar.OrderByType.Asc);
|
||||
if (!elevatorQueue.IsNullOrEmpty())
|
||||
{
|
||||
ElevatorPlcQueueDto destQueue = elevatorQueue.First();
|
||||
|
||||
await HandlePickup(destQueue);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Warn($"入库:1号提升机通道2014可以取货,但是PLC队列没有信息");
|
||||
}
|
||||
|
||||
PreElevatorOneChannelOneAllowPickUp = elevatorStatusOne.StockInPickupChannelOne;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
PreElevatorOneChannelOneAllowPickUp = elevatorStatusOne.StockInPickupChannelOne;
|
||||
}
|
||||
|
||||
if (!PreElevatorOneChannelTwAollowPickUp && elevatorStatusOne.StockInPickupChannelTwo)
|
||||
{
|
||||
LogHelper.Warn("入库:1号提升机通道2004可以取货");
|
||||
|
||||
_ = ElevatorCountService.IncrementCount(1, 2004);
|
||||
|
||||
List<ElevatorPlcQueueDto> elevatorQueue = await ElevatorPlcQueueService
|
||||
.GetListByExpression(p =>
|
||||
p.ElevatorNo == 1 && p.ElevatorChannel == 1001,
|
||||
nameof(ElevatorPlcQueueDto.CreationTime),
|
||||
SqlSugar.OrderByType.Asc);
|
||||
if (!elevatorQueue.IsNullOrEmpty())
|
||||
{
|
||||
ElevatorPlcQueueDto destQueue = elevatorQueue.First();
|
||||
|
||||
await HandlePickup(destQueue);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Warn($"入库:1号提升机通道2004可以取货,但是PLC队列没有信息");
|
||||
}
|
||||
|
||||
PreElevatorOneChannelTwAollowPickUp = elevatorStatusOne.StockInPickupChannelTwo;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
PreElevatorOneChannelTwAollowPickUp = elevatorStatusOne.StockInPickupChannelTwo;
|
||||
}
|
||||
|
||||
if (!PreElevatorTwoChannelOneAllowPickUp && elevatorStatusTwo.StockInPickupChannelOne)
|
||||
{
|
||||
LogHelper.Warn("入库:2号提升机通道2014可以取货");
|
||||
|
||||
_ = ElevatorCountService.IncrementCount(2, 2014);
|
||||
|
||||
List<ElevatorPlcQueueDto> elevatorQueue = await ElevatorPlcQueueService
|
||||
.GetListByExpression(p =>
|
||||
p.ElevatorNo == 2 && p.ElevatorChannel == 1011,
|
||||
nameof(ElevatorPlcQueueDto.CreationTime),
|
||||
SqlSugar.OrderByType.Asc);
|
||||
if (!elevatorQueue.IsNullOrEmpty())
|
||||
{
|
||||
ElevatorPlcQueueDto destQueue = elevatorQueue.First();
|
||||
|
||||
await HandlePickup(destQueue);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Warn($"入库:2号提升机通道2014可以取货,但是PLC队列没有信息");
|
||||
}
|
||||
|
||||
PreElevatorTwoChannelOneAllowPickUp = elevatorStatusTwo.StockInPickupChannelOne;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
PreElevatorTwoChannelOneAllowPickUp = elevatorStatusTwo.StockInPickupChannelOne;
|
||||
}
|
||||
|
||||
if (!PreElevatorTwoChannelTwoAllowPickUp && elevatorStatusTwo.StockInPickupChannelTwo)
|
||||
{
|
||||
LogHelper.Warn("入库:2号提升机通道2004可以取货");
|
||||
|
||||
_ = ElevatorCountService.IncrementCount(2, 2004);
|
||||
|
||||
List<ElevatorPlcQueueDto> elevatorQueue = await ElevatorPlcQueueService
|
||||
.GetListByExpression(p =>
|
||||
p.ElevatorNo == 2 && p.ElevatorChannel == 1001,
|
||||
nameof(ElevatorPlcQueueDto.CreationTime),
|
||||
SqlSugar.OrderByType.Asc);
|
||||
if (!elevatorQueue.IsNullOrEmpty())
|
||||
{
|
||||
ElevatorPlcQueueDto destQueue = elevatorQueue.First();
|
||||
|
||||
await HandlePickup(destQueue);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Warn($"入库:2号提升机通道2004可以取货,但是PLC队列没有信息");
|
||||
}
|
||||
|
||||
PreElevatorTwoChannelTwoAllowPickUp = elevatorStatusTwo.StockInPickupChannelTwo;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
PreElevatorTwoChannelTwoAllowPickUp = elevatorStatusTwo.StockInPickupChannelTwo;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task HandlePickup(ElevatorPlcQueueDto elevatorQue)
|
||||
{
|
||||
AGVTaskDto agvTask = await AGVTaskService.GetSingalByExpression(p => p.Id == elevatorQue.AgvTaskId);
|
||||
if (agvTask == null)
|
||||
{
|
||||
LogHelper.Error($"从PLC队列中获取的 AgvTask {elevatorQue.AgvTaskId} 不存在");
|
||||
return;
|
||||
}
|
||||
|
||||
StorageRackDto startWarehouseSecondFloor = await StorageRackService
|
||||
.GetElevatorWareHouse(elevatorQue.ElevatorNo, elevatorQue.ElevatorChannel == 1001 ? 2004 : 2014);
|
||||
|
||||
StockInSecondFloorCache.StockInSecondFloorQue.Enqueue(new AllowPickUpInfo
|
||||
{
|
||||
AgvTask = agvTask,
|
||||
ElevatorPlcQueue = elevatorQue,
|
||||
StartWarehouseSecondFloor = startWarehouseSecondFloor
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
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.ServiceImpl;
|
||||
using JSMachine.WMS.Business.StockOut.IService;
|
||||
using JSMachine.WMS.Common.Cache;
|
||||
using JSMachine.WMS.Domain.Entity;
|
||||
using JSMachine.WMS.Infrastructure;
|
||||
using JSMachine.WMS.Infrastructure.Helper;
|
||||
using JSMachine.WMS.Job.Enum;
|
||||
using JSMachine.WMS.Job.JobAttributes;
|
||||
using JSMachine.WMS.PLC.ModbusImpl.Elevator.ModbusIO.Read;
|
||||
using JSMachine.WMS.PLC.ModbusImpl.Elevator.Model;
|
||||
using Newtonsoft.Json;
|
||||
using Quartz;
|
||||
|
||||
namespace JSMachine.WMS.Job.Job
|
||||
{
|
||||
[DisallowConcurrentExecution]
|
||||
[PersistJobDataAfterExecution]
|
||||
[Job(Name = nameof(ElevatorOutJob)
|
||||
, Group = nameof(ElevatorOutJob) + "_Group"
|
||||
, Description = "提升机监控作业"
|
||||
, ScheduleType = ScheduleType.Simple
|
||||
, IntervalMilliSeconds = 500
|
||||
, RepeatCount = 0
|
||||
, StartTimeStr = null)]
|
||||
public class ElevatorOutJob : IJob
|
||||
{
|
||||
private static readonly IElevatorPlcQueueService ElevatorPlcQueueService = GlobalServericeProvidor.GetService<IElevatorPlcQueueService>();
|
||||
private static readonly ICommonService CommonService = GlobalServericeProvidor.GetService<ICommonService>();
|
||||
private static readonly IERPTaskService ERPTaskService = GlobalServericeProvidor.GetService<IERPTaskService>();
|
||||
private static readonly IAGVTaskService AGVTaskService = GlobalServericeProvidor.GetService<IAGVTaskService>();
|
||||
private static readonly IStorageRackService StorageRackService = GlobalServericeProvidor.GetService<IStorageRackService>();
|
||||
private static readonly IERPTaskService ErpTaskService = GlobalServericeProvidor.GetService<IERPTaskService>();
|
||||
private static readonly IStockOutService StockOutService= GlobalServericeProvidor.GetService<IStockOutService>();
|
||||
private static readonly IElevatorCountService ElevatorCountService = GlobalServericeProvidor.GetService<IElevatorCountService>();
|
||||
|
||||
/// <summary>
|
||||
/// 1号提升机1号取货通道前一个允许取货状态
|
||||
/// </summary>
|
||||
private static bool PreElevatorOneChannelOneAllowPickUp = false;
|
||||
/// <summary>
|
||||
/// 1号提升机2号取货通道前一个允许取货状态
|
||||
/// </summary>
|
||||
private static bool PreElevatorOneChannelTwAollowPickUp = false;
|
||||
/// <summary>
|
||||
/// 2号提升机1号取货通道前一个允许取货状态
|
||||
/// </summary>
|
||||
private static bool PreElevatorTwoChannelOneAllowPickUp = false;
|
||||
/// <summary>
|
||||
/// 2号提升机2号取货通道前一个允许取货状态
|
||||
/// </summary>
|
||||
private static bool PreElevatorTwoChannelTwoAllowPickUp = false;
|
||||
|
||||
public async Task Execute(IJobExecutionContext context)
|
||||
{
|
||||
List<ElevatorPlcStatus> elevatorPlcStatuses = await ElevatorStatusRead.ReadAllElevatorStatus();
|
||||
|
||||
if (elevatorPlcStatuses.IsNullOrEmpty())
|
||||
{
|
||||
LogHelper.Warn($"出库:读取提升机PLC信号失败");
|
||||
return;
|
||||
}
|
||||
|
||||
ElevatorPlcStatus elevatorStatusOne = elevatorPlcStatuses.First(p => p.ElevatorNo == 1);
|
||||
ElevatorPlcStatus elevatorStatusTwo = elevatorPlcStatuses.First(p => p.ElevatorNo == 2);
|
||||
|
||||
if (!PreElevatorOneChannelOneAllowPickUp && elevatorStatusOne.StockOutPickupChanelOne)
|
||||
{
|
||||
LogHelper.Info($"出库:1号提升机1016出库通道可以取货");
|
||||
|
||||
_ = ElevatorCountService.IncrementCount(1, 1016);
|
||||
|
||||
List<ElevatorPlcQueueDto> elevatorQueue = await ElevatorPlcQueueService
|
||||
.GetListByExpression(p =>
|
||||
p.ElevatorNo == 1 && p.ElevatorChannel == 2011,
|
||||
nameof(ElevatorPlcQueueDto.CreationTime),
|
||||
SqlSugar.OrderByType.Asc);
|
||||
if (!elevatorQueue.IsNullOrEmpty())
|
||||
{
|
||||
ElevatorPlcQueueDto destQueue = elevatorQueue.First();
|
||||
|
||||
await HandlePickup(destQueue);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Warn($"出库:1号提升机1016出库通道可以取货,但是PLC队列没有信息");
|
||||
}
|
||||
|
||||
PreElevatorOneChannelOneAllowPickUp = elevatorStatusOne.StockOutPickupChanelOne;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
PreElevatorOneChannelOneAllowPickUp = elevatorStatusOne.StockOutPickupChanelOne;
|
||||
}
|
||||
|
||||
if (!PreElevatorOneChannelTwAollowPickUp && elevatorStatusOne.StockOutPickupChanelTwo)
|
||||
{
|
||||
LogHelper.Info($"出库:1号提升机1006号出库通道可以取货");
|
||||
|
||||
_ = ElevatorCountService.IncrementCount(1, 1006);
|
||||
|
||||
List<ElevatorPlcQueueDto> elevatorQueue = await ElevatorPlcQueueService
|
||||
.GetListByExpression(p =>
|
||||
p.ElevatorNo == 1 && p.ElevatorChannel == 2001,
|
||||
nameof(ElevatorPlcQueueDto.CreationTime),
|
||||
SqlSugar.OrderByType.Asc);
|
||||
if (!elevatorQueue.IsNullOrEmpty())
|
||||
{
|
||||
ElevatorPlcQueueDto destQueue = elevatorQueue.First();
|
||||
|
||||
await HandlePickup(destQueue);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Warn($"出库:一号提升机1006号出库通道可以取货,但是PLC队列没有信息");
|
||||
}
|
||||
|
||||
PreElevatorOneChannelTwAollowPickUp = elevatorStatusOne.StockOutPickupChanelTwo;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
PreElevatorOneChannelTwAollowPickUp = elevatorStatusOne.StockOutPickupChanelTwo;
|
||||
}
|
||||
|
||||
if (!PreElevatorTwoChannelOneAllowPickUp && elevatorStatusTwo.StockOutPickupChanelOne)
|
||||
{
|
||||
LogHelper.Info($"出库:2号提升机1016出库通道可以取货");
|
||||
|
||||
_ = ElevatorCountService.IncrementCount(2, 1016);
|
||||
|
||||
List<ElevatorPlcQueueDto> elevatorQueue = await ElevatorPlcQueueService
|
||||
.GetListByExpression(p =>
|
||||
p.ElevatorNo == 2 && p.ElevatorChannel == 2011,
|
||||
nameof(ElevatorPlcQueueDto.CreationTime),
|
||||
SqlSugar.OrderByType.Asc);
|
||||
if (!elevatorQueue.IsNullOrEmpty())
|
||||
{
|
||||
ElevatorPlcQueueDto destQueue = elevatorQueue.First();
|
||||
|
||||
await HandlePickup(destQueue);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Warn($"出库:二号提升机1016出库通道可以取货,但是PLC队列没有信息");
|
||||
}
|
||||
|
||||
PreElevatorTwoChannelOneAllowPickUp = elevatorStatusTwo.StockOutPickupChanelOne;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
PreElevatorTwoChannelOneAllowPickUp = elevatorStatusTwo.StockOutPickupChanelOne;
|
||||
}
|
||||
|
||||
if (!PreElevatorTwoChannelTwoAllowPickUp && elevatorStatusTwo.StockOutPickupChanelTwo)
|
||||
{
|
||||
LogHelper.Info($"出库:二号提升机1006出库通道可以取货");
|
||||
|
||||
_ = ElevatorCountService.IncrementCount(2, 1006);
|
||||
|
||||
List<ElevatorPlcQueueDto> elevatorQueue = await ElevatorPlcQueueService
|
||||
.GetListByExpression(p =>
|
||||
p.ElevatorNo == 2 && p.ElevatorChannel == 2001,
|
||||
nameof(ElevatorPlcQueueDto.CreationTime),
|
||||
SqlSugar.OrderByType.Asc);
|
||||
if (!elevatorQueue.IsNullOrEmpty())
|
||||
{
|
||||
ElevatorPlcQueueDto destQueue = elevatorQueue.First();
|
||||
|
||||
await HandlePickup(destQueue);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogHelper.Warn($"出库:二号提升机1006出库通道可以取货,但是PLC队列没有信息");
|
||||
}
|
||||
|
||||
PreElevatorTwoChannelTwoAllowPickUp = elevatorStatusTwo.StockOutPickupChanelTwo;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
PreElevatorTwoChannelTwoAllowPickUp = elevatorStatusTwo.StockOutPickupChanelTwo;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 收到取货完成信号
|
||||
/// 根据二楼的提升机队列,生成一楼的AgvTask
|
||||
/// 生成一楼的agvTask
|
||||
/// </summary>
|
||||
/// <param name="elevatorQue"></param>
|
||||
/// <returns></returns>
|
||||
private async Task HandlePickup(ElevatorPlcQueueDto elevatorQue)
|
||||
{
|
||||
AGVTaskDto agvTaskSecondFloor = await AGVTaskService.GetSingalByExpression(p => p.Id == elevatorQue.AgvTaskId);
|
||||
if (agvTaskSecondFloor == null)
|
||||
{
|
||||
LogHelper.Error($"AgvTask {elevatorQue.AgvTaskId} 不存在");
|
||||
return;
|
||||
}
|
||||
|
||||
//获取起点 提升机库位信息
|
||||
StorageRackDto startWarehouseFirstFloor = await StorageRackService.GetElevatorWareHouse(
|
||||
elevatorQue.ElevatorNo, elevatorQue.ElevatorChannel == 2001 ? 1006 : 1016);
|
||||
|
||||
//计算终点出库码头
|
||||
StorageRackDto destWarehouseFirstFloor = await StockOutService.CalculateDestWarehouse_SaleOut(agvTaskSecondFloor.Transport);
|
||||
if (destWarehouseFirstFloor == null)
|
||||
{
|
||||
LogHelper.Warn($"一楼没有可用的库位,AgvTask {agvTaskSecondFloor.Id} 对应的一楼任务无法生成");
|
||||
|
||||
_ = ErpTaskService.UpdateTaskMsg(agvTaskSecondFloor.ErpTaskId, "一楼库位不足,请确保码头无货后在pda上点击清空码头按钮");
|
||||
return;
|
||||
}
|
||||
|
||||
ERPTaskDto erpTask = await ERPTaskService.GetSingalByExpression(p => p.Id == agvTaskSecondFloor.ErpTaskId);
|
||||
if (erpTask == null)
|
||||
{
|
||||
LogHelper.Error($"出库关联的ERP任务 {agvTaskSecondFloor.ErpTaskId} 不存在");
|
||||
return;
|
||||
}
|
||||
|
||||
startWarehouseFirstFloor.BingdingMaterial(new StorageRackDto.MateriaInfo
|
||||
{
|
||||
BarCode = agvTaskSecondFloor.BarCode,
|
||||
MateriaBatch = agvTaskSecondFloor.MateriaBatch,
|
||||
MateriaName = agvTaskSecondFloor.MateriaName,
|
||||
MateriaType = agvTaskSecondFloor.MateriaType,
|
||||
MateriaCode = agvTaskSecondFloor.MateriaCode,
|
||||
MateriaNum = agvTaskSecondFloor.MateriaNum.ToString(),
|
||||
OrderNo = agvTaskSecondFloor.OrderNo
|
||||
});
|
||||
|
||||
|
||||
await CommonService.CreateAndInsertAgvTask(new Business.Common.Models.AgvTaskCreationParam
|
||||
{
|
||||
StartPosition = startWarehouseFirstFloor,
|
||||
EndPosition = destWarehouseFirstFloor,
|
||||
ErpTaskId = erpTask.Id,
|
||||
StockOutWharf = erpTask.Transport,
|
||||
TaskType = erpTask.TaskType
|
||||
});
|
||||
|
||||
bool bRetTwo = await ElevatorPlcQueueService.DeleteById(elevatorQue.Id);
|
||||
bool bRetThree = await StorageRackService.Lock(destWarehouseFirstFloor);
|
||||
|
||||
LogHelper.Info($"出库任务已生成,提升机队列被删除,队列原始信息 {JsonConvert.SerializeObject(elevatorQue)}");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
using JSMachine.WMS.App.Dto;
|
||||
using JSMachine.WMS.App.Dto.Enum;
|
||||
using JSMachine.WMS.App.IService;
|
||||
using JSMachine.WMS.Business.StockIn.IService;
|
||||
using JSMachine.WMS.Business.StockOut.IService;
|
||||
using JSMachine.WMS.Domain.Entity;
|
||||
using JSMachine.WMS.Infrastructure;
|
||||
using JSMachine.WMS.Job.Enum;
|
||||
using JSMachine.WMS.Job.JobAttributes;
|
||||
using Quartz;
|
||||
using SqlSugar;
|
||||
|
||||
namespace JSMachine.WMS.Job.Job
|
||||
{
|
||||
[DisallowConcurrentExecution]
|
||||
[PersistJobDataAfterExecution]
|
||||
[Job(Name = nameof(ErpTaskJob)
|
||||
, Group = nameof(ErpTaskJob) + "_Group"
|
||||
, Description = "Erp任务作业"
|
||||
, ScheduleType = ScheduleType.Simple
|
||||
, IntervalMilliSeconds = 2000
|
||||
, RepeatCount = 0
|
||||
, StartTimeStr = null)]
|
||||
public class ErpTaskJob : IJob
|
||||
{
|
||||
private static readonly IERPTaskService ERPTaskService = GlobalServericeProvidor.GetService<IERPTaskService>();
|
||||
private static readonly IStockInService IStockInService = GlobalServericeProvidor.GetService<IStockInService>();
|
||||
private static readonly IStockOutService IStockOutService = GlobalServericeProvidor.GetService<IStockOutService>();
|
||||
private static readonly IAGVTaskService AGVTaskService = GlobalServericeProvidor.GetService<IAGVTaskService>();
|
||||
private static readonly IStorageRackService StorageRackService = GlobalServericeProvidor.GetService<IStorageRackService>();
|
||||
|
||||
public async Task Execute(IJobExecutionContext context)
|
||||
{
|
||||
//1.读取状态为初始化的erptask
|
||||
//2.任务类型为入库
|
||||
//2.1 计算目标库位
|
||||
//2.2 目标库位为1楼,直接生成AgvTask(起点为入库提交的库位,终点为目标库位)
|
||||
//2.3 目标库位为2楼,生成两个Agv任务:TaskOne(起点为入库提交的库位,终点一楼提升机入口) TaskTwo(起点为二楼提升机出口,终点为目标库位)
|
||||
//3.任务类型为出库
|
||||
//3.1 物料在1楼,直接生成AgvTask(起点为物料所在的库位,终点为出货码头)
|
||||
//3.2 物料在2楼,生成两个Agv任务:TaskOne(起点为物料所在的库位,终点为二楼提升机入口) TaskTwo(起点到一楼提升机出口,终点为出货码头)
|
||||
|
||||
ERPTaskDto erpTaskStockIn = await ERPTaskService
|
||||
.GetSingalByExpression(p =>
|
||||
p.CreationTime > DateTime.Now.AddDays(-1) &&
|
||||
p.TaskStatus == TaskStatusEnum.Initial &&
|
||||
(p.TaskType == TaskTypeEnum.PdaIn || p.TaskType == TaskTypeEnum.TailIn),
|
||||
p => p.CreationTime,
|
||||
OrderByType.Asc);
|
||||
|
||||
List<ERPTaskDto> erpTaskStockOuts = await ERPTaskService
|
||||
.GetListByExpression(p =>
|
||||
p.CreationTime > DateTime.Now.AddDays(-1) &&
|
||||
(p.TaskStatus == TaskStatusEnum.Initial || p.TaskStatus == TaskStatusEnum.InExecution) &&
|
||||
(p.TaskType == TaskTypeEnum.SaleOut || p.TaskType == TaskTypeEnum.ProductionOut)
|
||||
);
|
||||
|
||||
if (!erpTaskStockOuts.IsNullOrEmpty())
|
||||
{
|
||||
foreach (var erpTaskStockOut in erpTaskStockOuts)
|
||||
{
|
||||
await CreateAgvTask_SaleOut(erpTaskStockOut);
|
||||
|
||||
Thread.Sleep(2000);
|
||||
}
|
||||
}
|
||||
|
||||
if (erpTaskStockIn != null)
|
||||
{
|
||||
await CreateAgvTask_StockIn(erpTaskStockIn);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CreateAgvTask_StockIn(ERPTaskDto erpTask)
|
||||
{
|
||||
int taskNum = await AGVTaskService.Count(p =>
|
||||
p.CreationTime >= DateTime.Now.Date &&
|
||||
p.Floor == FloorEnum.FirstFloor &&
|
||||
(p.TaskStatus == TaskStatusEnum.InExecution) &&
|
||||
p.TaskType == TaskTypeEnum.PdaIn);
|
||||
|
||||
//一楼只有4个agv小车,因此当待完成的任务已经有4个以上的时候不再生成新的任务
|
||||
if (taskNum >= 4)
|
||||
{
|
||||
await ERPTaskService.UpdateTaskMsg(erpTask.Id, "当前所有小车都有任务,等待空余车辆");
|
||||
return;
|
||||
}
|
||||
|
||||
bool bRet = await IStockInService.CreateAgvTaskFirstFloor(erpTask);
|
||||
if (bRet)
|
||||
{
|
||||
erpTask.TaskStatus = TaskStatusEnum.InExecution;
|
||||
erpTask.TaskMsg = "开始生成子任务";
|
||||
erpTask.LastModifiedTime = DateTime.Now;
|
||||
await ERPTaskService.EditSingalWithSpecificCols(erpTask, ["TaskStatus", "TaskMsg", "LastModifiedTime"]);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 销售出库,生成agvTask
|
||||
/// </summary>
|
||||
/// <param name="erpTask"></param>
|
||||
/// <returns></returns>
|
||||
public async Task CreateAgvTask_SaleOut(ERPTaskDto erpTask)
|
||||
{
|
||||
//查询ErpTask关联的所有agvTask(二楼),
|
||||
//agvTask出库总数量,是否大于等于erpTask出库数量
|
||||
//是 ErpTask状态完成
|
||||
//否 生成一个agvTask
|
||||
|
||||
var sumNum = 0; //已生成的数量
|
||||
//不论agv任务什么状态,除了取消的任务,其余的都应该扣减,否则会导致少扣减,实际多出库(就算任务执行失败,后续通过PDA报警,人工处理也为成功状态)
|
||||
List<AGVTaskDto> agvTaskList = await AGVTaskService.GetListByExpression(p =>
|
||||
p.CreationTime >= DateTime.Now.AddDays(-1) &&
|
||||
p.ErpTaskId == erpTask.Id &&
|
||||
p.TaskType == erpTask.TaskType &&
|
||||
p.TaskStatus != TaskStatusEnum.Cancelled);
|
||||
|
||||
if (!agvTaskList.IsNullOrEmpty())
|
||||
{
|
||||
var groupAgvTaskList = agvTaskList.GroupBy(p => p.BarCode);
|
||||
foreach (var groupAgvTask in groupAgvTaskList)
|
||||
{
|
||||
sumNum += groupAgvTask.FirstOrDefault().MateriaNum;
|
||||
}
|
||||
}
|
||||
|
||||
//需求数量<=已生成数量 ErpTask状态改为结束
|
||||
if (
|
||||
((erpTask.ErpOrderNum - erpTask.ErpCancelNum) <= sumNum) ||
|
||||
((erpTask.ErpOrderNum - erpTask.ErpCancelNum) == erpTask.AlreadyUploadNum)
|
||||
)
|
||||
{
|
||||
erpTask.TaskStatus = TaskStatusEnum.Completed;
|
||||
await ERPTaskService.UpdateTaskStatus(erpTask);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool result = await IStockOutService.CreateAgvTaskSecondFloor_SaleOut(erpTask);
|
||||
if (result)
|
||||
{
|
||||
erpTask.TaskStatus = TaskStatusEnum.InExecution;
|
||||
await ERPTaskService.UpdateTaskStatus(erpTask);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
using JSMachine.WMS.App.Dto.Enum;
|
||||
using JSMachine.WMS.App.Dto;
|
||||
using JSMachine.WMS.Common.Cache;
|
||||
using JSMachine.WMS.Job.Enum;
|
||||
using JSMachine.WMS.Job.JobAttributes;
|
||||
using JSMachine.WMS.RPC.RcsRPC.Dto;
|
||||
using JSMachine.WMS.RPC.RcsRPC.Dto.In;
|
||||
using Quartz;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using JSMachine.WMS.Infrastructure.Helper;
|
||||
using JSMachine.WMS.App.IService;
|
||||
using JSMachine.WMS.Infrastructure;
|
||||
using JSMachine.WMS.Business.RcsCallBack.IService;
|
||||
|
||||
namespace JSMachine.WMS.Job.Job
|
||||
{
|
||||
[DisallowConcurrentExecution]
|
||||
[PersistJobDataAfterExecution]
|
||||
[Job(Name = nameof(RcsCallbackJob)
|
||||
, Group = nameof(RcsCallbackJob) + "_Group"
|
||||
, Description = "rcs回调作业"
|
||||
, ScheduleType = ScheduleType.Simple
|
||||
, IntervalMilliSeconds = 1000
|
||||
, RepeatCount = 0
|
||||
, StartTimeStr = null)]
|
||||
public class RcsCallbackJob : IJob
|
||||
{
|
||||
private static readonly IAGVTaskService AgvTaskService = GlobalServericeProvidor.GetService<IAGVTaskService>();
|
||||
private static readonly IRcsCallBackService RcsCallBackService = GlobalServericeProvidor.GetService<IRcsCallBackService>();
|
||||
|
||||
public async Task Execute(IJobExecutionContext context)
|
||||
{
|
||||
if (RcsCallbackCache.RcsCallbackQueue.TryDequeue(out AgvExcutionInfo agvExcutionInfo))
|
||||
{
|
||||
AGVTaskDto agvTask = await AgvTaskService.GetSingalByExpression(p => p.Id == new Guid(agvExcutionInfo.OrderId));
|
||||
if (agvTask == null)
|
||||
{
|
||||
LogHelper.Warn($"agv上报的任务 {agvExcutionInfo.OrderId} 不存在");
|
||||
return;
|
||||
}
|
||||
|
||||
string msg = $"agv上报的任务 ({agvExcutionInfo.OrderId}) 状态已经处理,属于重复上传,不再动作";
|
||||
if (agvExcutionInfo.Status == 7 && agvTask.TaskStatus == TaskStatusEnum.Failed)
|
||||
{
|
||||
LogHelper.Info(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (agvExcutionInfo.Status == 3 && agvTask.TaskStatus == TaskStatusEnum.Cancelled)
|
||||
{
|
||||
LogHelper.Info(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (agvExcutionInfo.Status == 21 && agvTask.TaskStatus == TaskStatusEnum.PickupCompleted)
|
||||
{
|
||||
LogHelper.Info(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (agvExcutionInfo.Status == 23 && agvTask.TaskStatus == TaskStatusEnum.Completed)
|
||||
{
|
||||
LogHelper.Info(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
await RcsCallBackService.DealwithExcutionStatus(agvExcutionInfo, agvTask);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
using JSMachine.WMS.App.Dto;
|
||||
using JSMachine.WMS.App.Dto.Enum;
|
||||
using JSMachine.WMS.App.IService;
|
||||
using JSMachine.WMS.Business.Common.IService;
|
||||
using JSMachine.WMS.Business.Common.Models;
|
||||
using JSMachine.WMS.Business.StockIn.IService;
|
||||
using JSMachine.WMS.Business.StockIn.ServiceImpl.Strategy;
|
||||
using JSMachine.WMS.Common.Cache;
|
||||
using JSMachine.WMS.Infrastructure;
|
||||
using JSMachine.WMS.Infrastructure.Helper;
|
||||
using JSMachine.WMS.Job.Enum;
|
||||
using JSMachine.WMS.Job.JobAttributes;
|
||||
using Newtonsoft.Json;
|
||||
using Quartz;
|
||||
|
||||
namespace JSMachine.WMS.Job.Job
|
||||
{
|
||||
[DisallowConcurrentExecution]
|
||||
[PersistJobDataAfterExecution]
|
||||
[Job(Name = nameof(StockInSecondFloorJob)
|
||||
, Group = nameof(StockInSecondFloorJob) + "_Group"
|
||||
, Description = "入库二楼任务生成作业"
|
||||
, ScheduleType = ScheduleType.Simple
|
||||
, IntervalMilliSeconds = 2000
|
||||
, RepeatCount = 0
|
||||
, StartTimeStr = null)]
|
||||
public class StockInSecondFloorJob : IJob
|
||||
{
|
||||
private static readonly ICommonService CommonService = GlobalServericeProvidor.GetService<ICommonService>();
|
||||
private static readonly IAGVTaskService AgvTaskService = GlobalServericeProvidor.GetService<IAGVTaskService>();
|
||||
private static readonly IStorageRackService StorageRackService = GlobalServericeProvidor.GetService<IStorageRackService>();
|
||||
private static readonly IERPTaskService ErpTaskService = GlobalServericeProvidor.GetService<IERPTaskService>();
|
||||
private static readonly IElevatorPlcQueueService ElevatorPlcQueueService = GlobalServericeProvidor.GetService<IElevatorPlcQueueService>();
|
||||
|
||||
public async Task Execute(IJobExecutionContext context)
|
||||
{
|
||||
if (StockInSecondFloorCache.StockInSecondFloorQue.TryDequeue(out AllowPickUpInfo allowPickUpInfo))
|
||||
{
|
||||
//二楼提升机出口可以取货,生成二楼agv任务
|
||||
IStockInStrategy stockInStrategy = StrategyFactory.CreateStockInStrategy(
|
||||
TransportEnum.Elevator,
|
||||
FloorEnum.SecondFloor,
|
||||
allowPickUpInfo.AgvTask.MateriaBatch);
|
||||
|
||||
StorageRackDto destWarehouseSecondFloor = await stockInStrategy.CalCulateWarehouse();
|
||||
if (destWarehouseSecondFloor == null)
|
||||
{
|
||||
LogHelper.Warn($"二楼暂无可用的库位,AgvTask {allowPickUpInfo.AgvTask.Id} 对应的二楼任务暂无法生成");
|
||||
//队列再写回去,没有库位的时候队列再写回去,此时整理出空余库位后任务会继续生成(可考虑给pda弹窗报警)
|
||||
StockInSecondFloorCache.StockInSecondFloorQue.Enqueue(allowPickUpInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
ERPTaskDto erpTask = await ErpTaskService.GetSingalByExpression(p => p.Id == allowPickUpInfo.AgvTask.ErpTaskId);
|
||||
|
||||
allowPickUpInfo.StartWarehouseSecondFloor.BingdingMaterial(new App.Dto.StorageRackDto.MateriaInfo
|
||||
{
|
||||
BarCode = allowPickUpInfo.AgvTask.BarCode,
|
||||
MateriaBatch = allowPickUpInfo.AgvTask.MateriaBatch,
|
||||
MateriaName = allowPickUpInfo.AgvTask.MateriaName,
|
||||
MateriaType = allowPickUpInfo.AgvTask.MateriaType,
|
||||
MateriaCode = allowPickUpInfo.AgvTask.MateriaCode,
|
||||
MateriaNum = allowPickUpInfo.AgvTask.MateriaNum.ToString(),
|
||||
OrderNo = allowPickUpInfo.AgvTask.OrderNo
|
||||
});
|
||||
|
||||
await CommonService.CreateAndInsertAgvTask(new AgvTaskCreationParam()
|
||||
{
|
||||
StartPosition = allowPickUpInfo.StartWarehouseSecondFloor,
|
||||
EndPosition = destWarehouseSecondFloor,
|
||||
ErpTaskId = erpTask.Id,
|
||||
TaskType = destWarehouseSecondFloor.Transport == TransportEnum.NormalArea ? erpTask.TaskType : TaskTypeEnum.TransferStockIn,
|
||||
ErpUploadStatus = (erpTask.TaskType == TaskTypeEnum.TailIn || destWarehouseSecondFloor.Transport != TransportEnum.NormalArea) ?
|
||||
ErpUploadStatusEnum.Unnecessary : ErpUploadStatusEnum.WaittingToUpload
|
||||
});
|
||||
|
||||
await ElevatorPlcQueueService.DeleteById(allowPickUpInfo.ElevatorPlcQueue.Id);
|
||||
LogHelper.Info($"入库任务已生成,提升机队列被删除,队列原始信息 {JsonConvert.SerializeObject(allowPickUpInfo.ElevatorPlcQueue)}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
using JSMachine.WMS.App.Dto;
|
||||
using JSMachine.WMS.App.Dto.Enum;
|
||||
using JSMachine.WMS.App.IService;
|
||||
using JSMachine.WMS.Business.Common.IService;
|
||||
using JSMachine.WMS.Infrastructure;
|
||||
using JSMachine.WMS.Infrastructure.Helper;
|
||||
using JSMachine.WMS.Job.Enum;
|
||||
using JSMachine.WMS.Job.JobAttributes;
|
||||
using Quartz;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace JSMachine.WMS.Job.Job
|
||||
{
|
||||
/// <summary>
|
||||
/// 中转区域调度作业
|
||||
/// </summary>
|
||||
[DisallowConcurrentExecution]
|
||||
[PersistJobDataAfterExecution]
|
||||
[Job(Name = nameof(TransferAreaJob)
|
||||
, Group = nameof(TransferAreaJob) + "_Group"
|
||||
, Description = "中转区域作业调度"
|
||||
, ScheduleType = ScheduleType.Simple
|
||||
, IntervalMilliSeconds = 2000
|
||||
, RepeatCount = 0
|
||||
, StartTimeStr = null)]
|
||||
public class TransferAreaJob : IJob
|
||||
{
|
||||
private static readonly IERPTaskService ERPTaskService = GlobalServericeProvidor.GetService<IERPTaskService>();
|
||||
private static readonly IAGVTaskService AgvTaskService = GlobalServericeProvidor.GetService<IAGVTaskService>();
|
||||
private static readonly ICommonService CommonService = GlobalServericeProvidor.GetService<ICommonService>();
|
||||
|
||||
private static readonly IStorageRackService StorageRackService = GlobalServericeProvidor.GetService<IStorageRackService>();
|
||||
|
||||
public async Task Execute(IJobExecutionContext context)
|
||||
{
|
||||
//1.查询关联的erp任务类型
|
||||
//2.如果是出库,且任务批次和当前物料批次一致(这种情况是出库没有可用的提升机库位,从而暂时运到中转区),则该任务需要去往提升机出库
|
||||
//3.除了2以外的所有情况,均搬运到存储区
|
||||
|
||||
StorageRackDto storageRack = await StorageRackService.GetSingalByExpression(p =>
|
||||
p.Transport == TransportEnum.TransitArea &&
|
||||
!p.IsLock &&
|
||||
!p.IsDisabled &&
|
||||
!string.IsNullOrEmpty(p.BarCode));
|
||||
|
||||
if (storageRack == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AGVTaskDto lastAgvTaskRelated = await AgvTaskService.GetSingalByExpression(
|
||||
p => p.EndPositionCode == storageRack.StorageRackNo,
|
||||
p => p.CreationTime,
|
||||
SqlSugar.OrderByType.Desc
|
||||
);
|
||||
|
||||
if (lastAgvTaskRelated==null)
|
||||
{
|
||||
LogHelper.Error($"中转区业务 未查询到物料 {storageRack.BarCode} 上一次agv任务,无法调度该物料,需要手动处理");
|
||||
return;
|
||||
}
|
||||
|
||||
ERPTaskDto erpTask = await ERPTaskService.GetSingalByExpression(p => p.Id == lastAgvTaskRelated.ErpTaskId);
|
||||
if(erpTask==null)
|
||||
{
|
||||
LogHelper.Error($"中转区业务 未查询到物料 {storageRack.BarCode} 关联的erp任务,无法调度该物料,需要手动处理");
|
||||
return;
|
||||
}
|
||||
|
||||
bool bRet = await CommonService.CreateAgvTaskFromTransferArea(storageRack, lastAgvTaskRelated, erpTask);
|
||||
if(!bRet)
|
||||
{
|
||||
_ = ERPTaskService.UpdateTaskMsg(erpTask.Id, "中转区作业调度中,存储区已满或者无可用提升机库位,调度失败");
|
||||
|
||||
LogHelper.Error("中转区作业调度中,存储区已满或者无可用提升机库位,调度失败");
|
||||
}
|
||||
else
|
||||
{
|
||||
_ = ERPTaskService.UpdateTaskMsg(erpTask.Id, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,344 @@
|
||||
using JSMachine.WMS.App.Dto;
|
||||
using JSMachine.WMS.App.Dto.Enum;
|
||||
using JSMachine.WMS.App.IService;
|
||||
using JSMachine.WMS.Common;
|
||||
using JSMachine.WMS.Infrastructure;
|
||||
using JSMachine.WMS.Infrastructure.Helper;
|
||||
using JSMachine.WMS.Job.Enum;
|
||||
using JSMachine.WMS.Job.JobAttributes;
|
||||
using JSMachine.WMS.RPC.ErpRPC.Dto.In;
|
||||
using JSMachine.WMS.RPC.ErpRPC.Dto.In.XRBusinessResult;
|
||||
using JSMachine.WMS.RPC.ErpRPC.Dto.Out.XRBusinessResult;
|
||||
using JSMachine.WMS.RPC.ErpRPC.IService;
|
||||
using Quartz;
|
||||
using SqlSugar;
|
||||
|
||||
|
||||
namespace JSMachine.WMS.Job.Job
|
||||
{
|
||||
[DisallowConcurrentExecution]
|
||||
[PersistJobDataAfterExecution]
|
||||
[Job(Name = nameof(XinRongErpJob)
|
||||
, Group = nameof(XinRongErpJob) + "_Group"
|
||||
, Description = "新荣Erp数据上传作业"
|
||||
, ScheduleType = ScheduleType.Simple
|
||||
, IntervalMilliSeconds = 2000
|
||||
, RepeatCount = 0
|
||||
, StartTimeStr = null)]
|
||||
public class XinRongErpJob : IJob
|
||||
{
|
||||
private static readonly IERPTaskService ErpTaskService = GlobalServericeProvidor.GetService<IERPTaskService>();
|
||||
private static readonly IAGVTaskService AGVTaskService = GlobalServericeProvidor.GetService<IAGVTaskService>();
|
||||
private static readonly IPaperStorageService ErpService = GlobalServericeProvidor.GetService<IPaperStorageService>();
|
||||
protected static readonly int erpUploadBefore = Global.AppSettings.ErpConfig.ErpUploadBefore;
|
||||
protected static readonly int retryNum = Global.AppSettings.ErpConfig.RetryNum;
|
||||
|
||||
public async Task Execute(IJobExecutionContext context)
|
||||
{
|
||||
List<AGVTaskDto> agvTaskList = await AGVTaskService.GetListByExpression(p =>
|
||||
p.CreationTime >= DateTime.Now.AddDays(erpUploadBefore) &&
|
||||
(p.TaskType == TaskTypeEnum.PdaIn || p.TaskType == TaskTypeEnum.TransferStockIn || p.TaskType == TaskTypeEnum.SaleOut || p.TaskType == TaskTypeEnum.ProductionOut) &&
|
||||
(p.ErpUploadStatus == ErpUploadStatusEnum.WaittingToUpload || p.ErpUploadStatus == ErpUploadStatusEnum.UploadFailed) &&
|
||||
p.TaskStatus == TaskStatusEnum.Completed &&
|
||||
p.RetryNum < retryNum);
|
||||
|
||||
if (agvTaskList.Count <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
agvTaskList = agvTaskList.OrderBy(p => p.CreationTime).ToList();
|
||||
|
||||
foreach (AGVTaskDto agvTask in agvTaskList)
|
||||
{
|
||||
ERPTaskDto erpTask = await ErpTaskService.GetSingalByExpression(p => p.Id == agvTask.ErpTaskId);
|
||||
if (erpTask == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
//已上传给Erp的数量
|
||||
var alreadyUploadNum = erpTask.AlreadyUploadNum;
|
||||
|
||||
switch (agvTask.TaskType)
|
||||
{
|
||||
case TaskTypeEnum.MachineHandIn:
|
||||
break;
|
||||
|
||||
case TaskTypeEnum.PdaIn:
|
||||
await UploadDataIn(agvTask, erpTask);
|
||||
break;
|
||||
|
||||
case TaskTypeEnum.TransferStockIn:
|
||||
await UploadDataIn(agvTask, erpTask);
|
||||
break;
|
||||
|
||||
case TaskTypeEnum.SaleOut:
|
||||
|
||||
await UploadDataSaleOut(agvTask, erpTask, alreadyUploadNum);
|
||||
break;
|
||||
|
||||
case TaskTypeEnum.ProductionOut:
|
||||
|
||||
await UploadDataProductionOut(agvTask, erpTask, alreadyUploadNum);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生产退库数据上传
|
||||
/// </summary>
|
||||
/// <param name="agvTask"></param>
|
||||
/// <param name="erpTask"></param>
|
||||
/// <param name="alreadyUploadNum"></param>
|
||||
/// <returns></returns>
|
||||
private static async Task UploadDataProductionOut(AGVTaskDto agvTask, ERPTaskDto erpTask, int alreadyUploadNum)
|
||||
{
|
||||
//if (alreadyUploadNum < (erpTask.ErpOrderNum - erpTask.ErpCancelNum))
|
||||
//{
|
||||
// if (alreadyUploadNum + agvTask.MateriaNum <= (erpTask.ErpOrderNum - erpTask.ErpCancelNum))
|
||||
// {
|
||||
// var param = new ErpProduceOutParam
|
||||
// {
|
||||
// produceReturnCode = erpTask.ProduceReturnCode,
|
||||
// barCode = erpTask.BarCode,
|
||||
// materiaName = erpTask.MateriaName,
|
||||
// materiaBatch = erpTask.MateriaBatch,
|
||||
// materiaCode = erpTask.MateriaCode,
|
||||
// num = agvTask.MateriaNum
|
||||
// };
|
||||
// XRResultDto erpReulst = await ErpService.AddProduceOut(param);
|
||||
// await HandErpUploadResult(agvTask, erpTask, erpReulst, param.num);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// var param = new ErpProduceOutParam
|
||||
// {
|
||||
// produceReturnCode = erpTask.ProduceReturnCode,
|
||||
// barCode = erpTask.BarCode,
|
||||
// materiaName = erpTask.MateriaName,
|
||||
// materiaBatch = erpTask.MateriaBatch,
|
||||
// materiaCode = erpTask.MateriaCode,
|
||||
// num = erpTask.ErpOrderNum - alreadyUploadNum
|
||||
// };
|
||||
// XRResultDto erpReulst = await ErpService.AddProduceOut(param);
|
||||
// await HandErpUploadResult(agvTask, erpTask, erpReulst, param.num);
|
||||
// }
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// agvTask.ErpUploadStatus = ErpUploadStatusEnum.UploadSuccess;
|
||||
// agvTask.LastModifiedTime = DateTime.Now;
|
||||
// agvTask.ErpReturnMsg = "已上传数量等于订单数";
|
||||
// agvTask.RetryNum = retryNum;
|
||||
// await AGVTaskService.EditSingal(agvTask);
|
||||
|
||||
// erpTask.AlreadyUploadNum = erpTask.ErpOrderNum;
|
||||
// erpTask.TaskStatus = TaskStatusEnum.Completed;
|
||||
// await ErpTaskService.EditSingal(erpTask);
|
||||
//}
|
||||
|
||||
if (alreadyUploadNum < (erpTask.ErpOrderNum - erpTask.ErpCancelNum))
|
||||
{
|
||||
var param = new ErpProduceOutParam
|
||||
{
|
||||
produceReturnCode = erpTask.ProduceReturnCode,
|
||||
barCode = agvTask.BarCode,
|
||||
materiaName = agvTask.MateriaName,
|
||||
materiaBatch = agvTask.MateriaBatch,
|
||||
materiaCode = agvTask.MateriaCode,
|
||||
num = agvTask.MateriaNum
|
||||
};
|
||||
XRResultDto erpReulst = await ErpService.AddProduceOut(param);
|
||||
await HandErpUploadResult(agvTask, erpTask, erpReulst, param.num);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (alreadyUploadNum > erpTask.ErpOrderNum - erpTask.ErpCancelNum)
|
||||
{
|
||||
agvTask.ErpReturnMsg = "请注意:已上传数量大于订单数";
|
||||
}
|
||||
agvTask.ErpUploadStatus = ErpUploadStatusEnum.UploadSuccess;
|
||||
agvTask.LastModifiedTime = DateTime.Now;
|
||||
agvTask.RetryNum = retryNum;
|
||||
await AGVTaskService.EditSingal(agvTask);
|
||||
|
||||
erpTask.AlreadyUploadNum = alreadyUploadNum;
|
||||
erpTask.TaskStatus = TaskStatusEnum.Completed;
|
||||
await ErpTaskService.EditSingal(erpTask);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 销售出库数据上传
|
||||
/// </summary>
|
||||
/// <param name="agvTask"></param>
|
||||
/// <param name="erpTask"></param>
|
||||
/// <param name="alreadyUploadNum"></param>
|
||||
/// <returns></returns>
|
||||
private static async Task UploadDataSaleOut(AGVTaskDto agvTask, ERPTaskDto erpTask, int alreadyUploadNum)
|
||||
{
|
||||
//if (alreadyUploadNum < (erpTask.ErpOrderNum - erpTask.ErpCancelNum))
|
||||
//{
|
||||
// if (alreadyUploadNum + agvTask.MateriaNum <= (erpTask.ErpOrderNum - erpTask.ErpCancelNum))
|
||||
// {
|
||||
// var param = new ErpSaleOutParam
|
||||
// {
|
||||
// saleNo = erpTask.SaleNo,
|
||||
// barCode = agvTask.BarCode,
|
||||
// materiaCode = agvTask.MateriaCode,
|
||||
// materiaBatch = agvTask.MateriaBatch,
|
||||
// num = agvTask.MateriaNum
|
||||
// };
|
||||
// XRResultDto erpReulst = await ErpService.AddSaleOut(param);
|
||||
// await HandErpUploadResult(agvTask, erpTask, erpReulst, param.num);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// var param = new ErpSaleOutParam
|
||||
// {
|
||||
// saleNo = erpTask.SaleNo,
|
||||
// barCode = agvTask.BarCode,
|
||||
// materiaCode = agvTask.MateriaCode,
|
||||
// materiaBatch = agvTask.MateriaBatch,
|
||||
// num = erpTask.ErpOrderNum - alreadyUploadNum
|
||||
// };
|
||||
// XRResultDto erpReulst = await ErpService.AddSaleOut(param);
|
||||
// await HandErpUploadResult(agvTask, erpTask, erpReulst, param.num);
|
||||
// }
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// agvTask.ErpUploadStatus = ErpUploadStatusEnum.UploadSuccess;
|
||||
// agvTask.LastModifiedTime = DateTime.Now;
|
||||
// agvTask.ErpReturnMsg = "已上传数量等于订单数";
|
||||
// agvTask.RetryNum = retryNum;
|
||||
// await AGVTaskService.EditSingal(agvTask);
|
||||
|
||||
|
||||
// erpTask.AlreadyUploadNum = erpTask.ErpOrderNum;
|
||||
// erpTask.TaskStatus = TaskStatusEnum.Completed;
|
||||
// await ErpTaskService.EditSingal(erpTask);
|
||||
//}
|
||||
|
||||
if (alreadyUploadNum < (erpTask.ErpOrderNum - erpTask.ErpCancelNum))
|
||||
{
|
||||
var param = new StockOutParam
|
||||
{
|
||||
saleNo = erpTask.SaleNo,
|
||||
barCode = agvTask.BarCode,
|
||||
materiaCode = agvTask.MateriaCode,
|
||||
materiaBatch = agvTask.MateriaBatch,
|
||||
num = agvTask.MateriaNum
|
||||
};
|
||||
XRResultDto erpReulst = await ErpService.AddSaleOut(param);
|
||||
await HandErpUploadResult(agvTask, erpTask, erpReulst, param.num);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (alreadyUploadNum > erpTask.ErpOrderNum - erpTask.ErpCancelNum)
|
||||
{
|
||||
agvTask.ErpReturnMsg = "请注意:已上传数量大于订单数";
|
||||
}
|
||||
agvTask.ErpUploadStatus = ErpUploadStatusEnum.UploadSuccess;
|
||||
agvTask.LastModifiedTime = DateTime.Now;
|
||||
agvTask.RetryNum = retryNum;
|
||||
await AGVTaskService.EditSingal(agvTask);
|
||||
|
||||
erpTask.AlreadyUploadNum = alreadyUploadNum;
|
||||
erpTask.TaskStatus = TaskStatusEnum.Completed;
|
||||
await ErpTaskService.EditSingal(erpTask);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pda入库数据上传
|
||||
/// </summary>
|
||||
/// <param name="agvTask"></param>
|
||||
/// <returns></returns>
|
||||
private static async Task UploadDataIn(AGVTaskDto agvTask, ERPTaskDto erpTask)
|
||||
{
|
||||
//入库:一个合格证号,只能成功上传一次Erp
|
||||
//var agvTaskList = await AGVTaskService.GetListByExpression(p => p.BarCode == agvTask.BarCode && p.ErpUploadStatus == ErpUploadStatusEnum.UploadSuccess);
|
||||
//if (!agvTaskList.IsNullOrEmpty())
|
||||
//{
|
||||
// LogHelper.Error($"合格证:{agvTask.BarCode},AgvTask任务Id:{agvTask.Id} 入库信息,已经上传到Erp,不能重复上传!");
|
||||
//}
|
||||
//else
|
||||
{
|
||||
var param = new ErpProduceInParam
|
||||
{
|
||||
barCode = agvTask.BarCode,
|
||||
materiaName = agvTask.MateriaName,
|
||||
materiaBatch = agvTask.MateriaBatch,
|
||||
materiaCode = agvTask.MateriaCode,
|
||||
materiaNum = agvTask.MateriaNum
|
||||
};
|
||||
XRResultDto erpReulst = await ErpService.AddProduceIn(param);
|
||||
await HandErpUploadResult(agvTask, erpTask, erpReulst, param.materiaNum);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理调用Erp接口,后Wms后续业务
|
||||
/// </summary>
|
||||
/// <param name="agvTask"></param>
|
||||
/// <param name="erpTask"></param>
|
||||
/// <param name="erpReulst"></param>
|
||||
/// <param name="num"></param>
|
||||
/// <returns></returns>
|
||||
private static async Task HandErpUploadResult(AGVTaskDto agvTask, ERPTaskDto erpTask, XRResultDto erpReulst, int num)
|
||||
{
|
||||
if (erpReulst.success)
|
||||
{
|
||||
agvTask.ErpUploadStatus = ErpUploadStatusEnum.UploadSuccess;
|
||||
agvTask.LastModifiedTime = DateTime.Now;
|
||||
agvTask.ErpReturnMsg = erpReulst.message;
|
||||
agvTask.RetryNum += 1;
|
||||
|
||||
bool bRet = await AGVTaskService.EditSingal(agvTask);
|
||||
if (!bRet)
|
||||
{
|
||||
agvTask.RetryNum++;
|
||||
LogHelper.Error($"更新ID为{agvTask.Id}的agvTask的Erp上传状态失败");
|
||||
}
|
||||
else
|
||||
{
|
||||
erpTask.AlreadyUploadNum += num;
|
||||
erpTask.LastModifiedTime = DateTime.Now;
|
||||
await ErpTaskService.EditSingalWithSpecificCols(erpTask, ["AlreadyUploadNum", "LastModifiedTime"]);
|
||||
}
|
||||
}
|
||||
//处理网络不通或超时
|
||||
else if (erpReulst == null)
|
||||
{
|
||||
agvTask.ErpUploadStatus = ErpUploadStatusEnum.UploadFailed;
|
||||
agvTask.LastModifiedTime = DateTime.Now;
|
||||
agvTask.ErpReturnMsg = "访问Erp连接超时";
|
||||
agvTask.RetryNum = 0;
|
||||
|
||||
bool bRet = await AGVTaskService.EditSingal(agvTask);
|
||||
if (!bRet)
|
||||
{
|
||||
LogHelper.Error($"更新ID为{agvTask.Id}的agvTask的Erp上传状态失败");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
agvTask.ErpUploadStatus = ErpUploadStatusEnum.UploadFailed;
|
||||
agvTask.LastModifiedTime = DateTime.Now;
|
||||
agvTask.ErpReturnMsg = erpReulst.errors;
|
||||
agvTask.RetryNum += 1;
|
||||
|
||||
bool bRet = await AGVTaskService.EditSingal(agvTask);
|
||||
if (!bRet)
|
||||
{
|
||||
agvTask.RetryNum++;
|
||||
LogHelper.Error($"更新ID为{agvTask.Id}的agvTask的Erp上传状态失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
using JSMachine.WMS.Job.Enum;
|
||||
|
||||
namespace JSMachine.WMS.Job.JobAttributes
|
||||
{
|
||||
/// <summary>
|
||||
/// Quartz 作业注册特性,描述作业名称、分组、触发方式和执行周期。
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
|
||||
public sealed class JobAttribute : Attribute
|
||||
{
|
||||
// 默认配置
|
||||
/// <summary>创建使用默认调度参数的作业特性。</summary>
|
||||
public JobAttribute()
|
||||
{
|
||||
ScheduleType = ScheduleType.Simple;
|
||||
Name = "MyJob";
|
||||
Group = "MyGroup";
|
||||
Description = "NoJobAttributeAndDefault";
|
||||
StartTimeStr = null;
|
||||
RepeatCount = 0;
|
||||
IntervalMilliSeconds = 5000;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Job的特性
|
||||
/// </summary>
|
||||
/// <param name="modeEnum">Job的Trigger的创建模式</param>
|
||||
/// <param name="name">JobKeyName</param>
|
||||
/// <param name="group">JobKeyGroup</param>
|
||||
/// <param name="decription">JobDecription</param>
|
||||
/// <param name="dateTimeOffset">Trigger开始时间</param>
|
||||
/// <param name="repeatCount">重复次数(null为Forever)</param>
|
||||
/// <param name="intervaMilliSeconds">间隔时间(毫秒)</param>
|
||||
/// <summary>使用指定调度参数创建作业特性。</summary>
|
||||
public JobAttribute(ScheduleType scheduleType
|
||||
, string name
|
||||
, string group
|
||||
, string decription
|
||||
, string dateTimeOffset
|
||||
, int repeatCount
|
||||
, int intervaMilliSeconds)
|
||||
{
|
||||
ScheduleType = scheduleType;
|
||||
Name = name;
|
||||
Description = decription;
|
||||
Group = group;
|
||||
StartTimeStr = dateTimeOffset;
|
||||
RepeatCount = repeatCount;
|
||||
IntervalMilliSeconds = intervaMilliSeconds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Job的Trigger的创建模式
|
||||
/// Simple、Corn、Calendar、XMLConfig、JsonConfig
|
||||
/// </summary>
|
||||
public ScheduleType ScheduleType { get; set; }
|
||||
/// <summary>
|
||||
/// JobKeyName
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
/// <summary>
|
||||
/// JobKeyGroup
|
||||
/// </summary>
|
||||
public string Group { get; set; }
|
||||
/// <summary>
|
||||
/// JobDescription
|
||||
/// </summary>
|
||||
public string Description { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 开始时间
|
||||
/// 可转为时间的字符串,标准格式为"yyyy-MM-dd HH:mm:ss.fff"
|
||||
/// null或string.Empty为立即开始
|
||||
/// </summary>
|
||||
public string StartTimeStr { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 重复次数,0为总是重复
|
||||
/// </summary>
|
||||
public int RepeatCount { get; set; }
|
||||
/// <summary>
|
||||
/// 任务执行间隔
|
||||
/// </summary>
|
||||
public int IntervalMilliSeconds { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using JSMachine.WMS.Infrastructure.Enums;
|
||||
|
||||
namespace JSMachine.WMS.Job.JobAttributes
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class ScannerSceneAttribute : Attribute
|
||||
{
|
||||
public ScannerScene ScannerScene { get; set; }
|
||||
public ScannerSceneAttribute(ScannerScene scannerScene)
|
||||
{
|
||||
ScannerScene = scannerScene;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
using JSMachine.WMS.Common;
|
||||
using JSMachine.WMS.Infrastructure.Enums;
|
||||
using JSMachine.WMS.Job.Enum;
|
||||
using JSMachine.WMS.Job.JobAttributes;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Quartz;
|
||||
using Quartz.Impl;
|
||||
using Quartz.Impl.Matchers;
|
||||
using System.Collections.Specialized;
|
||||
using System.Reflection;
|
||||
|
||||
namespace JSMachine.WMS.Job
|
||||
{
|
||||
/// <summary>
|
||||
/// Quartz 作业调度引擎,根据 JobAttribute 自动发现并注册作业。
|
||||
/// </summary>
|
||||
public static class JobEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// 启动 Quartz 调度器,并按作业属性创建周期触发器。
|
||||
/// 作业执行由 Quartz 管理,调用方无需等待单次作业完成。
|
||||
/// </summary>
|
||||
public async static void UseAllJobs(this IApplicationBuilder app)
|
||||
{
|
||||
List<(Type, JobAttribute)> tuples = ResolveAllJobTypes();
|
||||
|
||||
ISchedulerFactory schedulerFactory = new StdSchedulerFactory();
|
||||
IScheduler scheduler = await schedulerFactory.GetScheduler();
|
||||
await scheduler.Start();
|
||||
|
||||
// 每个作业独立创建 JobDetail 和 Trigger,避免不同作业共享调度配置。
|
||||
tuples?.ForEach(async tuple =>
|
||||
{
|
||||
IJobDetail jobDetail = JobBuilder
|
||||
.Create(tuple.Item1)
|
||||
.WithIdentity(tuple.Item2.Name, tuple.Item2.Group)
|
||||
.Build();
|
||||
|
||||
TriggerBuilder triggerBuilder = TriggerBuilder
|
||||
.Create()
|
||||
.WithIdentity($"{tuple.Item2.Name}Trigger", tuple.Item2.Group);
|
||||
|
||||
if (tuple.Item2.ScheduleType == ScheduleType.Simple)
|
||||
{
|
||||
triggerBuilder.WithSimpleSchedule(p =>
|
||||
{
|
||||
p.WithInterval(TimeSpan.FromMilliseconds(tuple.Item2.IntervalMilliSeconds));
|
||||
if (tuple.Item2.RepeatCount > 0)
|
||||
{
|
||||
p.WithRepeatCount(tuple.Item2.RepeatCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
p.RepeatForever();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ITrigger trigger = triggerBuilder.Build();
|
||||
|
||||
|
||||
await scheduler.ScheduleJob(jobDetail, trigger);
|
||||
});
|
||||
}
|
||||
|
||||
private static List<(Type, JobAttribute)> ResolveAllJobTypes()
|
||||
{
|
||||
Assembly assembly = typeof(JobEngine).Assembly;
|
||||
|
||||
//获取所有类
|
||||
Type[] jobTypes = assembly
|
||||
.GetTypes()
|
||||
.Where(t => t.IsDefined(typeof(JobAttribute), false) && typeof(IJob).IsAssignableFrom(t))
|
||||
.ToArray();
|
||||
|
||||
List<(Type, JobAttribute)> tuples = new();
|
||||
//获取类定义的
|
||||
foreach (Type jobType in jobTypes)
|
||||
{
|
||||
object[] attrs = jobType.GetCustomAttributes(typeof(JobAttribute), false);
|
||||
if (attrs.Length > 0)
|
||||
{
|
||||
foreach (var attr in attrs)
|
||||
{
|
||||
if (attr is JobAttribute attribute)
|
||||
{
|
||||
tuples.Add((jobType, attribute));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return tuples;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
using JSMachine.WMS.Infrastructure.Helper;
|
||||
using Quartz;
|
||||
|
||||
namespace JSMachine.WMS.Job
|
||||
{
|
||||
/// <summary>
|
||||
/// 作业监听器
|
||||
/// </summary>
|
||||
public class JobListener : IJobListener
|
||||
{
|
||||
/// <summary>
|
||||
/// Quartz 作业监听器名称。
|
||||
/// </summary>
|
||||
public string Name => "JobDurationListener";
|
||||
|
||||
/// <summary>
|
||||
/// 记录因禁止并发执行而被 Quartz 跳过的作业。
|
||||
/// </summary>
|
||||
/// <param name="context">Quartz 作业上下文。</param>
|
||||
/// <param name="cancellationToken">取消令牌。</param>
|
||||
/// <returns>已完成的监听任务。</returns>
|
||||
public Task JobExecutionVetoed(IJobExecutionContext context, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Task.Run(() =>
|
||||
{
|
||||
LogHelper.Info($"{context.JobDetail.Key.Name} actives the JobListener.JobExecutionVetoed method");
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 作业执行前
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public Task JobToBeExecuted(IJobExecutionContext context, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Task.Run(() =>
|
||||
{
|
||||
//LogHelp.Info($"{context.JobDetail.Key.Name} is excuting ......");
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 作业执行后
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="jobException"></param>
|
||||
/// <param name="cancellationToken"></param>
|
||||
/// <returns></returns>
|
||||
public Task JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException, CancellationToken cancellationToken = default)
|
||||
{
|
||||
return Task.Run(() =>
|
||||
{
|
||||
if (jobException != null)
|
||||
{
|
||||
LogHelper.Error(@$"{context.JobDetail.Key.Name} occurs an error.
|
||||
Error message is {jobException.InnerException?.InnerException?.Message} .
|
||||
StackTrace is {jobException.InnerException?.InnerException?.StackTrace}");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using JSMachine.WMS.RPC.PmsRPC.Dto.In;
|
||||
|
||||
namespace JSMachine.WMS.Job
|
||||
{
|
||||
/// <summary>
|
||||
/// 进程内保存的机台备纸数据及 ACS 记录标识。
|
||||
/// </summary>
|
||||
public static class PlateList
|
||||
{
|
||||
/// <summary>
|
||||
/// 各机台最近批次的备纸需求列表。
|
||||
/// </summary>
|
||||
public static List<List<PaperNeed>> Plates { get; set; }//记录所有机台下"前十"批的备纸数据
|
||||
public static Guid SavedAcsId { get; set; }//记录第一个Id
|
||||
public static List<Guid> AcsIdArray { get; set; }//记录第一个批订单下所有的Id
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user