using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using PARR.Constants; 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 ) { 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); 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 (isChanged) { logger.LogInformation($"Есть изменения, требуется обновление. {esppObject.TemplateName}"); SetUpdateStatus(ref template, robotConfigurationService, esppObject.Robot); if (!await templateService.CommitAsync()) logger.LogError($"Не удалось изменить запись Template {template.Name}, Robot: {esppObject.Robot}"); else logger.LogInformation($"Установлен принудительный статус {TaskStatusEnum.Updating}, Template {template.Name}, Robot: {esppObject.Robot}"); }//надо ли проверять если не изменился, но был статус Updating не понятно. Доверяем роботу пока, что после окончания работ он точно сообщит else { logger.LogInformation($"Нет изменений, обновление не требуется. {esppObject.TemplateName}"); //если все поля совпали //проверяем, какой был статус предыдущий статус в БД, если он был не Ок, то ставим ему ОК var robotConfig = robotConfigurationService.GetFromTemplateByRobotCode(esppObject.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: {esppObject.Robot}"); else logger.LogInformation($"Установлен принудительный статус {TaskStatusEnum.Ok}, Template {template.Name}, Robot: {esppObject.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) private bool IsChanged(object esppObj, object 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; } } }