372 lines
17 KiB
C#
372 lines
17 KiB
C#
using Microsoft.Extensions.DependencyInjection;
|
||
using Microsoft.Extensions.Logging;
|
||
using PARR.BLL.Helpers;
|
||
using PARR.BLL.Services.Interfaces;
|
||
using PARR.DAL.Contracts;
|
||
using PARR.DAL.Models;
|
||
using PARR.DAL.Services.Interfaces;
|
||
using PARR.EsppScheduleSync.Domain;
|
||
using PARR.EsppScheduleSync.Settings;
|
||
using PARR.EsppSync;
|
||
using System.Linq;
|
||
|
||
namespace PARR.EsppScheduleSync
|
||
{
|
||
internal class ScheduleSyncher : IScheduleSyncher
|
||
{
|
||
private readonly ILogger<ScheduleSyncher> logger;
|
||
private readonly GlobalSettings globalSettings;
|
||
private readonly IMqService mqService;
|
||
private readonly ISyncService<EsppObjectSchedule> syncService;
|
||
private readonly SettingsFromDb settingsFromDb;
|
||
private readonly IServiceProvider serviceProvider;
|
||
|
||
public ScheduleSyncher(
|
||
ILogger<ScheduleSyncher> logger,
|
||
GlobalSettings globalSettings,
|
||
IMqService mqService,
|
||
ISyncService<EsppObjectSchedule> syncService,
|
||
SettingsFromDb settingsFromDb,
|
||
IServiceProvider serviceProvider
|
||
)
|
||
{
|
||
this.logger = logger;
|
||
this.globalSettings = globalSettings;
|
||
this.mqService = mqService;
|
||
this.syncService = syncService;
|
||
this.settingsFromDb = settingsFromDb;
|
||
this.serviceProvider = serviceProvider;
|
||
if (globalSettings.MqSettings == null)
|
||
{
|
||
logger.LogError("Нет секции настроек хранилища. MqSettings, EsppTemplates");
|
||
throw new Exception("Нет секции настроек хранилища. MqSettings, EsppTemplates");
|
||
}
|
||
}
|
||
|
||
|
||
public void Start()
|
||
{
|
||
var isConnected = mqService.InitConsumer(globalSettings!.MqSettings!, SyncScheduleAsync);
|
||
|
||
if (!isConnected)
|
||
throw new Exception("Ошибка при подключении к RabbitMq");
|
||
|
||
logger.LogInformation($"Запущена проверка очереди {globalSettings.MqSettings!.QueueName}.");
|
||
}
|
||
|
||
|
||
public void Stop()
|
||
{
|
||
mqService.Dispose();
|
||
|
||
logger.LogInformation($"=== === === Соединение с очередью {globalSettings.MqSettings!.QueueName} закрыто === === ===");
|
||
}
|
||
|
||
|
||
private async Task SyncScheduleAsync(string str)
|
||
{
|
||
await syncService.SyncEsppObjectAsync(str, ParseStrToEsppObject, ConvertDbObjToEsppObj);
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// Преобразование модели БД в модель для сравнения
|
||
/// </summary>
|
||
/// <param name="template"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="NotImplementedException"></exception>
|
||
private EsppObjectSchedule ConvertDbObjToEsppObj(Template template)
|
||
{
|
||
var esppObjectFromDb = new EsppObjectSchedule
|
||
{
|
||
TemplateName = template.Name,
|
||
Code = template.ScheduleEsppId ?? "",
|
||
ScheduleName = template.Name,
|
||
IsActive = template.IsActiveSchedule,
|
||
ResponseArea = template.Host!.ResponseArea!.Name,
|
||
WorkGroup = template.Host!.WorkGroup!,
|
||
//Мы решили, что для всех расписаний "Нет исключений", если что-то поменяется, тут нужно переделать
|
||
TypeV60calendar = settingsFromDb.ScheduleExclude == "Нет исключений" ? "NONE" : "",
|
||
Scheduled = EsppScheduleHelpers.GetNextRun(template.ApplicationsInWork!.NextRun),
|
||
Timezone = settingsFromDb.ScheduleTimezone,
|
||
//Мы решили, что для всех расписаний "Отсутствует дата завершения", если что-то поменяется, тут нужно переделать
|
||
TerminationType = settingsFromDb.ScheduleRepeatRange == "Отсутствует дата завершения" ? "forever" : "",
|
||
CompleteAfter = "",
|
||
V60calendar = ""
|
||
};
|
||
|
||
FillScheduleFromDb(template, ref esppObjectFromDb);
|
||
|
||
return ClearOptionalFields(esppObjectFromDb);
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// Заполнить расписание из БД
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
private void FillScheduleFromDb(Template template, ref EsppObjectSchedule esppObject)
|
||
{
|
||
using (var scope = serviceProvider.CreateScope())
|
||
{
|
||
var esppSchTypeConfigService = scope.ServiceProvider.GetService<IEsppSchTypeConfigService>();
|
||
if (esppSchTypeConfigService == null)
|
||
throw new Exception($"Не найден сервис: {nameof(IEsppSchTypeConfigService)}");
|
||
|
||
var esppSchedule = esppSchTypeConfigService.GetEsppScheduleDto(template.ApplicationInWorkId);
|
||
if (esppSchedule == null)
|
||
{
|
||
logger.LogError($"Не смог получить расписание из БД для шаблона templateId: {template.Id}, {template.Name}");
|
||
return;
|
||
}
|
||
|
||
var typeSchedule = GetTypeScheduleByString(esppSchedule.TypeSchedule.Name);
|
||
if (!typeSchedule.HasValue)
|
||
return;
|
||
|
||
//тип повторения
|
||
esppObject.TypeSchedule = typeSchedule.Value;
|
||
|
||
//в зависимости от типа, присваиваем значения
|
||
switch (esppObject.TypeSchedule)
|
||
{
|
||
case EsppSchTypeScheduleEnum.Regularly:
|
||
esppObject.Interval = esppSchedule.Values.First(t => t.Order == 0).Value.EsppExportValue;
|
||
break;
|
||
case EsppSchTypeScheduleEnum.Weekly:
|
||
esppObject.Dayofweek = esppSchedule.Values.First(t => t.Order == 0).Value.EsppExportValue;
|
||
break;
|
||
case EsppSchTypeScheduleEnum.Monthly:
|
||
esppObject.Dayofmonth = esppSchedule.Values.First(t => t.Order == 0).Value.EsppExportValue;
|
||
break;
|
||
case EsppSchTypeScheduleEnum.Monthly2:
|
||
esppObject.Md1 = esppSchedule.Values.First(t => t.Order == 0).Value.EsppExportValue;
|
||
esppObject.Md2 = esppSchedule.Values.First(t => t.Order == 1).Value.EsppExportValue;
|
||
break;
|
||
case EsppSchTypeScheduleEnum.Annually:
|
||
esppObject.Annualm = esppSchedule.Values.First(t => t.Order == 0).Value.EsppExportValue;
|
||
esppObject.Annualday = esppSchedule.Values.First(t => t.Order == 1).Value.EsppExportValue;
|
||
break;
|
||
case EsppSchTypeScheduleEnum.Annually2:
|
||
esppObject.An1 = esppSchedule.Values.First(t => t.Order == 0).Value.EsppExportValue;
|
||
esppObject.An2 = esppSchedule.Values.First(t => t.Order == 1).Value.EsppExportValue;
|
||
esppObject.An3 = esppSchedule.Values.First(t => t.Order == 2).Value.EsppExportValue;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// Парсинг из строки в модель для сравнения
|
||
/// </summary>
|
||
/// <param name="str"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="NotImplementedException"></exception>
|
||
private EsppObjectSchedule? ParseStrToEsppObject(string str)
|
||
{
|
||
var splittedContent = str.Split(globalSettings.ParsingSeparator);
|
||
if (splittedContent.Length != 23)
|
||
{
|
||
logger.LogError($"Входная строка после сплита не содержит 23 объекта (факт: {splittedContent.Length}).");
|
||
return null;
|
||
}
|
||
|
||
var templateName = splittedContent[6];
|
||
var scheduleName = splittedContent[2];
|
||
|
||
if (!IsValidName(templateName) || !IsValidName(scheduleName))
|
||
return null;
|
||
|
||
bool.TryParse(splittedContent[1].Trim(), out var isActive);
|
||
|
||
var typeSchedule = GetTypeScheduleByString(splittedContent[7]);
|
||
if (!typeSchedule.HasValue)
|
||
return null;
|
||
|
||
var esppObject = new EsppObjectSchedule
|
||
{
|
||
TemplateName = templateName,
|
||
Code = splittedContent[0],
|
||
ScheduleName = scheduleName,
|
||
IsActive = isActive,
|
||
ResponseArea = splittedContent[5],
|
||
WorkGroup = splittedContent[3],
|
||
TypeSchedule = typeSchedule.Value,
|
||
Interval = splittedContent[8],
|
||
Dayofweek = splittedContent[15],
|
||
Dayofmonth = splittedContent[14],
|
||
Md1 = splittedContent[16],
|
||
Md2 = splittedContent[17],
|
||
Annualm = splittedContent[13],
|
||
Annualday = splittedContent[12],
|
||
An1 = splittedContent[9],
|
||
An2 = splittedContent[10],
|
||
An3 = splittedContent[11],
|
||
TypeV60calendar = splittedContent[21],
|
||
Scheduled = splittedContent[4],
|
||
Timezone = splittedContent[18],
|
||
TerminationType = splittedContent[19],
|
||
CompleteAfter = splittedContent[20],
|
||
V60calendar = splittedContent[22]
|
||
};
|
||
|
||
return ClearOptionalFields(esppObject);
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// Преобразовать из строки в Тип Повторения
|
||
/// </summary>
|
||
/// <param name="typeSchedule"></param>
|
||
/// <returns></returns>
|
||
private EsppSchTypeScheduleEnum? GetTypeScheduleByString(string typeSchedule)
|
||
{
|
||
typeSchedule = typeSchedule.ToLower();
|
||
|
||
//Regularly, Регулярно (значение в ЕСПП и в БД не совпадают, в бд Regularly, в ЕСПП simple)
|
||
if (typeSchedule == "simple" || typeSchedule == EsppSchTypeScheduleEnum.Regularly.ToString().ToLower())
|
||
return EsppSchTypeScheduleEnum.Regularly;
|
||
|
||
if (typeSchedule == EsppSchTypeScheduleEnum.Weekly.ToString().ToLower())
|
||
return EsppSchTypeScheduleEnum.Weekly;
|
||
|
||
if (typeSchedule == EsppSchTypeScheduleEnum.Monthly.ToString().ToLower())
|
||
return EsppSchTypeScheduleEnum.Monthly;
|
||
|
||
if (typeSchedule == EsppSchTypeScheduleEnum.Monthly2.ToString().ToLower())
|
||
return EsppSchTypeScheduleEnum.Monthly2;
|
||
|
||
if (typeSchedule == EsppSchTypeScheduleEnum.Annually.ToString().ToLower())
|
||
return EsppSchTypeScheduleEnum.Annually;
|
||
|
||
if (typeSchedule == EsppSchTypeScheduleEnum.Annually2.ToString().ToLower())
|
||
return EsppSchTypeScheduleEnum.Annually2;
|
||
|
||
logger.LogError($"Не смог преобразовать Тип повторения из ЕСПП в EsppSchTypeScheduleEnum. Получено значение {typeSchedule}");
|
||
|
||
return null;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// Проверка имени шаблона и расписание на соответствие префиксу из настроек
|
||
/// </summary>
|
||
/// <param name="name"></param>
|
||
/// <returns></returns>
|
||
private bool IsValidName(string name)
|
||
{
|
||
var currentCulture = Thread.CurrentThread.CurrentCulture;
|
||
|
||
//if (!string.IsNullOrEmpty(settingsFromDb.TemplatePrefixName) && name.StartsWith(settingsFromDb.TemplatePrefixName, true, currentCulture))
|
||
// return true;
|
||
|
||
if (!string.IsNullOrEmpty(settingsFromDb.TemplatePrefixWithoutVariable) && name.Contains(settingsFromDb.TemplatePrefixWithoutVariable, StringComparison.CurrentCultureIgnoreCase))
|
||
return true;
|
||
|
||
logger.LogWarning($"Имя шаблона или расписания не соответствует обязательному префиксу({settingsFromDb.TemplatePrefixWithoutVariable}). {name} игнорирован");
|
||
|
||
return false;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// Очистка полей которые не нуждаются в синхронизации
|
||
/// </summary>
|
||
/// <param name="esppObject"></param>
|
||
/// <returns></returns>
|
||
private EsppObjectSchedule ClearOptionalFields(EsppObjectSchedule esppObject)
|
||
{
|
||
esppObject.Code = string.Empty;
|
||
esppObject.ScheduleName = string.Empty;
|
||
esppObject.ResponseArea = string.Empty;
|
||
esppObject.WorkGroup = string.Empty;
|
||
esppObject.CompleteAfter = string.Empty;
|
||
esppObject.V60calendar = string.Empty;
|
||
|
||
// В ЕСПП, при изменении "Повторять задачу", остаются предыдущие значения, их не нужно синхронизировать (касается только данных полученных из ЕСПП, в БД все ок)
|
||
// т.е. если стояло Ежедненвно:понедельник, а изменили например на Еженедельно..., то в ежедневно значения останутся, но будут отрабатывать значения из Еженедельно.
|
||
// Т е значения из Ежедненвно проверять не нужно, вот их и будем очищать
|
||
|
||
switch (esppObject.TypeSchedule)
|
||
{
|
||
case EsppSchTypeScheduleEnum.Regularly:
|
||
//esppObject.Interval = string.Empty;
|
||
esppObject.Dayofweek = string.Empty;
|
||
esppObject.Dayofmonth = string.Empty;
|
||
esppObject.Md1 = string.Empty;
|
||
esppObject.Md2 = string.Empty;
|
||
esppObject.Annualm = string.Empty;
|
||
esppObject.Annualday = string.Empty;
|
||
esppObject.An1 = string.Empty;
|
||
esppObject.An2 = string.Empty;
|
||
esppObject.An3 = string.Empty;
|
||
break;
|
||
case EsppSchTypeScheduleEnum.Weekly:
|
||
esppObject.Interval = string.Empty;
|
||
//esppObject.Dayofweek = string.Empty;
|
||
esppObject.Dayofmonth = string.Empty;
|
||
esppObject.Md1 = string.Empty;
|
||
esppObject.Md2 = string.Empty;
|
||
esppObject.Annualm = string.Empty;
|
||
esppObject.Annualday = string.Empty;
|
||
esppObject.An1 = string.Empty;
|
||
esppObject.An2 = string.Empty;
|
||
esppObject.An3 = string.Empty;
|
||
break;
|
||
case EsppSchTypeScheduleEnum.Monthly:
|
||
esppObject.Interval = string.Empty;
|
||
esppObject.Dayofweek = string.Empty;
|
||
//esppObject.Dayofmonth = string.Empty;
|
||
esppObject.Md1 = string.Empty;
|
||
esppObject.Md2 = string.Empty;
|
||
esppObject.Annualm = string.Empty;
|
||
esppObject.Annualday = string.Empty;
|
||
esppObject.An1 = string.Empty;
|
||
esppObject.An2 = string.Empty;
|
||
esppObject.An3 = string.Empty;
|
||
break;
|
||
case EsppSchTypeScheduleEnum.Monthly2:
|
||
esppObject.Interval = string.Empty;
|
||
esppObject.Dayofweek = string.Empty;
|
||
esppObject.Dayofmonth = string.Empty;
|
||
//esppObject.Md1 = string.Empty;
|
||
//esppObject.Md2 = string.Empty;
|
||
esppObject.Annualm = string.Empty;
|
||
esppObject.Annualday = string.Empty;
|
||
esppObject.An1 = string.Empty;
|
||
esppObject.An2 = string.Empty;
|
||
esppObject.An3 = string.Empty;
|
||
break;
|
||
case EsppSchTypeScheduleEnum.Annually:
|
||
esppObject.Interval = string.Empty;
|
||
esppObject.Dayofweek = string.Empty;
|
||
esppObject.Dayofmonth = string.Empty;
|
||
esppObject.Md1 = string.Empty;
|
||
esppObject.Md2 = string.Empty;
|
||
//esppObject.Annualm = string.Empty;
|
||
//esppObject.Annualday = string.Empty;
|
||
esppObject.An1 = string.Empty;
|
||
esppObject.An2 = string.Empty;
|
||
esppObject.An3 = string.Empty;
|
||
break;
|
||
case EsppSchTypeScheduleEnum.Annually2:
|
||
esppObject.Interval = string.Empty;
|
||
esppObject.Dayofweek = string.Empty;
|
||
esppObject.Dayofmonth = string.Empty;
|
||
esppObject.Md1 = string.Empty;
|
||
esppObject.Md2 = string.Empty;
|
||
esppObject.Annualm = string.Empty;
|
||
esppObject.Annualday = string.Empty;
|
||
//esppObject.An1 = string.Empty;
|
||
//esppObject.An2 = string.Empty;
|
||
//esppObject.An3 = string.Empty;
|
||
break;
|
||
}
|
||
|
||
return esppObject;
|
||
}
|
||
|
||
}
|
||
}
|