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-12-23 18:27:31 +10:00
using PARR.DAL.DomainServices.Shortcodes ;
using PARR.DAL.DomainServices.Shortcodes.Models ;
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 ;
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 ;
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-01-22 11:46:05 +10:00
private readonly INextRunService nextRunService ;
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 ,
INextRunService nextRunService
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 ;
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
2025-12-30 14:18:58 +10:00
#region Т а к н е л ь з я д е л а т ь ! ! ! Д о л ж н о в с е г д а с о р т и р о в а т ь с я п о NextRun и н е в а ж н о к а к о й т и п у ш а б л о н а ! ! !
2025-12-30 14:12:49 +10:00
// Сортируем сначала по StatusTypeId, т е те что used, будут первыми, потом сортируем по NextRun, чтобы ближайшие даты выполнились скорее
2025-12-30 14:18:58 +10:00
//query = query.OrderBy(t => t.Template!.StatusTypeId).ThenBy(t => t.Template!.NextRun);
#endregion
2024-09-16 15:24:03 +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 ) ;
//TODO Вынести в отдельный метод ShortcodesService
2025-12-30 17:34:46 +10:00
// Построим TemplateForShortcodes из уже загруженного task.Template
2026-01-13 14:36:07 +10:00
//var templateForShortcodes = new TemplateForShortcodes
//{
// Id = task.Template!.Id,
// Index = task.Template.Index,
// JobId = task.Template.JobId,
// UnitId = task.Template.UnitId,
// Job = task.Template.Job == null ? null : new JobForShortcodes
// {
// Group = task.Template.Job.Group == null ? null : new JobGroupForShortcodes
// {
// Id = task.Template.Job.Group.Id,
// GroupingUnitFieldId = task.Template.Job.Group.GroupingUnitFieldId,
// GroupType = task.Template.Job.Group.GroupType == null ? null : new JobGroupTypeForShortcodes
// {
// Code = task.Template.Job.Group.GroupType.Code
// },
// GroupName = task.Template.Job.Group.GroupName
// },
// Tnk = task.Template.Job.Tnk == null ? null : new TnkForShortcodes
// {
// Name = task.Template.Job.Tnk.Name,
// ShortName = task.Template.Job.Tnk.ShortName ?? ""
// },
// WorkName = task.Template.Job.WorkName,
// Name = task.Template.Job.Name
// },
// UnitsInTemplate = task.Template.UnitsInTemplate?.Select(uit => new UnitInTemplateForShortcodes { UnitId = uit.UnitId }).ToList() ?? new List<UnitInTemplateForShortcodes>()
//};
2025-12-23 18:27:31 +10:00
2026-01-13 14:36:07 +10:00
//if (shortcodesService.IsAnyShortcodes(robotTaskTemplateResponse.FullDescription))
robotTaskTemplateResponse . FullDescription = await shortcodesService . ApplyShortcodesAsync ( robotTaskTemplateResponse . FullDescription , task . Template ! ) ;
//if (shortcodesService.IsAnyShortcodes(robotTaskTemplateResponse.ShortDescription))
robotTaskTemplateResponse . ShortDescription = await shortcodesService . ApplyShortcodesAsync ( robotTaskTemplateResponse . ShortDescription , task . Template ! ) ;
//if (shortcodesService.IsAnyShortcodes(robotTaskTemplateResponse.Solution))
robotTaskTemplateResponse . Solution = await shortcodesService . ApplyShortcodesAsync ( robotTaskTemplateResponse . Solution , task . Template ! ) ;
//if (shortcodesService.IsAnyShortcodes(robotTaskTemplateResponse.TnkName))
robotTaskTemplateResponse . TnkName = await shortcodesService . ApplyShortcodesAsync ( robotTaskTemplateResponse . TnkName , task . Template ! ) ;
//if (shortcodesService.IsAnyShortcodes(robotTaskTemplateResponse.WorkName))
robotTaskTemplateResponse . WorkName = await shortcodesService . ApplyShortcodesAsync ( robotTaskTemplateResponse . WorkName , task . Template ! ) ;
//if (shortcodesService.IsAnyShortcodes(robotTaskTemplateResponse.WorkGroup))
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, обновляем их
await UpdateLastNextRunDate ( task ) ;
//RobotTaskScheduleResponse
var robotTaskScheduleResponse = mapper . Map < RobotTaskScheduleResponse > ( task ) ;
2026-01-13 14:36:07 +10:00
//// Построим TemplateForShortcodes из уже загруженного task.Template
//var templateForShortcodes = new TemplateForShortcodes
//{
// Id = task.Template!.Id,
// Index = task.Template.Index,
// JobId = task.Template.JobId,
// UnitId = task.Template.UnitId,
// Job = task.Template.Job == null ? null : new JobForShortcodes
// {
// Group = task.Template.Job.Group == null ? null : new JobGroupForShortcodes
// {
// GroupingUnitFieldId = task.Template.Job.Group.GroupingUnitFieldId,
// GroupType = task.Template.Job.Group.GroupType == null ? null : new JobGroupTypeForShortcodes
// {
// Code = task.Template.Job.Group.GroupType.Code
// },
// GroupName = task.Template.Job.Group.GroupName
// },
// Tnk = task.Template.Job.Tnk == null ? null : new TnkForShortcodes
// {
// Name = task.Template.Job.Tnk.Name,
// ShortName = task.Template.Job.Tnk.ShortName
// },
// WorkName = task.Template.Job.WorkName,
// Name = task.Template.Job.Name
// },
// UnitsInTemplate = task.Template.UnitsInTemplate?.Select(uit => new UnitInTemplateForShortcodes { UnitId = uit.UnitId }).ToList() ?? new List<UnitInTemplateForShortcodes>()
//};
2023-10-17 10:53:02 +10:00
2026-01-13 14:36:07 +10:00
//if (shortcodesService.IsAnyShortcodes(robotTaskScheduleResponse.WorkGroup))
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
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
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
2025-11-25 16:49:28 +10:00
#region old
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-11-25 16:49:28 +10:00
//var nextRun = await esppScheduleTransformService.GetNextDateAsync(template.Job!.GroupId, template.NextRun);
#endregion
//пока у нас выключено автораспределение, считает по refDate
//TODO: когда заработает автораспределение, будем думать!!!!!
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
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
//if (template.NextRun < DateTimeOffset.UtcNow)
//{
// logger.LogDebug($"Для шаблона id {template.Id} обновляю lastRun, новое значение {template.NextRun}, старое значение {template.LastRun}");
// template.LastRun = template.NextRun;
//}
template . LastRun = template . NextRun ;
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 ) ;
//изменение статуса робота
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
}
}