2023-10-05 16:56:02 +10:00
using AutoMapper ;
2023-12-04 10:16:00 +10:00
using Microsoft.AspNetCore.Authorization ;
2023-10-05 16:56:02 +10:00
using Microsoft.AspNetCore.Mvc ;
using Microsoft.EntityFrameworkCore ;
using PARR.API.Contracts.V1 ;
2024-08-01 14:21:28 +10:00
using PARR.API.Contracts.V1.Requests.Queries ;
2023-10-05 16:56:02 +10:00
using PARR.API.Contracts.V1.Responses ;
using PARR.API.Contracts.V1.Responses.Base ;
using PARR.API.Controllers.V1.Base ;
2024-08-01 14:21:28 +10:00
using PARR.API.Services.Interfaces ;
2026-02-03 16:15:19 +10:00
using PARR.BLL.Helpers ;
2023-10-05 16:56:02 +10:00
using PARR.DAL.Contracts ;
2025-12-23 18:27:31 +10:00
using PARR.DAL.DomainServices.Shortcodes ;
2023-10-05 16:56:02 +10:00
using PARR.DAL.Models ;
2026-01-22 11:46:05 +10:00
using PARR.DAL.NextRunServices ;
2023-10-05 16:56:02 +10:00
using PARR.DAL.Services.Interfaces ;
2026-01-30 12:29:37 +10:00
using PARR.DAL.Services.Interfaces.Schedule ;
2026-04-14 12:01:49 +10:00
using PARR.Domain.Common.Roles ;
2026-04-13 16:58:30 +10:00
using PARR.Domain.Entities.Base.History ;
using PARR.Domain.Enums ;
2023-10-05 16:56:02 +10:00
namespace PARR.API.Controllers.V1
{
2023-12-04 10:16:00 +10:00
[Authorize(Roles = ParrRoles.EsppRobot.RoleOrAdmin)]
2023-10-05 16:56:02 +10:00
public class RobotTaskController : BaseApiController
{
private readonly IMapper mapper ;
private readonly SettingsFromDb settingsFromDb ;
private readonly IRobotConfigurationService robotConfigurationService ;
2026-01-22 11:46:05 +10:00
//private readonly IEsppScheduleTransformService esppScheduleTransformService;
2024-02-27 16:01:08 +10:00
private readonly ILogger < RobotTaskController > logger ;
2024-08-01 14:21:28 +10:00
private readonly IClientService clientService ;
private readonly IRobotHistoryService robotHistoryService ;
2025-08-06 10:33:55 +10:00
private readonly IShortcodesService shortcodesService ;
2026-03-05 10:19:54 +10:00
private readonly INextRunService nextRunService ;
2026-01-30 12:29:37 +10:00
private readonly IScheduleResponseAreaTimeOffsetService scheduleResponseAreaTimeOffsetService ;
2023-10-05 16:56:02 +10:00
public RobotTaskController (
IMapper mapper ,
SettingsFromDb settingsFromDb ,
2023-10-17 10:53:02 +10:00
IRobotConfigurationService robotConfigurationService ,
2026-01-22 11:46:05 +10:00
//IEsppScheduleTransformService esppScheduleTransformService,
2024-08-01 14:21:28 +10:00
ILogger < RobotTaskController > logger ,
IClientService clientService ,
2025-08-06 10:33:55 +10:00
IRobotHistoryService robotHistoryService ,
2026-01-22 11:46:05 +10:00
IShortcodesService shortcodesService ,
2026-03-05 10:19:54 +10:00
INextRunService nextRunService ,
2026-01-30 12:29:37 +10:00
IScheduleResponseAreaTimeOffsetService scheduleResponseAreaTimeOffsetService
2023-10-05 16:56:02 +10:00
)
{
this . mapper = mapper ;
this . settingsFromDb = settingsFromDb ;
this . robotConfigurationService = robotConfigurationService ;
2026-01-22 11:46:05 +10:00
//this.esppScheduleTransformService = esppScheduleTransformService;
2024-02-27 16:01:08 +10:00
this . logger = logger ;
2024-08-01 14:21:28 +10:00
this . clientService = clientService ;
this . robotHistoryService = robotHistoryService ;
2025-08-06 10:33:55 +10:00
this . shortcodesService = shortcodesService ;
2026-01-22 11:46:05 +10:00
this . nextRunService = nextRunService ;
2026-01-30 12:29:37 +10:00
this . scheduleResponseAreaTimeOffsetService = scheduleResponseAreaTimeOffsetService ;
2023-10-05 16:56:02 +10:00
}
/// <summary>
/// Получить задание для робота по коду робота и по статусу задания
/// </summary>
/// <param name="robotCode"></param>
/// <param name="taskStatusCode"></param>
/// <returns></returns>
[HttpGet(ApiRoutes.RobotTask.GetByRobotAndStatusTask)]
2024-08-01 14:21:28 +10:00
public async Task < IActionResult > GetByRobotAndStatusTask ( [ FromRoute ] RobotsEnum robotCode , [ FromRoute ] TaskStatusEnum taskStatusCode , [ FromQuery ] RobotTaskQuery requestQuery )
2023-10-05 16:56:02 +10:00
{
//Ищем все задания с превышенным кол-вом попыток и с просроченным временем и ставим им статус ошибки
await robotConfigurationService . FindUnfulfilledTaskAndSetRobotErrorStatusAsync ( settingsFromDb . RobotAttemptsNumber , settingsFromDb . RobotWaitTime ) ;
2023-10-11 15:28:37 +10:00
2023-10-05 16:56:02 +10:00
var query = robotConfigurationService . Get ( )
2023-10-11 11:10:35 +10:00
. Where ( t = > t . RobotCode = = ( int ) robotCode & & t . TaskStatusCode = = ( int ) taskStatusCode ) ;
2023-10-05 16:56:02 +10:00
switch ( robotCode )
{
case RobotsEnum . TemplateOrder :
2023-10-11 15:28:37 +10:00
// шаблоны
2025-12-23 18:27:31 +10:00
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 )
2025-12-24 11:25:25 +10:00
. ThenInclude ( g = > g . GroupType )
2025-12-23 18:27:31 +10:00
. 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 )
2025-12-24 11:25:25 +10:00
. ThenInclude ( t = > t ! . UnitsInTemplate ) ;
2025-12-23 18:27:31 +10:00
2023-10-05 16:56:02 +10:00
break ;
2025-12-23 18:27:31 +10:00
2023-10-05 16:56:02 +10:00
case RobotsEnum . ScheduleOrder :
2023-10-11 15:28:37 +10:00
//расписание
2025-12-23 18:27:31 +10:00
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 )
2025-12-24 11:25:25 +10:00
. Include ( t = > t . Template )
. ThenInclude ( a = > a ! . Job )
. ThenInclude ( t = > t ! . Group )
. ThenInclude ( g = > g . GroupType )
2025-12-23 18:27:31 +10:00
. Include ( t = > t . Template )
. ThenInclude ( a = > a ! . Job )
. ThenInclude ( t = > t ! . Group )
2025-12-25 17:01:42 +10:00
. 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 )
2025-12-23 18:27:31 +10:00
. Include ( t = > t . Template )
2025-12-29 19:21:51 +10:00
. ThenInclude ( t = > t ! . Job )
2025-12-30 14:12:49 +10:00
. ThenInclude ( t = > t ! . Tnk )
2025-12-29 19:21:51 +10:00
. Include ( t = > t . Template )
. ThenInclude ( t = > t ! . UnitsInTemplate ) ;
2023-10-11 15:28:37 +10:00
2024-08-12 15:21:07 +10:00
//выбираем только записи с созданными шаблонами (у которых статус 20 или 30), а только потом у них ищем расписания
2023-10-11 15:28:37 +10:00
var createdTemplates = robotConfigurationService . Get ( )
2025-12-23 18:27:31 +10:00
. Where ( t = > t . RobotCode = = ( int ) RobotsEnum . TemplateOrder & & ( t . TaskStatusCode = = ( int ) TaskStatusEnum . Ok ) )
. Select ( t = > t . TemplateId ) ;
2023-10-11 15:28:37 +10:00
query = query . Where ( t = > t . RobotCode = = ( int ) RobotsEnum . ScheduleOrder & & createdTemplates . Contains ( t . TemplateId ) ) ;
2025-12-30 14:12:49 +10:00
// query = query.Where(t => t.RobotCode == (int)RobotsEnum.ScheduleOrder && t.TemplateId==Guid.Parse("7cb7c3be-506d-40e0-a63f-4554edb52459"));
2023-10-05 16:56:02 +10:00
break ;
2025-12-23 18:27:31 +10:00
2023-10-05 16:56:02 +10:00
default :
break ;
}
2025-12-30 14:18:58 +10:00
2024-09-16 15:24:03 +10:00
// сортируем по NextRun, чтобы те у которых дата след срабатывания ближе к текущей, выполнились скорее
2026-01-13 08:42:17 +10:00
query = query . OrderBy ( t = > t . Template ! . NextRun ) . ThenBy ( t = > t . Template ! . IsActiveSchedule ) . ThenBy ( t = > t . Template . IsActiveTemplate ) ;
2025-12-30 14:12:49 +10:00
2023-10-05 16:56:02 +10:00
RobotConfiguration ? task = null ;
2023-10-11 15:28:37 +10:00
//ищем задание в ожидании, если нашли, выбираем е г о
2023-10-05 16:56:02 +10:00
task = await query . FirstOrDefaultAsync ( t = > t . RobotStatusCode = = ( int ) RobotStatusEnum . Wait ) ;
if ( task = = null )
{
//ищем задания в работе, которые можно перезапустить
2023-10-09 16:11:27 +10:00
//Поиск по `RobotStatusCode` = 22.
2023-10-05 16:56:02 +10:00
//Далее проверяется `LastStatusUpdated`, что время последнего смены статуса не превышает допустимого(берется из настроек, поле `RobotWaitTime`)
//и что текущая попытка не больше разрешенной(берется из настроек, поле `RobotAttemptsNumber`) - если это так, берется эта запись.
var endDate = DateTimeOffset . UtcNow . Add ( - settingsFromDb . RobotWaitTime ) ;
2023-10-11 11:10:35 +10:00
task = await query
. FirstOrDefaultAsync ( t = >
2023-10-05 16:56:02 +10:00
t . RobotStatusCode = = ( int ) RobotStatusEnum . InProgress
& & t . AttemptsNumber < settingsFromDb . RobotAttemptsNumber
2023-10-06 11:38:33 +10:00
& & t . LastRobotStatusUpdated < endDate
2023-10-05 16:56:02 +10:00
) ;
}
if ( task = = null )
return NotFound ( ) ;
2024-08-01 14:21:28 +10:00
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 = "Ошибка при выдаче задания." } } ) ) ;
}
}
2023-10-05 16:56:02 +10:00
switch ( robotCode )
{
case RobotsEnum . TemplateOrder :
2025-12-23 18:27:31 +10:00
{ //RobotTaskTemplateResponse
var robotTaskTemplateResponse = mapper . Map < RobotTaskTemplateResponse > ( task ) ;
2026-01-13 14:36:07 +10:00
robotTaskTemplateResponse . FullDescription = await shortcodesService . ApplyShortcodesAsync ( robotTaskTemplateResponse . FullDescription , task . Template ! ) ;
robotTaskTemplateResponse . ShortDescription = await shortcodesService . ApplyShortcodesAsync ( robotTaskTemplateResponse . ShortDescription , task . Template ! ) ;
robotTaskTemplateResponse . Solution = 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 ! ) ;
2025-12-23 18:27:31 +10:00
return Ok ( new Response < RobotTaskTemplateResponse > ( robotTaskTemplateResponse , true ) ) ;
}
2023-10-05 16:56:02 +10:00
case RobotsEnum . ScheduleOrder :
2025-12-23 18:27:31 +10:00
{ // если был запрос на расписание, проверяем у него nextRun, lastRun, обновляем их
2026-02-16 16:54:06 +10:00
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" } } ) ) ;
}
2025-12-23 18:27:31 +10:00
//RobotTaskScheduleResponse
var robotTaskScheduleResponse = mapper . Map < RobotTaskScheduleResponse > ( task ) ;
2026-02-16 16:54:06 +10:00
robotTaskScheduleResponse . Timezone = settingsFromDb . EsppScheduleTimezone ;
2026-01-30 12:29:37 +10:00
2026-01-13 14:36:07 +10:00
robotTaskScheduleResponse . WorkGroup = await shortcodesService . ApplyShortcodesAsync ( robotTaskScheduleResponse . WorkGroup , task . Template ! ) ;
robotTaskScheduleResponse . ResponseArea = await shortcodesService . ApplyShortcodesAsync ( robotTaskScheduleResponse . ResponseArea , task . Template ! ) ;
2023-11-27 16:42:15 +10:00
2026-02-16 16:54:06 +10:00
//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" } } ) ) ;
}
2026-01-30 12:29:37 +10:00
2026-02-16 16:54:06 +10:00
robotTaskScheduleResponse . NextStart = EsppScheduleHelpers . GetNextRun ( nextRunWithRobotTz ) ;
robotTaskScheduleResponse . GenerationTime = EsppScheduleHelpers . GetGenerationTime ( nextRunWithRobotTz ) ;
2026-01-30 12:29:37 +10:00
2025-12-23 18:27:31 +10:00
return Ok ( new Response < RobotTaskScheduleResponse > ( robotTaskScheduleResponse , true ) ) ;
}
2023-10-05 16:56:02 +10:00
default :
break ;
}
return BadRequest ( ) ;
}
2023-10-17 10:53:02 +10:00
2026-02-03 16:15:19 +10:00
/// <summary>
/// Обоновить NextRun если он устарел
/// </summary>
/// <param name="task"></param>
/// <returns></returns>
2026-02-16 16:54:06 +10:00
private async Task < bool > UpdateNextRunAsync ( RobotConfiguration task )
2023-10-17 10:53:02 +10:00
{
2024-07-03 15:19:09 +10:00
var template = task . Template ! ;
2023-10-17 10:53:02 +10:00
2026-01-22 11:46:05 +10:00
//var nextRun = await esppScheduleTransformService.GetNextDateAsync(template.Job!.GroupId, template!.Job!.Group!.ReferenceDate);
var nextRun = await nextRunService . GetNextRunForTemplateAsync ( template . Id , false ) ;
2023-10-17 10:53:02 +10:00
2026-02-16 16:54:06 +10:00
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 ;
}
2024-07-03 15:19:09 +10:00
if ( nextRun ! = template . NextRun )
2024-02-27 16:01:08 +10:00
{
2024-07-03 15:19:09 +10:00
logger . LogDebug ( $"Для шаблона id {template.Id} обновляю nextRun, новое значение {nextRun}, старое значение {template.NextRun}" ) ;
2024-02-27 16:01:08 +10:00
2025-11-25 16:49:28 +10:00
template . LastRun = template . NextRun ;
2026-02-16 16:54:06 +10:00
template . NextRun = nextRun . Value ;
2024-02-27 16:01:08 +10:00
2024-10-08 16:37:58 +10:00
await robotConfigurationService . CommitAsync ( new HistoryInitiator { InitiatorComment = "При получении задания роботом, обновил NextRun" , InitiatorIp = clientService . GetClientIp ( ) ? . ToString ( ) , InitiatorParrComponentId = ParrComponentsEnum . Api } ) ;
2024-02-27 16:01:08 +10:00
}
2026-02-16 16:54:06 +10:00
return true ;
2023-10-17 10:53:02 +10:00
}
2024-08-01 14:21:28 +10:00
/// <summary>
/// Устанавливаем статус "Робот взял в работу", пишем в историю работы роботов инф о начале работ
/// </summary>
/// <param name="taskId"></param>
/// <returns></returns>
private async Task < bool > SetInProgressStatusAsync ( Guid taskId )
{
var config = await robotConfigurationService . GetAsync ( taskId ) ;
//изменение статуса робота
2025-12-09 12:20:27 +10:00
robotConfigurationService . ChangeRobotStatus ( RobotStatusEnum . InProgress , config ! ) ;
2024-08-01 14:21:28 +10:00
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 ;
}
2023-10-05 16:56:02 +10:00
}
}