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 ;
2024-10-08 16:37:58 +10:00
using PARR.Common.Domain ;
2023-11-22 12:04:33 +10:00
using PARR.Constants ;
2023-10-05 16:56:02 +10:00
using PARR.DAL.Contracts ;
2025-08-12 11:50:29 +10:00
using PARR.DAL.DomainServices.Interfaces ;
2023-10-05 16:56:02 +10:00
using PARR.DAL.Models ;
using PARR.DAL.Services.Interfaces ;
2023-10-17 10:53:02 +10:00
using PARR.DAL.TransformServices ;
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 ;
2023-10-17 10:53:02 +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 ;
2023-10-05 16:56:02 +10:00
public RobotTaskController (
IMapper mapper ,
SettingsFromDb settingsFromDb ,
2023-10-17 10:53:02 +10:00
IRobotConfigurationService robotConfigurationService ,
2024-02-27 16:01:08 +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 ,
IShortcodesService shortcodesService
2023-10-05 16:56:02 +10:00
)
{
this . mapper = mapper ;
this . settingsFromDb = settingsFromDb ;
this . robotConfigurationService = robotConfigurationService ;
2023-10-17 10:53:02 +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 ;
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
2024-03-27 11:44:15 +10:00
//var query = robotConfigurationService.GetAsync();
2023-10-11 15:28:37 +10:00
2023-10-05 16:56:02 +10:00
switch ( robotCode )
{
case RobotsEnum . TemplateOrder :
2023-10-11 15:28:37 +10:00
// шаблоны
2023-10-05 16:56:02 +10:00
query = query . Include ( t = > t . Template )
2025-06-25 14:17:34 +10:00
. ThenInclude ( t = > t ! . Unit )
2025-06-27 13:42:13 +10:00
. 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 )
2025-06-25 14:17:34 +10:00
. ThenInclude ( a = > a ! . Job )
2025-06-27 13:42:13 +10:00
. ThenInclude ( t = > t ! . Group )
. Include ( t = > t . Template )
. ThenInclude ( w = > w ! . Job )
2023-10-05 16:56:02 +10:00
. ThenInclude ( t = > t ! . Tnk )
. ThenInclude ( s = > s ! . Subprocess )
2024-06-04 12:03:15 +10:00
. ThenInclude ( p = > p ! . Process ) ;
2023-10-05 16:56:02 +10:00
break ;
case RobotsEnum . ScheduleOrder :
2023-10-11 15:28:37 +10:00
//расписание
2023-10-11 11:10:35 +10:00
// тут не делаем AsSplitQuery, не может подтянуть все таблицы
2023-10-10 16:58:05 +10:00
query = query . Include ( t = > t . Template )
2025-06-27 13:42:13 +10:00
. 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 )
2023-10-11 11:10:35 +10:00
. ThenInclude ( t = > t ! . EsppSchValues )
. ThenInclude ( t = > t ! . EsppSchTypeConfig )
2023-10-11 15:28:37 +10:00
. ThenInclude ( t = > t ! . EsppSchTypeSchedule ) ;
2024-08-12 15:21:07 +10:00
//выбираем только записи с созданными шаблонами (у которых статус 20 или 30), а только потом у них ищем расписания
2023-10-11 15:28:37 +10:00
// сначала находим шаблоны с о статусом 30
var createdTemplates = robotConfigurationService . Get ( )
2024-08-12 15:21:07 +10:00
. Where ( t = > t . RobotCode = = ( int ) RobotsEnum . TemplateOrder & & ( t . TaskStatusCode = = ( int ) TaskStatusEnum . Updating | | t . TaskStatusCode = = ( int ) TaskStatusEnum . Ok ) )
2023-10-11 15:28:37 +10:00
. Select ( t = > t . TemplateId ) ;
//находим задания с расписанием по списку шаблонов createdTemplates
query = query . Where ( t = > t . RobotCode = = ( int ) RobotsEnum . ScheduleOrder & & createdTemplates . Contains ( t . TemplateId ) ) ;
2023-10-05 16:56:02 +10:00
break ;
default :
break ;
}
2024-09-16 15:24:03 +10:00
// сортируем по NextRun, чтобы те у которых дата след срабатывания ближе к текущей, выполнились скорее
query = query . OrderBy ( t = > t . Template ! . NextRun ) ;
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 :
//RobotTaskTemplateResponse
2025-08-06 10:33:55 +10:00
var robotTaskTemplateResponse = mapper . Map < RobotTaskTemplateResponse > ( task ) ;
//TODO Вынести в отдельный метод ShortcodesService
if ( shortcodesService . isAnyShortcodes ( robotTaskTemplateResponse . FullDescription ) )
robotTaskTemplateResponse . FullDescription = await shortcodesService . ApplyShortcodesAsync ( robotTaskTemplateResponse . FullDescription , task ! . Template ! . UnitId , task ! . Template ! . JobId ) ;
if ( shortcodesService . isAnyShortcodes ( robotTaskTemplateResponse . ShortDescription ) )
robotTaskTemplateResponse . ShortDescription = await shortcodesService . ApplyShortcodesAsync ( robotTaskTemplateResponse . ShortDescription , task ! . Template ! . UnitId , task ! . Template ! . JobId ) ;
if ( shortcodesService . isAnyShortcodes ( robotTaskTemplateResponse . Solution ) )
robotTaskTemplateResponse . Solution = await shortcodesService . ApplyShortcodesAsync ( robotTaskTemplateResponse . Solution , task ! . Template ! . UnitId , task ! . Template ! . JobId ) ;
if ( shortcodesService . isAnyShortcodes ( robotTaskTemplateResponse . TnkName ) )
robotTaskTemplateResponse . TnkName = await shortcodesService . ApplyShortcodesAsync ( robotTaskTemplateResponse . TnkName , task ! . Template ! . UnitId , task ! . Template ! . JobId ) ;
if ( shortcodesService . isAnyShortcodes ( robotTaskTemplateResponse . WorkName ) )
robotTaskTemplateResponse . WorkName = await shortcodesService . ApplyShortcodesAsync ( robotTaskTemplateResponse . WorkName , task ! . Template ! . UnitId , task ! . Template ! . JobId ) ;
2025-08-22 11:25:51 +10:00
if ( shortcodesService . isAnyShortcodes ( robotTaskTemplateResponse . WorkGroup ) )
robotTaskTemplateResponse . WorkGroup = await shortcodesService . ApplyShortcodesAsync ( robotTaskTemplateResponse . WorkGroup , task ! . Template ! . UnitId , task ! . Template ! . JobId ) ;
2025-08-06 10:33:55 +10:00
return Ok ( new Response < RobotTaskTemplateResponse > ( robotTaskTemplateResponse , true ) ) ;
2023-10-05 16:56:02 +10:00
case RobotsEnum . ScheduleOrder :
2023-10-17 10:53:02 +10:00
// если был запрос на расписание, проверяем у него nextRun, lastRun, обновляем их
await UpdateLastNextRunDate ( task ) ;
2023-10-05 16:56:02 +10:00
//RobotTaskScheduleResponse
2025-08-06 10:33:55 +10:00
var robotTaskScheduleResponse = mapper . Map < RobotTaskScheduleResponse > ( task ) ;
2025-08-22 11:25:51 +10:00
if ( shortcodesService . isAnyShortcodes ( robotTaskScheduleResponse . WorkGroup ) )
robotTaskScheduleResponse . WorkGroup = await shortcodesService . ApplyShortcodesAsync ( robotTaskScheduleResponse . WorkGroup , task ! . Template ! . UnitId , task ! . Template ! . JobId ) ;
2023-11-27 16:42:15 +10:00
2025-08-06 10:33:55 +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
private async Task UpdateLastNextRunDate ( RobotConfiguration task )
{
2024-07-03 15:19:09 +10:00
var template = task . Template ! ;
2023-10-17 10:53:02 +10:00
// передаем LastRun, если е г о нет, то NextRun
2024-02-28 08:32:57 +10:00
//var nextRun = await esppScheduleTransformService.GetNextDateAsync(task.Template!.ApplicationInWorkId, task.Template.ApplicationsInWork!.LastRun ?? task.Template.ApplicationsInWork.NextRun);
// всегда считаем по nextRun
2025-06-25 14:17:34 +10:00
var nextRun = await esppScheduleTransformService . GetNextDateAsync ( template . Job ! . GroupId , template . NextRun ) ;
2023-10-17 10:53:02 +10:00
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
2024-07-03 15:19:09 +10:00
if ( template . NextRun < DateTimeOffset . UtcNow )
2024-02-27 16:01:08 +10:00
{
2024-07-03 15:19:09 +10:00
logger . LogDebug ( $"Для шаблона id {template.Id} обновляю lastRun, новое значение {template.NextRun}, старое значение {template.LastRun}" ) ;
template . LastRun = template . NextRun ;
2024-02-27 16:01:08 +10:00
}
2024-06-18 15:10:12 +10:00
2024-07-03 15:19:09 +10:00
template . NextRun = nextRun ;
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
}
2024-07-03 15:19:09 +10:00
#region Old , д о в ы н о с а lastRun , nextRun в templates
//var appInWorks = task.Template!.ApplicationsInWork!;
2023-10-17 16:59:53 +10:00
2024-07-03 15:19:09 +10:00
//// передаем LastRun, если е г о нет, то NextRun
////var nextRun = await esppScheduleTransformService.GetNextDateAsync(task.Template!.ApplicationInWorkId, task.Template.ApplicationsInWork!.LastRun ?? task.Template.ApplicationsInWork.NextRun);
//// всегда считаем по nextRun
//var nextRun = await esppScheduleTransformService.GetNextDateAsync(task.Template!.ApplicationInWorkId, task.Template.ApplicationsInWork!.NextRun);
//if (nextRun != appInWorks.NextRun)
//{
// logger.LogDebug($"Для appilcationInWork id {task.Template.ApplicationInWorkId}, шаблона id {task.TemplateId} обновляю nextRun, новое значение {nextRun}, старое значение {appInWorks.NextRun}");
// if (appInWorks.NextRun < DateTimeOffset.UtcNow)
// {
// logger.LogDebug($"Для appilcationInWork id {task.Template.ApplicationInWorkId}, шаблона id {task.TemplateId} обновляю lastRun, новое значение {appInWorks.NextRun}, старое значение {appInWorks.LastRun}");
// appInWorks.LastRun = appInWorks.NextRun;
// }
// appInWorks.NextRun = nextRun;
// await robotConfigurationService.CommitAsync();
//}
#endregion
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 ) ;
//изменение статуса робота
robotConfigurationService . ChangeRobotStatus ( RobotStatusEnum . InProgress , ref 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 ;
}
2023-10-05 16:56:02 +10:00
}
}