2025-11-26 15:19:31 +10:00
using Microsoft.Extensions.Logging ;
2024-07-02 11:43:59 +10:00
using PARR.Constants ;
2023-10-18 10:09:51 +10:00
using PARR.DAL.Contracts ;
2023-10-17 09:42:18 +10:00
using PARR.DAL.DomainModels ;
2023-10-23 13:45:43 +10:00
using PARR.DAL.Extensions ;
2023-10-17 09:42:18 +10:00
using PARR.DAL.Services.Interfaces ;
namespace PARR.DAL.TransformServices
{
internal class EsppScheduleTransformService : IEsppScheduleTransformService
{
private readonly IEsppSchTypeConfigService esppSchTypeConfigService ;
2024-09-19 13:51:44 +10:00
private readonly INextRunModifierService nextRunModifierService ;
2023-10-17 09:42:18 +10:00
private readonly ILogger < EsppScheduleTransformService > logger ;
2025-11-26 15:19:31 +10:00
private static readonly Dictionary < string , int > monthDict = new Dictionary < string , int > ( )
2023-10-19 09:14:19 +10:00
{
{ "Январь" , 1 } ,
{ "Февраль" , 2 } ,
{ "Март" , 3 } ,
{ "Апрель" , 4 } ,
{ "Май" , 5 } ,
{ "Июнь" , 6 } ,
{ "Июль" , 7 } ,
{ "Август" , 8 } ,
{ "Сентябрь" , 9 } ,
{ "Октябрь" , 10 } ,
{ "Ноябрь" , 11 } ,
{ "Декабрь" , 12 }
} ;
2025-11-26 15:19:31 +10:00
private static readonly Dictionary < string , int > orderDict = new Dictionary < string , int > ( )
2023-10-19 09:14:19 +10:00
{
{ "Первый" , 1 } ,
{ "Второй" , 2 } ,
{ "Третий" , 3 } ,
{ "Четвертый" , 4 } ,
{ "Последний" , 5 }
} ;
2025-11-26 15:19:31 +10:00
private static readonly Dictionary < string , int > dwDict = new Dictionary < string , int > ( )
2023-10-19 09:14:19 +10:00
{
{ "Понедельник" , 1 } ,
{ "Вторник" , 2 } ,
{ "Среда" , 3 } ,
{ "Четверг" , 4 } ,
{ "Пятница" , 5 } ,
{ "Суббота" , 6 } ,
{ "Воскресенье" , 0 }
} ;
2024-02-05 16:05:02 +10:00
2024-09-18 16:32:45 +10:00
2024-02-05 16:05:02 +10:00
public EsppScheduleTransformService (
2024-07-05 15:17:48 +10:00
ILogger < EsppScheduleTransformService > logger ,
2024-02-05 16:05:02 +10:00
IEsppSchTypeConfigService esppSchTypeConfigService ,
2025-11-26 15:19:31 +10:00
INextRunModifierService nextRunModifierService
2024-02-05 16:05:02 +10:00
)
2023-10-17 09:42:18 +10:00
{
this . esppSchTypeConfigService = esppSchTypeConfigService ;
2024-09-19 13:51:44 +10:00
this . nextRunModifierService = nextRunModifierService ;
2023-10-17 09:42:18 +10:00
this . logger = logger ;
}
2025-11-26 15:19:31 +10:00
public async Task < DateTimeOffset > GetNextDateAsync ( Guid jobGroupId , DateTimeOffset referenceDate )
2023-10-17 09:42:18 +10:00
{
2025-11-26 15:19:31 +10:00
var esppSchedule = await GetEsppScheduleAsync ( jobGroupId ) ;
2024-09-18 16:32:45 +10:00
2025-11-26 15:19:31 +10:00
return GetNextDate ( esppSchedule , referenceDate ) ;
}
public DateTimeOffset GetNextDate ( EsppScheduleDto esppSchedule , DateTimeOffset referenceDate )
{
var nextRun = referenceDate ;
2023-10-23 13:45:43 +10:00
2025-11-28 12:35:18 +10:00
//---------
// Для рассчета по М С К времени, потому что в ЮТС может быть еще В С К , а по М С К это уже ПНД
var offsetReferenceDate = referenceDate . ToOffset ( new TimeSpan ( 3 , 0 , 0 ) ) ;
//---------
2023-10-18 10:09:51 +10:00
switch ( esppSchedule . TypeSchedule . Id )
{
2023-10-23 11:04:12 +10:00
case ( int ) EsppSchTypeScheduleEnum . Regularly :
2025-11-28 12:35:18 +10:00
nextRun = GetNextDateRegularly ( esppSchedule . Values , offsetReferenceDate ) ;
2024-09-18 16:32:45 +10:00
break ;
2023-10-19 09:14:19 +10:00
case ( int ) EsppSchTypeScheduleEnum . Weekly :
2025-11-28 12:35:18 +10:00
nextRun = GetNextDateWeekly ( esppSchedule . Values , offsetReferenceDate ) ;
2024-09-18 16:32:45 +10:00
break ;
2023-10-19 09:14:19 +10:00
case ( int ) EsppSchTypeScheduleEnum . Monthly :
2025-11-28 12:35:18 +10:00
nextRun = GetNextDateMonthly ( esppSchedule . Values , offsetReferenceDate ) ;
2024-09-18 16:32:45 +10:00
break ;
2023-10-19 09:14:19 +10:00
case ( int ) EsppSchTypeScheduleEnum . Monthly2 :
2025-11-28 12:35:18 +10:00
nextRun = GetNextDateMonthly2 ( esppSchedule . Values , offsetReferenceDate ) ;
2024-09-18 16:32:45 +10:00
break ;
2023-10-19 09:14:19 +10:00
case ( int ) EsppSchTypeScheduleEnum . Annually :
2025-11-28 12:35:18 +10:00
nextRun = GetNextDateAnnually ( esppSchedule . Values , offsetReferenceDate ) ;
2024-09-18 16:32:45 +10:00
break ;
2023-10-18 10:09:51 +10:00
case ( int ) EsppSchTypeScheduleEnum . Annually2 :
2025-11-28 12:35:18 +10:00
nextRun = GetNextDateAnnually2 ( esppSchedule . Values , offsetReferenceDate ) ;
2024-09-18 16:32:45 +10:00
break ;
2023-10-18 10:09:51 +10:00
}
2024-09-18 16:32:45 +10:00
2025-11-28 12:35:18 +10:00
// Возвращаем обратно в ЮТС
nextRun = nextRun . ToOffset ( TimeSpan . Zero ) ;
2025-11-26 15:19:31 +10:00
//возможно для автораспределения нужно nextRun = nextRunModifierService.GetWorkDayAsync(nextRun).GetAwaiter().GetResult();
2024-09-18 16:32:45 +10:00
2025-11-24 16:28:50 +10:00
// тут может быть 21 час по М С К , то это предыдущие сутки, нужно отнять 1 день
2025-11-28 12:35:18 +10:00
//if (!DateResolver.IsCurrentDayRelativeMskTime(nextRun.Hour))
// nextRun = nextRun.AddDays(-1);
2025-11-24 16:28:50 +10:00
2024-09-18 16:32:45 +10:00
return nextRun ;
2023-10-17 09:42:18 +10:00
}
2025-11-26 15:19:31 +10:00
private List < DateTimeOffset > GetNextSchedule ( EsppScheduleDto esppSchedule , DateTimeOffset referenceDate )
2023-10-17 09:42:18 +10:00
{
2023-10-18 10:09:51 +10:00
// расписание на оставшееся на сегодня время. е г о так мало...
2025-11-26 15:19:31 +10:00
referenceDate = referenceDate . UtcDateTime ;
2023-10-17 09:42:18 +10:00
var schedules = new List < DateTimeOffset > ( ) ;
2025-11-26 15:19:31 +10:00
var curTime = referenceDate ;
2023-11-28 11:59:26 +10:00
//Если ещё не произошло то добавляем расписание, возможно это новое AiW и он ещё ниразу не запускался.
//lastRun это будущее
2025-11-26 15:19:31 +10:00
if ( referenceDate > = DateTimeOffset . UtcNow & & referenceDate < = DateTimeOffset . UtcNow . EndOfDay ( ) )
schedules . Add ( referenceDate ) ;
2023-11-28 11:59:26 +10:00
2023-10-23 13:45:43 +10:00
while ( curTime < DateTimeOffset . UtcNow . EndOfDay ( ) )
{
switch ( esppSchedule . TypeSchedule . Id )
{
case ( int ) EsppSchTypeScheduleEnum . Regularly :
curTime = GetNextDateRegularly ( esppSchedule . Values , curTime ) ;
break ;
case ( int ) EsppSchTypeScheduleEnum . Weekly :
curTime = GetNextDateWeekly ( esppSchedule . Values , curTime ) ;
break ;
case ( int ) EsppSchTypeScheduleEnum . Monthly :
curTime = GetNextDateMonthly ( esppSchedule . Values , curTime ) ;
break ;
case ( int ) EsppSchTypeScheduleEnum . Monthly2 :
curTime = GetNextDateMonthly2 ( esppSchedule . Values , curTime ) ;
break ;
case ( int ) EsppSchTypeScheduleEnum . Annually :
curTime = GetNextDateAnnually ( esppSchedule . Values , curTime ) ;
break ;
case ( int ) EsppSchTypeScheduleEnum . Annually2 :
curTime = GetNextDateAnnually2 ( esppSchedule . Values , curTime ) ;
break ;
}
schedules . Add ( curTime ) ;
}
schedules . RemoveAll ( s = > s > DateTimeOffset . UtcNow . EndOfDay ( ) ) ;
2023-10-17 09:42:18 +10:00
return schedules . OrderBy ( t = > t ) . ToList ( ) ;
}
2024-07-05 15:17:48 +10:00
2024-07-11 11:32:14 +10:00
2025-11-26 15:19:31 +10:00
public async Task < List < DateTimeOffset > > GetNextScheduleAsync ( Guid jobGroupId , DateTimeOffset referenceDate )
2023-10-17 09:42:18 +10:00
{
2024-09-18 16:32:45 +10:00
//TODO: тут не проверен переход через выходные дни!!! Переход не используется, так как тут не рассчитываем NextRun.
//В общем проверить, когда будем тестировать агента, что с датами все ок
2025-06-25 14:17:34 +10:00
var esppSchedule = await GetEsppScheduleAsync ( jobGroupId ) ;
2025-11-26 15:19:31 +10:00
var nextSchedule = GetNextSchedule ( esppSchedule , referenceDate ) ;
2023-11-27 16:42:15 +10:00
return nextSchedule ;
2023-10-17 09:42:18 +10:00
}
2025-06-25 14:17:34 +10:00
private async Task < EsppScheduleDto > GetEsppScheduleAsync ( Guid jobGroupId )
2023-10-17 09:42:18 +10:00
{
2025-06-25 14:17:34 +10:00
var esppSchedule = await esppSchTypeConfigService . GetEsppScheduleDtoAsync ( jobGroupId ) ;
2023-10-17 09:42:18 +10:00
if ( esppSchedule = = null )
{
2025-06-25 14:17:34 +10:00
logger . LogError ( $"Н е найдено расписание в БД, jobId: {jobGroupId}" ) ;
throw new Exception ( $"Н е найдено расписание в БД, jobId: {jobGroupId}" ) ;
2023-10-17 09:42:18 +10:00
}
return esppSchedule ;
}
2023-10-18 10:09:51 +10:00
2025-11-26 15:19:31 +10:00
private DateTimeOffset GetNextDateRegularly ( List < EsppScheduleValDto > values , DateTimeOffset referenceDate )
2023-10-23 11:04:12 +10:00
{
var regDict = new Dictionary < string , int >
{
2023-10-23 13:45:43 +10:00
{ "Каждый час" , 1 } ,
2023-10-23 11:04:12 +10:00
{ "Каждые 2 часа" , 2 } ,
{ "Каждые 3 часа" , 3 } ,
{ "Каждые 4 часа" , 4 } ,
{ "Каждые 6 часов" , 6 } ,
{ "Каждые 12 часов" , 12 } ,
{ "Ежедневно" , 24 } ,
{ "Каждые 72 часа" , 72 } ,
{ "Каждые 96 часов" , 96 } ,
{ "Каждые 2 недели" , 336 } ,
{ "Каждые 60 дней" , 1440 } ,
{ "Каждые 80 дней" , 1920 } ,
{ "Каждые 90 дней" , 2160 } ,
{ "Каждые полгода" , 4380 } ,
{ "Каждые 1,5 года" , 13140 } ,
{ "Каждые 3 года" , 26280 } ,
2025-11-28 12:35:18 +10:00
} ;
2023-10-23 11:04:12 +10:00
2025-11-26 15:19:31 +10:00
if ( ! regDict . TryGetValue ( values [ 0 ] . Value . Value , out int regNum ) )
{
logger . LogError ( "Неизвестное значение: {Value}" , values [ 0 ] . Value . Value ) ;
throw new ArgumentException ( $"Неизвестное значение: {values[0].Value.Value}" ) ;
}
2023-10-23 13:45:43 +10:00
2025-11-27 14:21:27 +10:00
var calcDay = referenceDate ;
2023-10-23 13:45:43 +10:00
2023-10-23 11:04:12 +10:00
//TODO: вот это повторяется от метода к методу
2024-09-16 17:01:04 +10:00
//Если итоговая дата указывает на прошлое, то повторяем расчёт и уходим в рекурсию
2023-10-23 11:04:12 +10:00
if ( calcDay < DateTimeOffset . UtcNow )
2025-11-26 15:19:31 +10:00
calcDay = GetNextDateRegularly ( values , calcDay . AddHours ( regNum ) ) ;
2023-10-23 11:04:12 +10:00
return calcDay ;
}
2024-09-16 17:01:04 +10:00
2025-11-26 15:19:31 +10:00
private DateTimeOffset GetNextDateWeekly ( List < EsppScheduleValDto > values , DateTimeOffset referenceDate )
2023-10-19 09:14:19 +10:00
{
2025-11-26 15:19:31 +10:00
if ( ! dwDict . TryGetValue ( values [ 0 ] . Value . Value , out int dwNum ) )
{
logger . LogError ( "Неизвестное значение дня недели: {Value}" , values [ 0 ] . Value . Value ) ;
throw new ArgumentException ( $"Неизвестное значение: {values[0].Value.Value}" ) ;
}
2023-10-19 09:14:19 +10:00
2025-11-26 15:19:31 +10:00
var calcDay = referenceDate ;
if ( calcDay < DateTimeOffset . UtcNow )
calcDay = new DateTimeOffset ( DateTimeOffset . UtcNow . Year , DateTimeOffset . UtcNow . Month , DateTimeOffset . UtcNow . Day , referenceDate . Hour , referenceDate . Minute , referenceDate . Second , referenceDate . Offset ) ;
2023-10-19 09:14:19 +10:00
if ( ( ( int ) calcDay . DayOfWeek ) ! = dwNum )
2025-11-26 15:19:31 +10:00
calcDay = OffsetToDayOfWeek ( dwNum , calcDay ) ;
2023-10-19 09:14:19 +10:00
//TODO: вот это повторяется от метода к методу
//Если итоговая дата указывает на прошлое, то повторяем расчёт и ухоим в рекурсию
if ( calcDay < DateTimeOffset . UtcNow )
2025-11-24 16:28:50 +10:00
calcDay = GetNextDateWeekly ( values , calcDay . AddDays ( 7 ) ) ; //а вот тут что-то новенькое
2023-10-19 09:14:19 +10:00
return calcDay ;
}
2024-09-16 17:01:04 +10:00
2025-11-26 15:19:31 +10:00
private DateTimeOffset GetNextDateMonthly ( List < EsppScheduleValDto > values , DateTimeOffset referenceDate )
2023-10-19 09:14:19 +10:00
{
2025-11-26 15:19:31 +10:00
if ( ! int . TryParse ( values [ 0 ] . Value . Value , out int dayNum ) )
{
logger . LogError ( "Неизвестное значение дня месяца: {Value}" , values [ 0 ] . Value . Value ) ;
throw new ArgumentException ( $"Неизвестное значение: {values[0].Value.Value}" ) ;
}
2025-11-24 16:28:50 +10:00
2025-11-26 15:19:31 +10:00
var calcDay = new DateTimeOffset ( referenceDate . Year , referenceDate . Month , dayNum , referenceDate . Hour , referenceDate . Minute , referenceDate . Second , referenceDate . Offset ) ;
if ( referenceDate < DateTimeOffset . UtcNow )
calcDay = new DateTimeOffset ( DateTimeOffset . UtcNow . Year , DateTimeOffset . UtcNow . Month , dayNum , referenceDate . Hour , referenceDate . Minute , referenceDate . Second , referenceDate . Offset ) ;
2023-10-19 09:14:19 +10:00
//TODO: вот это повторяется от метода к методу
//Если итоговая дата указывает на прошлое, то повторяем расчёт и ухоим в рекурсию
if ( calcDay < DateTimeOffset . UtcNow )
2025-11-26 15:19:31 +10:00
calcDay = GetNextDateMonthly ( values , calcDay . AddMonths ( 1 ) ) ;
2023-10-19 09:14:19 +10:00
return calcDay ;
}
2024-09-16 17:01:04 +10:00
2025-11-26 15:19:31 +10:00
private DateTimeOffset GetNextDateMonthly2 ( List < EsppScheduleValDto > values , DateTimeOffset referenceDate )
2023-10-19 09:14:19 +10:00
{
2025-11-26 15:19:31 +10:00
if ( ! orderDict . TryGetValue ( values [ 0 ] . Value . Value , out int orderNum ) )
{
logger . LogError ( "Неизвестное значение порядка дня: {Value}" , values [ 0 ] . Value . Value ) ;
throw new ArgumentException ( $"Неизвестное значение: {values[0].Value.Value}" ) ;
}
2023-10-19 09:14:19 +10:00
2025-11-26 15:19:31 +10:00
if ( ! dwDict . TryGetValue ( values [ 1 ] . Value . Value , out int dwNum ) )
{
logger . LogError ( "Неизвестное значение дня недели: {Value}" , values [ 1 ] . Value . Value ) ;
throw new ArgumentException ( $"Неизвестное значение: {values[1].Value.Value}" ) ;
}
2025-11-24 16:28:50 +10:00
2025-11-26 15:19:31 +10:00
var startDay = referenceDate < DateTimeOffset . UtcNow
? new DateTimeOffset ( DateTimeOffset . UtcNow . Year , DateTimeOffset . UtcNow . Month , 1 , referenceDate . Hour , referenceDate . Minute , referenceDate . Second , referenceDate . Offset )
: new DateTimeOffset ( referenceDate . Year , referenceDate . Month , 1 , referenceDate . Hour , referenceDate . Minute , referenceDate . Second , referenceDate . Offset ) ;
2023-10-19 09:14:19 +10:00
2025-11-26 15:19:31 +10:00
var daysList = FindAllDaysInMonth ( dwNum , startDay ) ;
2023-10-19 09:14:19 +10:00
2025-11-26 15:19:31 +10:00
DateTimeOffset calcDay ;
if ( orderNum = = 5 ) // Последний
{
2023-10-19 09:14:19 +10:00
calcDay = daysList . Last ( ) ;
2025-11-26 15:19:31 +10:00
}
2023-10-19 09:14:19 +10:00
else
2025-11-26 15:19:31 +10:00
{
if ( orderNum > daysList . Count )
{
logger . LogError ( "Запрошенный порядковый день недели ({OrderNum}) не существует в месяце {Month}/{Year}. Найдено только {Count} дней." , orderNum , startDay . Month , startDay . Year , daysList . Count ) ;
throw new InvalidOperationException ( $"Запрошенный порядковый день недели ({orderNum}) не существует в месяце {startDay.Month}/{startDay.Year}. Найдено только {daysList.Count} дней." ) ;
}
else
calcDay = daysList [ orderNum - 1 ] ;
}
2023-10-19 09:14:19 +10:00
2025-11-26 15:19:31 +10:00
// Если дата <= текущей, переходим на следующий месяц
if ( calcDay < = DateTimeOffset . UtcNow )
return GetNextDateMonthly2 ( values , startDay . AddMonths ( 1 ) ) ;
2023-10-19 09:14:19 +10:00
return calcDay ;
}
2024-09-16 17:01:04 +10:00
2025-11-27 14:21:27 +10:00
2025-11-26 15:19:31 +10:00
private DateTimeOffset GetNextDateAnnually ( List < EsppScheduleValDto > values , DateTimeOffset referenceDate )
2023-10-19 09:14:19 +10:00
{
2025-11-26 15:19:31 +10:00
if ( ! monthDict . TryGetValue ( values [ 0 ] . Value . Value , out int monthNum ) )
{
logger . LogError ( "Неизвестное значение номера месяца: {Value}" , values [ 0 ] . Value . Value ) ;
throw new ArgumentException ( $"Неизвестное значение: {values[0].Value.Value}" ) ;
}
if ( ! int . TryParse ( values [ 1 ] . Value . Value , out int dayNum ) )
{
logger . LogError ( "Неизвестное значение дня месяца: {Value}" , values [ 0 ] . Value . Value ) ;
throw new ArgumentException ( $"Неизвестное значение: {values[0].Value.Value}" ) ;
}
var year = ( referenceDate . Year < DateTimeOffset . UtcNow . Year ) ? DateTimeOffset . UtcNow . Year : referenceDate . Year ;
var calcDay = new DateTimeOffset (
year , monthNum , dayNum ,
referenceDate . Hour , referenceDate . Minute , referenceDate . Second , referenceDate . Offset ) ;
2023-10-19 09:14:19 +10:00
//TODO: вот это повторяется от метода к методу
//Если итоговая дата указывает на прошлое, то повторяем расчёт и ухоим в рекурсию
if ( calcDay < DateTimeOffset . UtcNow )
2025-11-24 16:28:50 +10:00
calcDay = GetNextDateAnnually ( values , calcDay . AddYears ( 1 ) ) ;
2023-10-19 09:14:19 +10:00
return calcDay ;
}
2024-09-16 17:01:04 +10:00
2025-11-26 15:19:31 +10:00
private DateTimeOffset GetNextDateAnnually2 ( List < EsppScheduleValDto > values , DateTimeOffset referenceDate )
2023-10-18 10:09:51 +10:00
{
2023-10-19 09:14:19 +10:00
var monthADict = new Dictionary < string , int >
{
{ "Января" , 1 } ,
{ "Февраля" , 2 } ,
{ "Марта" , 3 } ,
{ "Апреля" , 4 } ,
{ "Мая" , 5 } ,
{ "Июня" , 6 } ,
{ "Июля" , 7 } ,
{ "Августа" , 8 } ,
{ "Сентября" , 9 } ,
{ "Октября" , 10 } ,
{ "Ноября" , 11 } ,
{ "Декабря" , 12 }
} ;
2025-11-26 15:19:31 +10:00
if ( ! monthADict . TryGetValue ( values [ 2 ] . Value . Value , out int monthNum ) )
{
logger . LogError ( "Неизвестное значение номера месяца: {Value}" , values [ 2 ] . Value . Value ) ;
throw new ArgumentException ( $"Неизвестное значение: {values[2].Value.Value}" ) ;
}
if ( ! orderDict . TryGetValue ( values [ 0 ] . Value . Value , out int orderNum ) )
{
logger . LogError ( "Неизвестное значение порядка дня: {Value}" , values [ 0 ] . Value . Value ) ;
throw new ArgumentException ( $"Неизвестное значение: {values[0].Value.Value}" ) ;
}
if ( ! dwDict . TryGetValue ( values [ 1 ] . Value . Value , out int dwNum ) )
{
logger . LogError ( "Неизвестное значение дня недели: {Value}" , values [ 1 ] . Value . Value ) ;
throw new ArgumentException ( $"Неизвестное значение: {values[1].Value.Value}" ) ;
}
var year = ( referenceDate . Year < DateTimeOffset . UtcNow . Year ) ? DateTimeOffset . UtcNow . Year : referenceDate . Year ;
if ( year = = DateTimeOffset . UtcNow . Year & & referenceDate . Month < DateTimeOffset . UtcNow . Month )
year + = 1 ;
2023-10-18 10:09:51 +10:00
2025-11-26 15:19:31 +10:00
var calcDay = new DateTimeOffset (
year , monthNum , 1 ,
referenceDate . Hour , referenceDate . Minute , referenceDate . Second , referenceDate . Offset ) ;
2023-10-18 10:09:51 +10:00
2025-11-26 15:19:31 +10:00
List < DateTimeOffset > daysList = FindAllDaysInMonth ( dwNum , calcDay ) ;
2023-10-18 10:09:51 +10:00
2023-10-19 09:14:19 +10:00
if ( orderNum = = 5 ) //5-последний
calcDay = daysList . Last ( ) ;
else
2025-11-26 15:19:31 +10:00
calcDay = daysList [ orderNum - 1 ] ;
2023-10-18 10:09:51 +10:00
2023-10-19 09:14:19 +10:00
//TODO: вот это повторяется от метода к методу
//Если итоговая дата указывает на прошлое, то повторяем расчёт и ухоим в рекурсию
if ( calcDay < DateTimeOffset . UtcNow )
2025-11-24 16:28:50 +10:00
calcDay = GetNextDateAnnually2 ( values , calcDay . AddYears ( 1 ) ) ;
2023-10-19 09:14:19 +10:00
return calcDay ;
}
2024-09-16 17:01:04 +10:00
2025-11-26 15:19:31 +10:00
private List < DateTimeOffset > FindAllDaysInMonth ( int dwNum , DateTimeOffset startDay )
2023-10-19 09:14:19 +10:00
{
2025-11-26 15:19:31 +10:00
var calcDay = startDay ;
2023-10-19 09:14:19 +10:00
if ( ( ( int ) calcDay . DayOfWeek ) ! = dwNum )
2025-11-26 15:19:31 +10:00
calcDay = OffsetToDayOfWeek ( dwNum , calcDay ) ;
2023-10-18 10:09:51 +10:00
var daysList = new List < DateTimeOffset > ( ) ;
2023-10-19 09:14:19 +10:00
var monthNum = calcDay . Month ;
2023-10-18 10:09:51 +10:00
while ( calcDay . Month = = monthNum )
{
daysList . Add ( calcDay ) ;
calcDay = calcDay . AddDays ( 7 ) ;
}
2023-10-19 09:14:19 +10:00
return daysList ;
2023-10-18 10:09:51 +10:00
}
2024-09-16 17:01:04 +10:00
2025-11-26 15:19:31 +10:00
private DateTimeOffset OffsetToDayOfWeek ( int dwNum , DateTimeOffset calcDay )
2023-10-19 09:14:19 +10:00
{
var daysOffset = dwNum - ( ( int ) calcDay . DayOfWeek ) ;
if ( daysOffset < 0 )
daysOffset = 7 + daysOffset ;
2025-11-26 15:19:31 +10:00
return calcDay . AddDays ( daysOffset ) ;
2023-10-19 09:14:19 +10:00
}
2024-07-02 11:43:59 +10:00
public DateTimeOffset GetNextDateForDistributionRun ( DateTimeOffset lastRun , DistributionPeriodTypeEnum periodType , string distributionPeriod )
{
2024-09-18 16:32:45 +10:00
var nextRun = lastRun ;
2024-07-02 11:43:59 +10:00
switch ( periodType )
{
case ( DistributionPeriodTypeEnum . Day ) :
2024-09-18 16:32:45 +10:00
nextRun = lastRun . AddDays ( ParseInt ( distributionPeriod ) ) ;
break ;
2024-07-02 11:43:59 +10:00
case ( DistributionPeriodTypeEnum . Month ) :
2024-09-18 16:32:45 +10:00
nextRun = lastRun . AddMonths ( ParseInt ( distributionPeriod ) ) ;
break ;
2024-07-02 11:43:59 +10:00
case ( DistributionPeriodTypeEnum . Year ) :
2024-09-18 16:32:45 +10:00
nextRun = lastRun . AddYears ( ParseInt ( distributionPeriod ) ) ;
break ;
2024-07-02 11:43:59 +10:00
}
2024-09-19 13:51:44 +10:00
return nextRunModifierService . GetWorkDayAsync ( nextRun ) . GetAwaiter ( ) . GetResult ( ) ;
2024-07-11 11:32:14 +10:00
}
2024-09-16 17:01:04 +10:00
2024-07-11 11:32:14 +10:00
private DateTimeOffset GetPrevDateForDistributionRun ( DateTimeOffset lastRun , DistributionPeriodTypeEnum periodType , string distributionPeriod )
{
switch ( periodType )
{
case ( DistributionPeriodTypeEnum . Day ) :
return lastRun . AddDays ( - ParseInt ( distributionPeriod ) ) ;
case ( DistributionPeriodTypeEnum . Month ) :
return lastRun . AddMonths ( - ParseInt ( distributionPeriod ) ) ;
case ( DistributionPeriodTypeEnum . Year ) :
return lastRun . AddYears ( - ParseInt ( distributionPeriod ) ) ;
}
2024-07-02 11:43:59 +10:00
return lastRun ;
}
2024-09-16 17:01:04 +10:00
2025-06-25 14:17:34 +10:00
public async Task < DateOnly > GetStartPeriodForDateAsync ( Guid jobGroupId , DateTimeOffset date , DateTimeOffset referenceDate , DistributionPeriodTypeEnum periodType , string distributionPeriod )
2024-07-05 15:17:48 +10:00
{
2025-06-25 14:17:34 +10:00
var esppSchedule = await GetEsppScheduleAsync ( jobGroupId ) ;
2024-07-05 15:17:48 +10:00
2024-07-11 11:32:14 +10:00
var currentStartPeriod = referenceDate ;
var currentEndPeriod = GetNextDateForDistributionRun ( currentStartPeriod , periodType , distributionPeriod ) ;
2024-07-05 15:17:48 +10:00
2024-07-11 11:32:14 +10:00
while ( ! ( date > = currentStartPeriod & & date < currentEndPeriod ) )
2024-07-05 15:17:48 +10:00
{
2024-07-11 11:32:14 +10:00
if ( date > currentEndPeriod )
{
currentStartPeriod = currentEndPeriod ;
currentEndPeriod = GetNextDateForDistributionRun ( currentStartPeriod , periodType , distributionPeriod ) ;
}
else
{
currentEndPeriod = currentStartPeriod ;
currentStartPeriod = GetPrevDateForDistributionRun ( currentStartPeriod , periodType , distributionPeriod ) ;
}
2024-07-05 15:17:48 +10:00
}
return DateOnly . FromDateTime ( currentStartPeriod . DateTime ) ;
}
2024-07-02 11:43:59 +10:00
private int ParseInt ( string value )
{
try
{
return int . Parse ( value ) ;
}
catch ( Exception ex )
{
logger . LogError ( ex , $"{nameof(this.GetType)}, получение конца периода. Н е смог распарсить string в int для значения {value}." ) ;
return 0 ;
}
}
2024-07-11 11:32:14 +10:00
2024-09-16 17:01:04 +10:00
2024-07-11 11:32:14 +10:00
private DistributionPeriodTypeEnum ParseDistributionPeriodType ( string value )
{
var result = ( DistributionPeriodTypeEnum ) Enum . Parse ( typeof ( DistributionPeriodTypeEnum ) , value ) ;
return result ;
}
2024-09-18 16:32:45 +10:00
2023-10-17 09:42:18 +10:00
}
}