2025-12-23 18:27:31 +10:00
using Microsoft.EntityFrameworkCore ;
using Microsoft.Extensions.DependencyInjection ;
2023-11-22 11:37:22 +10:00
using Microsoft.Extensions.Logging ;
2023-11-22 12:04:33 +10:00
using PARR.Constants ;
2023-11-22 11:37:22 +10:00
using PARR.DAL.Contracts ;
2025-12-23 18:27:31 +10:00
using PARR.DAL.DomainServices.Shortcodes ;
2023-11-22 11:37:22 +10:00
using PARR.DAL.Models ;
using PARR.DAL.Services.Interfaces ;
2025-08-06 10:33:55 +10:00
using System.Reflection ;
2023-11-22 11:37:22 +10:00
namespace PARR.EsppSync
{
internal class SyncService < EsppObject > : ISyncService < EsppObject > where EsppObject : class , IEsppObject
{
private readonly ILogger < SyncService < EsppObject > > logger ;
2025-08-20 14:10:22 +10:00
private readonly IServiceProvider serviceProvider ;
2023-11-22 11:37:22 +10:00
public SyncService (
ILogger < SyncService < EsppObject > > logger ,
2025-08-20 14:10:22 +10:00
IServiceProvider serviceProvider
2023-11-22 11:37:22 +10:00
)
{
this . logger = logger ;
2025-08-20 14:10:22 +10:00
this . serviceProvider = serviceProvider ;
2023-11-22 11:37:22 +10:00
}
public async Task SyncEsppObjectAsync (
string str ,
ParserHandlerDelegate < EsppObject > parser ,
2023-11-22 12:04:33 +10:00
ConvertDbObjToComparisonObjHandlerDelegate < EsppObject > converterToEsppObject
2023-11-22 11:37:22 +10:00
)
{
logger . LogDebug ( $"Получил строку. Начинаю работать. Строка: {str}" ) ;
if ( string . IsNullOrEmpty ( str ) )
{
logger . LogWarning ( "Получил пустую строку, ничего не делаю." ) ;
return ;
}
var esppObject = parser . Invoke ( str ) ;
if ( esppObject = = null )
{
logger . LogWarning ( "После парсинга строки, esppObject = null. Дальше ничего не буду делать." ) ;
return ;
}
2025-08-20 14:10:22 +10:00
using ( var scope = serviceProvider . CreateScope ( ) )
2023-11-22 11:37:22 +10:00
{
2025-08-20 14:10:22 +10:00
var templateService = GetServiceInScope < ITemplateService > ( scope ) ;
var robotConfigurationService = GetServiceInScope < IRobotConfigurationService > ( scope ) ;
var shortcodesService = GetServiceInScope < IShortcodesService > ( scope ) ;
2023-11-22 11:37:22 +10:00
2025-08-20 14:10:22 +10:00
try
2023-11-22 11:37:22 +10:00
{
2025-12-23 18:27:31 +10:00
// Загружаем Template и TemplateForShortcodes в одном запросе
var query = templateService . Get ( )
2025-12-30 09:42:21 +10:00
//.AsNoTracking() <- не надо так, а то потом не сохранится
2025-12-29 19:21:51 +10:00
. Include ( h = > h . Unit )
. ThenInclude ( t = > t ! . UnitValues )
2026-01-13 14:36:07 +10:00
. ThenInclude ( t = > t . Value )
2025-12-29 19:21:51 +10:00
. Include ( h = > h . Unit )
. ThenInclude ( t = > t ! . UnitValues )
2026-01-13 14:36:07 +10:00
. ThenInclude ( t = > t . Field )
2025-12-29 19:21:51 +10:00
. Include ( t = > t . RobotConfigurations )
2025-12-23 18:27:31 +10:00
. Include ( t = > t . Job )
. ThenInclude ( j = > j . Group )
. ThenInclude ( g = > g . GroupType )
2025-12-25 17:01:42 +10:00
. Include ( t = > t . Job )
. ThenInclude ( t = > t . Group )
. ThenInclude ( t = > t . ScheduleExcludeType )
. Include ( t = > t . Job )
. ThenInclude ( t = > t . Group )
. ThenInclude ( t = > t . ScheduleExcludeTypeCalendar )
2025-12-23 18:27:31 +10:00
. Include ( t = > t . Job )
. ThenInclude ( j = > j . Tnk )
2025-12-29 19:21:51 +10:00
. ThenInclude ( s = > s ! . Subprocess )
. ThenInclude ( p = > p ! . Process )
2025-12-23 18:27:31 +10:00
. Include ( t = > t . UnitsInTemplate ) ;
var template = await query . FirstOrDefaultAsync ( t = > t . Name = = esppObject . TemplateName ) ;
2025-08-06 10:33:55 +10:00
2025-08-20 14:10:22 +10:00
if ( template = = null )
2025-08-06 10:33:55 +10:00
{
2025-08-20 14:10:22 +10:00
logger . LogWarning ( $"Найден объект в ЕСПП с именем шаблона {esppObject.TemplateName} незарегистрированный в ПАРР." ) ;
return ;
2025-08-06 10:33:55 +10:00
}
2025-12-23 18:27:31 +10:00
var dbObjectInEsppObject = converterToEsppObject . Invoke ( template ) ;
2024-02-28 10:17:01 +10:00
2026-01-16 18:26:06 +10:00
// Проверяем наличие Shortcode в полях объекта из БД
2025-12-23 18:27:31 +10:00
var properties = dbObjectInEsppObject . GetType ( ) . GetProperties ( ) ;
foreach ( PropertyInfo property in properties )
{
2026-01-16 18:26:06 +10:00
if ( property . PropertyType = = typeof ( string ) )
{
2026-01-14 10:34:37 +10:00
var value = property . GetValue ( dbObjectInEsppObject ) ? . ToString ( ) ;
2026-01-16 18:26:06 +10:00
if ( ! string . IsNullOrEmpty ( value ) )
2026-01-14 10:34:37 +10:00
{
2026-01-16 18:26:06 +10:00
// Передаём исходный template — он уже загружен с Include
var processedValue = await shortcodesService . ApplyShortcodesAsync ( value , template ) ;
2026-01-14 10:34:37 +10:00
property . SetValue ( dbObjectInEsppObject , processedValue ) ;
}
2025-08-20 14:10:22 +10:00
}
2025-12-23 18:27:31 +10:00
}
bool isChanged = false ;
//TODO: FIX ME Please, BRO
//bool isChanged;
2023-11-22 11:37:22 +10:00
2025-12-23 18:27:31 +10:00
// если в БД isActive == false, то синхронизировать только по полям из IEsppObject
if ( dbObjectInEsppObject . IsActive = = false )
{
logger . LogDebug ( $"Объект деактивирован в ПАРР. Сравниваем только обязательные поля. {esppObject.TemplateName}" ) ;
var lightDbObj = new EsppLightObject ( dbObjectInEsppObject ) ;
var lightEsppObject = new EsppLightObject ( esppObject ) ;
2023-11-24 16:52:56 +10:00
2025-12-23 18:27:31 +10:00
isChanged = IsChanged ( lightEsppObject , lightDbObj , esppObject . TemplateName ) ;
}
else
{
logger . LogDebug ( $"Объект активирован в ПАРР. Сравниваем все поля. {esppObject.TemplateName}" ) ;
isChanged = IsChanged ( esppObject , dbObjectInEsppObject , esppObject . TemplateName ) ;
}
2024-08-02 09:38:05 +10:00
2025-12-23 18:27:31 +10:00
if ( isChanged )
{
logger . LogDebug ( $"Есть изменения, требуется обновление. {esppObject.TemplateName}" ) ;
var config = robotConfigurationService . GetFromTemplateByRobotCode ( esppObject . Robot , template ) ;
// Если предыдущий статус был Create или Ок, то ставим ему Update
// пусть даже Create завершился с ошибками, но раз он уже есть в ЕСПП, то изменим на Update, сбросим все счетчики и пусть попробует обновить и исправить все
if ( config . TaskStatusCode ! = ( int ) TaskStatusEnum . Updating )
2024-08-02 09:38:05 +10:00
{
2025-12-23 18:27:31 +10:00
SetUpdateStatus ( ref template , robotConfigurationService , esppObject . Robot ) ;
2024-08-02 09:38:05 +10:00
2025-12-23 18:27:31 +10:00
if ( ! await templateService . CommitAsync ( ) )
logger . LogError ( $"Н е удалось изменить запись Template {template.Name}, Robot: {esppObject.Robot}" ) ;
else
logger . LogInformation ( $"Установлен принудительный статус {TaskStatusEnum.Updating}, Template {template.Name}, Robot: {esppObject.Robot}" ) ;
2024-08-02 09:38:05 +10:00
}
2023-11-22 11:37:22 +10:00
else
2024-08-02 09:38:05 +10:00
{
2025-12-23 18:27:31 +10:00
// Если пред статус был Update, то ничего не делаем, так е г о и оставляем, не сбрасывам кол-во попыток и ошибок
logger . LogInformation ( $"Есть изменения в Template {template.Name}, но предыдущий статус TaskStatusCode: {(TaskStatusEnum)config.TaskStatusCode}. Н е меняем статус, будем разбираться вручную." ) ;
2024-08-02 09:38:05 +10:00
}
2025-12-23 18:27:31 +10:00
#region Old logic
2025-08-20 14:10:22 +10:00
2025-12-23 18:27:31 +10:00
//SetUpdateStatus(ref template, robotConfigurationService, esppObject.Robot);
2025-08-20 14:10:22 +10:00
2025-12-23 18:27:31 +10:00
//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}" ) ;
2025-08-20 14:10:22 +10:00
2025-12-23 18:27:31 +10:00
//если все поля совпали
//проверяем, какой был статус предыдущий статус в БД, если он был не Ок, то ставим ему О К
var robotConfig = robotConfigurationService . GetFromTemplateByRobotCode ( esppObject . Robot , template ) ;
if ( robotConfig . TaskStatusCode ! = ( int ) TaskStatusEnum . Ok )
2025-08-20 14:10:22 +10:00
{
2025-12-23 18:27:31 +10:00
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}" ) ;
2023-11-22 11:37:22 +10:00
}
}
}
2025-08-20 14:10:22 +10:00
catch ( Exception ex )
{
logger . LogError ( ex , $"Ошибка синхронизации объекта А С У ЕСПП {esppObject.TemplateName}" ) ;
}
2025-08-06 10:33:55 +10:00
}
2023-11-22 11:37:22 +10:00
}
private void SetUpdateStatus ( ref Template template , IRobotConfigurationService robotConfigurationService , RobotsEnum robot )
{
2025-11-28 09:12:26 +10:00
var robotConfig = robotConfigurationService . GetFromTemplateByRobotCode ( robot , template ) ;
robotConfigurationService . ChangeTaskStatus ( TaskStatusEnum . Updating , robotConfig ) ;
2023-11-22 11:37:22 +10:00
}
private Service GetServiceInScope < Service > ( IServiceScope scope )
{
var service = scope . ServiceProvider . GetService < Service > ( ) ;
if ( service = = null )
throw new Exception ( $"Н е найден сервис: {nameof(Service)}" ) ;
return service ;
}
2024-02-28 10:17:01 +10:00
//private bool IsChanged(EsppObject esppObj, EsppObject dbObj)
2025-12-04 09:26:17 +10:00
private bool IsChanged ( object esppObj , object dbObj , string templateName )
2023-11-22 11:37:22 +10:00
{
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 прилетает без переносов. Убираем переносы для стравнения
2025-08-21 14:51:40 +10:00
var dbValueStr = Normalize ( dbValue ! . ToString ( ) ! ) ;
var esppValueStr = Normalize ( esppValue ! . ToString ( ) ! ) ;
2023-11-22 11:37:22 +10:00
if ( dbValueStr ! = esppValueStr )
{
2025-12-04 12:10:10 +10:00
logger . LogInformation ( $"Н е совпадают поля ({prop.Name}). dbValueStr: {dbValueStr}, esppValueStr: {esppValueStr}. Имя шаблона: {templateName}" ) ;
2023-11-22 11:37:22 +10:00
return true ;
}
}
return false ;
}
2025-11-28 09:12:26 +10:00
2025-08-21 14:51:40 +10:00
/// <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 ) ;
2023-11-22 11:37:22 +10:00
2025-08-21 14:51:40 +10:00
return str . ToLower ( ) ;
}
2023-11-22 11:37:22 +10:00
}
}