Files
parr_api/PARR.EsppSync/SyncService.cs

234 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using PARR.Constants;
using PARR.DAL.Contracts;
using PARR.DAL.DomainServices.Interfaces;
using PARR.DAL.Models;
using PARR.DAL.Services.Interfaces;
using System.Reflection;
namespace PARR.EsppSync
{
internal class SyncService<EsppObject> : ISyncService<EsppObject> where EsppObject : class, IEsppObject
{
private readonly ILogger<SyncService<EsppObject>> logger;
private readonly IServiceProvider serviceProvider;
//private readonly ITemplateService templateService;
//private readonly IRobotConfigurationService robotConfigurationService;
//private readonly IShortcodesService shortcodesService;
public SyncService(
ILogger<SyncService<EsppObject>> logger,
IServiceProvider serviceProvider
//ITemplateService templateService,
//IRobotConfigurationService robotConfigurationService,
//IShortcodesService shortcodesService
)
{
this.logger = logger;
this.serviceProvider = serviceProvider;
//this.templateService = templateService;
//this.robotConfigurationService = robotConfigurationService;
//this.shortcodesService = shortcodesService;
}
public async Task SyncEsppObjectAsync(
string str,
ParserHandlerDelegate<EsppObject> parser,
ConvertDbObjToComparisonObjHandlerDelegate<EsppObject> 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<ITemplateService>(scope);
var robotConfigurationService = GetServiceInScope<IRobotConfigurationService>(scope);
var shortcodesService = GetServiceInScope<IShortcodesService>(scope);
try
{
var template = await templateService.GetTemplateByNameAsync(esppObject.TemplateName);
//todo: существует в ЕСПП но отсутствует в ПАРР. Может его деактивировать или еще что-то сделать. Пока просто пропустим
if (template == null)
{
logger.LogWarning($"Найден объект в ЕСПП с именем шаблона {esppObject.TemplateName} незарегистрированный в ПАРР.");
return;
}
else
{
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, esppObject.TemplateName);
}
else
{
logger.LogDebug($"Объект активирован в ПАРР. Сравниваем все поля. {esppObject.TemplateName}");
isChanged = IsChanged(esppObject, dbObjectInEsppObject, esppObject.TemplateName);
}
if (isChanged)
{
logger.LogDebug($"Есть изменения, требуется обновление. {esppObject.TemplateName}");
var config = robotConfigurationService.GetFromTemplateByRobotCode(esppObject.Robot, template);
// Если предыдущий статус был Create или Ок, то ставим ему Update
// пусть даже Create завершился с ошибками, но раз он уже есть в ЕСПП, то изменим на Update, сбросим все счетчики и пусть попробует обновить и исправить все
if (config.TaskStatusCode != (int)TaskStatusEnum.Updating)
{
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}");
}
else
{
// Если пред статус был Update, то ничего не делаем, так его и оставляем, не сбрасывам кол-во попыток и ошибок
logger.LogInformation($"Есть изменения в Template {template.Name}, но предыдущий статус TaskStatusCode: {(TaskStatusEnum)config.TaskStatusCode}. Не меняем статус, будем разбираться вручную.");
}
#region Old logic
//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}");
#endregion
}//надо ли проверять если не изменился, но был статус Updating не понятно. Доверяем роботу пока, что после окончания работ он точно сообщит
else
{
logger.LogDebug($"Нет изменений, обновление не требуется. {esppObject.TemplateName}");
//если все поля совпали
//проверяем, какой был статус предыдущий статус в БД, если он был не Ок, то ставим ему ОК
var robotConfig = robotConfigurationService.GetFromTemplateByRobotCode(esppObject.Robot, template);
if (robotConfig.TaskStatusCode != (int)TaskStatusEnum.Ok)
{
robotConfigurationService.ChangeTaskStatus(TaskStatusEnum.Ok, robotConfig);
if (!await templateService.CommitAsync())
logger.LogError($"Не удалось изменить запись Template {template.Name}, Robot: {esppObject.Robot}");
else
logger.LogInformation($"Установлен принудительный статус {TaskStatusEnum.Ok}, Template {template.Name}, Robot: {esppObject.Robot}");
}
}
}
}
catch (Exception ex)
{
logger.LogError(ex, $"Ошибка синхронизации объекта АСУ ЕСПП {esppObject.TemplateName}");
}
}
}
private void SetUpdateStatus(ref Template template, IRobotConfigurationService robotConfigurationService, RobotsEnum robot)
{
var robotConfig = robotConfigurationService.GetFromTemplateByRobotCode(robot, template);
robotConfigurationService.ChangeTaskStatus(TaskStatusEnum.Updating, robotConfig);
}
private Service GetServiceInScope<Service>(IServiceScope scope)
{
var service = scope.ServiceProvider.GetService<Service>();
if (service == null)
throw new Exception($"Не найден сервис: {nameof(Service)}");
return service;
}
//private bool IsChanged(EsppObject esppObj, EsppObject dbObj)
private bool IsChanged(object esppObj, object dbObj, string templateName)
{
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 = Normalize(dbValue!.ToString()!);
var esppValueStr = Normalize(esppValue!.ToString()!);
if (dbValueStr != esppValueStr)
{
logger.LogInformation($"Не совпадают поля ({prop.Name}). dbValueStr: {dbValueStr}, esppValueStr: {esppValueStr}. Имя шаблона: {templateName}");
return true;
}
}
return false;
}
/// <summary>
/// Удаляет ненужные символы из строки
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
private string Normalize(string str)
{
str = str.Replace("\r", string.Empty);
str = str.Replace("\n", string.Empty);
str = str.Replace(" ", string.Empty);
return str.ToLower();
}
}
}