From f351a8863a439ce0ca22dbea40a85415f365b4e2 Mon Sep 17 00:00:00 2001 From: Mikhail Kuznetsov Date: Wed, 6 Aug 2025 10:33:55 +1000 Subject: [PATCH] =?UTF-8?q?feat(api,dal,esppSync,esppTemplateSync,esppSche?= =?UTF-8?q?duleSync):=20=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=BE=D0=B2?= =?UTF-8?q?=D0=B0=D0=BD=20=D1=81=D0=B5=D1=80=D0=B2=D0=B8=D1=81=20Shortcode?= =?UTF-8?q?sService=20=D0=BF=D0=BE=D0=B4=D0=BC=D0=B5=D0=BD=D1=8F=D1=8E?= =?UTF-8?q?=D1=89=D0=B8=D0=B9=20=D0=B4=D0=B8=D0=BD=D0=B0=D0=BC=D0=B8=D1=87?= =?UTF-8?q?=D0=B5=D1=81=D0=BA=D0=B8=D0=B5=20=D1=81=D0=BE=D1=81=D1=82=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D1=8F=D1=8E=D1=89=D0=B8=D0=B5=20=D0=B2=20=D0=BF?= =?UTF-8?q?=D0=BE=D0=BB=D1=8F=D1=85=20=D1=88=D0=B0=D0=B1=D0=BB=D0=BE=D0=BD?= =?UTF-8?q?=D0=BE=D0=B2=20=D0=B8=20=D1=80=D0=B0=D1=81=D0=BF=D0=B8=D1=81?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D0=B9.=20=D0=92=20API=20=D0=BA=D0=BE=D0=BD?= =?UTF-8?q?=D1=82=D1=80=D0=BE=D0=BB=D0=BB=D0=B5=D1=80=20=D0=B2=D1=8B=D0=B4?= =?UTF-8?q?=D0=B0=D1=87=D0=B8=20=D0=B7=D0=B0=D0=B4=D0=B0=D0=BD=D0=B8=D0=B9?= =?UTF-8?q?=20=D1=80=D0=BE=D0=B1=D0=BE=D1=82=D1=83=20=D1=82=D0=B5=D0=BF?= =?UTF-8?q?=D0=B5=D1=80=D1=8C=20=D0=B2=D1=8B=D0=B4=D0=B0=D1=91=D1=82=20?= =?UTF-8?q?=D0=B7=D0=BD=D0=B0=D1=87=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=BB=D0=B9=20=D0=B2=20=D0=BD=D0=BE=D0=B2=D0=BE=D0=BC=20=D0=B2?= =?UTF-8?q?=D0=B8=D0=B4=D0=B5,=20=D1=80=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7?= =?UTF-8?q?=D1=83=D1=8F=20Shortcodes.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/V1/RobotTaskController.cs | 26 ++++++-- .../DomainToResponseProfile.cs | 2 +- PARR.DAL/DomainServices/IShortcodesService.cs | 2 + PARR.DAL/DomainServices/ShortcodesService.cs | 17 +++--- .../Implementations/TemplateService.cs | 10 +++- PARR.EsppScheduleSync/ScheduleSyncher.cs | 3 +- PARR.EsppSync/ISyncService.cs | 2 +- PARR.EsppSync/SyncService.cs | 59 ++++++++++++------- .../EsppTemplateSyncInstaller.cs | 2 +- PARR.EsppTemplateSync/TemplateMQSyncer.cs | 35 ++++++----- PARR.EsppTemplateSyncWorker/Worker.cs | 6 +- 11 files changed, 106 insertions(+), 58 deletions(-) diff --git a/PARR.API/Controllers/V1/RobotTaskController.cs b/PARR.API/Controllers/V1/RobotTaskController.cs index b7081525..8d5fd7cd 100644 --- a/PARR.API/Controllers/V1/RobotTaskController.cs +++ b/PARR.API/Controllers/V1/RobotTaskController.cs @@ -11,6 +11,7 @@ using PARR.API.Services.Interfaces; using PARR.Common.Domain; using PARR.Constants; using PARR.DAL.Contracts; +using PARR.DAL.DomainServices; using PARR.DAL.Models; using PARR.DAL.Services.Interfaces; using PARR.DAL.TransformServices; @@ -27,6 +28,7 @@ namespace PARR.API.Controllers.V1 private readonly ILogger logger; private readonly IClientService clientService; private readonly IRobotHistoryService robotHistoryService; + private readonly IShortcodesService shortcodesService; public RobotTaskController( IMapper mapper, @@ -35,7 +37,8 @@ namespace PARR.API.Controllers.V1 IEsppScheduleTransformService esppScheduleTransformService, ILogger logger, IClientService clientService, - IRobotHistoryService robotHistoryService + IRobotHistoryService robotHistoryService, + IShortcodesService shortcodesService ) { this.mapper = mapper; @@ -45,6 +48,7 @@ namespace PARR.API.Controllers.V1 this.logger = logger; this.clientService = clientService; this.robotHistoryService = robotHistoryService; + this.shortcodesService = shortcodesService; } @@ -158,15 +162,29 @@ namespace PARR.API.Controllers.V1 { case RobotsEnum.TemplateOrder: //RobotTaskTemplateResponse - return Ok(new Response(mapper.Map(task), true)); + var robotTaskTemplateResponse = mapper.Map(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); + + return Ok(new Response(robotTaskTemplateResponse, true)); case RobotsEnum.ScheduleOrder: // если был запрос на расписание, проверяем у него nextRun, lastRun, обновляем их await UpdateLastNextRunDate(task); //RobotTaskScheduleResponse - var response = mapper.Map(task); + var robotTaskScheduleResponse = mapper.Map(task); - return Ok(new Response(response, true)); + return Ok(new Response(robotTaskScheduleResponse, true)); default: break; } diff --git a/PARR.API/MappingProfiles/DomainToResponseProfile.cs b/PARR.API/MappingProfiles/DomainToResponseProfile.cs index 73dc566f..d993de6f 100644 --- a/PARR.API/MappingProfiles/DomainToResponseProfile.cs +++ b/PARR.API/MappingProfiles/DomainToResponseProfile.cs @@ -160,7 +160,7 @@ namespace PARR.API.MappingProfiles .ForMember(d => d.Solution, o => o.MapFrom(s => s.Template!.Job!.Group!.Solution)) //.ForMember(d => d.ResponseArea, o => o.MapFrom(s => s.Template!.Host!.ResponseArea!.Name)) //ЗО берем у группы а не у хоста - .ForMember(d => d.ResponseArea, o => o.MapFrom(s => s.Template!.Unit.BaseFields!.ResponseArea)) + .ForMember(d => d.ResponseArea, o => o.MapFrom(s => s.Template!.Unit!.BaseFields!.ResponseArea)) .ForMember(d => d.TemplateDuration, o => o.MapFrom(s => s.Template!.Job!.Group!.TemplateDuration)) .ForMember(d => d.Initiator, o => o.MapFrom()) .ForMember(d => d.Category, o => o.MapFrom()) diff --git a/PARR.DAL/DomainServices/IShortcodesService.cs b/PARR.DAL/DomainServices/IShortcodesService.cs index 71beb311..8b51835a 100644 --- a/PARR.DAL/DomainServices/IShortcodesService.cs +++ b/PARR.DAL/DomainServices/IShortcodesService.cs @@ -9,5 +9,7 @@ namespace PARR.DAL.DomainServices public interface IShortcodesService { Task ApplyShortcodesAsync(string str, Guid unitId, Guid jobId); + + bool isAnyShortcodes(string str); } } diff --git a/PARR.DAL/DomainServices/ShortcodesService.cs b/PARR.DAL/DomainServices/ShortcodesService.cs index 963c4b95..0ef7f4b4 100644 --- a/PARR.DAL/DomainServices/ShortcodesService.cs +++ b/PARR.DAL/DomainServices/ShortcodesService.cs @@ -1,20 +1,14 @@ using Microsoft.EntityFrameworkCore; using PARR.DAL.Contracts; -using PARR.DAL.Services.Implementations.Job; -using PARR.DAL.Services.Implementations.Unit; using PARR.DAL.Services.Interfaces.Job; using PARR.DAL.Services.Interfaces.Unit; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Text.RegularExpressions; -using System.Threading.Tasks; namespace PARR.DAL.DomainServices { internal class ShortcodesService : IShortcodesService { + private const string shortcodePattern = "%[^%\\s]+%"; private readonly SettingsFromDb settingsFromDb; private readonly IJobService jobService; private readonly IUnitService unitService; @@ -41,7 +35,7 @@ namespace PARR.DAL.DomainServices if (job != null && unit != null && job.TemplateNameMask != null) { - var resultName = job.TemplateNameMask; + var resultName = str; var shortcodesInMask = GetShortCodes(resultName); @@ -72,6 +66,12 @@ namespace PARR.DAL.DomainServices } + public bool isAnyShortcodes(string str) + { + return Regex.IsMatch(str, shortcodePattern); + } + + private async Task ReplaceFieldValues(Guid unitId, string resultName, List shortcodesInMask) { var unitWithFields = await unitService.Get() @@ -120,7 +120,6 @@ namespace PARR.DAL.DomainServices private static List GetShortCodes(string resultName) { - var shortcodePattern = "%[^%\\s]+%"; var shortcodesInMask = Regex.Matches(resultName, shortcodePattern).ToList(); return shortcodesInMask; } diff --git a/PARR.DAL/Services/Implementations/TemplateService.cs b/PARR.DAL/Services/Implementations/TemplateService.cs index d800f75f..82ed3c7f 100644 --- a/PARR.DAL/Services/Implementations/TemplateService.cs +++ b/PARR.DAL/Services/Implementations/TemplateService.cs @@ -35,12 +35,18 @@ namespace PARR.DAL.Services.Implementations { return Get() .Include(h => h.Unit) + .ThenInclude(t => t!.UnitValues) + .ThenInclude(t => t.Value) + .Include(h => h.Unit) + .ThenInclude(t => t!.UnitValues) + .ThenInclude(t => t.Field) .Include(a => a.Job) .ThenInclude(t => t!.Tnk) .ThenInclude(s => s!.Subprocess) .ThenInclude(p => p!.Process) - .Include(t=>t.Job) - .ThenInclude(t=>t!.Group); + .Include(t => t.Job) + .ThenInclude(t => t!.Group); + //return Get() // .Include(h => h.Host) diff --git a/PARR.EsppScheduleSync/ScheduleSyncher.cs b/PARR.EsppScheduleSync/ScheduleSyncher.cs index 3020efdf..bfa1c7ac 100644 --- a/PARR.EsppScheduleSync/ScheduleSyncher.cs +++ b/PARR.EsppScheduleSync/ScheduleSyncher.cs @@ -78,7 +78,7 @@ namespace PARR.EsppScheduleSync /// /// /// - private async Task ConvertDbObjToEsppObj(Template template) + private EsppObjectSchedule ConvertDbObjToEsppObj(Template template) { var esppObjectFromDb = new EsppObjectSchedule { @@ -102,7 +102,6 @@ namespace PARR.EsppScheduleSync }; FillScheduleFromDb(template, ref esppObjectFromDb); - await Task.Delay(1);//TODO Нет парни нет!!! return ClearOptionalFields(esppObjectFromDb); } diff --git a/PARR.EsppSync/ISyncService.cs b/PARR.EsppSync/ISyncService.cs index ec716718..449d5e1d 100644 --- a/PARR.EsppSync/ISyncService.cs +++ b/PARR.EsppSync/ISyncService.cs @@ -16,7 +16,7 @@ namespace PARR.EsppSync /// /// /// - public delegate Task ConvertDbObjToComparisonObjHandlerDelegate(Template template) where EsppObject : class, IEsppObject; + public delegate EsppObject ConvertDbObjToComparisonObjHandlerDelegate(Template template) where EsppObject : class, IEsppObject; public interface ISyncService where EsppObject : class, IEsppObject { diff --git a/PARR.EsppSync/SyncService.cs b/PARR.EsppSync/SyncService.cs index 266326f8..2f31f702 100644 --- a/PARR.EsppSync/SyncService.cs +++ b/PARR.EsppSync/SyncService.cs @@ -2,23 +2,31 @@ using Microsoft.Extensions.Logging; using PARR.Constants; using PARR.DAL.Contracts; +using PARR.DAL.DomainServices; using PARR.DAL.Models; using PARR.DAL.Services.Interfaces; +using System.Reflection; namespace PARR.EsppSync { internal class SyncService : ISyncService where EsppObject : class, IEsppObject { private readonly ILogger> logger; - private readonly IServiceProvider serviceProvider; + private readonly ITemplateService templateService; + private readonly IRobotConfigurationService robotConfigurationService; + private readonly IShortcodesService shortcodesService; public SyncService( ILogger> logger, - IServiceProvider serviceProvider + ITemplateService templateService, + IRobotConfigurationService robotConfigurationService, + IShortcodesService shortcodesService ) { this.logger = logger; - this.serviceProvider = serviceProvider; + this.templateService = templateService; + this.robotConfigurationService = robotConfigurationService; + this.shortcodesService = shortcodesService; } @@ -44,11 +52,8 @@ namespace PARR.EsppSync return; } - using (var scope = serviceProvider.CreateScope()) + try { - var templateService = GetServiceInScope(scope); - var robotConfigurationService = GetServiceInScope(scope); - var template = await templateService.GetTemplateByNameAsync(esppObject.TemplateName); //todo: существует в ЕСПП но отсутствует в ПАРР. Может его деактивировать или еще что-то сделать. Пока просто пропустим @@ -62,26 +67,36 @@ namespace PARR.EsppSync { var dbObjectInEsppObject = converterToEsppObject.Invoke(template); + //Проверяем наличие Shortcode в полях объекта из БД + var properties = dbObjectInEsppObject.GetType().GetProperties(); + + foreach (PropertyInfo property in properties) + { + var value = property.GetValue(dbObjectInEsppObject)?.ToString(); + + if (value != null && shortcodesService.isAnyShortcodes(value)) + property.SetValue(dbObjectInEsppObject, await shortcodesService.ApplyShortcodesAsync(value, template.UnitId, template.JobId)); + } + bool isChanged = false; //TODO: FIX ME Please, BRO //bool isChanged; // если в БД isActive == false, то синхронизировать только по полям из IEsppObject - //if (dbObjectInEsppObject.IsActive == false) - //{ - // logger.LogDebug($"Объект деактивирован в ПАРР. Сравниваем только обязательные поля. {esppObject.TemplateName}"); - // var lightDbObj = new EsppLightObject(dbObjectInEsppObject); - // var lightEsppObject = new EsppLightObject(esppObject); - - // isChanged = IsChanged(lightEsppObject, lightDbObj); - //} - //else - //{ - // logger.LogDebug($"Объект активирован в ПАРР. Сравниваем все поля. {esppObject.TemplateName}"); - // isChanged = IsChanged(esppObject, dbObjectInEsppObject); - //} + if (dbObjectInEsppObject.IsActive == false) + { + logger.LogDebug($"Объект деактивирован в ПАРР. Сравниваем только обязательные поля. {esppObject.TemplateName}"); + var lightDbObj = new EsppLightObject(dbObjectInEsppObject); + var lightEsppObject = new EsppLightObject(esppObject); + isChanged = IsChanged(lightEsppObject, lightDbObj); + } + else + { + logger.LogDebug($"Объект активирован в ПАРР. Сравниваем все поля. {esppObject.TemplateName}"); + isChanged = IsChanged(esppObject, dbObjectInEsppObject); + } if (isChanged) { @@ -134,6 +149,10 @@ namespace PARR.EsppSync } } } + catch (Exception ex) + { + logger.LogError(ex, $"Ошибка синхронизации объекта АСУ ЕСПП {esppObject.TemplateName}"); + } } diff --git a/PARR.EsppTemplateSync/EsppTemplateSyncInstaller.cs b/PARR.EsppTemplateSync/EsppTemplateSyncInstaller.cs index b4ee4398..e0dbdd9f 100644 --- a/PARR.EsppTemplateSync/EsppTemplateSyncInstaller.cs +++ b/PARR.EsppTemplateSync/EsppTemplateSyncInstaller.cs @@ -12,8 +12,8 @@ namespace PARR.EsppTemplateSync { public static void InstallEsppTemplateSyncServices(this IServiceCollection services, IConfiguration configuration) { + services.InstallDalServices(configuration); services.InstallBllServices(configuration); - //services.InstallDalServices(configuration); services.InstallEsppSyncServices(configuration); var globalSettings = new GlobalSettings(); diff --git a/PARR.EsppTemplateSync/TemplateMQSyncer.cs b/PARR.EsppTemplateSync/TemplateMQSyncer.cs index 4fafaaf9..78152e67 100644 --- a/PARR.EsppTemplateSync/TemplateMQSyncer.cs +++ b/PARR.EsppTemplateSync/TemplateMQSyncer.cs @@ -1,13 +1,11 @@ -using Microsoft.Extensions.Logging; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using PARR.BLL.Services.Interfaces; using PARR.DAL.Contracts; -using PARR.DAL.DomainServices; -using PARR.DAL.Extensions; using PARR.DAL.Models; using PARR.EsppSync; using PARR.EsppTemplateSync.Domain; using PARR.EsppTemplateSync.Settings; -using System.Threading.Tasks; namespace PARR.EsppTemplateSync { @@ -16,25 +14,22 @@ namespace PARR.EsppTemplateSync private readonly ILogger logger; private readonly GlobalSettings globalSettings; private readonly IMqService mqService; - private readonly ISyncService syncService; private readonly SettingsFromDb settingsFromDb; - private readonly IShortcodesService shortcodesService; + private readonly IServiceProvider serviceProvider; public TemplateMQSyncer( ILogger logger, GlobalSettings globalSettings, IMqService mqService, - ISyncService syncService, SettingsFromDb settingsFromDb, - IShortcodesService shortcodesService + IServiceProvider serviceProvider ) { this.logger = logger; this.globalSettings = globalSettings; this.mqService = mqService; - this.syncService = syncService; this.settingsFromDb = settingsFromDb; - this.shortcodesService = shortcodesService; + this.serviceProvider = serviceProvider; if (globalSettings.MqSettings == null) { logger.LogError("Нет секции настроек хранилища. MqSettings, EsppTemplates"); @@ -44,6 +39,7 @@ namespace PARR.EsppTemplateSync public void Start() { + var isConnected = mqService.InitConsumer(globalSettings!.MqSettings!, SyncTemplateAsync); if (!isConnected) @@ -62,7 +58,16 @@ namespace PARR.EsppTemplateSync private async Task SyncTemplateAsync(string str) { - await syncService.SyncEsppObjectAsync(str, ParseStrToEsppObject, ConvertDbObjToEsppObjAsync); + using (var scope = serviceProvider.CreateScope()) + { + var syncService = scope.ServiceProvider.GetService>(); + + if (syncService == null) + throw new Exception($"Не смог получить серивс {nameof(ITemplateSyncer)}"); + + await syncService.SyncEsppObjectAsync(str, ParseStrToEsppObject, ConvertDbObjToEsppObj); + } + } @@ -71,7 +76,7 @@ namespace PARR.EsppTemplateSync /// /// template должен обязательно содержать в себе информацию о Job+Group и Unit+BaseFields /// - private async Task ConvertDbObjToEsppObjAsync(Template template) + private EsppObjectTemplate ConvertDbObjToEsppObj(Template template) { var templateFromDb = new EsppObjectTemplate { @@ -80,7 +85,7 @@ namespace PARR.EsppTemplateSync //WorkGroup = template.Host!.WorkGroup!, WorkGroup = template.Unit!.BaseFields!.WorkGroup!, //ShortDescription = Normalize(template.Job.Group.ShortDescription.ApplyShortcode(Constants.Shortcodes.ShortcodeEnum.EK,template.Unit.Name)), - ShortDescription = Normalize(await shortcodesService.ApplyShortcodesAsync(template.Job!.Group!.ShortDescription,template.UnitId,template.JobId)),//TODO Вынести в переменную + ShortDescription = Normalize(template.Job!.Group!.ShortDescription),//TODO Вынести в переменную //ResponseArea = template.Host!.ResponseArea!.Name, //ЗО берем РГ а не хоста ResponseArea = template.Unit.BaseFields.ResponseArea!, @@ -91,8 +96,8 @@ namespace PARR.EsppTemplateSync Process = template.Job.Tnk!.Subprocess!.Process!.Name, SubProcess = template.Job.Tnk.Subprocess.Name, //TNK = template.Job.Tnk.Name.ApplyShortcode(Constants.Shortcodes.ShortcodeEnum.EK, template.Unit.Name), - TNK = Normalize(await shortcodesService.ApplyShortcodesAsync(template.Job.Tnk.Name, template.UnitId, template.JobId)), - Work = Normalize(await shortcodesService.ApplyShortcodesAsync(template.Job.WorkName, template.UnitId, template.JobId)), + TNK = template.Job.Tnk.Name, + Work = template.Job.WorkName, Initiator = settingsFromDb.Initiator }; diff --git a/PARR.EsppTemplateSyncWorker/Worker.cs b/PARR.EsppTemplateSyncWorker/Worker.cs index d2c15b86..ccada57b 100644 --- a/PARR.EsppTemplateSyncWorker/Worker.cs +++ b/PARR.EsppTemplateSyncWorker/Worker.cs @@ -1,11 +1,13 @@ +using Microsoft.Extensions.DependencyInjection; using PARR.EsppTemplateSync; +using System; namespace PARR.EsppTemplateSyncWorker { public class Worker : BackgroundService { private readonly ILogger _logger; - private ITemplateSyncer templateSyncer; + private readonly ITemplateSyncer templateSyncer; public Worker( ILogger logger, @@ -19,13 +21,11 @@ namespace PARR.EsppTemplateSyncWorker protected override async Task ExecuteAsync(CancellationToken stoppingToken) { templateSyncer.Start(); - //TODO Периодично нужно проверять шаблоны в ПАРР и создавать их если они отсутствуют в ЕСПП. По ним то ничего не приходит из экспорта } public override Task StopAsync(CancellationToken cancellationToken) { templateSyncer.Stop(); - return base.StopAsync(cancellationToken); } }