diff --git a/PARR.API.sln b/PARR.API.sln index 547d9e78..2abc5c3e 100644 --- a/PARR.API.sln +++ b/PARR.API.sln @@ -51,7 +51,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PARR.EsppApi", "PARR.EsppAp EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PARR.Test", "PARR.Test\PARR.Test.csproj", "{CFE2A198-67BF-4828-8E8D-31A01858FDA7}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PARR.Constants", "PARR.Constants\PARR.Constants.csproj", "{46B09885-C9FB-449C-ACAA-24C671194C4D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PARR.Constants", "PARR.Constants\PARR.Constants.csproj", "{46B09885-C9FB-449C-ACAA-24C671194C4D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PARR.EsppSync", "PARR.EsppSync\PARR.EsppSync.csproj", "{71121EF7-D4C1-43A4-9243-EF5C4C82030F}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -141,6 +143,10 @@ Global {46B09885-C9FB-449C-ACAA-24C671194C4D}.Debug|Any CPU.Build.0 = Debug|Any CPU {46B09885-C9FB-449C-ACAA-24C671194C4D}.Release|Any CPU.ActiveCfg = Release|Any CPU {46B09885-C9FB-449C-ACAA-24C671194C4D}.Release|Any CPU.Build.0 = Release|Any CPU + {71121EF7-D4C1-43A4-9243-EF5C4C82030F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {71121EF7-D4C1-43A4-9243-EF5C4C82030F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {71121EF7-D4C1-43A4-9243-EF5C4C82030F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {71121EF7-D4C1-43A4-9243-EF5C4C82030F}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/PARR.EsppSync/IEsppObject.cs b/PARR.EsppSync/IEsppObject.cs new file mode 100644 index 00000000..c1f410fc --- /dev/null +++ b/PARR.EsppSync/IEsppObject.cs @@ -0,0 +1,7 @@ +namespace PARR.EsppSync +{ + public interface IEsppObject + { + public string TemplateName { get; set; } + } +} diff --git a/PARR.EsppSync/ISyncService.cs b/PARR.EsppSync/ISyncService.cs new file mode 100644 index 00000000..f8a092a7 --- /dev/null +++ b/PARR.EsppSync/ISyncService.cs @@ -0,0 +1,26 @@ +using PARR.DAL.Contracts; +using PARR.DAL.Models; + +namespace PARR.EsppSync +{ + /// + /// Делегат парсинга из строки в модель EsppObject + /// + /// + /// + /// + public delegate EsppObject ParserHandlerDelegate(string str) where EsppObject : class, IEsppObject; + + /// + /// Конвертирует Template в модель для сравнения + /// + /// + /// + /// + public delegate EsppObject ConvertDbObjToComparisonObjHandlerDelegate(Template template) where EsppObject : class, IEsppObject; + + public interface ISyncService where EsppObject : class, IEsppObject + { + Task SyncEsppObjectAsync(string str, ParserHandlerDelegate parser, ConvertDbObjToComparisonObjHandlerDelegate converterToEsppObject, RobotsEnum robot); + } +} \ No newline at end of file diff --git a/PARR.EsppSync/PARR.EsppSync.csproj b/PARR.EsppSync/PARR.EsppSync.csproj new file mode 100644 index 00000000..52abd3ef --- /dev/null +++ b/PARR.EsppSync/PARR.EsppSync.csproj @@ -0,0 +1,17 @@ + + + + net7.0 + enable + enable + + + + + + + + + + + diff --git a/PARR.EsppSync/SyncService.cs b/PARR.EsppSync/SyncService.cs new file mode 100644 index 00000000..f2986e87 --- /dev/null +++ b/PARR.EsppSync/SyncService.cs @@ -0,0 +1,140 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using PARR.DAL.Contracts; +using PARR.DAL.Models; +using PARR.DAL.Services.Interfaces; + +namespace PARR.EsppSync +{ + internal class SyncService : ISyncService where EsppObject : class, IEsppObject + { + private readonly ILogger> logger; + private readonly IServiceProvider serviceProvider; + + public SyncService( + ILogger> logger, + IServiceProvider serviceProvider + ) + { + this.logger = logger; + this.serviceProvider = serviceProvider; + } + + + public async Task SyncEsppObjectAsync( + string str, + ParserHandlerDelegate parser, + ConvertDbObjToComparisonObjHandlerDelegate converterToEsppObject, + RobotsEnum robot + ) + { + logger.LogDebug($"Получил строку. Начинаю работать. Строка: {str}"); + + if (string.IsNullOrEmpty(str)) + { + logger.LogWarning("Получил пустую строку, ничего не делаю."); + return; + } + + var esppObject = parser.Invoke(str); + + if (esppObject == null) + { + logger.LogWarning("После парсинга строки, esppObject = null. Дальше ничего не буду делать."); + return; + } + + using (var scope = serviceProvider.CreateScope()) + { + var templateService = GetServiceInScope(scope); + var robotConfigurationService = GetServiceInScope(scope); + + var template = await templateService.GetTemplateByNameAsync(esppObject.TemplateName); + + //todo: существует в ЕСПП но отсутствует в ПАРР. Может его деактивировать или еще что-то сделать. Пока просто пропустим + if (template == null) + { + logger.LogWarning($"Найден объект в ЕСПП с именем шаблона {esppObject.TemplateName} незарегистрированный в ПАРР."); + + return; + } + else + { + var dbObjectInEsppObject = converterToEsppObject.Invoke(template); + var isChanged = IsChanged(esppObject, dbObjectInEsppObject); + + if (isChanged) + { + SetUpdateStatus(ref template, robotConfigurationService, robot); + + if (!await templateService.CommitAsync()) + logger.LogError($"Не удалось изменить запись Template {template.Name}, Robot: {robot}"); + else + logger.LogInformation($"Установлен принудительный статус {TaskStatusEnum.Updating}, Template {template.Name}, Robot: {robot}"); + }//надо ли проверять если не изменился, но был статус Updating не понятно. Доверяем роботу пока, что после окончания работ он точно сообщит + else + { + //если все поля совпали + //проверяем, какой был статус предыдущий статус в БД, если он был не Ок, то ставим ему ОК + var robotConfig = robotConfigurationService.GetFromTemplateByRobotCode(robot, ref template); + if (robotConfig.TaskStatusCode != (int)TaskStatusEnum.Ok) + { + robotConfigurationService.ChangeTaskStatus(TaskStatusEnum.Ok, ref robotConfig); + if (!await templateService.CommitAsync()) + logger.LogError($"Не удалось изменить запись Template {template.Name}, Robot: {robot}"); + else + logger.LogInformation($"Установлен принудительный статус {TaskStatusEnum.Ok}, Template {template.Name}, Robot: {robot}"); + } + } + } + } + } + + + private void SetUpdateStatus(ref Template template, IRobotConfigurationService robotConfigurationService, RobotsEnum robot) + { + var robotConfig = robotConfigurationService.GetFromTemplateByRobotCode(robot, ref template); + robotConfigurationService.ChangeTaskStatus(TaskStatusEnum.Updating, ref robotConfig); + } + + + private Service GetServiceInScope(IServiceScope scope) + { + var service = scope.ServiceProvider.GetService(); + if (service == null) + throw new Exception($"Не найден сервис: {nameof(Service)}"); + + return service; + } + + + private bool IsChanged(EsppObject esppObj, EsppObject dbObj) + { + foreach (var prop in dbObj.GetType().GetProperties()) + { + if (prop == null) + continue; + + var dbValue = dbObj.GetType().GetProperty(prop.Name)?.GetValue(dbObj, null); + var esppValue = esppObj.GetType().GetProperty(prop.Name)?.GetValue(esppObj, null); + + if (dbValue == null || esppValue == null) + continue; + + //Replace("\r","").Replace("\n","") - в подробном описании могут быть переносы строк, в Rabbit прилетает без переносов. Убираем переносы для стравнения + var dbValueStr = dbValue!.ToString()!.ToLower().Replace("\r", "").Replace("\n", ""); + var esppValueStr = esppValue!.ToString()!.ToLower(); + + if (dbValueStr != esppValueStr) + { + logger.LogDebug($"Не совпадают поля. dbValueStr: {dbValueStr}, esppValueStr: {esppValueStr}"); + + return true; + } + } + + return false; + } + + } +} diff --git a/PARR.EsppTemplateSync/Services/Manager.cs b/PARR.EsppTemplateSync/Services/Manager.cs index 83f2f6f5..4dc4b864 100644 --- a/PARR.EsppTemplateSync/Services/Manager.cs +++ b/PARR.EsppTemplateSync/Services/Manager.cs @@ -116,9 +116,9 @@ namespace PARR.EsppTemplateSync.Services if (!await templateService.CommitAsync()) logger.LogError($"Не удалось изменить запись Template {template.Name}"); else - logger.LogInformation($"----- Установлен принудительный статус {TaskStatusEnum.Updating.ToString()} Template {template.Name} -----"); + logger.LogInformation($"----- Установлен принудительный статус {TaskStatusEnum.Updating} Template {template.Name} -----"); - } //надо ли проверять если не изменился, но был статус Updating не понятно. Доверяем роботу пока, что после окончания работ от точно сообщит + } //надо ли проверять если не изменился, но был статус Updating не понятно. Доверяем роботу пока, что после окончания работ он точно сообщит else { //если все поля совпали @@ -151,9 +151,11 @@ namespace PARR.EsppTemplateSync.Services { foreach (var prop in template.GetType().GetProperties()) { - if (prop == null) continue; + if (prop == null) + continue; - if (globalSettings.IgnoreTemplateFields != null && globalSettings.IgnoreTemplateFields.Contains(prop.Name)) continue; + if (globalSettings.IgnoreTemplateFields != null && globalSettings.IgnoreTemplateFields.Contains(prop.Name)) + continue; var parrValue = template.GetType().GetProperty(prop.Name)?.GetValue(template, null); var esppValue = esppTemplate.GetType().GetProperty(prop.Name)?.GetValue(esppTemplate, null); diff --git a/PARR.EsppTemplateSync/Services/ParserService.cs b/PARR.EsppTemplateSync/Services/ParserService.cs index 226bae23..43635045 100644 --- a/PARR.EsppTemplateSync/Services/ParserService.cs +++ b/PARR.EsppTemplateSync/Services/ParserService.cs @@ -119,7 +119,7 @@ namespace PARR.EsppTemplateSync.Services } - // dll + //// dll //public delegate Dt CustomParserHandlerDelegate
(string str); @@ -135,7 +135,7 @@ namespace PARR.EsppTemplateSync.Services //public class RunConverter //{ - // public void Run(CustomParserHandlerDelegate customParser) + // public void Run(CustomParserHandlerDelegate customParser) // { // var conv = new Converter(); // //var obj = conv.ParseString("sdfsdfsdf", SuperParser); diff --git a/README.md b/README.md index f299d19b..90a2cca7 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ - PARR.EsppOrderLoaderWorker - PARR.EsppOrderManager - управление нарядами в ЕСПП (в работу, выполнить, и т.п.) - PARR.EsppOrderManagerWorker +- PARR.EsppSync - общая логика синхронизации шаблонов и расписаний ЕСПП с БД PARR - PARR.EsppTemplateSync - логика синхронизации шаблонов ESPP с БД PARR - PARR.EsppTemplateSyncWorker - worker для PARR.EsppTemplateSync - PARR.GeneratorTemplates - логика генерации шаблонов в ПАРР