From 2c005f038e5dfac5504c57603acebd61e27951a3 Mon Sep 17 00:00:00 2001 From: Mikhail Kuznetsov Date: Thu, 14 Aug 2025 15:20:04 +1000 Subject: [PATCH] =?UTF-8?q?feat(templateGeneratorWorker):=20=D0=A1=D0=BE?= =?UTF-8?q?=D0=B7=D0=B4=D0=B0=D0=BD=20Worker=20=D1=87=D0=B8=D1=82=D0=B0?= =?UTF-8?q?=D1=8E=D1=89=D0=B8=D0=B9=20=D0=BE=D1=87=D0=B5=D1=80=D0=B5=D0=B4?= =?UTF-8?q?=D1=8C=20=D0=B8=20=D0=B3=D0=B5=D0=BD=D0=B5=D1=80=D0=B8=D1=80?= =?UTF-8?q?=D1=83=D1=8E=D1=89=D0=B8=D0=B9=20=D0=BD=D0=BE=D0=B2=D1=8B=D0=B5?= =?UTF-8?q?=20=D0=BE=D0=B1=D1=8A=D0=B5=D0=BA=D1=82=D1=8B=20Template?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PARR.API.sln | 6 + .../Domain/Mq/TemplateGeneratorWorkerMq.cs | 36 ++++++ PARR.Constants/ParrComponentsEnum.cs | 7 +- .../Implementations/UnitFilterService.cs | 3 - .../Services/ValidatorService.cs | 1 + PARR.TemplateGeneratorWorker/Dockerfile | 28 ++++ .../PARR.TemplateGeneratorWorker.csproj | 25 ++++ PARR.TemplateGeneratorWorker/Program.cs | 30 +++++ .../Properties/launchSettings.json | 14 ++ .../Services/IValidatorService.cs | 7 + .../Services/ValidatorService.cs | 62 +++++++++ .../Settings/MqSettings.cs | 12 ++ .../TemplateGeneratorWorkerInstaller.cs | 36 ++++++ PARR.TemplateGeneratorWorker/Worker.cs | 121 ++++++++++++++++++ .../appsettings.Development.json | 11 ++ PARR.TemplateGeneratorWorker/appsettings.json | 35 +++++ PARR.Test/Worker.cs | 32 ++--- 17 files changed, 446 insertions(+), 20 deletions(-) create mode 100644 PARR.BLL/Domain/Mq/TemplateGeneratorWorkerMq.cs create mode 100644 PARR.TemplateGeneratorWorker/Dockerfile create mode 100644 PARR.TemplateGeneratorWorker/PARR.TemplateGeneratorWorker.csproj create mode 100644 PARR.TemplateGeneratorWorker/Program.cs create mode 100644 PARR.TemplateGeneratorWorker/Properties/launchSettings.json create mode 100644 PARR.TemplateGeneratorWorker/Services/IValidatorService.cs create mode 100644 PARR.TemplateGeneratorWorker/Services/ValidatorService.cs create mode 100644 PARR.TemplateGeneratorWorker/Settings/MqSettings.cs create mode 100644 PARR.TemplateGeneratorWorker/TemplateGeneratorWorkerInstaller.cs create mode 100644 PARR.TemplateGeneratorWorker/Worker.cs create mode 100644 PARR.TemplateGeneratorWorker/appsettings.Development.json create mode 100644 PARR.TemplateGeneratorWorker/appsettings.json diff --git a/PARR.API.sln b/PARR.API.sln index 38dd4826..898fdffb 100644 --- a/PARR.API.sln +++ b/PARR.API.sln @@ -90,6 +90,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PARR.AIHITRelationshipsSync EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PARR.AIHITRelationshipsSyncerWorker", "PARR.AIHITRelationshipsSyncerWorker\PARR.AIHITRelationshipsSyncerWorker.csproj", "{64010D07-4053-4EA9-B0F0-E773B5749DBD}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PARR.TemplateGeneratorWorker", "PARR.TemplateGeneratorWorker\PARR.TemplateGeneratorWorker.csproj", "{17245D0B-3290-4C96-B5B1-4B0711BABAF2}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -250,6 +252,10 @@ Global {64010D07-4053-4EA9-B0F0-E773B5749DBD}.Debug|Any CPU.Build.0 = Debug|Any CPU {64010D07-4053-4EA9-B0F0-E773B5749DBD}.Release|Any CPU.ActiveCfg = Release|Any CPU {64010D07-4053-4EA9-B0F0-E773B5749DBD}.Release|Any CPU.Build.0 = Release|Any CPU + {17245D0B-3290-4C96-B5B1-4B0711BABAF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {17245D0B-3290-4C96-B5B1-4B0711BABAF2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {17245D0B-3290-4C96-B5B1-4B0711BABAF2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {17245D0B-3290-4C96-B5B1-4B0711BABAF2}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/PARR.BLL/Domain/Mq/TemplateGeneratorWorkerMq.cs b/PARR.BLL/Domain/Mq/TemplateGeneratorWorkerMq.cs new file mode 100644 index 00000000..9029aca1 --- /dev/null +++ b/PARR.BLL/Domain/Mq/TemplateGeneratorWorkerMq.cs @@ -0,0 +1,36 @@ +using PARR.Common.Domain; + +namespace PARR.BLL.Domain.Mq +{ + /// + /// Модель в MQ, простого создания Template + /// + public class TemplateGeneratorWorkerMq + { + /// + /// Id регламентной работы + /// + public Guid JobId { get; set; } + + /// + /// Id Юнита(единицы обслуживания)/ЭК + /// + public Guid UnitId { get; set; } + + /// + /// Актировать шаблон при инициализации + /// + public bool? IsActiveTemplate { get; set; } + + /// + /// Актировать расписание при инициализации + /// + public bool? IsActiveSchedule { get; set; } + + /// + /// Инициатор запроса к генератору + /// + public HistoryInitiator? HistoryInitiator { get; set; } + + } +} diff --git a/PARR.Constants/ParrComponentsEnum.cs b/PARR.Constants/ParrComponentsEnum.cs index 3603cf76..ac3f1091 100644 --- a/PARR.Constants/ParrComponentsEnum.cs +++ b/PARR.Constants/ParrComponentsEnum.cs @@ -71,6 +71,11 @@ /// /// Автораспределение РР /// - TemplateDistributor = 12 + TemplateDistributor = 12, + + /// + /// Генератор Template + /// + TemplateGenerator = 13 } } diff --git a/PARR.DAL/DomainServices/Implementations/UnitFilterService.cs b/PARR.DAL/DomainServices/Implementations/UnitFilterService.cs index d7f80a5c..7822fd9b 100644 --- a/PARR.DAL/DomainServices/Implementations/UnitFilterService.cs +++ b/PARR.DAL/DomainServices/Implementations/UnitFilterService.cs @@ -66,8 +66,6 @@ namespace PARR.DAL.DomainServices.Implementations .ThenInclude(t => t.UnitValues) .ThenInclude(t => t.Value); - logger.LogInformation($"В baseQuery записей {await baseQuery.CountAsync()}"); - foreach (var unitFilter in job.UnitFilters) { var query = baseQuery.Where(t => EF.Functions.ILike(t.Name, unitFilter.UnitFilter)); @@ -94,7 +92,6 @@ namespace PARR.DAL.DomainServices.Implementations else query = query.Where(t => !t.ParentUnits.Any() || !t.ParentUnits.Any(p => p.ParentUnit!.UnitValues.Any(pf => pf.FieldId == parentFilter.FieldId && (pf.Value!.Value != null && EF.Functions.ILike(pf.Value.Value, parentFilter.ValueMask))))); } - logger.LogInformation($"!В query записей {await query.CountAsync()}"); } } var newUnits = await query.Select(t => t.Id).ToListAsync(); diff --git a/PARR.TemplateActivator/Services/ValidatorService.cs b/PARR.TemplateActivator/Services/ValidatorService.cs index b4b31388..af645101 100644 --- a/PARR.TemplateActivator/Services/ValidatorService.cs +++ b/PARR.TemplateActivator/Services/ValidatorService.cs @@ -18,6 +18,7 @@ internal class ValidatorService : IValidatorService this.logger = logger; } + public async Task IsValidApplicationInWorkAsync(Guid applicationInWorkId) { using (var scope = serviceProvider.CreateScope()) diff --git a/PARR.TemplateGeneratorWorker/Dockerfile b/PARR.TemplateGeneratorWorker/Dockerfile new file mode 100644 index 00000000..4b3d1ba6 --- /dev/null +++ b/PARR.TemplateGeneratorWorker/Dockerfile @@ -0,0 +1,28 @@ +# See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. + +# This stage is used when running from VS in fast mode (Default for Debug configuration) +FROM mcr.microsoft.com/dotnet/runtime:7.0 AS base +WORKDIR /app + + +# This stage is used to build the service project +FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build +ARG BUILD_CONFIGURATION=Release +WORKDIR /src +COPY ["NuGet.config", "."] +COPY ["PARR.TemplateGeneratorWorker/PARR.TemplateGeneratorWorker.csproj", "PARR.TemplateGeneratorWorker/"] +RUN dotnet restore "./PARR.TemplateGeneratorWorker/PARR.TemplateGeneratorWorker.csproj" +COPY . . +WORKDIR "/src/PARR.TemplateGeneratorWorker" +RUN dotnet build "./PARR.TemplateGeneratorWorker.csproj" -c $BUILD_CONFIGURATION -o /app/build + +# This stage is used to publish the service project to be copied to the final stage +FROM build AS publish +ARG BUILD_CONFIGURATION=Release +RUN dotnet publish "./PARR.TemplateGeneratorWorker.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false + +# This stage is used in production or when running from VS in regular mode (Default when not using the Debug configuration) +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "PARR.TemplateGeneratorWorker.dll"] \ No newline at end of file diff --git a/PARR.TemplateGeneratorWorker/PARR.TemplateGeneratorWorker.csproj b/PARR.TemplateGeneratorWorker/PARR.TemplateGeneratorWorker.csproj new file mode 100644 index 00000000..3d16e5a9 --- /dev/null +++ b/PARR.TemplateGeneratorWorker/PARR.TemplateGeneratorWorker.csproj @@ -0,0 +1,25 @@ + + + + net7.0 + enable + enable + dotnet-PARR.TemplateGeneratorWorker-4ea24dbb-6876-46db-9b6e-68e93850120e + Linux + + + + + + + + + + + + + + + + + diff --git a/PARR.TemplateGeneratorWorker/Program.cs b/PARR.TemplateGeneratorWorker/Program.cs new file mode 100644 index 00000000..6295dd43 --- /dev/null +++ b/PARR.TemplateGeneratorWorker/Program.cs @@ -0,0 +1,30 @@ +using Elastic.CommonSchema.Serilog; +using PARR.TemplateGeneratorWorker; +using Serilog; + +var builder = Host.CreateApplicationBuilder(); + +builder.Services.AddLogging(config => +{ + config.ClearProviders(); + + var logger = new LoggerConfiguration(); + + if (builder.Environment.IsProduction()) + logger.WriteTo.Console(new EcsTextFormatter()); + else + logger.WriteTo.Console(); + + logger.ReadFrom.Configuration(builder.Configuration); + + config.AddSerilog(logger.CreateLogger()); +}); + +builder.Services.InstallTemplateGeneratorWorkerSerivces(builder.Configuration); +builder.Configuration.AddTemplateGeneratorWorkerConfigurations(builder.Services); +builder.Services.AddTemplateGeneratorWorkerSettings(builder.Configuration); + +builder.Services.AddHostedService(); + +var host = builder.Build(); +host.Run(); diff --git a/PARR.TemplateGeneratorWorker/Properties/launchSettings.json b/PARR.TemplateGeneratorWorker/Properties/launchSettings.json new file mode 100644 index 00000000..77f33fba --- /dev/null +++ b/PARR.TemplateGeneratorWorker/Properties/launchSettings.json @@ -0,0 +1,14 @@ +{ + "profiles": { + "PARR.TemplateGeneratorWorker": { + "commandName": "Project", + "environmentVariables": { + "DOTNET_ENVIRONMENT": "Development" + }, + "dotnetRunMessages": true + }, + "Container (Dockerfile)": { + "commandName": "Docker" + } + } +} \ No newline at end of file diff --git a/PARR.TemplateGeneratorWorker/Services/IValidatorService.cs b/PARR.TemplateGeneratorWorker/Services/IValidatorService.cs new file mode 100644 index 00000000..34a57370 --- /dev/null +++ b/PARR.TemplateGeneratorWorker/Services/IValidatorService.cs @@ -0,0 +1,7 @@ +namespace PARR.TemplateGeneratorWorker.Services +{ + public interface IValidatorService + { + Task IsValidAsync(Guid jobId, Guid unitId); + } +} diff --git a/PARR.TemplateGeneratorWorker/Services/ValidatorService.cs b/PARR.TemplateGeneratorWorker/Services/ValidatorService.cs new file mode 100644 index 00000000..88077c40 --- /dev/null +++ b/PARR.TemplateGeneratorWorker/Services/ValidatorService.cs @@ -0,0 +1,62 @@ +using Microsoft.EntityFrameworkCore; +using PARR.DAL.Services.Interfaces.Job; +using PARR.DAL.Services.Interfaces.Unit; + +namespace PARR.TemplateGeneratorWorker.Services +{ + internal class ValidatorService : IValidatorService + { + private readonly IServiceProvider serviceProvider; + private readonly ILogger logger; + + public ValidatorService( + IServiceProvider serviceProvider, + ILogger logger + ) + { + this.serviceProvider = serviceProvider; + this.logger = logger; + } + + + public async Task IsValidAsync(Guid jobId, Guid unitId) + { + using (var scope = serviceProvider.CreateScope()) + { + var jobService = GetServiceInScope(scope); + var job = await jobService + .Get().AsNoTracking() + .FirstOrDefaultAsync(t => t.Id == jobId); + + if (job == null) + { + logger.LogError($"Не найдена регалментная работа {nameof(jobId)}: {jobId}"); + return false; + } + + var unitService = GetServiceInScope(scope); + var unit = await unitService + .Get().AsNoTracking() + .FirstOrDefaultAsync(t => t.Id == unitId); + + if (unit == null) + { + logger.LogError($"Не найден элемент конфигурации {nameof(unitId)}: {unitId}"); + return false; + } + + return true; + } + } + + + private Service GetServiceInScope(IServiceScope scope) + { + var service = scope.ServiceProvider.GetService(); + if (service == null) + throw new Exception($"Не найден сервис: {nameof(Service)}"); + + return service; + } + } +} diff --git a/PARR.TemplateGeneratorWorker/Settings/MqSettings.cs b/PARR.TemplateGeneratorWorker/Settings/MqSettings.cs new file mode 100644 index 00000000..652588ab --- /dev/null +++ b/PARR.TemplateGeneratorWorker/Settings/MqSettings.cs @@ -0,0 +1,12 @@ +using PARR.BLL.Contracts.Interfaces; + +namespace PARR.TemplateGeneratorWorker.Settings +{ + public class MqSettings : IMqSettings//TODO почему-то только публик работает + { + public string HostName { get; set; } = string.Empty; + public string QueueName { get; set; } = string.Empty; + public string User { get; set; } = string.Empty; + public string Password { get; set; } = string.Empty; + } +} diff --git a/PARR.TemplateGeneratorWorker/TemplateGeneratorWorkerInstaller.cs b/PARR.TemplateGeneratorWorker/TemplateGeneratorWorkerInstaller.cs new file mode 100644 index 00000000..708189e8 --- /dev/null +++ b/PARR.TemplateGeneratorWorker/TemplateGeneratorWorkerInstaller.cs @@ -0,0 +1,36 @@ +using PARR.BLL; +using PARR.DAL; +using PARR.TemplateGeneratorWorker.Services; +using PARR.TemplateGeneratorWorker.Settings; + +namespace PARR.TemplateGeneratorWorker +{ + public static class TemplateGeneratorWorkerInstaller + { + public static void InstallTemplateGeneratorWorkerSerivces(this IServiceCollection services, IConfiguration configuration) + { + services.InstallBllServices(configuration); + services.InstallDalServices(configuration); + + var mqSettings = new MqSettings(); + configuration.GetSection(nameof(MqSettings)).Bind(mqSettings); + services.AddSingleton(mqSettings); + + //services.AddTransient(); + //services.AddTransient(); + services.AddTransient(); + } + + public static IConfigurationBuilder AddTemplateGeneratorWorkerConfigurations(this IConfigurationBuilder builder, IServiceCollection services) + { + builder.AddDalConfigurations(services); + + return builder; + } + + public static void AddTemplateGeneratorWorkerSettings(this IServiceCollection services, IConfiguration configuration) + { + services.AddDallSettings(configuration); + } + } +} diff --git a/PARR.TemplateGeneratorWorker/Worker.cs b/PARR.TemplateGeneratorWorker/Worker.cs new file mode 100644 index 00000000..f3be9a1e --- /dev/null +++ b/PARR.TemplateGeneratorWorker/Worker.cs @@ -0,0 +1,121 @@ +using Microsoft.EntityFrameworkCore; +using PARR.BLL.Contracts.Interfaces; +using PARR.BLL.Domain.Mq; +using PARR.BLL.Services.Interfaces; +using PARR.Common.Domain; +using PARR.Constants; +using PARR.DAL.DomainServices.Interfaces; +using PARR.DAL.Models; +using PARR.DAL.Services.Interfaces; +using PARR.DAL.Services.Interfaces.Job; +using PARR.TemplateGeneratorWorker.Services; +using PARR.TemplateGeneratorWorker.Settings; + +namespace PARR.TemplateGeneratorWorker +{ + public class Worker : BackgroundService + { + private readonly ILogger logger; + private readonly IMqSettings mqSettings; + private readonly IMqService mqService; + private readonly ITransformService transformService; + private readonly IValidatorService validatorService; + private readonly IServiceProvider serviceProvider; + + public Worker( + ILogger logger, + MqSettings mqSettings, + IMqService mqService, + ITransformService transformService, + IValidatorService validatorService, + IServiceProvider serviceProvider + ) + { + this.logger = logger; + this.mqSettings = mqSettings; + this.mqService = mqService; + this.transformService = transformService; + this.validatorService = validatorService; + this.serviceProvider = serviceProvider; + } + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + while (!stoppingToken.IsCancellationRequested) + { + var isConnected = mqService.InitConsumer(mqSettings, GenerateTemplateAsync); + + if (!isConnected) + throw new Exception(" RabbitMq"); + } + } + + + public override Task StopAsync(CancellationToken cancellationToken) + { + mqService.Dispose(); + + return base.StopAsync(cancellationToken); + } + + + private async Task GenerateTemplateAsync(string msg) + { + logger.LogInformation($"{this.GetType().Name}. : {msg}"); + + var query = transformService.GetModelFromJson(msg); + if (query == null) + return; + + if (!await validatorService.IsValidAsync(query.JobId, query.UnitId)) + { + logger.LogError($" {nameof(query.JobId)}: {query.JobId}"); + return; + } + + using (var scope = serviceProvider.CreateScope()) + { + var jobService = GetServiceInScope(scope); + + var job = await jobService + .Get().AsNoTracking() + .FirstOrDefaultAsync(t => t.Id == query.JobId); + + var shortcodesService = GetServiceInScope(scope); + var templateName = await shortcodesService.ApplyShortcodesAsync(job!.TemplateNameMask!, query.UnitId, query.JobId); + + var template = new Template + { + Id = Guid.NewGuid(), + Name = templateName, + UnitId = query.UnitId, + JobId = query.JobId, + IsActiveTemplate = query.IsActiveTemplate ?? false, + IsActiveSchedule = query.IsActiveSchedule ?? false, + InitiatorComment = query.HistoryInitiator?.InitiatorComment, + InitiatorParrComponentId = query.HistoryInitiator?.InitiatorParrComponentId + }; + var templateService = GetServiceInScope(scope); + + if (!await templateService.CreateAsync(template) || !await templateService.CommitAsync(new HistoryInitiator { InitiatorComment = " ", InitiatorParrComponentId = ParrComponentsEnum.TemplateGenerator })) + { + logger.LogError($" : Name: {template.Name}, {nameof(template.Job)}: {template.JobId}, {nameof(template.Unit)}: {template.UnitId}"); + } + else + { + logger.LogInformation($" : Name: {template.Name}, {nameof(template.Job)}: {template.JobId}, {nameof(template.Unit)}: {template.UnitId}"); + } + + } + } + + private Service GetServiceInScope(IServiceScope scope) + { + var service = scope.ServiceProvider.GetService(); + if (service == null) + throw new Exception($" : {nameof(Service)}"); + + return service; + } + } +} diff --git a/PARR.TemplateGeneratorWorker/appsettings.Development.json b/PARR.TemplateGeneratorWorker/appsettings.Development.json new file mode 100644 index 00000000..992d2719 --- /dev/null +++ b/PARR.TemplateGeneratorWorker/appsettings.Development.json @@ -0,0 +1,11 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "MqSettings": { + "HostName": "10.99.253.216" + } +} diff --git a/PARR.TemplateGeneratorWorker/appsettings.json b/PARR.TemplateGeneratorWorker/appsettings.json new file mode 100644 index 00000000..b7b41d4e --- /dev/null +++ b/PARR.TemplateGeneratorWorker/appsettings.json @@ -0,0 +1,35 @@ +{ + "ConnectionStrings": { + "DefaultConnection": "Server=10.99.253.184;Database=parr;User Id=app_parr; Password=PosdfkhT&)%sdfligL&%5546;" + }, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "Serilog": { + "MinimumLevel": { + "Default": "Debug", + "Override": { + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Debug" + } + }, + "WriteTo": [ + { + "Name": "File", + "Args": { + "path": "log/log-.txt", + "rollingInterval": "Day" + } + } + ] + }, + "MqSettings": { + "HostName": "parr-rabbitmq", + "QueueName": "parr-template-generator", + "User": "template_generator_reader", + "Password": "Jy7vsoygcl7e0:Qy" + } +} diff --git a/PARR.Test/Worker.cs b/PARR.Test/Worker.cs index 70062f76..919ade88 100644 --- a/PARR.Test/Worker.cs +++ b/PARR.Test/Worker.cs @@ -35,28 +35,28 @@ namespace PARR.Test protected override async Task ExecuteAsync(CancellationToken stoppingToken) { #region test - //using (var scope = serviceProvider.CreateScope()) - //{ - // var unitFilterService = scope.ServiceProvider.GetService(); + using (var scope = serviceProvider.CreateScope()) + { + var unitFilterService = scope.ServiceProvider.GetService(); - // if (unitFilterService == null) - // return; + if (unitFilterService == null) + return; - // var jobId = Guid.Parse("58b28517-8178-4683-a519-22f5989c9912"); - // var unitsId = await unitFilterService.GetUnitsIdByJobFilterAsync(jobId); + var jobId = Guid.Parse("926793f7-c6d3-4f08-b5ce-517ce1a1ac37"); + //var unitsId = await unitFilterService.GetUnitsIdByJobFilterAsync(jobId); - // var unitService = scope.ServiceProvider.GetService(); + var unitService = scope.ServiceProvider.GetService(); - // if (unitService == null) - // return; + if (unitService == null) + return; - // var tForCreate = await unitFilterService.GetUnitsIdForExistTemplatesByJobFilterAsync(jobId); - // if (tForCreate == null) - // return; + var tForCreate = await unitFilterService.GetUnitsIdForExistTemplatesByJobFilterAsync(jobId); + if (tForCreate == null) + return; - // var units = await unitService - // .Get().AsNoTracking() - // .Where(t => tForCreate.Any(x => x == t.Id)).ToListAsync(); + var units = await unitService + .Get().AsNoTracking() + .Where(t => tForCreate.Any(x => x == t.Id)).ToListAsync(); } #endregion