feat(api, core): Доделал атомарный захват задачи роботом.
This commit is contained in:
@@ -6,5 +6,10 @@
|
|||||||
/// Установить статус задания - InProgress (Робот взял в работу)
|
/// Установить статус задания - InProgress (Робот взял в работу)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool? SetInProgressStatus { get; init; }
|
public bool? SetInProgressStatus { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Идентификатор робота
|
||||||
|
/// </summary>
|
||||||
|
public string? RobotId { get; init; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,84 +3,375 @@ using Microsoft.AspNetCore.Authorization;
|
|||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using PARR.API.Contracts.V1;
|
using PARR.API.Contracts.V1;
|
||||||
using PARR.API.Contracts.V1.Requests.Queries;
|
using PARR.API.Contracts.V1.Requests.Queries;
|
||||||
|
using PARR.API.Contracts.V1.Responses;
|
||||||
|
using PARR.API.Contracts.V1.Responses.Base;
|
||||||
using PARR.API.Controllers.V1.Base;
|
using PARR.API.Controllers.V1.Base;
|
||||||
using PARR.API.Services.Interfaces;
|
using PARR.API.Services.Interfaces;
|
||||||
using PARR.Core.Repositories.Interfaces;
|
|
||||||
using PARR.Core.Services.NextRunServices;
|
|
||||||
using PARR.Core.Services.RobotTask.Interfaces;
|
using PARR.Core.Services.RobotTask.Interfaces;
|
||||||
using PARR.Core.Services.Shortcodes;
|
|
||||||
using PARR.Domain.Common.Roles;
|
using PARR.Domain.Common.Roles;
|
||||||
|
using PARR.Domain.Entities.Base.History;
|
||||||
using PARR.Domain.Enums;
|
using PARR.Domain.Enums;
|
||||||
using PARR.Domain.Settings;
|
using PARR.Domain.Exceptions;
|
||||||
|
|
||||||
namespace PARR.API.Controllers.V1
|
namespace PARR.API.Controllers.V1
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Формирование заданий роботам
|
|
||||||
/// </summary>
|
|
||||||
[Authorize(Roles = ParrRoles.EsppRobot.RoleOrAdmin)]
|
[Authorize(Roles = ParrRoles.EsppRobot.RoleOrAdmin)]
|
||||||
public class RobotTaskController : BaseApiController
|
public class RobotTaskController : BaseApiController
|
||||||
{
|
{
|
||||||
private readonly IMapper mapper;
|
|
||||||
private readonly SettingsFromDb settingsFromDb;
|
|
||||||
private readonly IRobotConfigurationRepository robotConfigurationService;
|
|
||||||
private readonly ILogger<RobotTaskOldController> logger;
|
|
||||||
private readonly IClientService clientService;
|
|
||||||
private readonly IRobotHistoryRepository robotHistoryService;
|
|
||||||
private readonly IShortcodesService shortcodesService;
|
|
||||||
private readonly INextRunService nextRunService;
|
|
||||||
private readonly IRobotTaskService robotTaskService;
|
private readonly IRobotTaskService robotTaskService;
|
||||||
|
|
||||||
|
private readonly IMapper mapper;
|
||||||
|
//private readonly SettingsFromDb settingsFromDb;
|
||||||
|
//private readonly IRobotConfigurationRepository robotConfigurationService;
|
||||||
|
//private readonly ILogger<RobotTaskController> logger;
|
||||||
|
private readonly IClientService clientService;
|
||||||
|
//private readonly IRobotHistoryRepository robotHistoryService;
|
||||||
|
//private readonly IShortcodesService shortcodesService;
|
||||||
|
//private readonly INextRunService nextRunService;
|
||||||
|
|
||||||
public RobotTaskController(
|
public RobotTaskController(
|
||||||
IMapper mapper,
|
IMapper mapper,
|
||||||
SettingsFromDb settingsFromDb,
|
//SettingsFromDb settingsFromDb,
|
||||||
IRobotConfigurationRepository robotConfigurationService,
|
//IRobotConfigurationRepository robotConfigurationService,
|
||||||
ILogger<RobotTaskOldController> logger,
|
//ILogger<RobotTaskController> logger,
|
||||||
IClientService clientService,
|
IClientService clientService,
|
||||||
IRobotHistoryRepository robotHistoryService,
|
//IRobotHistoryRepository robotHistoryService,
|
||||||
IShortcodesService shortcodesService,
|
//IShortcodesService shortcodesService,
|
||||||
INextRunService nextRunService,
|
//INextRunService nextRunService
|
||||||
|
|
||||||
|
|
||||||
IRobotTaskService robotTaskService
|
IRobotTaskService robotTaskService
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this.mapper = mapper;
|
|
||||||
this.settingsFromDb = settingsFromDb;
|
|
||||||
this.robotConfigurationService = robotConfigurationService;
|
|
||||||
this.logger = logger;
|
|
||||||
this.clientService = clientService;
|
|
||||||
this.robotHistoryService = robotHistoryService;
|
|
||||||
this.shortcodesService = shortcodesService;
|
|
||||||
this.nextRunService = nextRunService;
|
|
||||||
this.robotTaskService = robotTaskService;
|
this.robotTaskService = robotTaskService;
|
||||||
|
this.mapper = mapper;
|
||||||
|
//this.settingsFromDb = settingsFromDb;
|
||||||
|
//this.robotConfigurationService = robotConfigurationService;
|
||||||
|
//this.logger = logger;
|
||||||
|
this.clientService = clientService;
|
||||||
|
//this.robotHistoryService = robotHistoryService;
|
||||||
|
//this.shortcodesService = shortcodesService;
|
||||||
|
//this.nextRunService = nextRunService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Получить задание для робота по коду робота и статусу задания
|
/// Получить задание для робота по коду робота и по статусу задания
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="robotCode">Код робота</param>
|
/// <param name="robotCode"></param>
|
||||||
/// <param name="taskStatusCode">Статус задания</param>
|
/// <param name="taskStatusCode"></param>
|
||||||
/// <param name="requestQuery">Параметры</param>
|
/// <param name="requestQuery"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
[HttpGet(ApiRoutes.RobotTask.GetByRobotAndStatusTask)]
|
[HttpGet(ApiRoutes.RobotTask.GetByRobotAndStatusTask)]
|
||||||
public async Task<IActionResult> GetByRobotAndStatusTask([FromRoute] RobotsEnum robotCode, [FromRoute] TaskStatusEnum taskStatusCode, [FromQuery] RobotTaskQuery requestQuery)
|
public async Task<IActionResult> GetByRobotAndStatusTask([FromRoute] RobotsEnum robotCode, [FromRoute] TaskStatusEnum taskStatusCode, [FromQuery] RobotTaskQuery requestQuery)
|
||||||
{
|
{
|
||||||
|
switch (robotCode)
|
||||||
|
{
|
||||||
|
case RobotsEnum.TemplateOrder:
|
||||||
|
var templateTask = await robotTaskService.GetTemplateTaskAsync(
|
||||||
|
taskStatusCode,
|
||||||
|
requestQuery.SetInProgressStatus ?? false,
|
||||||
|
clientService.GetClientIp()?.ToString(),
|
||||||
|
requestQuery.RobotId
|
||||||
|
);
|
||||||
|
var templateResponse = mapper.Map<RobotTaskTemplateResponse>(templateTask);
|
||||||
|
|
||||||
//robotTaskService
|
return Ok(new Response<RobotTaskTemplateResponse>(templateResponse, true));
|
||||||
|
case RobotsEnum.ScheduleOrder:
|
||||||
|
var historyIniciator = new HistoryInitiator
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
var scheduleTask = await robotTaskService.GetScheduleTaskAsync(
|
||||||
|
taskStatusCode,
|
||||||
|
requestQuery.SetInProgressStatus ?? false,
|
||||||
|
historyIniciator.InitiatorIp,
|
||||||
|
requestQuery.RobotId,
|
||||||
|
historyIniciator
|
||||||
|
);
|
||||||
|
|
||||||
|
var scheduleResponse = mapper.Map<RobotTaskScheduleResponse>(scheduleTask);
|
||||||
|
|
||||||
|
return Ok(new Response<RobotTaskScheduleResponse>(scheduleResponse, true));
|
||||||
return Ok();
|
default:
|
||||||
|
throw new AppValidationException("Некорректное значение robotCode");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#region Old
|
||||||
|
|
||||||
|
// /// <summary>
|
||||||
|
// /// Получить задание для робота по коду робота и по статусу задания
|
||||||
|
// /// </summary>
|
||||||
|
// /// <param name="robotCode"></param>
|
||||||
|
// /// <param name="taskStatusCode"></param>
|
||||||
|
// /// <returns></returns>
|
||||||
|
// [HttpGet(ApiRoutes.RobotTask.GetByRobotAndStatusTask)]
|
||||||
|
// public async Task<IActionResult> GetByRobotAndStatusTask([FromRoute] RobotsEnum robotCode, [FromRoute] TaskStatusEnum taskStatusCode, [FromQuery] RobotTaskQuery requestQuery)
|
||||||
|
// {
|
||||||
|
// //Ищем все задания с превышенным кол-вом попыток и с просроченным временем и ставим им статус ошибки
|
||||||
|
// await robotConfigurationService.MarkExpiredTasksAsFailedAsync(settingsFromDb.RobotAttemptsNumber, settingsFromDb.RobotWaitTime);
|
||||||
|
|
||||||
|
|
||||||
|
// var query = robotConfigurationService.Get()
|
||||||
|
// .AsSingleQuery()
|
||||||
|
// .Where(t => t.RobotCode == (int)robotCode && t.TaskStatusCode == (int)taskStatusCode);
|
||||||
|
|
||||||
|
// switch (robotCode)
|
||||||
|
// {
|
||||||
|
// case RobotsEnum.TemplateOrder:
|
||||||
|
// // шаблоны
|
||||||
|
// query = query
|
||||||
|
// .Include(t => t.Template)
|
||||||
|
// .ThenInclude(t => t!.Unit)
|
||||||
|
// .ThenInclude(t => t!.UnitValues)
|
||||||
|
// .ThenInclude(t => t.Field)
|
||||||
|
// .Include(t => t.Template)
|
||||||
|
// .ThenInclude(t => t!.Unit)
|
||||||
|
// .ThenInclude(t => t!.UnitValues)
|
||||||
|
// .ThenInclude(t => t.Value)
|
||||||
|
// .Include(t => t.Template)
|
||||||
|
// .ThenInclude(a => a!.Job)
|
||||||
|
// .ThenInclude(t => t!.Group)
|
||||||
|
// .ThenInclude(g => g.GroupType)
|
||||||
|
// .Include(t => t.Template)
|
||||||
|
// .ThenInclude(w => w!.Job)
|
||||||
|
// .ThenInclude(t => t!.Tnk)
|
||||||
|
// .ThenInclude(s => s!.Subprocess)
|
||||||
|
// .ThenInclude(p => p!.Process);
|
||||||
|
|
||||||
|
// query = query
|
||||||
|
// .Include(t => t.Template)
|
||||||
|
// .ThenInclude(t => t!.UnitsInTemplate);
|
||||||
|
|
||||||
|
// break;
|
||||||
|
|
||||||
|
// case RobotsEnum.ScheduleOrder:
|
||||||
|
// //расписание
|
||||||
|
// query = query
|
||||||
|
// .Include(t => t.Template)
|
||||||
|
// .ThenInclude(t => t!.Unit)
|
||||||
|
// .ThenInclude(t => t!.UnitValues)
|
||||||
|
// .ThenInclude(t => t.Field)
|
||||||
|
// .Include(t => t.Template)
|
||||||
|
// .ThenInclude(t => t!.Unit)
|
||||||
|
// .ThenInclude(t => t!.UnitValues)
|
||||||
|
// .ThenInclude(t => t.Value)
|
||||||
|
// .Include(t => t.Template)
|
||||||
|
// .ThenInclude(a => a!.Job)
|
||||||
|
// .ThenInclude(t => t!.Group)
|
||||||
|
// .ThenInclude(g => g.GroupType)
|
||||||
|
// .Include(t => t.Template)
|
||||||
|
// .ThenInclude(a => a!.Job)
|
||||||
|
// .ThenInclude(t => t!.Group)
|
||||||
|
// .ThenInclude(t => t!.EsppSchValues)
|
||||||
|
// .ThenInclude(t => t!.EsppSchTypeConfig)
|
||||||
|
// .ThenInclude(t => t!.EsppSchTypeSchedule)
|
||||||
|
// .Include(t => t.Template)
|
||||||
|
// .ThenInclude(t => t!.Job)
|
||||||
|
// .ThenInclude(t => t!.Group)
|
||||||
|
// .ThenInclude(t => t!.ScheduleExcludeType)
|
||||||
|
// .Include(t => t.Template)
|
||||||
|
// .ThenInclude(t => t!.Job)
|
||||||
|
// .ThenInclude(t => t!.Group)
|
||||||
|
// .ThenInclude(t => t.ScheduleExcludeTypeCalendar)
|
||||||
|
// .Include(t => t.Template)
|
||||||
|
// .ThenInclude(t => t!.Job)
|
||||||
|
// .ThenInclude(t => t!.Tnk)
|
||||||
|
// .Include(t => t.Template)
|
||||||
|
// .ThenInclude(t => t!.UnitsInTemplate);
|
||||||
|
|
||||||
|
// //выбираем только записи с созданными шаблонами (у которых статус 20 или 30), а только потом у них ищем расписания
|
||||||
|
// var createdTemplates = robotConfigurationService.Get()
|
||||||
|
// .Where(t => t.RobotCode == (int)RobotsEnum.TemplateOrder && (t.TaskStatusCode == (int)TaskStatusEnum.Ok))
|
||||||
|
// .Select(t => t.TemplateId);
|
||||||
|
// query = query.Where(t => t.RobotCode == (int)RobotsEnum.ScheduleOrder && createdTemplates.Contains(t.TemplateId));
|
||||||
|
// // query = query.Where(t => t.RobotCode == (int)RobotsEnum.ScheduleOrder && t.TemplateId==Guid.Parse("7cb7c3be-506d-40e0-a63f-4554edb52459"));
|
||||||
|
// break;
|
||||||
|
|
||||||
|
// default:
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// // сортируем по NextRun, чтобы те у которых дата след срабатывания ближе к текущей, выполнились скорее
|
||||||
|
// query = query.OrderBy(t => t.Template!.NextRun).ThenBy(t => t.Template!.IsActiveSchedule).ThenBy(t => t.Template.IsActiveTemplate);
|
||||||
|
|
||||||
|
// RobotConfiguration? task = null;
|
||||||
|
|
||||||
|
// //ищем задание в ожидании, если нашли, выбираем его
|
||||||
|
// task = await query.FirstOrDefaultAsync(t => t.RobotStatusCode == (int)RobotStatusEnum.Wait);
|
||||||
|
|
||||||
|
// if (task == null)
|
||||||
|
// {
|
||||||
|
// //ищем задания в работе, которые можно перезапустить
|
||||||
|
// //Поиск по `RobotStatusCode` = 22.
|
||||||
|
// //Далее проверяется `LastStatusUpdated`, что время последнего смены статуса не превышает допустимого(берется из настроек, поле `RobotWaitTime`)
|
||||||
|
// //и что текущая попытка не больше разрешенной(берется из настроек, поле `RobotAttemptsNumber`) - если это так, берется эта запись.
|
||||||
|
|
||||||
|
// var endDate = DateTimeOffset.UtcNow.Add(-settingsFromDb.RobotWaitTime);
|
||||||
|
// task = await query
|
||||||
|
// .FirstOrDefaultAsync(t =>
|
||||||
|
// t.RobotStatusCode == (int)RobotStatusEnum.InProgress
|
||||||
|
// && t.AttemptsNumber < settingsFromDb.RobotAttemptsNumber
|
||||||
|
// && t.LastRobotStatusUpdated < endDate
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (task == null)
|
||||||
|
// return NotFound();
|
||||||
|
|
||||||
|
// if (requestQuery?.SetInProgressStatus == true)
|
||||||
|
// {
|
||||||
|
// var resultSetStatus = await SetInProgressStatusAsync(task.Id);
|
||||||
|
// if (resultSetStatus == false)
|
||||||
|
// {
|
||||||
|
// logger.LogError($"Ошибка при установке статуса {RobotStatusEnum.InProgress.ToString()} для задания RobotConfigutationId {task.Id} (при выдаче задания роботу)");
|
||||||
|
// return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Ошибка при выдаче задания." } }));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// switch (robotCode)
|
||||||
|
// {
|
||||||
|
// case RobotsEnum.TemplateOrder:
|
||||||
|
// { //RobotTaskTemplateResponse
|
||||||
|
// var robotTaskTemplateResponse = mapper.Map<RobotTaskTemplateResponse>(task);
|
||||||
|
|
||||||
|
// robotTaskTemplateResponse.FullDescription = NormalizeLineEndingsToCrlf(await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.FullDescription, task.Template!));
|
||||||
|
// robotTaskTemplateResponse.ShortDescription = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.ShortDescription, task.Template!);
|
||||||
|
// robotTaskTemplateResponse.Solution = NormalizeLineEndingsToCrlf(await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.Solution, task.Template!));
|
||||||
|
// robotTaskTemplateResponse.TnkName = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.TnkName, task.Template!);
|
||||||
|
// robotTaskTemplateResponse.WorkName = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.WorkName, task.Template!);
|
||||||
|
// robotTaskTemplateResponse.WorkGroup = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.WorkGroup, task.Template!);
|
||||||
|
// robotTaskTemplateResponse.ResponseArea = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.ResponseArea, task.Template!);
|
||||||
|
|
||||||
|
// return Ok(new Response<RobotTaskTemplateResponse>(robotTaskTemplateResponse, true));
|
||||||
|
// }
|
||||||
|
// case RobotsEnum.ScheduleOrder:
|
||||||
|
// { // если был запрос на расписание, проверяем у него nextRun, lastRun, обновляем их
|
||||||
|
// var resultUpdateNextRun = await UpdateNextRunAsync(task);
|
||||||
|
// if (!resultUpdateNextRun)
|
||||||
|
// {
|
||||||
|
// logger.LogError("Ошибка при расчете NextRun для templateId: {templateId}", task.TemplateId);
|
||||||
|
// return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Ошибка при расчете NextRun" } }));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// //RobotTaskScheduleResponse
|
||||||
|
// var robotTaskScheduleResponse = mapper.Map<RobotTaskScheduleResponse>(task);
|
||||||
|
|
||||||
|
// robotTaskScheduleResponse.Timezone = settingsFromDb.EsppScheduleTimezone;
|
||||||
|
|
||||||
|
// robotTaskScheduleResponse.WorkGroup = await shortcodesService.ApplyShortcodesAsync(robotTaskScheduleResponse.WorkGroup, task.Template!);
|
||||||
|
// robotTaskScheduleResponse.ResponseArea = await shortcodesService.ApplyShortcodesAsync(robotTaskScheduleResponse.ResponseArea, task.Template!);
|
||||||
|
|
||||||
|
// //var nextRunWithRobotTz = nextRunService.GetNextRunWithTimezoneEsppAndResponseArea(task.Template!.NextRun, task.Template!.Job?.Group?.IsResponseAreaTimezone, robotTaskScheduleResponse.ResponseArea);
|
||||||
|
// //nextRun в часовой зоне УЗ Робота ЕСПП
|
||||||
|
// var nextRunWithRobotTz = task.Template!.NextRun.Add(nextRunService.GetEsppAccountOffset());
|
||||||
|
|
||||||
|
// //на всякий случай еще раз проверяем, что дата не устарела и отправляем задание
|
||||||
|
// if (nextRunWithRobotTz < DateTimeOffset.UtcNow)
|
||||||
|
// {
|
||||||
|
// logger.LogError("Ошибка при расчете NextRun для templateId: {templateId}, итоговое значение для робота, меньше чем сейчас {nextRunWithRobotTz}<{now}",
|
||||||
|
// task.TemplateId, nextRunWithRobotTz, DateTimeOffset.UtcNow);
|
||||||
|
// return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Ошибка при расчете NextRun" } }));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// robotTaskScheduleResponse.NextStart = EsppScheduleHelpers.GetNextRun(nextRunWithRobotTz);
|
||||||
|
// robotTaskScheduleResponse.GenerationTime = EsppScheduleHelpers.GetGenerationTime(nextRunWithRobotTz);
|
||||||
|
|
||||||
|
// return Ok(new Response<RobotTaskScheduleResponse>(robotTaskScheduleResponse, true));
|
||||||
|
// }
|
||||||
|
// default:
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return BadRequest();
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// /// <summary>
|
||||||
|
// /// Обоновить NextRun если он устарел
|
||||||
|
// /// </summary>
|
||||||
|
// /// <param name="task"></param>
|
||||||
|
// /// <returns></returns>
|
||||||
|
// private async Task<bool> UpdateNextRunAsync(RobotConfiguration task)
|
||||||
|
// {
|
||||||
|
// var template = task.Template!;
|
||||||
|
|
||||||
|
// //var nextRun = await esppScheduleTransformService.GetNextDateAsync(template.Job!.GroupId, template!.Job!.Group!.ReferenceDate);
|
||||||
|
// var nextRun = await nextRunService.GetNextRunForTemplateAsync(template.Id, false);
|
||||||
|
|
||||||
|
// if (!nextRun.HasValue)
|
||||||
|
// {
|
||||||
|
// logger.LogError("При обновлении nextRun для шаблона {templateId}, расчитанный nextRun=null, ошибка в расчетах.", template.Id);
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (nextRun.Value < DateTimeOffset.UtcNow)
|
||||||
|
// {
|
||||||
|
// logger.LogError("При обновлении nextRun для шаблона {templateId}, расчитанный nextRun<Now [{nextRun}<{now}], ошибка в расчетах.", template.Id, nextRun.Value, DateTimeOffset.UtcNow);
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (nextRun != template.NextRun)
|
||||||
|
// {
|
||||||
|
// logger.LogDebug($"Для шаблона id {template.Id} обновляю nextRun, новое значение {nextRun}, старое значение {template.NextRun}");
|
||||||
|
|
||||||
|
// template.LastRun = template.NextRun;
|
||||||
|
// template.NextRun = nextRun.Value;
|
||||||
|
|
||||||
|
// await robotConfigurationService.CommitAsync(new HistoryInitiator { InitiatorComment = "При получении задания роботом, обновил NextRun", InitiatorIp = clientService.GetClientIp()?.ToString(), InitiatorParrComponentId = ParrComponentsEnum.Api });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// /// <summary>
|
||||||
|
// /// Устанавливаем статус "Робот взял в работу", пишем в историю работы роботов инф о начале работ
|
||||||
|
// /// </summary>
|
||||||
|
// /// <param name="taskId"></param>
|
||||||
|
// /// <returns></returns>
|
||||||
|
// private async Task<bool> SetInProgressStatusAsync(Guid taskId)
|
||||||
|
// {
|
||||||
|
// var config = await robotConfigurationService.GetAsync(taskId);
|
||||||
|
|
||||||
|
// //изменение статуса робота
|
||||||
|
// robotConfigurationService.ChangeRobotStatus(RobotStatusEnum.InProgress, config!);
|
||||||
|
|
||||||
|
// if (!await robotConfigurationService.CommitAsync())
|
||||||
|
// return false;
|
||||||
|
|
||||||
|
// //записываем в лог робота
|
||||||
|
// var history = new RobotHistory
|
||||||
|
// {
|
||||||
|
// Id = Guid.NewGuid(),
|
||||||
|
// HistoryLevel = (int)RobotHistoryLevelEnum.Start,
|
||||||
|
// TaskStatusCode = config.TaskStatusCode,
|
||||||
|
// RobotConfigurationId = config.Id,
|
||||||
|
// RobotIp = clientService.GetClientIp()?.ToString()
|
||||||
|
// };
|
||||||
|
|
||||||
|
// if (!await robotHistoryService.CreateAsync(history) || !await robotHistoryService.CommitAsync())
|
||||||
|
// return false;
|
||||||
|
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// /// <summary>
|
||||||
|
// /// Приводит переносы строк в тексте к формату CRLF (\r\n)
|
||||||
|
// /// </summary>
|
||||||
|
// /// <param name="text">Исходный текст</param>
|
||||||
|
// /// <returns>Текст с унифицированными переносами строк</returns>
|
||||||
|
// private string NormalizeLineEndingsToCrlf(string? text)
|
||||||
|
// {
|
||||||
|
// if (string.IsNullOrEmpty(text))
|
||||||
|
// return string.Empty;
|
||||||
|
|
||||||
|
// // Заменяем любые варианты переносов (\r\n, \r, \n) на единый \r\n
|
||||||
|
// return System.Text.RegularExpressions.Regex.Replace(text, @"\r\n|\r|\n", "\r\n");
|
||||||
|
// }
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,330 +0,0 @@
|
|||||||
using AutoMapper;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
using PARR.API.Contracts.V1;
|
|
||||||
using PARR.API.Contracts.V1.Requests.Queries;
|
|
||||||
using PARR.API.Contracts.V1.Responses;
|
|
||||||
using PARR.API.Contracts.V1.Responses.Base;
|
|
||||||
using PARR.API.Controllers.V1.Base;
|
|
||||||
using PARR.API.Services.Interfaces;
|
|
||||||
using PARR.BLL.Helpers;
|
|
||||||
using PARR.Core.Repositories.Interfaces;
|
|
||||||
using PARR.Core.Services.NextRunServices;
|
|
||||||
using PARR.Core.Services.Shortcodes;
|
|
||||||
using PARR.Domain.Common.Roles;
|
|
||||||
using PARR.Domain.Entities;
|
|
||||||
using PARR.Domain.Entities.Base.History;
|
|
||||||
using PARR.Domain.Enums;
|
|
||||||
using PARR.Domain.Settings;
|
|
||||||
|
|
||||||
namespace PARR.API.Controllers.V1
|
|
||||||
{
|
|
||||||
[Authorize(Roles = ParrRoles.EsppRobot.RoleOrAdmin)]
|
|
||||||
public class RobotTaskOldController : BaseApiController
|
|
||||||
{
|
|
||||||
private readonly IMapper mapper;
|
|
||||||
private readonly SettingsFromDb settingsFromDb;
|
|
||||||
private readonly IRobotConfigurationRepository robotConfigurationService;
|
|
||||||
private readonly ILogger<RobotTaskOldController> logger;
|
|
||||||
private readonly IClientService clientService;
|
|
||||||
private readonly IRobotHistoryRepository robotHistoryService;
|
|
||||||
private readonly IShortcodesService shortcodesService;
|
|
||||||
private readonly INextRunService nextRunService;
|
|
||||||
|
|
||||||
public RobotTaskOldController(
|
|
||||||
IMapper mapper,
|
|
||||||
SettingsFromDb settingsFromDb,
|
|
||||||
IRobotConfigurationRepository robotConfigurationService,
|
|
||||||
ILogger<RobotTaskOldController> logger,
|
|
||||||
IClientService clientService,
|
|
||||||
IRobotHistoryRepository robotHistoryService,
|
|
||||||
IShortcodesService shortcodesService,
|
|
||||||
INextRunService nextRunService
|
|
||||||
)
|
|
||||||
{
|
|
||||||
this.mapper = mapper;
|
|
||||||
this.settingsFromDb = settingsFromDb;
|
|
||||||
this.robotConfigurationService = robotConfigurationService;
|
|
||||||
this.logger = logger;
|
|
||||||
this.clientService = clientService;
|
|
||||||
this.robotHistoryService = robotHistoryService;
|
|
||||||
this.shortcodesService = shortcodesService;
|
|
||||||
this.nextRunService = nextRunService;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Получить задание для робота по коду робота и по статусу задания
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="robotCode"></param>
|
|
||||||
/// <param name="taskStatusCode"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
[HttpGet(ApiRoutes.RobotTask.GetByRobotAndStatusTask)]
|
|
||||||
public async Task<IActionResult> GetByRobotAndStatusTask([FromRoute] RobotsEnum robotCode, [FromRoute] TaskStatusEnum taskStatusCode, [FromQuery] RobotTaskQuery requestQuery)
|
|
||||||
{
|
|
||||||
//Ищем все задания с превышенным кол-вом попыток и с просроченным временем и ставим им статус ошибки
|
|
||||||
await robotConfigurationService.MarkExpiredTasksAsFailedAsync(settingsFromDb.RobotAttemptsNumber, settingsFromDb.RobotWaitTime);
|
|
||||||
|
|
||||||
|
|
||||||
var query = robotConfigurationService.Get()
|
|
||||||
.AsSingleQuery()
|
|
||||||
.Where(t => t.RobotCode == (int)robotCode && t.TaskStatusCode == (int)taskStatusCode);
|
|
||||||
|
|
||||||
switch (robotCode)
|
|
||||||
{
|
|
||||||
case RobotsEnum.TemplateOrder:
|
|
||||||
// шаблоны
|
|
||||||
query = query
|
|
||||||
.Include(t => t.Template)
|
|
||||||
.ThenInclude(t => t!.Unit)
|
|
||||||
.ThenInclude(t => t!.UnitValues)
|
|
||||||
.ThenInclude(t => t.Field)
|
|
||||||
.Include(t => t.Template)
|
|
||||||
.ThenInclude(t => t!.Unit)
|
|
||||||
.ThenInclude(t => t!.UnitValues)
|
|
||||||
.ThenInclude(t => t.Value)
|
|
||||||
.Include(t => t.Template)
|
|
||||||
.ThenInclude(a => a!.Job)
|
|
||||||
.ThenInclude(t => t!.Group)
|
|
||||||
.ThenInclude(g => g.GroupType)
|
|
||||||
.Include(t => t.Template)
|
|
||||||
.ThenInclude(w => w!.Job)
|
|
||||||
.ThenInclude(t => t!.Tnk)
|
|
||||||
.ThenInclude(s => s!.Subprocess)
|
|
||||||
.ThenInclude(p => p!.Process);
|
|
||||||
|
|
||||||
query = query
|
|
||||||
.Include(t => t.Template)
|
|
||||||
.ThenInclude(t => t!.UnitsInTemplate);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RobotsEnum.ScheduleOrder:
|
|
||||||
//расписание
|
|
||||||
query = query
|
|
||||||
.Include(t => t.Template)
|
|
||||||
.ThenInclude(t => t!.Unit)
|
|
||||||
.ThenInclude(t => t!.UnitValues)
|
|
||||||
.ThenInclude(t => t.Field)
|
|
||||||
.Include(t => t.Template)
|
|
||||||
.ThenInclude(t => t!.Unit)
|
|
||||||
.ThenInclude(t => t!.UnitValues)
|
|
||||||
.ThenInclude(t => t.Value)
|
|
||||||
.Include(t => t.Template)
|
|
||||||
.ThenInclude(a => a!.Job)
|
|
||||||
.ThenInclude(t => t!.Group)
|
|
||||||
.ThenInclude(g => g.GroupType)
|
|
||||||
.Include(t => t.Template)
|
|
||||||
.ThenInclude(a => a!.Job)
|
|
||||||
.ThenInclude(t => t!.Group)
|
|
||||||
.ThenInclude(t => t!.EsppSchValues)
|
|
||||||
.ThenInclude(t => t!.EsppSchTypeConfig)
|
|
||||||
.ThenInclude(t => t!.EsppSchTypeSchedule)
|
|
||||||
.Include(t => t.Template)
|
|
||||||
.ThenInclude(t => t!.Job)
|
|
||||||
.ThenInclude(t => t!.Group)
|
|
||||||
.ThenInclude(t => t!.ScheduleExcludeType)
|
|
||||||
.Include(t => t.Template)
|
|
||||||
.ThenInclude(t => t!.Job)
|
|
||||||
.ThenInclude(t => t!.Group)
|
|
||||||
.ThenInclude(t => t.ScheduleExcludeTypeCalendar)
|
|
||||||
.Include(t => t.Template)
|
|
||||||
.ThenInclude(t => t!.Job)
|
|
||||||
.ThenInclude(t => t!.Tnk)
|
|
||||||
.Include(t => t.Template)
|
|
||||||
.ThenInclude(t => t!.UnitsInTemplate);
|
|
||||||
|
|
||||||
//выбираем только записи с созданными шаблонами (у которых статус 20 или 30), а только потом у них ищем расписания
|
|
||||||
var createdTemplates = robotConfigurationService.Get()
|
|
||||||
.Where(t => t.RobotCode == (int)RobotsEnum.TemplateOrder && (t.TaskStatusCode == (int)TaskStatusEnum.Ok))
|
|
||||||
.Select(t => t.TemplateId);
|
|
||||||
query = query.Where(t => t.RobotCode == (int)RobotsEnum.ScheduleOrder && createdTemplates.Contains(t.TemplateId));
|
|
||||||
// query = query.Where(t => t.RobotCode == (int)RobotsEnum.ScheduleOrder && t.TemplateId==Guid.Parse("7cb7c3be-506d-40e0-a63f-4554edb52459"));
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// сортируем по NextRun, чтобы те у которых дата след срабатывания ближе к текущей, выполнились скорее
|
|
||||||
query = query.OrderBy(t => t.Template!.NextRun).ThenBy(t => t.Template!.IsActiveSchedule).ThenBy(t => t.Template.IsActiveTemplate);
|
|
||||||
|
|
||||||
RobotConfiguration? task = null;
|
|
||||||
|
|
||||||
//ищем задание в ожидании, если нашли, выбираем его
|
|
||||||
task = await query.FirstOrDefaultAsync(t => t.RobotStatusCode == (int)RobotStatusEnum.Wait);
|
|
||||||
|
|
||||||
if (task == null)
|
|
||||||
{
|
|
||||||
//ищем задания в работе, которые можно перезапустить
|
|
||||||
//Поиск по `RobotStatusCode` = 22.
|
|
||||||
//Далее проверяется `LastStatusUpdated`, что время последнего смены статуса не превышает допустимого(берется из настроек, поле `RobotWaitTime`)
|
|
||||||
//и что текущая попытка не больше разрешенной(берется из настроек, поле `RobotAttemptsNumber`) - если это так, берется эта запись.
|
|
||||||
|
|
||||||
var endDate = DateTimeOffset.UtcNow.Add(-settingsFromDb.RobotWaitTime);
|
|
||||||
task = await query
|
|
||||||
.FirstOrDefaultAsync(t =>
|
|
||||||
t.RobotStatusCode == (int)RobotStatusEnum.InProgress
|
|
||||||
&& t.AttemptsNumber < settingsFromDb.RobotAttemptsNumber
|
|
||||||
&& t.LastRobotStatusUpdated < endDate
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (task == null)
|
|
||||||
return NotFound();
|
|
||||||
|
|
||||||
if (requestQuery?.SetInProgressStatus == true)
|
|
||||||
{
|
|
||||||
var resultSetStatus = await SetInProgressStatusAsync(task.Id);
|
|
||||||
if (resultSetStatus == false)
|
|
||||||
{
|
|
||||||
logger.LogError($"Ошибка при установке статуса {RobotStatusEnum.InProgress.ToString()} для задания RobotConfigutationId {task.Id} (при выдаче задания роботу)");
|
|
||||||
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Ошибка при выдаче задания." } }));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (robotCode)
|
|
||||||
{
|
|
||||||
case RobotsEnum.TemplateOrder:
|
|
||||||
{ //RobotTaskTemplateResponse
|
|
||||||
var robotTaskTemplateResponse = mapper.Map<RobotTaskTemplateResponse>(task);
|
|
||||||
|
|
||||||
robotTaskTemplateResponse.FullDescription = NormalizeLineEndingsToCrlf(await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.FullDescription, task.Template!));
|
|
||||||
robotTaskTemplateResponse.ShortDescription = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.ShortDescription, task.Template!);
|
|
||||||
robotTaskTemplateResponse.Solution = NormalizeLineEndingsToCrlf(await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.Solution, task.Template!));
|
|
||||||
robotTaskTemplateResponse.TnkName = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.TnkName, task.Template!);
|
|
||||||
robotTaskTemplateResponse.WorkName = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.WorkName, task.Template!);
|
|
||||||
robotTaskTemplateResponse.WorkGroup = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.WorkGroup, task.Template!);
|
|
||||||
robotTaskTemplateResponse.ResponseArea = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.ResponseArea, task.Template!);
|
|
||||||
|
|
||||||
return Ok(new Response<RobotTaskTemplateResponse>(robotTaskTemplateResponse, true));
|
|
||||||
}
|
|
||||||
case RobotsEnum.ScheduleOrder:
|
|
||||||
{ // если был запрос на расписание, проверяем у него nextRun, lastRun, обновляем их
|
|
||||||
var resultUpdateNextRun = await UpdateNextRunAsync(task);
|
|
||||||
if (!resultUpdateNextRun)
|
|
||||||
{
|
|
||||||
logger.LogError("Ошибка при расчете NextRun для templateId: {templateId}", task.TemplateId);
|
|
||||||
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Ошибка при расчете NextRun" } }));
|
|
||||||
}
|
|
||||||
|
|
||||||
//RobotTaskScheduleResponse
|
|
||||||
var robotTaskScheduleResponse = mapper.Map<RobotTaskScheduleResponse>(task);
|
|
||||||
|
|
||||||
robotTaskScheduleResponse.Timezone = settingsFromDb.EsppScheduleTimezone;
|
|
||||||
|
|
||||||
robotTaskScheduleResponse.WorkGroup = await shortcodesService.ApplyShortcodesAsync(robotTaskScheduleResponse.WorkGroup, task.Template!);
|
|
||||||
robotTaskScheduleResponse.ResponseArea = await shortcodesService.ApplyShortcodesAsync(robotTaskScheduleResponse.ResponseArea, task.Template!);
|
|
||||||
|
|
||||||
//var nextRunWithRobotTz = nextRunService.GetNextRunWithTimezoneEsppAndResponseArea(task.Template!.NextRun, task.Template!.Job?.Group?.IsResponseAreaTimezone, robotTaskScheduleResponse.ResponseArea);
|
|
||||||
//nextRun в часовой зоне УЗ Робота ЕСПП
|
|
||||||
var nextRunWithRobotTz = task.Template!.NextRun.Add(nextRunService.GetEsppAccountOffset());
|
|
||||||
|
|
||||||
//на всякий случай еще раз проверяем, что дата не устарела и отправляем задание
|
|
||||||
if (nextRunWithRobotTz < DateTimeOffset.UtcNow)
|
|
||||||
{
|
|
||||||
logger.LogError("Ошибка при расчете NextRun для templateId: {templateId}, итоговое значение для робота, меньше чем сейчас {nextRunWithRobotTz}<{now}",
|
|
||||||
task.TemplateId, nextRunWithRobotTz, DateTimeOffset.UtcNow);
|
|
||||||
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Ошибка при расчете NextRun" } }));
|
|
||||||
}
|
|
||||||
|
|
||||||
robotTaskScheduleResponse.NextStart = EsppScheduleHelpers.GetNextRun(nextRunWithRobotTz);
|
|
||||||
robotTaskScheduleResponse.GenerationTime = EsppScheduleHelpers.GetGenerationTime(nextRunWithRobotTz);
|
|
||||||
|
|
||||||
return Ok(new Response<RobotTaskScheduleResponse>(robotTaskScheduleResponse, true));
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return BadRequest();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Обоновить NextRun если он устарел
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="task"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private async Task<bool> UpdateNextRunAsync(RobotConfiguration task)
|
|
||||||
{
|
|
||||||
var template = task.Template!;
|
|
||||||
|
|
||||||
//var nextRun = await esppScheduleTransformService.GetNextDateAsync(template.Job!.GroupId, template!.Job!.Group!.ReferenceDate);
|
|
||||||
var nextRun = await nextRunService.GetNextRunForTemplateAsync(template.Id, false);
|
|
||||||
|
|
||||||
if (!nextRun.HasValue)
|
|
||||||
{
|
|
||||||
logger.LogError("При обновлении nextRun для шаблона {templateId}, расчитанный nextRun=null, ошибка в расчетах.", template.Id);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nextRun.Value < DateTimeOffset.UtcNow)
|
|
||||||
{
|
|
||||||
logger.LogError("При обновлении nextRun для шаблона {templateId}, расчитанный nextRun<Now [{nextRun}<{now}], ошибка в расчетах.", template.Id, nextRun.Value, DateTimeOffset.UtcNow);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nextRun != template.NextRun)
|
|
||||||
{
|
|
||||||
logger.LogDebug($"Для шаблона id {template.Id} обновляю nextRun, новое значение {nextRun}, старое значение {template.NextRun}");
|
|
||||||
|
|
||||||
template.LastRun = template.NextRun;
|
|
||||||
template.NextRun = nextRun.Value;
|
|
||||||
|
|
||||||
await robotConfigurationService.CommitAsync(new HistoryInitiator { InitiatorComment = "При получении задания роботом, обновил NextRun", InitiatorIp = clientService.GetClientIp()?.ToString(), InitiatorParrComponentId = ParrComponentsEnum.Api });
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Устанавливаем статус "Робот взял в работу", пишем в историю работы роботов инф о начале работ
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="taskId"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private async Task<bool> SetInProgressStatusAsync(Guid taskId)
|
|
||||||
{
|
|
||||||
var config = await robotConfigurationService.GetAsync(taskId);
|
|
||||||
|
|
||||||
//изменение статуса робота
|
|
||||||
robotConfigurationService.ChangeRobotStatus(RobotStatusEnum.InProgress, config!);
|
|
||||||
|
|
||||||
if (!await robotConfigurationService.CommitAsync())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
//записываем в лог робота
|
|
||||||
var history = new RobotHistory
|
|
||||||
{
|
|
||||||
Id = Guid.NewGuid(),
|
|
||||||
HistoryLevel = (int)RobotHistoryLevelEnum.Start,
|
|
||||||
TaskStatusCode = config.TaskStatusCode,
|
|
||||||
RobotConfigurationId = config.Id,
|
|
||||||
RobotIp = clientService.GetClientIp()?.ToString()
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!await robotHistoryService.CreateAsync(history) || !await robotHistoryService.CommitAsync())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Приводит переносы строк в тексте к формату CRLF (\r\n)
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="text">Исходный текст</param>
|
|
||||||
/// <returns>Текст с унифицированными переносами строк</returns>
|
|
||||||
private string NormalizeLineEndingsToCrlf(string? text)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(text))
|
|
||||||
return string.Empty;
|
|
||||||
|
|
||||||
// Заменяем любые варианты переносов (\r\n, \r, \n) на единый \r\n
|
|
||||||
return System.Text.RegularExpressions.Regex.Replace(text, @"\r\n|\r|\n", "\r\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -32,6 +32,7 @@ namespace PARR.API.Infrastructure.Middleware
|
|||||||
AlreadyExistsException => StatusCodes.Status409Conflict,
|
AlreadyExistsException => StatusCodes.Status409Conflict,
|
||||||
UnauthorizedException => StatusCodes.Status401Unauthorized,
|
UnauthorizedException => StatusCodes.Status401Unauthorized,
|
||||||
ForbiddenException => StatusCodes.Status403Forbidden,
|
ForbiddenException => StatusCodes.Status403Forbidden,
|
||||||
|
NextRunException => StatusCodes.Status422UnprocessableEntity,
|
||||||
//todo: ---------- другие ошибки ----------
|
//todo: ---------- другие ошибки ----------
|
||||||
_ => StatusCodes.Status500InternalServerError
|
_ => StatusCodes.Status500InternalServerError
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using PARR.API.Contracts.V1.Responses.Statistics;
|
|||||||
using PARR.API.MappingProfiles.Resolvers;
|
using PARR.API.MappingProfiles.Resolvers;
|
||||||
using PARR.Core.Repositories.Interfaces.Schedule;
|
using PARR.Core.Repositories.Interfaces.Schedule;
|
||||||
using PARR.Domain.DTOs.Matching;
|
using PARR.Domain.DTOs.Matching;
|
||||||
|
using PARR.Domain.DTOs.RobotTask;
|
||||||
using PARR.Domain.DTOs.Shortcode;
|
using PARR.Domain.DTOs.Shortcode;
|
||||||
using PARR.Domain.DTOs.TaskDTO;
|
using PARR.Domain.DTOs.TaskDTO;
|
||||||
using PARR.Domain.DTOs.Workload;
|
using PARR.Domain.DTOs.Workload;
|
||||||
@@ -180,64 +181,73 @@ namespace PARR.API.MappingProfiles
|
|||||||
|
|
||||||
#region RobotConfiguration
|
#region RobotConfiguration
|
||||||
// --- RobotConfiguration ---
|
// --- RobotConfiguration ---
|
||||||
CreateMap<RobotConfiguration, RobotTaskBaseResponse>()
|
|
||||||
.Include<RobotConfiguration, RobotTaskTemplateResponse>()
|
|
||||||
.Include<RobotConfiguration, RobotTaskScheduleResponse>()
|
|
||||||
.ForMember(d => d.TaskId, o => o.MapFrom(s => s.Id));
|
|
||||||
|
|
||||||
CreateMap<RobotConfiguration, RobotTaskTemplateResponse>()
|
CreateMap<RobotTaskTemplate, RobotTaskTemplateResponse>();
|
||||||
.ForMember(d => d.IsActive, o => o.MapFrom(s => s.Template!.IsActiveTemplate))
|
CreateMap<RobotTaskSchedule, RobotTaskScheduleResponse>();
|
||||||
.ForMember(d => d.ClosingCode, o => o.MapFrom<RobotTaskTemplateClosingCodeResolver>())
|
|
||||||
.ForMember(d => d.FullDescription, o => o.MapFrom(s => s.Template!.Job!.Group!.FullDescription))
|
|
||||||
.ForMember(d => d.ShortDescription, o => o.MapFrom(s => s.Template!.Job!.Group!.ShortDescription))
|
|
||||||
.ForMember(d => d.Solution, o => o.MapFrom(s => s.Template!.Job!.Group!.Solution))
|
|
||||||
//.ForMember(d => d.ResponseArea, o => o.MapFrom(s => s.Template!.Host!.ResponseArea!.Name))
|
|
||||||
//ЗО берем у группы а не у хоста
|
|
||||||
.ForMember(d => d.ResponseArea, o => o.MapFrom(s => s.Template!.Unit!.BaseFields!.ResponseArea))
|
|
||||||
.ForMember(d => d.TemplateDuration, o => o.MapFrom(s => s.Template!.Job!.Group!.TemplateDuration))
|
|
||||||
.ForMember(d => d.Initiator, o => o.MapFrom<RobotTaskTemplateInitiatorResolver>())
|
|
||||||
.ForMember(d => d.Category, o => o.MapFrom<RobotTaskTemplateCategoryResolver>())
|
|
||||||
.ForMember(d => d.WorkGroup, o => o.MapFrom(s => s.Template!.Job!.WorkGroupMask))
|
|
||||||
.ForMember(d => d.Ek, o => o.MapFrom(s => s.Template!.Unit!.Name))
|
|
||||||
.ForMember(d => d.Name, o => o.MapFrom(s => s.Template!.Name))
|
|
||||||
.ForMember(d => d.ProcessName, o => o.MapFrom(s => s.Template!.Job!.Tnk!.Subprocess!.Process!.Name))
|
|
||||||
.ForMember(d => d.ProcessEsppId, o => o.MapFrom(s => s.Template!.Job!.Tnk!.Subprocess!.Process!.EsppId))
|
|
||||||
.ForMember(d => d.SubprocessName, o => o.MapFrom(s => s.Template!.Job!.Tnk!.Subprocess!.Name))
|
|
||||||
.ForMember(d => d.SubprocessEsppId, o => o.MapFrom(s => s.Template!.Job!.Tnk!.Subprocess!.EsppId))
|
|
||||||
.ForMember(d => d.TnkName, o => o.MapFrom(s => s.Template!.Job!.Tnk!.Name))
|
|
||||||
.ForMember(d => d.TnkEsppId, o => o.MapFrom(s =>
|
|
||||||
s.Template!.Job!.Tnk!.EsppId.HasValue
|
|
||||||
? s.Template!.Job!.Tnk!.EsppId.Value.ToString()
|
|
||||||
: string.Empty
|
|
||||||
))
|
|
||||||
.ForMember(d => d.WorkName, o => o.MapFrom(s => s.Template!.Job!.WorkName))
|
|
||||||
//.ForMember(d => d.WorkEsppId, o => o.MapFrom(s => s.Template!.Job!.EsppId))
|
|
||||||
.ForMember(d => d.ScheduleEsppId, o => o.MapFrom(s => s.Template!.ScheduleEsppId));
|
|
||||||
|
|
||||||
CreateMap<RobotConfiguration, RobotTaskScheduleResponse>()
|
CreateMap<RobotTaskScheduleSch, RobotTaskScheduleSchResponse>();
|
||||||
.ForMember(d => d.EsppId, o => o.MapFrom(s => s.Template!.ScheduleEsppId))
|
|
||||||
.ForMember(d => d.ScheduleName, o => o.MapFrom(s => s.Template!.Name))
|
#region old robot task
|
||||||
.ForMember(d => d.IsActive, o => o.MapFrom(s => s.Template!.IsActiveSchedule))
|
//CreateMap<RobotConfiguration, RobotTaskBaseResponse>()
|
||||||
.ForMember(d => d.ResponseArea, o => o.MapFrom(s => s.Template!.Unit!.BaseFields!.ResponseArea))
|
// .Include<RobotConfiguration, RobotTaskTemplateResponse>()
|
||||||
.ForMember(d => d.TemplateName, o => o.MapFrom(s => s.Template!.Name))
|
// .Include<RobotConfiguration, RobotTaskScheduleResponse>()
|
||||||
.ForMember(d => d.TemplateId, o => o.MapFrom(s => s.Template!.Id))
|
// .ForMember(d => d.TaskId, o => o.MapFrom(s => s.Id));
|
||||||
.ForMember(d => d.WorkGroup, o => o.MapFrom(s => s.Template!.Job!.WorkGroupMask))
|
|
||||||
//.ForMember(d => d.Exclude, o => o.MapFrom<RobotTaskScheduleExcludeResolver>())
|
//CreateMap<RobotConfiguration, RobotTaskTemplateResponse>()
|
||||||
.ForMember(d => d.Exclude, o => o.MapFrom(s => s.Template!.Job!.Group!.ScheduleExcludeType!.EsppName))
|
// .ForMember(d => d.IsActive, o => o.MapFrom(s => s.Template!.IsActiveTemplate))
|
||||||
//.ForMember(d => d.ExcludeCalendar, o => o.MapFrom<RobotTaskScheduleExcludeCalendarResolver>())
|
// .ForMember(d => d.ClosingCode, o => o.MapFrom<RobotTaskTemplateClosingCodeResolver>())
|
||||||
.ForMember(d => d.ExcludeCalendar, o => o.MapFrom(s => s.Template!.Job!.Group!.ScheduleExcludeTypeCalendar != null ? s.Template!.Job!.Group!.ScheduleExcludeTypeCalendar.EsppName : null))
|
// .ForMember(d => d.FullDescription, o => o.MapFrom(s => s.Template!.Job!.Group!.FullDescription))
|
||||||
//.ForMember(d => d.Timezone, o => o.MapFrom<RobotTaskScheduleTimezoneResolver>())
|
// .ForMember(d => d.ShortDescription, o => o.MapFrom(s => s.Template!.Job!.Group!.ShortDescription))
|
||||||
.ForMember(d => d.RepeatRange, o => o.MapFrom<RobotTaskScheduleRepeatRangeResolver>())
|
// .ForMember(d => d.Solution, o => o.MapFrom(s => s.Template!.Job!.Group!.Solution))
|
||||||
//todo: GenerationTime
|
// //.ForMember(d => d.ResponseArea, o => o.MapFrom(s => s.Template!.Host!.ResponseArea!.Name))
|
||||||
//.ForMember(d => d.GenerationTime, o => o.MapFrom(s => EsppScheduleHelpers.GetGenerationTime(s.Template!.NextRun)))
|
// //ЗО берем у группы а не у хоста
|
||||||
//.ForMember(d => d.GenerationTime, o => o.MapFrom<RobotTaskScheduleGenerationTimeResolver>())
|
// .ForMember(d => d.ResponseArea, o => o.MapFrom(s => s.Template!.Unit!.BaseFields!.ResponseArea))
|
||||||
//.ForMember(d => d.NextStart, o => o.MapFrom(s => EsppScheduleHelpers.GetNextRun(s.Template!.NextRun)))
|
// .ForMember(d => d.TemplateDuration, o => o.MapFrom(s => s.Template!.Job!.Group!.TemplateDuration))
|
||||||
//.ForMember(d => d.NextStart, o => o.MapFrom<RobotTaskScheduleNextStartResolver>())
|
// .ForMember(d => d.Initiator, o => o.MapFrom<RobotTaskTemplateInitiatorResolver>())
|
||||||
.ForMember(d => d.ScheduleType, o => o.MapFrom(s =>
|
// .ForMember(d => d.Category, o => o.MapFrom<RobotTaskTemplateCategoryResolver>())
|
||||||
s.Template!.Job!.Group!.EsppSchValues!.First()!.EsppSchTypeConfig!.EsppSchTypeSchedule!.Description))
|
// .ForMember(d => d.WorkGroup, o => o.MapFrom(s => s.Template!.Job!.WorkGroupMask))
|
||||||
.ForMember(d => d.ScheduleTypeCode, o => o.MapFrom(s =>
|
// .ForMember(d => d.Ek, o => o.MapFrom(s => s.Template!.Unit!.Name))
|
||||||
s.Template!.Job!.Group!.EsppSchValues!.First()!.EsppSchTypeConfig!.EsppSchTypeSchedule!.Id))
|
// .ForMember(d => d.Name, o => o.MapFrom(s => s.Template!.Name))
|
||||||
.ForMember(d => d.Schedule, o => o.MapFrom<RobotTaskScheduleSchResolver>());
|
// .ForMember(d => d.ProcessName, o => o.MapFrom(s => s.Template!.Job!.Tnk!.Subprocess!.Process!.Name))
|
||||||
|
// .ForMember(d => d.ProcessEsppId, o => o.MapFrom(s => s.Template!.Job!.Tnk!.Subprocess!.Process!.EsppId))
|
||||||
|
// .ForMember(d => d.SubprocessName, o => o.MapFrom(s => s.Template!.Job!.Tnk!.Subprocess!.Name))
|
||||||
|
// .ForMember(d => d.SubprocessEsppId, o => o.MapFrom(s => s.Template!.Job!.Tnk!.Subprocess!.EsppId))
|
||||||
|
// .ForMember(d => d.TnkName, o => o.MapFrom(s => s.Template!.Job!.Tnk!.Name))
|
||||||
|
// .ForMember(d => d.TnkEsppId, o => o.MapFrom(s =>
|
||||||
|
// s.Template!.Job!.Tnk!.EsppId.HasValue
|
||||||
|
// ? s.Template!.Job!.Tnk!.EsppId.Value.ToString()
|
||||||
|
// : string.Empty
|
||||||
|
// ))
|
||||||
|
// .ForMember(d => d.WorkName, o => o.MapFrom(s => s.Template!.Job!.WorkName))
|
||||||
|
// //.ForMember(d => d.WorkEsppId, o => o.MapFrom(s => s.Template!.Job!.EsppId))
|
||||||
|
// .ForMember(d => d.ScheduleEsppId, o => o.MapFrom(s => s.Template!.ScheduleEsppId));
|
||||||
|
|
||||||
|
//CreateMap<RobotConfiguration, RobotTaskScheduleResponse>()
|
||||||
|
// .ForMember(d => d.EsppId, o => o.MapFrom(s => s.Template!.ScheduleEsppId))
|
||||||
|
// .ForMember(d => d.ScheduleName, o => o.MapFrom(s => s.Template!.Name))
|
||||||
|
// .ForMember(d => d.IsActive, o => o.MapFrom(s => s.Template!.IsActiveSchedule))
|
||||||
|
// .ForMember(d => d.ResponseArea, o => o.MapFrom(s => s.Template!.Unit!.BaseFields!.ResponseArea))
|
||||||
|
// .ForMember(d => d.TemplateName, o => o.MapFrom(s => s.Template!.Name))
|
||||||
|
// .ForMember(d => d.TemplateId, o => o.MapFrom(s => s.Template!.Id))
|
||||||
|
// .ForMember(d => d.WorkGroup, o => o.MapFrom(s => s.Template!.Job!.WorkGroupMask))
|
||||||
|
// //.ForMember(d => d.Exclude, o => o.MapFrom<RobotTaskScheduleExcludeResolver>())
|
||||||
|
// .ForMember(d => d.Exclude, o => o.MapFrom(s => s.Template!.Job!.Group!.ScheduleExcludeType!.EsppName))
|
||||||
|
// //.ForMember(d => d.ExcludeCalendar, o => o.MapFrom<RobotTaskScheduleExcludeCalendarResolver>())
|
||||||
|
// .ForMember(d => d.ExcludeCalendar, o => o.MapFrom(s => s.Template!.Job!.Group!.ScheduleExcludeTypeCalendar != null ? s.Template!.Job!.Group!.ScheduleExcludeTypeCalendar.EsppName : null))
|
||||||
|
// //.ForMember(d => d.Timezone, o => o.MapFrom<RobotTaskScheduleTimezoneResolver>())
|
||||||
|
// .ForMember(d => d.RepeatRange, o => o.MapFrom<RobotTaskScheduleRepeatRangeResolver>())
|
||||||
|
// //todo: GenerationTime
|
||||||
|
// //.ForMember(d => d.GenerationTime, o => o.MapFrom(s => EsppScheduleHelpers.GetGenerationTime(s.Template!.NextRun)))
|
||||||
|
// //.ForMember(d => d.GenerationTime, o => o.MapFrom<RobotTaskScheduleGenerationTimeResolver>())
|
||||||
|
// //.ForMember(d => d.NextStart, o => o.MapFrom(s => EsppScheduleHelpers.GetNextRun(s.Template!.NextRun)))
|
||||||
|
// //.ForMember(d => d.NextStart, o => o.MapFrom<RobotTaskScheduleNextStartResolver>())
|
||||||
|
// .ForMember(d => d.ScheduleType, o => o.MapFrom(s =>
|
||||||
|
// s.Template!.Job!.Group!.EsppSchValues!.First()!.EsppSchTypeConfig!.EsppSchTypeSchedule!.Description))
|
||||||
|
// .ForMember(d => d.ScheduleTypeCode, o => o.MapFrom(s =>
|
||||||
|
// s.Template!.Job!.Group!.EsppSchValues!.First()!.EsppSchTypeConfig!.EsppSchTypeSchedule!.Id))
|
||||||
|
// .ForMember(d => d.Schedule, o => o.MapFrom<RobotTaskScheduleSchResolver>());
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
CreateMap<Robot, RobotResponse>();
|
CreateMap<Robot, RobotResponse>();
|
||||||
|
|
||||||
@@ -460,7 +470,7 @@ namespace PARR.API.MappingProfiles
|
|||||||
//CreateMap<TaskItemBase, TaskItemResponse>();
|
//CreateMap<TaskItemBase, TaskItemResponse>();
|
||||||
|
|
||||||
CreateMap<ActiveTask, ActiveTaskResponse>();
|
CreateMap<ActiveTask, ActiveTaskResponse>();
|
||||||
|
|
||||||
// ---
|
// ---
|
||||||
|
|
||||||
CreateMap<TaskType, TaskItemTypeResponse>();
|
CreateMap<TaskType, TaskItemTypeResponse>();
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using PARR.Core.Repositories.Interfaces.Schedule;
|
||||||
|
using PARR.Domain.DTOs.RobotTask;
|
||||||
|
using PARR.Domain.Entities;
|
||||||
|
|
||||||
|
namespace PARR.Core.Infrastructure.Mapping.RobotTask.Resolvers
|
||||||
|
{
|
||||||
|
public class RobotTaskScheduleSchResolver : IValueResolver<RobotConfiguration, RobotTaskSchedule, List<RobotTaskScheduleSch>?>
|
||||||
|
{
|
||||||
|
private readonly IEsppSchTypeConfigRepository esppConfigRepository;
|
||||||
|
private readonly ILogger<RobotTaskScheduleSchResolver> logger;
|
||||||
|
|
||||||
|
public RobotTaskScheduleSchResolver(
|
||||||
|
IEsppSchTypeConfigRepository esppConfigRepository,
|
||||||
|
ILogger<RobotTaskScheduleSchResolver> logger
|
||||||
|
)
|
||||||
|
{
|
||||||
|
this.esppConfigRepository = esppConfigRepository;
|
||||||
|
this.logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<RobotTaskScheduleSch>? Resolve(RobotConfiguration source, RobotTaskSchedule destination, List<RobotTaskScheduleSch>? destMember, ResolutionContext context)
|
||||||
|
{
|
||||||
|
var jobGroupId = source.Template!.Job!.GroupId;
|
||||||
|
|
||||||
|
var schedule = esppConfigRepository.GetEsppScheduleDto(jobGroupId);
|
||||||
|
|
||||||
|
if (schedule == null)
|
||||||
|
{
|
||||||
|
logger.LogError("RobotTaskScheduleSchResolver: Не смог замапить расписание для робота, так как оно null. JobGroupId: {JobGroupId}", jobGroupId);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var response = schedule.Values.Select(t => new RobotTaskScheduleSch
|
||||||
|
{
|
||||||
|
Order = t.Order,
|
||||||
|
Type = t.Type.Name,
|
||||||
|
TypeCode = t.Type.Id,
|
||||||
|
Value = t.Value.Value
|
||||||
|
}).OrderBy(t => t.Order).ToList();
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using PARR.Core.Infrastructure.Mapping.RobotTask.Resolvers;
|
||||||
|
using PARR.Domain.DTOs.RobotTask;
|
||||||
|
using PARR.Domain.Entities;
|
||||||
|
using PARR.Domain.Settings;
|
||||||
|
|
||||||
|
namespace PARR.Core.Infrastructure.Mapping.RobotTask
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Маппинг RobotTask
|
||||||
|
/// </summary>
|
||||||
|
internal class RobotTaskMappingProfile : Profile
|
||||||
|
{
|
||||||
|
public RobotTaskMappingProfile()
|
||||||
|
{
|
||||||
|
|
||||||
|
CreateMap<RobotConfiguration, RobotTaskBase>()
|
||||||
|
.Include<RobotConfiguration, RobotTaskTemplate>()
|
||||||
|
.Include<RobotConfiguration, RobotTaskSchedule>()
|
||||||
|
.ForMember(d => d.TaskId, o => o.MapFrom(s => s.Id));
|
||||||
|
|
||||||
|
// Задание роботам, шаблоны
|
||||||
|
CreateMap<RobotConfiguration, RobotTaskTemplate>()
|
||||||
|
.ForMember(d => d.IsActive, o => o.MapFrom(s => s.Template!.IsActiveTemplate))
|
||||||
|
//.ForMember(d => d.ClosingCode, o => o.MapFrom<RobotTaskTemplateClosingCodeResolver>())
|
||||||
|
.ForMember(d => d.FullDescription, o => o.MapFrom(s => s.Template!.Job!.Group!.FullDescription))
|
||||||
|
.ForMember(d => d.ShortDescription, o => o.MapFrom(s => s.Template!.Job!.Group!.ShortDescription))
|
||||||
|
.ForMember(d => d.Solution, o => o.MapFrom(s => s.Template!.Job!.Group!.Solution))
|
||||||
|
//ЗО берем у группы а не у хоста
|
||||||
|
.ForMember(d => d.ResponseArea, o => o.MapFrom(s => s.Template!.Unit!.BaseFields!.ResponseArea))
|
||||||
|
.ForMember(d => d.TemplateDuration, o => o.MapFrom(s => s.Template!.Job!.Group!.TemplateDuration))
|
||||||
|
//.ForMember(d => d.Initiator, o => o.MapFrom<RobotTaskTemplateInitiatorResolver>())
|
||||||
|
//.ForMember(d => d.Category, o => o.MapFrom<RobotTaskTemplateCategoryResolver>())
|
||||||
|
.ForMember(d => d.WorkGroup, o => o.MapFrom(s => s.Template!.Job!.WorkGroupMask))
|
||||||
|
.ForMember(d => d.Ek, o => o.MapFrom(s => s.Template!.Unit!.Name))
|
||||||
|
.ForMember(d => d.Name, o => o.MapFrom(s => s.Template!.Name))
|
||||||
|
.ForMember(d => d.ProcessName, o => o.MapFrom(s => s.Template!.Job!.Tnk!.Subprocess!.Process!.Name))
|
||||||
|
.ForMember(d => d.ProcessEsppId, o => o.MapFrom(s => s.Template!.Job!.Tnk!.Subprocess!.Process!.EsppId))
|
||||||
|
.ForMember(d => d.SubprocessName, o => o.MapFrom(s => s.Template!.Job!.Tnk!.Subprocess!.Name))
|
||||||
|
.ForMember(d => d.SubprocessEsppId, o => o.MapFrom(s => s.Template!.Job!.Tnk!.Subprocess!.EsppId))
|
||||||
|
.ForMember(d => d.TnkName, o => o.MapFrom(s => s.Template!.Job!.Tnk!.Name))
|
||||||
|
.ForMember(d => d.TnkEsppId, o => o.MapFrom(s =>
|
||||||
|
s.Template!.Job!.Tnk!.EsppId.HasValue
|
||||||
|
? s.Template!.Job!.Tnk!.EsppId.Value.ToString()
|
||||||
|
: string.Empty
|
||||||
|
))
|
||||||
|
.ForMember(d => d.WorkName, o => o.MapFrom(s => s.Template!.Job!.WorkName))
|
||||||
|
.ForMember(d => d.ScheduleEsppId, o => o.MapFrom(s => s.Template!.ScheduleEsppId));
|
||||||
|
|
||||||
|
|
||||||
|
// Задание роботам, расписания
|
||||||
|
CreateMap<RobotConfiguration, RobotTaskSchedule>()
|
||||||
|
.ForMember(d => d.EsppId, o => o.MapFrom(s => s.Template!.ScheduleEsppId))
|
||||||
|
.ForMember(d => d.ScheduleName, o => o.MapFrom(s => s.Template!.Name))
|
||||||
|
.ForMember(d => d.IsActive, o => o.MapFrom(s => s.Template!.IsActiveSchedule))
|
||||||
|
.ForMember(d => d.ResponseArea, o => o.MapFrom(s => s.Template!.Unit!.BaseFields!.ResponseArea))
|
||||||
|
.ForMember(d => d.TemplateName, o => o.MapFrom(s => s.Template!.Name))
|
||||||
|
.ForMember(d => d.TemplateId, o => o.MapFrom(s => s.Template!.Id))
|
||||||
|
.ForMember(d => d.WorkGroup, o => o.MapFrom(s => s.Template!.Job!.WorkGroupMask))
|
||||||
|
.ForMember(d => d.Exclude, o => o.MapFrom(s => s.Template!.Job!.Group!.ScheduleExcludeType!.EsppName))
|
||||||
|
.ForMember(d => d.ExcludeCalendar, o => o.MapFrom(s => s.Template!.Job!.Group!.ScheduleExcludeTypeCalendar != null ? s.Template!.Job!.Group!.ScheduleExcludeTypeCalendar.EsppName : null))
|
||||||
|
//.ForMember(d => d.RepeatRange, o => o.MapFrom<RobotTaskScheduleRepeatRangeResolver>())
|
||||||
|
.ForMember(d => d.ScheduleType, o => o.MapFrom(s =>
|
||||||
|
s.Template!.Job!.Group!.EsppSchValues!.First()!.EsppSchTypeConfig!.EsppSchTypeSchedule!.Description))
|
||||||
|
.ForMember(d => d.ScheduleTypeCode, o => o.MapFrom(s =>
|
||||||
|
s.Template!.Job!.Group!.EsppSchValues!.First()!.EsppSchTypeConfig!.EsppSchTypeSchedule!.Id))
|
||||||
|
.ForMember(d => d.Schedule, o => o.MapFrom<RobotTaskScheduleSchResolver>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,14 @@
|
|||||||
using InfluxDB.Client.Api.Domain;
|
using AutoMapper;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
using PARR.BLL.Helpers;
|
||||||
using PARR.Core.Repositories.Interfaces;
|
using PARR.Core.Repositories.Interfaces;
|
||||||
|
using PARR.Core.Services.NextRunServices;
|
||||||
using PARR.Core.Services.RobotTask.Interfaces;
|
using PARR.Core.Services.RobotTask.Interfaces;
|
||||||
|
using PARR.Core.Services.Shortcodes;
|
||||||
|
using PARR.Domain.DTOs.RobotTask;
|
||||||
using PARR.Domain.Entities;
|
using PARR.Domain.Entities;
|
||||||
|
using PARR.Domain.Entities.Base.History;
|
||||||
using PARR.Domain.Enums;
|
using PARR.Domain.Enums;
|
||||||
using PARR.Domain.Exceptions;
|
using PARR.Domain.Exceptions;
|
||||||
using PARR.Domain.Settings;
|
using PARR.Domain.Settings;
|
||||||
@@ -21,21 +26,102 @@ namespace PARR.Core.Services.RobotTask.Implementations
|
|||||||
private readonly IRobotConfigurationRepository robotConfigurationRepository;
|
private readonly IRobotConfigurationRepository robotConfigurationRepository;
|
||||||
private readonly SettingsFromDb settingsFromDb;
|
private readonly SettingsFromDb settingsFromDb;
|
||||||
private readonly IRobotHistoryRepository robotHistoryRepository;
|
private readonly IRobotHistoryRepository robotHistoryRepository;
|
||||||
|
private readonly IMapper mapper;
|
||||||
|
private readonly IShortcodesService shortcodesService;
|
||||||
|
private readonly INextRunService nextRunService;
|
||||||
|
|
||||||
public RobotTaskService(
|
public RobotTaskService(
|
||||||
ILogger<RobotTaskService> logger,
|
ILogger<RobotTaskService> logger,
|
||||||
IRobotConfigurationRepository robotConfigurationRepository,
|
IRobotConfigurationRepository robotConfigurationRepository,
|
||||||
SettingsFromDb settingsFromDb,
|
SettingsFromDb settingsFromDb,
|
||||||
IRobotHistoryRepository robotHistoryRepository
|
IRobotHistoryRepository robotHistoryRepository,
|
||||||
|
IMapper mapper,
|
||||||
|
IShortcodesService shortcodesService,
|
||||||
|
INextRunService nextRunService
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
this.robotConfigurationRepository = robotConfigurationRepository;
|
this.robotConfigurationRepository = robotConfigurationRepository;
|
||||||
this.settingsFromDb = settingsFromDb;
|
this.settingsFromDb = settingsFromDb;
|
||||||
this.robotHistoryRepository = robotHistoryRepository;
|
this.robotHistoryRepository = robotHistoryRepository;
|
||||||
|
this.mapper = mapper;
|
||||||
|
this.shortcodesService = shortcodesService;
|
||||||
|
this.nextRunService = nextRunService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task GetTaskAsync(RobotsEnum robotCode, TaskStatusEnum taskStatusCode, bool acquireTask, string? robotIp)
|
|
||||||
|
public async Task<RobotTaskTemplate> GetTemplateTaskAsync(TaskStatusEnum taskStatusCode, bool acquireTask, string? robotIp, string? robotId)
|
||||||
|
{
|
||||||
|
var templateTask = await GetTaskAsync(RobotsEnum.TemplateOrder, taskStatusCode, acquireTask, robotIp, robotId);
|
||||||
|
|
||||||
|
var task = mapper.Map<RobotTaskTemplate>(templateTask);
|
||||||
|
|
||||||
|
task = task with { FullDescription = NormalizeLineEndingsToCrlf(await shortcodesService.ApplyShortcodesAsync(task.FullDescription, templateTask.Template!)) };
|
||||||
|
task = task with { ShortDescription = await shortcodesService.ApplyShortcodesAsync(task.ShortDescription, templateTask.Template!) };
|
||||||
|
task = task with { Solution = NormalizeLineEndingsToCrlf(await shortcodesService.ApplyShortcodesAsync(task.Solution, templateTask.Template!)) };
|
||||||
|
task = task with { TnkName = await shortcodesService.ApplyShortcodesAsync(task.TnkName, templateTask.Template!) };
|
||||||
|
task = task with { WorkName = await shortcodesService.ApplyShortcodesAsync(task.WorkName, templateTask.Template!) };
|
||||||
|
task = task with { WorkGroup = await shortcodesService.ApplyShortcodesAsync(task.WorkGroup, templateTask.Template!) };
|
||||||
|
task = task with { ResponseArea = await shortcodesService.ApplyShortcodesAsync(task.ResponseArea, templateTask.Template!) };
|
||||||
|
|
||||||
|
task = task with { ClosingCode = settingsFromDb.ClosingCode };
|
||||||
|
task = task with { Initiator = settingsFromDb.Initiator };
|
||||||
|
task = task with { Category = settingsFromDb.Category };
|
||||||
|
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async Task<RobotTaskSchedule> GetScheduleTaskAsync(TaskStatusEnum taskStatusCode, bool acquireTask, string? robotIp, string? robotId, IHistoryInitiator historyInitiator)
|
||||||
|
{
|
||||||
|
var scheduleTask = await GetTaskAsync(RobotsEnum.ScheduleOrder, taskStatusCode, acquireTask, robotIp, robotId);
|
||||||
|
|
||||||
|
// Проверяем nextRun, lastRun, обновляем их
|
||||||
|
|
||||||
|
var resultUpdateNextRun = await UpdateNextRunAsync(scheduleTask, historyInitiator);
|
||||||
|
if (!resultUpdateNextRun)
|
||||||
|
{
|
||||||
|
logger.LogError("Ошибка при расчете NextRun для templateId: {templateId}", scheduleTask.TemplateId);
|
||||||
|
throw new NextRunException($"Ошибка при расчете NextRun для templateId: {scheduleTask.TemplateId}");
|
||||||
|
}
|
||||||
|
|
||||||
|
var task = mapper.Map<RobotTaskSchedule>(scheduleTask);
|
||||||
|
|
||||||
|
task = task with { Timezone = settingsFromDb.EsppScheduleTimezone };
|
||||||
|
task = task with { WorkGroup = await shortcodesService.ApplyShortcodesAsync(task.WorkGroup, scheduleTask.Template!) };
|
||||||
|
task = task with { ResponseArea = await shortcodesService.ApplyShortcodesAsync(task.ResponseArea, scheduleTask.Template!) };
|
||||||
|
|
||||||
|
//nextRun в часовой зоне УЗ Робота ЕСПП
|
||||||
|
var nextRunWithRobotTz = scheduleTask.Template!.NextRun.Add(nextRunService.GetEsppAccountOffset());
|
||||||
|
//на всякий случай еще раз проверяем, что дата не устарела и отправляем задание
|
||||||
|
if (nextRunWithRobotTz < DateTimeOffset.UtcNow)
|
||||||
|
{
|
||||||
|
logger.LogError("Ошибка при расчете NextRun для templateId: {templateId}, итоговое значение для робота, меньше чем сейчас {nextRunWithRobotTz}<{now}",
|
||||||
|
task.TemplateId, nextRunWithRobotTz, DateTimeOffset.UtcNow);
|
||||||
|
throw new NextRunException($"Ошибка при расчете NextRun для templateId: {scheduleTask.TemplateId}");
|
||||||
|
}
|
||||||
|
|
||||||
|
task = task with { NextStart = EsppScheduleHelpers.GetNextRun(nextRunWithRobotTz) };
|
||||||
|
task = task with { GenerationTime = EsppScheduleHelpers.GetGenerationTime(nextRunWithRobotTz) };
|
||||||
|
|
||||||
|
task = task with { RepeatRange = settingsFromDb.ScheduleRepeatRange };
|
||||||
|
task = task with { };
|
||||||
|
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить задачу для робота.
|
||||||
|
/// Метод может генерировать исключения.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="robotCode"></param>
|
||||||
|
/// <param name="taskStatusCode"></param>
|
||||||
|
/// <param name="acquireTask">Взять в работу</param>
|
||||||
|
/// <param name="robotIp"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
/// <exception cref="NotFoundException"></exception>
|
||||||
|
private async Task<RobotConfiguration> GetTaskAsync(RobotsEnum robotCode, TaskStatusEnum taskStatusCode, bool acquireTask, string? robotIp, string? robotId)
|
||||||
{
|
{
|
||||||
// 1. Ищем все задания с превышенным кол-вом попыток и просроченным временем, ставим им статус ошибки
|
// 1. Ищем все задания с превышенным кол-вом попыток и просроченным временем, ставим им статус ошибки
|
||||||
await robotConfigurationRepository.MarkExpiredTasksAsFailedAsync(settingsFromDb.RobotAttemptsNumber, settingsFromDb.RobotWaitTime);
|
await robotConfigurationRepository.MarkExpiredTasksAsFailedAsync(settingsFromDb.RobotAttemptsNumber, settingsFromDb.RobotWaitTime);
|
||||||
@@ -52,10 +138,10 @@ namespace PARR.Core.Services.RobotTask.Implementations
|
|||||||
if (acquireTask)
|
if (acquireTask)
|
||||||
{
|
{
|
||||||
// Берем задание в работу, устанавливаем ей статус "В работе"
|
// Берем задание в работу, устанавливаем ей статус "В работе"
|
||||||
acquiredTaskId = await AcquireTaskAsync(availableTasks, robotIp);
|
acquiredTaskId = await AcquireTaskAsync(availableTasks, robotIp, robotId);
|
||||||
|
|
||||||
if (acquiredTaskId == null)
|
if (acquiredTaskId == null)
|
||||||
throw new NotFoundException($"Не удалось взять ни одну из доступных задач ({availableTasks.Count}) в работу");
|
throw new Exception($"Не удалось взять ни одну из доступных задач ({availableTasks.Count}) в работу");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -65,13 +151,10 @@ namespace PARR.Core.Services.RobotTask.Implementations
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//3. Готовим модель ответа
|
//3. Получаем задачу со всеми нужными инклудами в зависимости от типа робота
|
||||||
var task = await GetTaskWithAllDataAsync(acquiredTaskId.Value, robotCode);
|
var task = await GetTaskWithAllDataAsync(acquiredTaskId.Value, robotCode);
|
||||||
|
|
||||||
//todo:
|
return task;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -138,7 +221,7 @@ namespace PARR.Core.Services.RobotTask.Implementations
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="taskId"></param>
|
/// <param name="taskId"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private async Task<Guid?> AcquireTaskAsync(List<Guid> tasks, string? robotIp)
|
private async Task<Guid?> AcquireTaskAsync(List<Guid> tasks, string? robotIp, string? robotId)
|
||||||
{
|
{
|
||||||
foreach (var taskId in tasks)
|
foreach (var taskId in tasks)
|
||||||
{
|
{
|
||||||
@@ -159,6 +242,8 @@ namespace PARR.Core.Services.RobotTask.Implementations
|
|||||||
TaskStatusCode = task.TaskStatusCode,
|
TaskStatusCode = task.TaskStatusCode,
|
||||||
RobotConfigurationId = taskId,
|
RobotConfigurationId = taskId,
|
||||||
RobotIp = robotIp
|
RobotIp = robotIp
|
||||||
|
//todo: Тут добавить RobotId
|
||||||
|
//RobotId = robotId
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!await robotHistoryRepository.CreateAsync(history) || !await robotHistoryRepository.CommitAsync())
|
if (!await robotHistoryRepository.CreateAsync(history) || !await robotHistoryRepository.CommitAsync())
|
||||||
@@ -186,19 +271,118 @@ namespace PARR.Core.Services.RobotTask.Implementations
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private async Task<RobotConfiguration> GetTaskWithAllDataAsync(Guid taskId, RobotsEnum robotCode)
|
private async Task<RobotConfiguration> GetTaskWithAllDataAsync(Guid taskId, RobotsEnum robotCode)
|
||||||
{
|
{
|
||||||
var query = robotConfigurationRepository.Get()
|
IQueryable<RobotConfiguration> query = robotConfigurationRepository.Get()
|
||||||
.AsNoTracking()
|
//.AsNoTracking() // нужно обязательно трекать, так как может измениться nextRun и его нужно будет сохранить
|
||||||
.AsSingleQuery()
|
.AsSingleQuery()
|
||||||
//todo: тут общие инклуды
|
// Общие инклуды для шаблонов и расписаний
|
||||||
;
|
// Units
|
||||||
|
.Include(t => t.Template)
|
||||||
|
.ThenInclude(t => t!.Unit)
|
||||||
|
.ThenInclude(t => t!.UnitValues)
|
||||||
|
.ThenInclude(t => t!.Field)
|
||||||
|
.Include(t => t.Template)
|
||||||
|
.ThenInclude(t => t!.Unit)
|
||||||
|
.ThenInclude(t => t!.UnitValues)
|
||||||
|
.ThenInclude(t => t!.Value)
|
||||||
|
.Include(t => t.Template)
|
||||||
|
.ThenInclude(t => t!.UnitsInTemplate)
|
||||||
|
// Группа с типом
|
||||||
|
.Include(t => t.Template)
|
||||||
|
.ThenInclude(t => t!.Job)
|
||||||
|
.ThenInclude(t => t!.Group)
|
||||||
|
.ThenInclude(t => t!.GroupType)
|
||||||
|
// ТНК
|
||||||
|
.Include(t => t.Template)
|
||||||
|
.ThenInclude(t => t!.Job)
|
||||||
|
.ThenInclude(t => t!.Tnk)
|
||||||
|
.ThenInclude(t => t!.Subprocess)
|
||||||
|
.ThenInclude(t => t!.Process);
|
||||||
|
|
||||||
if(robotCode== RobotsEnum.ScheduleOrder)
|
if (robotCode == RobotsEnum.ScheduleOrder)
|
||||||
{
|
{
|
||||||
// тут инклуды только для расписаний
|
// Инклуды только для расписаний
|
||||||
|
query = query
|
||||||
|
// Расписание
|
||||||
|
.Include(t => t.Template)
|
||||||
|
.ThenInclude(t => t!.Job)
|
||||||
|
.ThenInclude(t => t!.Group)
|
||||||
|
.ThenInclude(t => t!.EsppSchValues)
|
||||||
|
.ThenInclude(t => t!.EsppSchTypeConfig)
|
||||||
|
.ThenInclude(t => t!.EsppSchTypeSchedule)
|
||||||
|
// Исключения по типу
|
||||||
|
.Include(t => t.Template)
|
||||||
|
.ThenInclude(t => t!.Job)
|
||||||
|
.ThenInclude(t => t!.Group)
|
||||||
|
.ThenInclude(t => t!.ScheduleExcludeType)
|
||||||
|
// Исключения по календарю
|
||||||
|
.Include(t => t.Template)
|
||||||
|
.ThenInclude(t => t!.Job)
|
||||||
|
.ThenInclude(t => t!.Group)
|
||||||
|
.ThenInclude(t => t!.ScheduleExcludeTypeCalendar);
|
||||||
}
|
}
|
||||||
|
|
||||||
return await query.FirstAsync(t => t.Id == taskId);
|
return await query.FirstAsync(t => t.Id == taskId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Приводит переносы строк в тексте к формату CRLF (\r\n)
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">Исходный текст</param>
|
||||||
|
/// <returns>Текст с унифицированными переносами строк</returns>
|
||||||
|
private string NormalizeLineEndingsToCrlf(string? text)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(text))
|
||||||
|
return string.Empty;
|
||||||
|
|
||||||
|
// Заменяем любые варианты переносов (\r\n, \r, \n) на единый \r\n
|
||||||
|
return System.Text.RegularExpressions.Regex.Replace(text, @"\r\n|\r|\n", "\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Обоновить NextRun если он устарел
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="task"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private async Task<bool> UpdateNextRunAsync(RobotConfiguration task, IHistoryInitiator historyInitiator)
|
||||||
|
{
|
||||||
|
var template = task.Template!;
|
||||||
|
|
||||||
|
//var nextRun = await esppScheduleTransformService.GetNextDateAsync(template.Job!.GroupId, template!.Job!.Group!.ReferenceDate);
|
||||||
|
var nextRun = await nextRunService.GetNextRunForTemplateAsync(template.Id, false);
|
||||||
|
|
||||||
|
if (!nextRun.HasValue)
|
||||||
|
{
|
||||||
|
logger.LogError("При обновлении nextRun для шаблона {templateId}, расчитанный nextRun=null, ошибка в расчетах.", template.Id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextRun.Value < DateTimeOffset.UtcNow)
|
||||||
|
{
|
||||||
|
logger.LogError("При обновлении nextRun для шаблона {templateId}, расчитанный nextRun<Now [{nextRun}<{now}], ошибка в расчетах.", template.Id, nextRun.Value, DateTimeOffset.UtcNow);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextRun != template.NextRun)
|
||||||
|
{
|
||||||
|
logger.LogDebug($"Для шаблона id {template.Id} обновляю nextRun, новое значение {nextRun}, старое значение {template.NextRun}");
|
||||||
|
|
||||||
|
template.LastRun = template.NextRun;
|
||||||
|
template.NextRun = nextRun.Value;
|
||||||
|
|
||||||
|
var suffix = "При получении задания роботом, обновил NextRun";
|
||||||
|
historyInitiator.InitiatorComment =
|
||||||
|
string.IsNullOrEmpty(historyInitiator.InitiatorComment)
|
||||||
|
? suffix
|
||||||
|
: $"{historyInitiator.InitiatorComment}. {suffix}";
|
||||||
|
|
||||||
|
if (!await robotConfigurationRepository.CommitAsync(historyInitiator))
|
||||||
|
throw new DbErrorException("Ошибка при сохранении изменения NextRun");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,35 @@
|
|||||||
namespace PARR.Core.Services.RobotTask.Interfaces
|
using PARR.Domain.DTOs.RobotTask;
|
||||||
|
using PARR.Domain.Entities.Base.History;
|
||||||
|
using PARR.Domain.Enums;
|
||||||
|
|
||||||
|
namespace PARR.Core.Services.RobotTask.Interfaces
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Управление заданиями роботам
|
/// Управление заданиями роботам
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IRobotTaskService
|
public interface IRobotTaskService
|
||||||
{
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить задание роботу - шаблоны.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="taskStatusCode"></param>
|
||||||
|
/// <param name="acquireTask"></param>
|
||||||
|
/// <param name="robotIp"></param>
|
||||||
|
/// <param name="robotId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<RobotTaskTemplate> GetTemplateTaskAsync(TaskStatusEnum taskStatusCode, bool acquireTask, string? robotIp, string? robotId);
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Получить задание роботу - расписания.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="taskStatusCode"></param>
|
||||||
|
/// <param name="acquireTask"></param>
|
||||||
|
/// <param name="robotIp"></param>
|
||||||
|
/// <param name="robotId"></param>
|
||||||
|
/// <param name="historyInitiator"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
Task<RobotTaskSchedule> GetScheduleTaskAsync(TaskStatusEnum taskStatusCode, bool acquireTask, string? robotIp, string? robotId, IHistoryInitiator historyInitiator);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
13
PARR.Domain/DTOs/RobotTask/RobotTaskBase.cs
Normal file
13
PARR.Domain/DTOs/RobotTask/RobotTaskBase.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
namespace PARR.Domain.DTOs.RobotTask
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Базовая модель для заданий роботам
|
||||||
|
/// </summary>
|
||||||
|
public record RobotTaskBase
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// RobotConfigurationId
|
||||||
|
/// </summary>
|
||||||
|
public Guid TaskId { get; init; }
|
||||||
|
}
|
||||||
|
}
|
||||||
67
PARR.Domain/DTOs/RobotTask/RobotTaskSchedule.cs
Normal file
67
PARR.Domain/DTOs/RobotTask/RobotTaskSchedule.cs
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
namespace PARR.Domain.DTOs.RobotTask
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Модель для задания роботам - расписания
|
||||||
|
/// </summary>
|
||||||
|
public record RobotTaskSchedule : RobotTaskBase
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// ИД расписания из ЕСПП. При создании, его не будет
|
||||||
|
/// </summary>
|
||||||
|
public string? EsppId { get; init; }
|
||||||
|
|
||||||
|
public required string ScheduleName { get; init; }
|
||||||
|
|
||||||
|
public bool IsActive { get; init; }
|
||||||
|
|
||||||
|
public required string ResponseArea { get; init; }
|
||||||
|
|
||||||
|
public required string TemplateName { get; init; }
|
||||||
|
|
||||||
|
public Guid TemplateId { get; init; }
|
||||||
|
|
||||||
|
public required string WorkGroup { get; init; }
|
||||||
|
|
||||||
|
public string? Description { get; init; }
|
||||||
|
|
||||||
|
public required string Exclude { get; init; }
|
||||||
|
|
||||||
|
// сделал возможный null, так как может в будущем это поле может не заполняться
|
||||||
|
public string? ExcludeCalendar { get; init; }
|
||||||
|
|
||||||
|
public required string Timezone { get; init; }
|
||||||
|
|
||||||
|
public required string RepeatRange { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Время создания наряда
|
||||||
|
/// </summary>
|
||||||
|
public required string GenerationTime { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Следующее срабатывание
|
||||||
|
/// </summary>
|
||||||
|
public required string NextStart { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Тип задания: Регулярно, еженедельно...
|
||||||
|
/// </summary>
|
||||||
|
public required string ScheduleType { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Код задания
|
||||||
|
/// </summary>
|
||||||
|
public int ScheduleTypeCode { get; init; }
|
||||||
|
|
||||||
|
public List<RobotTaskScheduleSch>? Schedule { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public record RobotTaskScheduleSch
|
||||||
|
{
|
||||||
|
public required string Type { get; init; }
|
||||||
|
public int TypeCode { get; init; }
|
||||||
|
public required string Value { get; init; }
|
||||||
|
public int Order { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
53
PARR.Domain/DTOs/RobotTask/RobotTaskTemplate.cs
Normal file
53
PARR.Domain/DTOs/RobotTask/RobotTaskTemplate.cs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
namespace PARR.Domain.DTOs.RobotTask
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Модель для задания роботам - шаблоны
|
||||||
|
/// </summary>
|
||||||
|
public record RobotTaskTemplate : RobotTaskBase
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// ИД расписания из ЕСПП. При создании, его не будет
|
||||||
|
/// (при создании шаблона, это поле не смотрим, используем только при изменении)
|
||||||
|
/// </summary>
|
||||||
|
public string? ScheduleEsppId { get; init; }
|
||||||
|
|
||||||
|
public bool IsActive { get; init; }
|
||||||
|
|
||||||
|
public required string ClosingCode { get; init; }
|
||||||
|
|
||||||
|
public required string FullDescription { get; init; }
|
||||||
|
|
||||||
|
public required string ShortDescription { get; init; }
|
||||||
|
|
||||||
|
public required string Solution { get; init; }
|
||||||
|
|
||||||
|
public required string ResponseArea { get; init; }
|
||||||
|
|
||||||
|
public required string TemplateDuration { get; init; }
|
||||||
|
|
||||||
|
public required string Initiator { get; init; }
|
||||||
|
|
||||||
|
public required string WorkGroup { get; init; }
|
||||||
|
|
||||||
|
public required string Ek { get; init; }
|
||||||
|
|
||||||
|
public required string Name { get; init; }
|
||||||
|
|
||||||
|
public required string Category { get; init; }
|
||||||
|
|
||||||
|
|
||||||
|
public required string ProcessName { get; init; }
|
||||||
|
|
||||||
|
public required string ProcessEsppId { get; init; }
|
||||||
|
|
||||||
|
public required string SubprocessName { get; init; }
|
||||||
|
|
||||||
|
public required string SubprocessEsppId { get; init; }
|
||||||
|
|
||||||
|
public required string TnkName { get; init; }
|
||||||
|
|
||||||
|
public required string TnkEsppId { get; init; }
|
||||||
|
|
||||||
|
public required string WorkName { get; init; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -93,4 +93,17 @@
|
|||||||
/// <param name="message"></param>
|
/// <param name="message"></param>
|
||||||
public ForbiddenException(string message) : base(message) { }
|
public ForbiddenException(string message) : base(message) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ошибка при расчете NextRun. 422 (запрос валиден, но бизнес логика не смогла нормально его обработать)
|
||||||
|
/// </summary>
|
||||||
|
public class NextRunException : BaseException
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Ошибка при расчете NextRun
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
public NextRunException(string message) : base(message){}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user