2023-09-01 12:40:41 +10:00
using Microsoft.EntityFrameworkCore ;
using Microsoft.Extensions.Logging ;
2026-01-16 18:26:06 +10:00
using Npgsql ;
using PARR.Common.Domain ;
2023-11-22 12:04:33 +10:00
using PARR.Constants ;
2023-09-01 12:40:41 +10:00
using PARR.DAL.Context ;
2023-10-04 12:00:43 +10:00
using PARR.DAL.Contracts ;
2023-09-01 12:40:41 +10:00
using PARR.DAL.Models ;
using PARR.DAL.Services.Abstracts ;
using PARR.DAL.Services.Interfaces ;
namespace PARR.DAL.Services.Implementations
{
internal class TemplateService : BaseService < Template > , ITemplateService
{
private readonly DataContext dataContext ;
private readonly ILogger < TemplateService > logger ;
protected override DbSet < Template > EntitySet = > dataContext . Templates ;
protected override DataContext EntitiContext = > dataContext ;
public TemplateService ( DataContext dataContext , ILogger < TemplateService > logger ) : base ( logger )
{
this . dataContext = dataContext ;
this . logger = logger ;
}
2023-09-01 16:19:32 +10:00
public async Task < Template ? > GetTemplateByNameAsync ( string name )
{
2026-02-09 12:00:46 +10:00
logger . LogDebug ( "Поиск шаблона по имени: {TemplateName}" , name ) ;
var template = await GetWithIncludes ( )
2024-06-04 12:03:15 +10:00
. Include ( t = > t . RobotConfigurations )
2023-10-06 17:09:25 +10:00
. FirstOrDefaultAsync ( t = > t . Name = = name ) ;
2026-02-09 12:00:46 +10:00
if ( template ! = null )
{
logger . LogDebug ( "Шаблон найден: {TemplateId}, имя: {TemplateName}" , template . Id , template . Name ) ;
}
else
{
logger . LogDebug ( "Шаблон с именем {TemplateName} не найден" , name ) ;
}
return template ;
2023-09-01 16:19:32 +10:00
}
2023-09-19 16:42:06 +10:00
public IQueryable < Template > GetWithIncludes ( )
{
2026-02-09 12:00:46 +10:00
logger . LogDebug ( "Получаю шаблоны с include связями" ) ;
2023-09-19 16:42:06 +10:00
return Get ( )
2025-06-25 14:17:34 +10:00
. Include ( h = > h . Unit )
2025-08-06 10:33:55 +10:00
. ThenInclude ( t = > t ! . UnitValues )
. ThenInclude ( t = > t . Value )
. Include ( h = > h . Unit )
. ThenInclude ( t = > t ! . UnitValues )
. ThenInclude ( t = > t . Field )
2025-06-25 14:17:34 +10:00
. Include ( a = > a . Job )
2023-09-19 16:42:06 +10:00
. ThenInclude ( t = > t ! . Tnk )
. ThenInclude ( s = > s ! . Subprocess )
2025-06-27 13:42:13 +10:00
. ThenInclude ( p = > p ! . Process )
2025-08-06 10:33:55 +10:00
. Include ( t = > t . Job )
2026-01-13 14:36:07 +10:00
. ThenInclude ( t = > t ! . Group )
2026-01-22 14:05:48 +10:00
. ThenInclude ( t = > t ! . GroupType )
. Include ( t = > t . Job )
. ThenInclude ( t = > t ! . Group )
. ThenInclude ( t = > t . DistributionConfig )
. ThenInclude ( t = > t . DistributionPeriod ) ;
2023-09-19 16:42:06 +10:00
}
2023-10-04 12:00:43 +10:00
2023-10-05 16:56:02 +10:00
public override Task < bool > CreateAsync ( Template obj )
{
2026-02-09 12:00:46 +10:00
logger . LogDebug ( "Создание шаблона: {TemplateName}" , obj . Name ) ;
2023-10-05 16:56:02 +10:00
// добавление роботов для шаблона
obj . RobotConfigurations = new List < RobotConfiguration >
{
// робот по управлению шаблоном
new RobotConfiguration
{
Id = Guid . NewGuid ( ) ,
DateCreated = DateTimeOffset . UtcNow ,
TemplateId = obj . Id ,
RobotCode = ( int ) RobotsEnum . TemplateOrder ,
TaskStatusCode = ( int ) TaskStatusEnum . Creating ,
RobotStatusCode = ( int ) RobotStatusEnum . Wait ,
AttemptsNumber = 0 ,
2023-10-06 11:38:33 +10:00
LastRobotStatusUpdated = null
2023-10-05 16:56:02 +10:00
} ,
// робот по управлениею расписанием
new RobotConfiguration
{
Id = Guid . NewGuid ( ) ,
DateCreated = DateTimeOffset . UtcNow ,
TemplateId = obj . Id ,
RobotCode = ( int ) RobotsEnum . ScheduleOrder ,
TaskStatusCode = ( int ) TaskStatusEnum . Creating ,
RobotStatusCode = ( int ) RobotStatusEnum . Wait ,
AttemptsNumber = 0 ,
2023-10-06 11:38:33 +10:00
LastRobotStatusUpdated = null
2023-10-05 16:56:02 +10:00
}
} ;
2026-02-09 12:00:46 +10:00
logger . LogDebug ( "Добавлены роботы для шаблона {TemplateName}" , obj . Name ) ;
2023-10-05 16:56:02 +10:00
return base . CreateAsync ( obj ) ;
}
2026-01-16 18:26:06 +10:00
2026-03-26 18:08:13 +10:00
public async Task < Guid ? > ReserveUnusedTemplateAsync ( Guid newUnitId , Guid newJobId , HistoryInitiator initiator )
2026-01-16 18:26:06 +10:00
{
2026-03-26 18:08:13 +10:00
logger . LogDebug ( "Резервирую неиспользуемый шаблон с проверкой конфигураций роботов для UnitId: {UnitId}, JobId: {JobId}" , newUnitId , newJobId ) ;
2026-02-09 12:00:46 +10:00
2026-01-16 18:26:06 +10:00
var sql = @ "
2026-03-26 18:08:13 +10:00
UPDATE "" Templates ""
SET "" StatusTypeId "" = @NewStatus ,
"" DateModified "" = @DateModified ,
"" UnitId "" = @NewUnitId ,
"" JobId "" = @NewJobId ,
"" InitiatorIp "" = @InitiatorIp ,
"" InitiatorParrComponentId "" = @InitiatorComponent ,
"" InitiatorComment "" = @InitiatorComment
WHERE "" Id "" = (
SELECT t . "" Id ""
FROM "" Templates "" t
WHERE t . "" StatusTypeId "" = @OldStatus
AND t . "" UnitId "" ! = @NewUnitId
AND EXISTS (
SELECT 1
FROM "" RobotConfigurations "" rc
WHERE rc . "" TemplateId "" = t . "" Id ""
AND rc . "" RobotCode "" = @RobotCode1
AND rc . "" TaskStatusCode "" = @TaskStatus
AND rc . "" RobotStatusCode "" = @RobotStatus
)
AND EXISTS (
SELECT 1
FROM "" RobotConfigurations "" rc
WHERE rc . "" TemplateId "" = t . "" Id ""
AND rc . "" RobotCode "" = @RobotCode2
AND rc . "" TaskStatusCode "" = @TaskStatus
AND rc . "" RobotStatusCode "" = @RobotStatus
)
ORDER BY t . "" DateCreated "" ASC
LIMIT 1
)
RETURNING "" Id "" ; ";
2026-01-16 18:26:06 +10:00
var parameters = new [ ]
{
2026-03-26 18:08:13 +10:00
new NpgsqlParameter ( "@NewStatus" , ( int ) TemplateStatusTypeEnum . Updating ) ,
new NpgsqlParameter ( "@DateModified" , DateTimeOffset . UtcNow ) ,
new NpgsqlParameter ( "@NewUnitId" , newUnitId ) ,
new NpgsqlParameter ( "@NewJobId" , newJobId ) ,
new NpgsqlParameter ( "@InitiatorIp" , initiator . InitiatorIp ? ? ( object ) DBNull . Value ) ,
new NpgsqlParameter ( "@InitiatorComponent" ,
initiator . InitiatorParrComponentId . HasValue
? ( object ) ( int ) initiator . InitiatorParrComponentId . Value
: DBNull . Value ) ,
new NpgsqlParameter ( "@InitiatorComment" , initiator . InitiatorComment ? ? ( object ) DBNull . Value ) ,
new NpgsqlParameter ( "@OldStatus" , ( int ) TemplateStatusTypeEnum . Unused ) ,
// Параметры для проверки конфигураций роботов
new NpgsqlParameter ( "@RobotCode1" , ( int ) RobotsEnum . TemplateOrder ) ,
new NpgsqlParameter ( "@RobotCode2" , ( int ) RobotsEnum . ScheduleOrder ) ,
new NpgsqlParameter ( "@TaskStatus" , ( int ) TaskStatusEnum . Ok ) ,
new NpgsqlParameter ( "@RobotStatus" , ( int ) RobotStatusEnum . Complete )
} ;
2026-02-09 12:00:46 +10:00
try
{
var result = await dataContext . Database
. SqlQueryRaw < Guid > ( sql , parameters )
. ToListAsync ( ) ;
var reservedTemplateId = result . FirstOrDefault ( ) ;
if ( reservedTemplateId ! = default ( Guid ) )
{
2026-03-26 18:08:13 +10:00
logger . LogInformation ( "Успешно зарезервирован шаблон с ID: {TemplateId} для UnitId: {UnitId}, JobId: {JobId}" ,
reservedTemplateId , newUnitId , newJobId ) ;
2026-02-09 12:00:46 +10:00
}
else
{
2026-03-26 18:08:13 +10:00
logger . LogDebug ( "Н е удалось зарезервировать шаблон для UnitId: {UnitId}, JobId: {JobId} (не найдено подходящих конфигураций роботов)" , newUnitId , newJobId ) ;
2026-02-09 12:00:46 +10:00
}
return reservedTemplateId ;
}
catch ( Exception ex )
{
2026-03-26 18:08:13 +10:00
logger . LogError ( ex , "Ошибка при резервировании шаблона для UnitId: {UnitId}, JobId: {JobId}" , newUnitId , newJobId ) ;
2026-02-09 12:00:46 +10:00
throw ;
}
2026-01-16 18:26:06 +10:00
}
2023-09-01 12:40:41 +10:00
}
2026-02-09 12:00:46 +10:00
}