feat(api,bll,dal,esppScheduleSync,TemplateGenerator): изменен рассчет nextRun для задания роботу и синхронизатору, подставляется в зависимости от настроек ЗО и таймзоны УЗ робота ЕСПП. Переименование полей в БД

This commit is contained in:
Mikhail Trubnikov
2026-02-03 16:15:19 +10:00
parent c0210656d9
commit ead4653ad0
36 changed files with 13010 additions and 290 deletions

View File

@@ -16,6 +16,12 @@
public DateTimeOffset NextRun { get; set; } public DateTimeOffset NextRun { get; set; }
/// <summary>
/// NextRun с учетом ЗО
/// </summary>
public DateTimeOffset? NextRunWithResponseAreaOffset { get; set; }
public bool IsResponseAreaTimezone { get; set; }
/// <summary> /// <summary>
/// Рабочая группа (формируется из шорткода) /// Рабочая группа (формируется из шорткода)

View File

@@ -1,17 +1,12 @@
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using PARR.API.Contracts.V1; using PARR.API.Contracts.V1;
using PARR.API.Contracts.V1.Requests.Queries; using PARR.API.Contracts.V1.Requests.Queries;
using PARR.API.Contracts.V1.Responses;
using PARR.API.Contracts.V1.Responses.Base;
using PARR.API.Controllers.V1.Base; using PARR.API.Controllers.V1.Base;
using PARR.API.Services.Interfaces; using PARR.API.Services.Interfaces;
using PARR.Constants; using PARR.Constants;
using PARR.DAL.Contracts;
using PARR.DAL.Services.Interfaces; using PARR.DAL.Services.Interfaces;
using PARR.DAL.Services.Interfaces.Unit; using PARR.DAL.Services.Interfaces.Unit;
using PARR.DAL.TransformServices;
namespace PARR.API.Controllers.V1 namespace PARR.API.Controllers.V1
{ {

View File

@@ -18,8 +18,10 @@ using PARR.DAL.DomainModels;
using PARR.DAL.DomainServices.Interfaces; using PARR.DAL.DomainServices.Interfaces;
using PARR.DAL.Models; using PARR.DAL.Models;
using PARR.DAL.Models.Job; using PARR.DAL.Models.Job;
using PARR.DAL.NextRunServices;
using PARR.DAL.Services.Interfaces; using PARR.DAL.Services.Interfaces;
using PARR.DAL.Services.Interfaces.Job; using PARR.DAL.Services.Interfaces.Job;
using PARR.DAL.Services.Interfaces.Schedule;
namespace PARR.API.Controllers.V1 namespace PARR.API.Controllers.V1
{ {
@@ -39,6 +41,7 @@ namespace PARR.API.Controllers.V1
private readonly IJobGroupTypeService jobGroupTypeService; private readonly IJobGroupTypeService jobGroupTypeService;
private readonly SettingsFromDb settingsFromDb; private readonly SettingsFromDb settingsFromDb;
private readonly IMatchingStatusService matchingStatusService; private readonly IMatchingStatusService matchingStatusService;
private readonly IScheduleResponseAreaTimeOffsetService scheduleResponseAreaTimeOffsetService;
public JobGroupController( public JobGroupController(
ILogger<JobController> logger, ILogger<JobController> logger,
@@ -50,7 +53,8 @@ namespace PARR.API.Controllers.V1
IValidator<JobGroupRequest> validator, IValidator<JobGroupRequest> validator,
IJobGroupTypeService jobGroupTypeService, IJobGroupTypeService jobGroupTypeService,
SettingsFromDb settingsFromDb, SettingsFromDb settingsFromDb,
IMatchingStatusService matchingStatusService IMatchingStatusService matchingStatusService,
IScheduleResponseAreaTimeOffsetService scheduleResponseAreaTimeOffsetService
) )
{ {
this.logger = logger; this.logger = logger;
@@ -63,6 +67,7 @@ namespace PARR.API.Controllers.V1
this.jobGroupTypeService = jobGroupTypeService; this.jobGroupTypeService = jobGroupTypeService;
this.settingsFromDb = settingsFromDb; this.settingsFromDb = settingsFromDb;
this.matchingStatusService = matchingStatusService; this.matchingStatusService = matchingStatusService;
this.scheduleResponseAreaTimeOffsetService = scheduleResponseAreaTimeOffsetService;
} }
@@ -166,7 +171,7 @@ namespace PARR.API.Controllers.V1
ScheduleExcludeTypeId = request.ScheduleExcludeTypeId, ScheduleExcludeTypeId = request.ScheduleExcludeTypeId,
ScheduleExcludeTypeCalendarId = request.ScheduleExcludeTypeCalendarId, ScheduleExcludeTypeCalendarId = request.ScheduleExcludeTypeCalendarId,
IsAutoDistributionEnabled = request.IsAutoDistributionEnabled, IsAutoDistributionEnabled = request.IsAutoDistributionEnabled,
IsWorkGroupTimezone = request.IsWorkGroupTimezone IsResponseAreaTimezone = request.IsWorkGroupTimezone
//IsAgent = request.IsAgent, //IsAgent = request.IsAgent,
//AgentName = request.AgentName, //AgentName = request.AgentName,
//AgentTimeOutSec = request.AgentTimeOutSec, //AgentTimeOutSec = request.AgentTimeOutSec,
@@ -260,7 +265,7 @@ namespace PARR.API.Controllers.V1
orig.ScheduleExcludeTypeId = request.ScheduleExcludeTypeId; orig.ScheduleExcludeTypeId = request.ScheduleExcludeTypeId;
orig.ScheduleExcludeTypeCalendarId = request.ScheduleExcludeTypeCalendarId; orig.ScheduleExcludeTypeCalendarId = request.ScheduleExcludeTypeCalendarId;
orig.IsAutoDistributionEnabled = request.IsAutoDistributionEnabled; orig.IsAutoDistributionEnabled = request.IsAutoDistributionEnabled;
orig.IsWorkGroupTimezone = request.IsWorkGroupTimezone; orig.IsResponseAreaTimezone = request.IsWorkGroupTimezone;
//orig.IsAgent = request.IsAgent; //orig.IsAgent = request.IsAgent;
//orig.AgentName = request.AgentName; //orig.AgentName = request.AgentName;
//orig.AgentTimeOutSec = request.AgentTimeOutSec; //orig.AgentTimeOutSec = request.AgentTimeOutSec;
@@ -445,7 +450,8 @@ namespace PARR.API.Controllers.V1
var scheduleResponse = new JobGroupScheduleResponse var scheduleResponse = new JobGroupScheduleResponse
{ {
Timezone = settingsFromDb.ScheduleTimezone, //Timezone = settingsFromDb.ScheduleTimezone,
Timezone = scheduleResponseAreaTimeOffsetService.GetDefault.EsppValue,
TypeSchedule = mapper.Map<EsppScheduleTypeScheduleResponse>(schedule.TypeSchedule), TypeSchedule = mapper.Map<EsppScheduleTypeScheduleResponse>(schedule.TypeSchedule),
Values = mapper.Map<List<EsppScheduleValResponse>>(schedule.Values).OrderBy(t => t.Order).ToList() Values = mapper.Map<List<EsppScheduleValResponse>>(schedule.Values).OrderBy(t => t.Order).ToList()
}; };

View File

@@ -8,6 +8,7 @@ using PARR.API.Contracts.V1.Responses;
using PARR.API.Contracts.V1.Responses.Base; using PARR.API.Contracts.V1.Responses.Base;
using PARR.API.Controllers.V1.Base; using PARR.API.Controllers.V1.Base;
using PARR.API.Services.Interfaces; using PARR.API.Services.Interfaces;
using PARR.BLL.Helpers;
using PARR.Common.Domain; using PARR.Common.Domain;
using PARR.Constants; using PARR.Constants;
using PARR.DAL.Contracts; using PARR.DAL.Contracts;
@@ -200,17 +201,11 @@ namespace PARR.API.Controllers.V1
{ //RobotTaskTemplateResponse { //RobotTaskTemplateResponse
var robotTaskTemplateResponse = mapper.Map<RobotTaskTemplateResponse>(task); var robotTaskTemplateResponse = mapper.Map<RobotTaskTemplateResponse>(task);
//if (shortcodesService.IsAnyShortcodes(robotTaskTemplateResponse.FullDescription))
robotTaskTemplateResponse.FullDescription = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.FullDescription, task.Template!); robotTaskTemplateResponse.FullDescription = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.FullDescription, task.Template!);
//if (shortcodesService.IsAnyShortcodes(robotTaskTemplateResponse.ShortDescription))
robotTaskTemplateResponse.ShortDescription = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.ShortDescription, task.Template!); robotTaskTemplateResponse.ShortDescription = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.ShortDescription, task.Template!);
//if (shortcodesService.IsAnyShortcodes(robotTaskTemplateResponse.Solution))
robotTaskTemplateResponse.Solution = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.Solution, task.Template!); robotTaskTemplateResponse.Solution = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.Solution, task.Template!);
//if (shortcodesService.IsAnyShortcodes(robotTaskTemplateResponse.TnkName))
robotTaskTemplateResponse.TnkName = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.TnkName, task.Template!); robotTaskTemplateResponse.TnkName = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.TnkName, task.Template!);
//if (shortcodesService.IsAnyShortcodes(robotTaskTemplateResponse.WorkName))
robotTaskTemplateResponse.WorkName = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.WorkName, task.Template!); robotTaskTemplateResponse.WorkName = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.WorkName, task.Template!);
//if (shortcodesService.IsAnyShortcodes(robotTaskTemplateResponse.WorkGroup))
robotTaskTemplateResponse.WorkGroup = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.WorkGroup, task.Template!); robotTaskTemplateResponse.WorkGroup = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.WorkGroup, task.Template!);
robotTaskTemplateResponse.ResponseArea = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.ResponseArea, task.Template!); robotTaskTemplateResponse.ResponseArea = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.ResponseArea, task.Template!);
@@ -223,12 +218,15 @@ namespace PARR.API.Controllers.V1
//RobotTaskScheduleResponse //RobotTaskScheduleResponse
var robotTaskScheduleResponse = mapper.Map<RobotTaskScheduleResponse>(task); var robotTaskScheduleResponse = mapper.Map<RobotTaskScheduleResponse>(task);
robotTaskScheduleResponse.Timezone = await GetTimezoneForTemplateAsync(task.Template!); robotTaskScheduleResponse.Timezone = GetTimezoneForTemplate(task.Template!);
robotTaskScheduleResponse.WorkGroup = await shortcodesService.ApplyShortcodesAsync(robotTaskScheduleResponse.WorkGroup, task.Template!); robotTaskScheduleResponse.WorkGroup = await shortcodesService.ApplyShortcodesAsync(robotTaskScheduleResponse.WorkGroup, task.Template!);
robotTaskScheduleResponse.ResponseArea = await shortcodesService.ApplyShortcodesAsync(robotTaskScheduleResponse.ResponseArea, task.Template!); robotTaskScheduleResponse.ResponseArea = await shortcodesService.ApplyShortcodesAsync(robotTaskScheduleResponse.ResponseArea, task.Template!);
var nextRunWithTimezone = nextRunService.GetNextRunWithTimezoneEsppAndResponseArea(task.Template!.NextRun, task.Template!.Job?.Group?.IsResponseAreaTimezone, robotTaskScheduleResponse.ResponseArea);
robotTaskScheduleResponse.NextStart = EsppScheduleHelpers.GetNextRun(nextRunWithTimezone);
robotTaskScheduleResponse.GenerationTime = EsppScheduleHelpers.GetGenerationTime(nextRunWithTimezone);
return Ok(new Response<RobotTaskScheduleResponse>(robotTaskScheduleResponse, true)); return Ok(new Response<RobotTaskScheduleResponse>(robotTaskScheduleResponse, true));
} }
@@ -240,6 +238,11 @@ namespace PARR.API.Controllers.V1
} }
/// <summary>
/// Обоновить NextRun если он устарел
/// </summary>
/// <param name="task"></param>
/// <returns></returns>
private async Task UpdateLastNextRunDate(RobotConfiguration task) private async Task UpdateLastNextRunDate(RobotConfiguration task)
{ {
var template = task.Template!; var template = task.Template!;
@@ -251,9 +254,6 @@ namespace PARR.API.Controllers.V1
//var nextRun = await esppScheduleTransformService.GetNextDateAsync(template.Job!.GroupId, template.NextRun); //var nextRun = await esppScheduleTransformService.GetNextDateAsync(template.Job!.GroupId, template.NextRun);
#endregion #endregion
//пока у нас выключено автораспределение, считает по refDate
//TODO: когда заработает автораспределение, будем думать!!!!!
//var nextRun = await esppScheduleTransformService.GetNextDateAsync(template.Job!.GroupId, template!.Job!.Group!.ReferenceDate); //var nextRun = await esppScheduleTransformService.GetNextDateAsync(template.Job!.GroupId, template!.Job!.Group!.ReferenceDate);
var nextRun = await nextRunService.GetNextRunForTemplateAsync(template.Id, false); var nextRun = await nextRunService.GetNextRunForTemplateAsync(template.Id, false);
@@ -261,11 +261,6 @@ namespace PARR.API.Controllers.V1
{ {
logger.LogDebug($"Для шаблона id {template.Id} обновляю nextRun, новое значение {nextRun}, старое значение {template.NextRun}"); logger.LogDebug($"Для шаблона id {template.Id} обновляю nextRun, новое значение {nextRun}, старое значение {template.NextRun}");
//if (template.NextRun < DateTimeOffset.UtcNow)
//{
// logger.LogDebug($"Для шаблона id {template.Id} обновляю lastRun, новое значение {template.NextRun}, старое значение {template.LastRun}");
// template.LastRun = template.NextRun;
//}
template.LastRun = template.NextRun; template.LastRun = template.NextRun;
template.NextRun = nextRun; template.NextRun = nextRun;
@@ -331,10 +326,17 @@ namespace PARR.API.Controllers.V1
return true; return true;
} }
private async Task<string> GetTimezoneForTemplateAsync(Template template)
/// <summary>
/// Получить таймзону для шаблона
/// </summary>
/// <param name="template"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
private string GetTimezoneForTemplate(Template template)
{ {
if (template.Job?.Group?.IsWorkGroupTimezone != true) if (template.Job?.Group?.IsResponseAreaTimezone != true)
return settingsFromDb.ScheduleTimezone; return scheduleResponseAreaTimeOffsetService.GetDefault.EsppValue;
var responseArea = template.Unit?.BaseFields?.ResponseArea; var responseArea = template.Unit?.BaseFields?.ResponseArea;
@@ -345,18 +347,7 @@ namespace PARR.API.Controllers.V1
"но включена настройка 'использовать часовой пояс рабочей группы'."); "но включена настройка 'использовать часовой пояс рабочей группы'.");
} }
var offsets = await scheduleResponseAreaTimeOffsetService return scheduleResponseAreaTimeOffsetService.GetByResponseAreaOrDefault(responseArea).EsppValue;
.Get()
.ToDictionaryAsync(t => t.ResponseArea, t => t.TimeOffset);
if (!offsets.TryGetValue(responseArea, out var offset))
{
throw new InvalidOperationException(
$"Не найдено временное смещение для ResponseArea '{responseArea}' у шаблона Id={template.Id}, Name='{template.Name}'. " +
"Проверьте наличие записи в таблице ScheduleResponseAreaTimeOffset.");
}
return offset;
} }
} }

View File

@@ -17,8 +17,8 @@ using PARR.DAL.Contracts;
using PARR.DAL.DomainModels; using PARR.DAL.DomainModels;
using PARR.DAL.DomainServices.Shortcodes; using PARR.DAL.DomainServices.Shortcodes;
using PARR.DAL.Models; using PARR.DAL.Models;
using PARR.DAL.NextRunServices;
using PARR.DAL.Services.Interfaces; using PARR.DAL.Services.Interfaces;
using System.Diagnostics;
namespace PARR.API.Controllers.V1 namespace PARR.API.Controllers.V1
{ {
@@ -35,6 +35,7 @@ namespace PARR.API.Controllers.V1
private readonly ILogger<TemplateController> logger; private readonly ILogger<TemplateController> logger;
private readonly IShortcodesService shortcodesService; private readonly IShortcodesService shortcodesService;
private readonly IOrderService orderService; private readonly IOrderService orderService;
private readonly INextRunService nextRunService;
public TemplateController( public TemplateController(
IMapper mapper, IMapper mapper,
@@ -43,7 +44,8 @@ namespace PARR.API.Controllers.V1
IClientService clientService, IClientService clientService,
ILogger<TemplateController> logger, ILogger<TemplateController> logger,
IShortcodesService shortcodesService, IShortcodesService shortcodesService,
IOrderService orderService IOrderService orderService,
INextRunService nextRunService
) )
{ {
this.mapper = mapper; this.mapper = mapper;
@@ -53,6 +55,7 @@ namespace PARR.API.Controllers.V1
this.logger = logger; this.logger = logger;
this.shortcodesService = shortcodesService; this.shortcodesService = shortcodesService;
this.orderService = orderService; this.orderService = orderService;
this.nextRunService = nextRunService;
} }
@@ -135,7 +138,7 @@ namespace PARR.API.Controllers.V1
var templatesDict = templates.ToDictionary(t => t.Id); var templatesDict = templates.ToDictionary(t => t.Id);
var templateResponseDict = templateResponse.ToDictionary(t => t.Id); var templateResponseDict = templateResponse.ToDictionary(t => t.Id);
#region Заполняем шорткоды #region Заполняем шорткоды и NextRunWithResponseAreaOffset
if (filter.ApplyShortcode == true) if (filter.ApplyShortcode == true)
{ {
//sw.Restart(); //sw.Restart();
@@ -143,6 +146,7 @@ namespace PARR.API.Controllers.V1
{ {
//await ApplyTemplateShortcodesAsync(responseItem, templates.First(t => t.Id == responseItem.Id)); //await ApplyTemplateShortcodesAsync(responseItem, templates.First(t => t.Id == responseItem.Id));
await ApplyTemplateShortcodesAsync(responseItem, templatesDict[responseItem.Id]); await ApplyTemplateShortcodesAsync(responseItem, templatesDict[responseItem.Id]);
FillNextRunWithResponseAreaOffset(responseItem);
} }
//logger.LogDebug("Получение шорткодов: {ElapsedMs} мс", sw.ElapsedMilliseconds); //logger.LogDebug("Получение шорткодов: {ElapsedMs} мс", sw.ElapsedMilliseconds);
//sw.Stop(); //sw.Stop();
@@ -187,6 +191,7 @@ namespace PARR.API.Controllers.V1
var response = mapper.Map<TemplateResponse>(template); var response = mapper.Map<TemplateResponse>(template);
await ApplyTemplateShortcodesAsync(response, template); await ApplyTemplateShortcodesAsync(response, template);
FillNextRunWithResponseAreaOffset(response);
var ordersCountResult = await GetOrdersCountAsync(new List<Guid> { response.Id }); var ordersCountResult = await GetOrdersCountAsync(new List<Guid> { response.Id });
response.OrderCount = ordersCountResult.Count > 0 ? ordersCountResult.First().Value : 0; response.OrderCount = ordersCountResult.Count > 0 ? ordersCountResult.First().Value : 0;
@@ -280,6 +285,7 @@ namespace PARR.API.Controllers.V1
var response = mapper.Map<TemplateListResponse>(templateToResponse); var response = mapper.Map<TemplateListResponse>(templateToResponse);
await ApplyTemplateShortcodesAsync(response, templateToResponse); await ApplyTemplateShortcodesAsync(response, templateToResponse);
FillNextRunWithResponseAreaOffset(response);
var ordersCountResult = await GetOrdersCountAsync(new List<Guid> { response.Id }); var ordersCountResult = await GetOrdersCountAsync(new List<Guid> { response.Id });
response.OrderCount = ordersCountResult.Count > 0 ? ordersCountResult.First().Value : 0; response.OrderCount = ordersCountResult.Count > 0 ? ordersCountResult.First().Value : 0;
@@ -324,5 +330,17 @@ namespace PARR.API.Controllers.V1
return templateWithOrders.ToDictionary(t => t.TemplateId!.Value, t => t.OrderCount); return templateWithOrders.ToDictionary(t => t.TemplateId!.Value, t => t.OrderCount);
} }
/// <summary>
/// Заполнить NextRunWithResponseAreaOffset
/// </summary>
/// <param name="response"></param>
private void FillNextRunWithResponseAreaOffset(TemplateBaseResponse response)
{
response.NextRunWithResponseAreaOffset = response.IsResponseAreaTimezone && !string.IsNullOrEmpty(response.ResponseArea)
? nextRunService.GetNextRunWithResponseAreaOffset(response.NextRun, response.ResponseArea)
: response.NextRun;
}
} }
} }

View File

@@ -17,7 +17,7 @@ using PARR.DAL.Models.Job;
using PARR.DAL.Services.Interfaces; using PARR.DAL.Services.Interfaces;
using PARR.DAL.Services.Interfaces.Job; using PARR.DAL.Services.Interfaces.Job;
using PARR.DAL.Services.Interfaces.Unit; using PARR.DAL.Services.Interfaces.Unit;
using PARR.DAL.TransformServices;
namespace PARR.API.Controllers.V1 namespace PARR.API.Controllers.V1
{ {

View File

@@ -26,7 +26,8 @@ namespace PARR.API.MappingProfiles
.ForMember(d => d.Agent, o => o.MapFrom(s => s.Job!.Group!)) .ForMember(d => d.Agent, o => o.MapFrom(s => s.Job!.Group!))
.ForMember(d => d.SyncStatus, o => o.MapFrom(s => s.RobotConfigurations.OrderBy(t => t.RobotCode))) .ForMember(d => d.SyncStatus, o => o.MapFrom(s => s.RobotConfigurations.OrderBy(t => t.RobotCode)))
.ForMember(d => d.OrderCount, o => o.MapFrom(s => s.Orders.Count())) .ForMember(d => d.OrderCount, o => o.MapFrom(s => s.Orders.Count()))
.ForMember(d => d.IsAutoDistributionEnabled, o => o.MapFrom(s => s.Job!.Group!.IsAutoDistributionEnabled)); .ForMember(d => d.IsAutoDistributionEnabled, o => o.MapFrom(s => s.Job!.Group!.IsAutoDistributionEnabled))
.ForMember(d => d.IsResponseAreaTimezone, o => o.MapFrom(s => s.Job!.Group!.IsResponseAreaTimezone));
CreateMap<Template, TemplateListResponse>(); CreateMap<Template, TemplateListResponse>();
@@ -246,13 +247,13 @@ namespace PARR.API.MappingProfiles
.ForMember(d => d.Exclude, o => o.MapFrom(s => s.Template!.Job!.Group!.ScheduleExcludeType!.EsppName)) .ForMember(d => d.Exclude, o => o.MapFrom(s => s.Template!.Job!.Group!.ScheduleExcludeType!.EsppName))
//.ForMember(d => d.ExcludeCalendar, o => o.MapFrom<RobotTaskScheduleExcludeCalendarResolver>()) //.ForMember(d => d.ExcludeCalendar, o => o.MapFrom<RobotTaskScheduleExcludeCalendarResolver>())
.ForMember(d => d.ExcludeCalendar, o => o.MapFrom(s => s.Template!.Job!.Group!.ScheduleExcludeTypeCalendar != null ? s.Template!.Job!.Group!.ScheduleExcludeTypeCalendar.EsppName : null)) .ForMember(d => d.ExcludeCalendar, o => o.MapFrom(s => s.Template!.Job!.Group!.ScheduleExcludeTypeCalendar != null ? s.Template!.Job!.Group!.ScheduleExcludeTypeCalendar.EsppName : null))
.ForMember(d => d.Timezone, o => o.MapFrom<RobotTaskScheduleTimezoneResolver>()) //.ForMember(d => d.Timezone, o => o.MapFrom<RobotTaskScheduleTimezoneResolver>())
.ForMember(d => d.RepeatRange, o => o.MapFrom<RobotTaskScheduleRepeatRangeResolver>()) .ForMember(d => d.RepeatRange, o => o.MapFrom<RobotTaskScheduleRepeatRangeResolver>())
//todo: GenerationTime //todo: GenerationTime
//.ForMember(d => d.GenerationTime, o => o.MapFrom(s => EsppScheduleHelpers.GetGenerationTime(s.Template!.NextRun))) //.ForMember(d => d.GenerationTime, o => o.MapFrom(s => EsppScheduleHelpers.GetGenerationTime(s.Template!.NextRun)))
.ForMember(d => d.GenerationTime, o => o.MapFrom<RobotTaskScheduleGenerationTimeResolver>()) //.ForMember(d => d.GenerationTime, o => o.MapFrom<RobotTaskScheduleGenerationTimeResolver>())
//.ForMember(d => d.NextStart, o => o.MapFrom(s => EsppScheduleHelpers.GetNextRun(s.Template!.NextRun))) //.ForMember(d => d.NextStart, o => o.MapFrom(s => EsppScheduleHelpers.GetNextRun(s.Template!.NextRun)))
.ForMember(d => d.NextStart, o => o.MapFrom<RobotTaskScheduleNextStartResolver>()) //.ForMember(d => d.NextStart, o => o.MapFrom<RobotTaskScheduleNextStartResolver>())
.ForMember(d => d.ScheduleType, o => o.MapFrom(s => .ForMember(d => d.ScheduleType, o => o.MapFrom(s =>
s.Template!.Job!.Group!.EsppSchValues!.First()!.EsppSchTypeConfig!.EsppSchTypeSchedule!.Description)) s.Template!.Job!.Group!.EsppSchValues!.First()!.EsppSchTypeConfig!.EsppSchTypeSchedule!.Description))
.ForMember(d => d.ScheduleTypeCode, o => o.MapFrom(s => .ForMember(d => d.ScheduleTypeCode, o => o.MapFrom(s =>
@@ -372,7 +373,8 @@ namespace PARR.API.MappingProfiles
.Include<JobGroup, JobGroupResponse>() .Include<JobGroup, JobGroupResponse>()
.Include<JobGroup, JobGroupWithDistributionConfigResponse>() .Include<JobGroup, JobGroupWithDistributionConfigResponse>()
.ForMember(d => d.GroupType, o => o.MapFrom(s => s.GroupType)) .ForMember(d => d.GroupType, o => o.MapFrom(s => s.GroupType))
.ForMember(d => d.GroupingUnitField, o => o.MapFrom(s => s.GroupingUnitField)); .ForMember(d => d.GroupingUnitField, o => o.MapFrom(s => s.GroupingUnitField))
.ForMember(d => d.IsWorkGroupTimezone, o => o.MapFrom(s => s.IsResponseAreaTimezone));
CreateMap<JobGroup, JobGroupBaseResponse>() CreateMap<JobGroup, JobGroupBaseResponse>()
.ForMember(d => d.Name, o => o.MapFrom(s => s.GroupName)); .ForMember(d => d.Name, o => o.MapFrom(s => s.GroupName));

View File

@@ -3,6 +3,7 @@ using PARR.API.Contracts.V1.Responses;
using PARR.DAL.Contracts; using PARR.DAL.Contracts;
using PARR.DAL.Models; using PARR.DAL.Models;
using PARR.DAL.Services.Interfaces; using PARR.DAL.Services.Interfaces;
using PARR.DAL.Services.Interfaces.Schedule;
namespace PARR.API.MappingProfiles.Resolvers namespace PARR.API.MappingProfiles.Resolvers
{ {
@@ -12,18 +13,21 @@ namespace PARR.API.MappingProfiles.Resolvers
private readonly ILogger<ApplicationInWorkScheduleResolver> logger; private readonly ILogger<ApplicationInWorkScheduleResolver> logger;
private readonly IMapper mapper; private readonly IMapper mapper;
private readonly SettingsFromDb settingsFromDb; private readonly SettingsFromDb settingsFromDb;
private readonly IScheduleResponseAreaTimeOffsetService scheduleResponseAreaTimeOffsetService;
public ApplicationInWorkScheduleResolver( public ApplicationInWorkScheduleResolver(
IEsppSchTypeConfigService esppConfigService, IEsppSchTypeConfigService esppConfigService,
ILogger<ApplicationInWorkScheduleResolver> logger, ILogger<ApplicationInWorkScheduleResolver> logger,
IMapper mapper, IMapper mapper,
SettingsFromDb settingsFromDb SettingsFromDb settingsFromDb,
IScheduleResponseAreaTimeOffsetService scheduleResponseAreaTimeOffsetService
) )
{ {
this.esppConfigService = esppConfigService; this.esppConfigService = esppConfigService;
this.logger = logger; this.logger = logger;
this.mapper = mapper; this.mapper = mapper;
this.settingsFromDb = settingsFromDb; this.settingsFromDb = settingsFromDb;
this.scheduleResponseAreaTimeOffsetService = scheduleResponseAreaTimeOffsetService;
} }
public ApplicationInWorkScheduleResponse? Resolve(ApplicationsInWork source, ApplicationInWorkResponse destination, ApplicationInWorkScheduleResponse? destMember, ResolutionContext context) public ApplicationInWorkScheduleResponse? Resolve(ApplicationsInWork source, ApplicationInWorkResponse destination, ApplicationInWorkScheduleResponse? destMember, ResolutionContext context)
@@ -38,7 +42,8 @@ namespace PARR.API.MappingProfiles.Resolvers
var response = new ApplicationInWorkScheduleResponse var response = new ApplicationInWorkScheduleResponse
{ {
Timezone = settingsFromDb.ScheduleTimezone, //Timezone = settingsFromDb.ScheduleTimezone,
Timezone = scheduleResponseAreaTimeOffsetService.GetDefault.EsppValue,
TypeSchedule = mapper.Map<EsppScheduleTypeScheduleResponse>(schedule.TypeSchedule), TypeSchedule = mapper.Map<EsppScheduleTypeScheduleResponse>(schedule.TypeSchedule),
Values = mapper.Map<List<EsppScheduleValResponse>>(schedule.Values).OrderBy(t => t.Order).ToList() Values = mapper.Map<List<EsppScheduleValResponse>>(schedule.Values).OrderBy(t => t.Order).ToList()
}; };

View File

@@ -3,6 +3,7 @@ using PARR.API.Contracts.V1.Responses;
using PARR.DAL.Contracts; using PARR.DAL.Contracts;
using PARR.DAL.Models.Job; using PARR.DAL.Models.Job;
using PARR.DAL.Services.Interfaces; using PARR.DAL.Services.Interfaces;
using PARR.DAL.Services.Interfaces.Schedule;
namespace PARR.API.MappingProfiles.Resolvers namespace PARR.API.MappingProfiles.Resolvers
{ {
@@ -12,18 +13,21 @@ namespace PARR.API.MappingProfiles.Resolvers
private readonly ILogger<JobGroupScheduleResolver> logger; private readonly ILogger<JobGroupScheduleResolver> logger;
private readonly IMapper mapper; private readonly IMapper mapper;
private readonly SettingsFromDb settingsFromDb; private readonly SettingsFromDb settingsFromDb;
private readonly IScheduleResponseAreaTimeOffsetService scheduleResponseAreaTimeOffsetService;
public JobGroupScheduleResolver( public JobGroupScheduleResolver(
IEsppSchTypeConfigService esppConfigService, IEsppSchTypeConfigService esppConfigService,
ILogger<JobGroupScheduleResolver> logger, ILogger<JobGroupScheduleResolver> logger,
IMapper mapper, IMapper mapper,
SettingsFromDb settingsFromDb SettingsFromDb settingsFromDb,
IScheduleResponseAreaTimeOffsetService scheduleResponseAreaTimeOffsetService
) )
{ {
this.esppConfigService = esppConfigService; this.esppConfigService = esppConfigService;
this.logger = logger; this.logger = logger;
this.mapper = mapper; this.mapper = mapper;
this.settingsFromDb = settingsFromDb; this.settingsFromDb = settingsFromDb;
this.scheduleResponseAreaTimeOffsetService = scheduleResponseAreaTimeOffsetService;
} }
@@ -39,7 +43,8 @@ namespace PARR.API.MappingProfiles.Resolvers
var response = new JobGroupScheduleResponse var response = new JobGroupScheduleResponse
{ {
Timezone = settingsFromDb.ScheduleTimezone, //Timezone = settingsFromDb.ScheduleTimezone,
Timezone = scheduleResponseAreaTimeOffsetService.GetDefault.EsppValue,
TypeSchedule = mapper.Map<EsppScheduleTypeScheduleResponse>(schedule.TypeSchedule), TypeSchedule = mapper.Map<EsppScheduleTypeScheduleResponse>(schedule.TypeSchedule),
Values = mapper.Map<List<EsppScheduleValResponse>>(schedule.Values).OrderBy(t => t.Order).ToList() Values = mapper.Map<List<EsppScheduleValResponse>>(schedule.Values).OrderBy(t => t.Order).ToList()
}; };

View File

@@ -3,26 +3,26 @@ using PARR.API.Contracts.V1.Responses;
using PARR.BLL.Helpers; using PARR.BLL.Helpers;
using PARR.DAL.Contracts; using PARR.DAL.Contracts;
using PARR.DAL.Models; using PARR.DAL.Models;
using PARR.DAL.TransformServices;
namespace PARR.API.MappingProfiles.Resolvers namespace PARR.API.MappingProfiles.Resolvers
{ {
public class RobotTaskScheduleGenerationTimeResolver : IValueResolver<RobotConfiguration, RobotTaskScheduleResponse, string> //public class RobotTaskScheduleGenerationTimeResolver : IValueResolver<RobotConfiguration, RobotTaskScheduleResponse, string>
{ //{
private readonly SettingsFromDb settingsFromDb; // private readonly SettingsFromDb settingsFromDb;
private readonly INextRunModifierService nextRunModifierService; // private readonly INextRunModifierService nextRunModifierService;
public RobotTaskScheduleGenerationTimeResolver(SettingsFromDb settingsFromDb, INextRunModifierService nextRunModifierService) // public RobotTaskScheduleGenerationTimeResolver(SettingsFromDb settingsFromDb, INextRunModifierService nextRunModifierService)
{ // {
this.settingsFromDb = settingsFromDb; // this.settingsFromDb = settingsFromDb;
this.nextRunModifierService = nextRunModifierService; // this.nextRunModifierService = nextRunModifierService;
} // }
public string Resolve(RobotConfiguration source, RobotTaskScheduleResponse destination, string destMember, ResolutionContext context) // public string Resolve(RobotConfiguration source, RobotTaskScheduleResponse destination, string destMember, ResolutionContext context)
{ // {
var nextRunForRobot = nextRunModifierService.GetNextRunByAccountRobotTimeZone(source.Template!.NextRun); // var nextRunForRobot = nextRunModifierService.GetNextRunByAccountRobotTimeZone(source.Template!.NextRun);
return EsppScheduleHelpers.GetGenerationTime(nextRunForRobot); // return EsppScheduleHelpers.GetGenerationTime(nextRunForRobot);
} // }
} //}
} }

View File

@@ -3,26 +3,47 @@ using PARR.API.Contracts.V1.Responses;
using PARR.BLL.Helpers; using PARR.BLL.Helpers;
using PARR.DAL.Contracts; using PARR.DAL.Contracts;
using PARR.DAL.Models; using PARR.DAL.Models;
using PARR.DAL.TransformServices; using PARR.DAL.Services.Interfaces.Schedule;
namespace PARR.API.MappingProfiles.Resolvers namespace PARR.API.MappingProfiles.Resolvers
{ {
public class RobotTaskScheduleNextStartResolver : IValueResolver<RobotConfiguration, RobotTaskScheduleResponse, string> //public class RobotTaskScheduleNextStartResolver : IValueResolver<RobotConfiguration, RobotTaskScheduleResponse, string>
{ //{
private readonly SettingsFromDb settingsFromDb; // private readonly SettingsFromDb settingsFromDb;
private readonly INextRunModifierService nextRunModifierService; // private readonly INextRunModifierService nextRunModifierService;
// private readonly IScheduleResponseAreaTimeOffsetService scheduleResponseAreaTimeOffsetService;
public RobotTaskScheduleNextStartResolver(SettingsFromDb settingsFromDb, INextRunModifierService nextRunModifierService) // public RobotTaskScheduleNextStartResolver(
{ // SettingsFromDb settingsFromDb,
this.settingsFromDb = settingsFromDb; // INextRunModifierService nextRunModifierService,
this.nextRunModifierService = nextRunModifierService; // IScheduleResponseAreaTimeOffsetService scheduleResponseAreaTimeOffsetService
} // )
// {
// this.settingsFromDb = settingsFromDb;
// this.nextRunModifierService = nextRunModifierService;
// this.scheduleResponseAreaTimeOffsetService = scheduleResponseAreaTimeOffsetService;
// }
public string Resolve(RobotConfiguration source, RobotTaskScheduleResponse destination, string destMember, ResolutionContext context) // public string Resolve(RobotConfiguration source, RobotTaskScheduleResponse destination, string destMember, ResolutionContext context)
{ // {
var nextRunForRobot = nextRunModifierService.GetNextRunByAccountRobotTimeZone(source.Template!.NextRun); // var nextRunForRobot = nextRunModifierService.GetNextRunByAccountRobotTimeZone(source.Template!.NextRun);
return EsppScheduleHelpers.GetNextRun(nextRunForRobot); // // Сначала прибавляем офсет УЗ ЕСПП
} // // потом прибаляем = офсет УЗ ЕСПП - offset ЗО
}
// // если включен - IsWorkGroupTimezone - группировка по таймозне группы, применяем тайм зону группы
// if (source.Template?.Job?.Group?.IsWorkGroupTimezone == true)
// {
// var responseArea = "TODO";
// var esppOffset = new TimeSpan(settingsFromDb.EsppRobotAccountTimeZoneHour, 0, 0);
// var workGroupOffset = scheduleResponseAreaTimeOffsetService.GetByResponseAreaOrDefault(responseArea).UtcTimeOffset;
// var resultOffset = esppOffset - workGroupOffset;
// nextRunForRobot = nextRunForRobot.Add(resultOffset);
// }
// return EsppScheduleHelpers.GetNextRun(nextRunForRobot);
// }
//}
} }

View File

@@ -1,9 +1,8 @@
using AutoMapper; using AutoMapper;
using PARR.API.Contracts.V1.Responses; using PARR.API.Contracts.V1.Responses;
using PARR.DAL.Contracts;
using PARR.DAL.Models; using PARR.DAL.Models;
using PARR.DAL.Services.Interfaces; using PARR.DAL.Services.Interfaces;
using PARR.DAL.TransformServices;
namespace PARR.API.MappingProfiles.Resolvers namespace PARR.API.MappingProfiles.Resolvers
{ {
@@ -11,17 +10,14 @@ namespace PARR.API.MappingProfiles.Resolvers
{ {
private readonly IEsppSchTypeConfigService esppConfigService; private readonly IEsppSchTypeConfigService esppConfigService;
private readonly ILogger<RobotTaskScheduleSchResolver> logger; private readonly ILogger<RobotTaskScheduleSchResolver> logger;
private readonly INextRunModifierService nextRunModifierService;
public RobotTaskScheduleSchResolver( public RobotTaskScheduleSchResolver(
IEsppSchTypeConfigService esppConfigService, IEsppSchTypeConfigService esppConfigService,
ILogger<RobotTaskScheduleSchResolver> logger, ILogger<RobotTaskScheduleSchResolver> logger
INextRunModifierService nextRunModifierService
) )
{ {
this.esppConfigService = esppConfigService; this.esppConfigService = esppConfigService;
this.logger = logger; this.logger = logger;
this.nextRunModifierService = nextRunModifierService;
} }
public List<RobotTaskScheduleSchResponse>? Resolve(RobotConfiguration source, RobotTaskScheduleResponse destination, List<RobotTaskScheduleSchResponse>? destMember, ResolutionContext context) public List<RobotTaskScheduleSchResponse>? Resolve(RobotConfiguration source, RobotTaskScheduleResponse destination, List<RobotTaskScheduleSchResponse>? destMember, ResolutionContext context)
@@ -44,14 +40,15 @@ namespace PARR.API.MappingProfiles.Resolvers
Value = t.Value.Value Value = t.Value.Value
}).OrderBy(t => t.Order).ToList(); }).OrderBy(t => t.Order).ToList();
//Если задача относится к распределенной модели исполнения за период месяц устанавливаем день равный NextRun ////Если задача относится к распределенной модели исполнения за период месяц устанавливаем день равный NextRun
if (source.Template!.Job!.Group!.IsAutoDistributionEnabled && schedule.TypeSchedule.Id == (int)EsppSchTypeScheduleEnum.Monthly) ////УСТАРЕВШЕЕ
{ //if (source.Template!.Job!.Group!.IsAutoDistributionEnabled && schedule.TypeSchedule.Id == (int)EsppSchTypeScheduleEnum.Monthly)
var nextRunForRobot = nextRunModifierService.GetNextRunByAccountRobotTimeZone(source.Template.NextRun); //{
// var nextRunForRobot = nextRunModifierService.GetNextRunByAccountRobotTimeZone(source.Template.NextRun);
//response.First().Value = source.Template.NextRun.Day.ToString(); // //response.First().Value = source.Template.NextRun.Day.ToString();
response.First().Value = nextRunForRobot.Day.ToString(); // response.First().Value = nextRunForRobot.Day.ToString();
} //}
return response; return response;
} }

View File

@@ -5,18 +5,18 @@ using PARR.DAL.Models;
namespace PARR.API.MappingProfiles.Resolvers namespace PARR.API.MappingProfiles.Resolvers
{ {
public class RobotTaskScheduleTimezoneResolver : IValueResolver<RobotConfiguration, RobotTaskScheduleResponse, string> //public class RobotTaskScheduleTimezoneResolver : IValueResolver<RobotConfiguration, RobotTaskScheduleResponse, string>
{ //{
private readonly SettingsFromDb settingsFromDb; // private readonly SettingsFromDb settingsFromDb;
public RobotTaskScheduleTimezoneResolver(SettingsFromDb settingsFromDb) // public RobotTaskScheduleTimezoneResolver(SettingsFromDb settingsFromDb)
{ // {
this.settingsFromDb = settingsFromDb; // this.settingsFromDb = settingsFromDb;
} // }
public string Resolve(RobotConfiguration source, RobotTaskScheduleResponse destination, string destMember, ResolutionContext context) // public string Resolve(RobotConfiguration source, RobotTaskScheduleResponse destination, string destMember, ResolutionContext context)
{ // {
return settingsFromDb.ScheduleTimezone; // return settingsFromDb.ScheduleTimezone;
} // }
} //}
} }

View File

@@ -3,6 +3,7 @@ using PARR.API.Contracts.V1.Responses;
using PARR.DAL.Contracts; using PARR.DAL.Contracts;
using PARR.DAL.Models; using PARR.DAL.Models;
using PARR.DAL.Services.Interfaces; using PARR.DAL.Services.Interfaces;
using PARR.DAL.Services.Interfaces.Schedule;
namespace PARR.API.MappingProfiles.Resolvers namespace PARR.API.MappingProfiles.Resolvers
{ {
@@ -12,18 +13,21 @@ namespace PARR.API.MappingProfiles.Resolvers
private readonly ILogger<TemplateScheduleResolver> logger; private readonly ILogger<TemplateScheduleResolver> logger;
private readonly IMapper mapper; private readonly IMapper mapper;
private readonly SettingsFromDb settingsFromDb; private readonly SettingsFromDb settingsFromDb;
private readonly IScheduleResponseAreaTimeOffsetService scheduleResponseAreaTimeOffsetService;
public TemplateScheduleResolver( public TemplateScheduleResolver(
IEsppSchTypeConfigService esppConfigService, IEsppSchTypeConfigService esppConfigService,
ILogger<TemplateScheduleResolver> logger, ILogger<TemplateScheduleResolver> logger,
IMapper mapper, IMapper mapper,
SettingsFromDb settingsFromDb SettingsFromDb settingsFromDb,
IScheduleResponseAreaTimeOffsetService scheduleResponseAreaTimeOffsetService
) )
{ {
this.esppConfigService = esppConfigService; this.esppConfigService = esppConfigService;
this.logger = logger; this.logger = logger;
this.mapper = mapper; this.mapper = mapper;
this.settingsFromDb = settingsFromDb; this.settingsFromDb = settingsFromDb;
this.scheduleResponseAreaTimeOffsetService = scheduleResponseAreaTimeOffsetService;
} }
public EsppScheduleResponse? Resolve(Template source, TemplateResponse destination, EsppScheduleResponse? destMember, ResolutionContext context) public EsppScheduleResponse? Resolve(Template source, TemplateResponse destination, EsppScheduleResponse? destMember, ResolutionContext context)
@@ -42,7 +46,8 @@ namespace PARR.API.MappingProfiles.Resolvers
//LastRun = source.ApplicationsInWork.LastRun, //LastRun = source.ApplicationsInWork.LastRun,
NextRun = source.NextRun, NextRun = source.NextRun,
LastRun = source.LastRun, LastRun = source.LastRun,
Timezone = settingsFromDb.ScheduleTimezone, // Timezone = settingsFromDb.ScheduleTimezone,
Timezone = scheduleResponseAreaTimeOffsetService.GetDefault.EsppValue,
TypeSchedule = mapper.Map<EsppScheduleTypeScheduleResponse>(schedule.TypeSchedule), TypeSchedule = mapper.Map<EsppScheduleTypeScheduleResponse>(schedule.TypeSchedule),
Values = mapper.Map<List<EsppScheduleValResponse>>(schedule.Values).OrderBy(t => t.Order).ToList() Values = mapper.Map<List<EsppScheduleValResponse>>(schedule.Values).OrderBy(t => t.Order).ToList()
}; };

View File

@@ -4,29 +4,6 @@ namespace PARR.BLL.Helpers
{ {
public static class EsppScheduleHelpers public static class EsppScheduleHelpers
{ {
///// <summary>
///// Получить дату первого старта в формате ЕСПП
///// </summary>
///// <param name="startDate"></param>
///// <param name="time"></param>
///// <returns></returns>
//public static string GetFirstStart(DateOnly startDate, TimeSpan time)
//{
// var date = new DateTime(startDate.Year, startDate.Month, startDate.Day, time.Hours, time.Minutes, time.Seconds);
// return date.ToString("dd/MM/yy HH:mm:ss", CultureInfo.InvariantCulture);
//}
///// <summary>
///// Получить дату следующего старта в формате для ЕСПП
///// </summary>
///// <param name="date"></param>
///// <returns></returns>
//public static string GetNextScheduleStart(DateTimeOffset date)
//{
// return date.ToString("dd/MM/yy HH:mm:ss", CultureInfo.InvariantCulture);
//}
/// <summary> /// <summary>
/// Получить время создания наряда в формате ЕСПП /// Получить время создания наряда в формате ЕСПП
/// </summary> /// </summary>

View File

@@ -1,4 +1,5 @@
using Microsoft.Extensions.Configuration; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using PARR.DAL.Context; using PARR.DAL.Context;
using PARR.DAL.Contracts; using PARR.DAL.Contracts;
@@ -21,7 +22,7 @@ namespace PARR.DAL.Configurations.DbSettings
//если миграциями БД еще не создана, то SettingsInDbs будет недоступна //если миграциями БД еще не создана, то SettingsInDbs будет недоступна
try try
{ {
var settings = dataContext?.Setting.ToList(); var settings = dataContext?.Setting.AsNoTracking().ToList();
if (settings == null) if (settings == null)
return; return;

View File

@@ -189,7 +189,7 @@ namespace PARR.DAL.Context
new { Name = nameof(SettingsFromDb.TemplatePrefixName), Description = "Префикс имени шаблона в ЕСПП", Value = "%PREFIX%-ЭИТИ-ПТК-ПАРР" }, new { Name = nameof(SettingsFromDb.TemplatePrefixName), Description = "Префикс имени шаблона в ЕСПП", Value = "%PREFIX%-ЭИТИ-ПТК-ПАРР" },
new { Name = nameof(SettingsFromDb.RobotAttemptsNumber), Description = "Количество попыток выполнения задания роботом", Value = "3" }, new { Name = nameof(SettingsFromDb.RobotAttemptsNumber), Description = "Количество попыток выполнения задания роботом", Value = "3" },
new { Name = nameof(SettingsFromDb.RobotWaitTime), Description = "Время ожидания выполнения роботом задания", Value = "00:15:00" }, new { Name = nameof(SettingsFromDb.RobotWaitTime), Description = "Время ожидания выполнения роботом задания", Value = "00:15:00" },
new { Name = nameof(SettingsFromDb.ScheduleTimezone), Description = "Расписание регламентной работы - В каком часовом поясе", Value = "MSK" }, //new { Name = nameof(SettingsFromDb.ScheduleTimezone), Description = "Расписание регламентной работы - В каком часовом поясе", Value = "MSK" },
//new { Name = nameof(SettingsFromDb.ScheduleExcludeType), Description = "Расписание регламентной работы - Тип исключения", Value = "Выполнить ТОЛЬКО В указанном календаре" }, //new { Name = nameof(SettingsFromDb.ScheduleExcludeType), Description = "Расписание регламентной работы - Тип исключения", Value = "Выполнить ТОЛЬКО В указанном календаре" },
//new { Name = nameof(SettingsFromDb.ScheduleExcludeCalendar), Description = "Расписание регламентной работы - Календарь", Value = "8x5 (8.00-17.00)" }, //new { Name = nameof(SettingsFromDb.ScheduleExcludeCalendar), Description = "Расписание регламентной работы - Календарь", Value = "8x5 (8.00-17.00)" },
new { Name = nameof(SettingsFromDb.ScheduleRepeatRange), Description = "Расписание регламентной работы - Диапазн повторов", Value = "Отсутствует дата завершения" }, new { Name = nameof(SettingsFromDb.ScheduleRepeatRange), Description = "Расписание регламентной работы - Диапазн повторов", Value = "Отсутствует дата завершения" },
@@ -202,12 +202,12 @@ namespace PARR.DAL.Context
Description = "Список неизменных частей имени шаблона", Description = "Список неизменных частей имени шаблона",
Value = Value =
new List<TemplateNameConstantPart> { new List<TemplateNameConstantPart> {
new TemplateNameConstantPart { Name = "П-1", Value = "ЭИТИ" }, new TemplateNameConstantPart { Name = "П-1", Value = "ЭИТИ-ПАРР" }
new TemplateNameConstantPart { Name = "П-2", Value = "ПАРР" }
}.ToJson() }.ToJson()
}, },
new { Name = nameof(SettingsFromDb.EsppUnitTag), Description = "Префикс тега в поле ЭК \"Дополнительная информация\"", Value = АРР_" }, new { Name = nameof(SettingsFromDb.EsppUnitTag), Description = "Префикс тега в поле ЭК \"Дополнительная информация\"", Value = АРР_" },
new { Name = nameof(SettingsFromDb.JobIdForUnusedTemplates), Description = "Job в который перемещаем ниспользованные шаблоны", Value = "8f85a91c-a223-4686-bb69-1f0ee73624f2" } new { Name = nameof(SettingsFromDb.JobIdForUnusedTemplates), Description = "Job в который перемещаем ниспользованные шаблоны", Value = "8f85a91c-a223-4686-bb69-1f0ee73624f2" },
new { Name = nameof(SettingsFromDb.DefaultResponseAreaToTimeOffset), Description = "Зона ответственности для получения тайм зоны по умолчанию для расписаний", Value = "17-МСК" }
); );
}); });
#endregion #endregion

View File

@@ -77,10 +77,10 @@ namespace PARR.DAL.Contracts
/// </summary> /// </summary>
public TimeSpan RobotWaitTime { get; set; } public TimeSpan RobotWaitTime { get; set; }
/// <summary> ///// <summary>
/// Расписание регламентной работы - В каком часовом поясе ///// Расписание регламентной работы - В каком часовом поясе
/// </summary> ///// </summary>
public string ScheduleTimezone { get; set; } = string.Empty; //public string ScheduleTimezone { get; set; } = string.Empty;
///// <summary> ///// <summary>
///// Расписание регламентной работы - Тип исключения ///// Расписание регламентной работы - Тип исключения
@@ -93,7 +93,7 @@ namespace PARR.DAL.Contracts
//public string ScheduleExcludeCalendar { get; set; } = string.Empty; //public string ScheduleExcludeCalendar { get; set; } = string.Empty;
/// <summary> /// <summary>
/// Расписание регламентной работы - Диапазн повторов /// Расписание регламентной работы - Диапазон повторов
/// </summary> /// </summary>
public string ScheduleRepeatRange { get; set; } = string.Empty; public string ScheduleRepeatRange { get; set; } = string.Empty;
@@ -122,6 +122,11 @@ namespace PARR.DAL.Contracts
/// </summary> /// </summary>
public Guid JobIdForUnusedTemplates { get; set; } public Guid JobIdForUnusedTemplates { get; set; }
/// <summary>
/// Зона ответственности для получения тайм зоны по умолчанию для расписаний
/// </summary>
public string DefaultResponseAreaToTimeOffset { get; set; } = string.Empty;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace PARR.DAL.Migrations
{
/// <inheritdoc />
public partial class tblScheduleResponseAreaTimeOffsetAddUtcTimeOffset : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<TimeSpan>(
name: "UtcTimeOffset",
schema: "schedule",
table: "ResponseAreaTimeOffsets",
type: "interval",
nullable: false,
defaultValue: new TimeSpan(0, 0, 0, 0, 0));
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "UtcTimeOffset",
schema: "schedule",
table: "ResponseAreaTimeOffsets");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,52 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace PARR.DAL.Migrations
{
/// <inheritdoc />
public partial class tblRenameFields : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.RenameColumn(
name: "TimeOffset",
schema: "schedule",
table: "ResponseAreaTimeOffsets",
newName: "EsppValue");
migrationBuilder.RenameColumn(
name: "IsWorkGroupTimezone",
schema: "job",
table: "Groups",
newName: "IsResponseAreaTimezone");
migrationBuilder.InsertData(
table: "Settings",
columns: new[] { "Name", "Description", "Value" },
values: new object[] { "DefaultResponseAreaToTimeOffset", "Зона ответственности для получения тайм зоны по умолчанию для расписаний", "17-МСК" });
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DeleteData(
table: "Settings",
keyColumn: "Name",
keyValue: "DefaultResponseAreaToTimeOffset");
migrationBuilder.RenameColumn(
name: "EsppValue",
schema: "schedule",
table: "ResponseAreaTimeOffsets",
newName: "TimeOffset");
migrationBuilder.RenameColumn(
name: "IsResponseAreaTimezone",
schema: "job",
table: "Groups",
newName: "IsWorkGroupTimezone");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,42 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace PARR.DAL.Migrations
{
/// <inheritdoc />
public partial class tbsSettingsRemoveScheduleTimezone : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DeleteData(
table: "Settings",
keyColumn: "Name",
keyValue: "ScheduleTimezone");
migrationBuilder.UpdateData(
table: "Settings",
keyColumn: "Name",
keyValue: "TemplateNameConstantParts",
column: "Value",
value: "[{\"Name\":\"П-1\",\"Value\":\"ЭИТИ-ПАРР\"}]");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.UpdateData(
table: "Settings",
keyColumn: "Name",
keyValue: "TemplateNameConstantParts",
column: "Value",
value: "[{\"Name\":\"П-1\",\"Value\":\"ЭИТИ\"},{\"Name\":\"П-2\",\"Value\":\"ПАРР\"}]");
migrationBuilder.InsertData(
table: "Settings",
columns: new[] { "Name", "Description", "Value" },
values: new object[] { "ScheduleTimezone", "Расписание регламентной работы - В каком часовом поясе", "MSK" });
}
}
}

View File

@@ -1678,7 +1678,7 @@ namespace PARR.DAL.Migrations
b.Property<bool>("IsAutoDistributionEnabled") b.Property<bool>("IsAutoDistributionEnabled")
.HasColumnType("boolean"); .HasColumnType("boolean");
b.Property<bool>("IsWorkGroupTimezone") b.Property<bool>("IsResponseAreaTimezone")
.HasColumnType("boolean"); .HasColumnType("boolean");
b.Property<DateTimeOffset>("ReferenceDate") b.Property<DateTimeOffset>("ReferenceDate")
@@ -2581,10 +2581,13 @@ namespace PARR.DAL.Migrations
b.Property<string>("ResponseArea") b.Property<string>("ResponseArea")
.HasColumnType("text"); .HasColumnType("text");
b.Property<string>("TimeOffset") b.Property<string>("EsppValue")
.IsRequired() .IsRequired()
.HasColumnType("text"); .HasColumnType("text");
b.Property<TimeSpan>("UtcTimeOffset")
.HasColumnType("interval");
b.HasKey("ResponseArea"); b.HasKey("ResponseArea");
b.ToTable("ResponseAreaTimeOffsets", "schedule", t => b.ToTable("ResponseAreaTimeOffsets", "schedule", t =>
@@ -2648,12 +2651,6 @@ namespace PARR.DAL.Migrations
Value = "00:15:00" Value = "00:15:00"
}, },
new new
{
Name = "ScheduleTimezone",
Description = "Расписание регламентной работы - В каком часовом поясе",
Value = "MSK"
},
new
{ {
Name = "ScheduleRepeatRange", Name = "ScheduleRepeatRange",
Description = "Расписание регламентной работы - Диапазн повторов", Description = "Расписание регламентной работы - Диапазн повторов",
@@ -2681,7 +2678,7 @@ namespace PARR.DAL.Migrations
{ {
Name = "TemplateNameConstantParts", Name = "TemplateNameConstantParts",
Description = "Список неизменных частей имени шаблона", Description = "Список неизменных частей имени шаблона",
Value = "[{\"Name\":\"П-1\",\"Value\":\"ЭИТИ\"},{\"Name\":\"П-2\",\"Value\":\"ПАРР\"}]" Value = "[{\"Name\":\"П-1\",\"Value\":\"ЭИТИ-ПАРР\"}]"
}, },
new new
{ {
@@ -2694,6 +2691,12 @@ namespace PARR.DAL.Migrations
Name = "JobIdForUnusedTemplates", Name = "JobIdForUnusedTemplates",
Description = "Job в который перемещаем ниспользованные шаблоны", Description = "Job в который перемещаем ниспользованные шаблоны",
Value = "8f85a91c-a223-4686-bb69-1f0ee73624f2" Value = "8f85a91c-a223-4686-bb69-1f0ee73624f2"
},
new
{
Name = "DefaultResponseAreaToTimeOffset",
Description = "Зона ответственности для получения тайм зоны по умолчанию для расписаний",
Value = "17-МСК"
}); });
}); });

View File

@@ -95,7 +95,7 @@ namespace PARR.DAL.Models.Job
/// <summary> /// <summary>
/// Использовать таймзону рабочей группы ответственного за ЭК шаблона /// Использовать таймзону рабочей группы ответственного за ЭК шаблона
/// </summary> /// </summary>
public bool IsWorkGroupTimezone { get; set; } = false; public bool IsResponseAreaTimezone { get; set; } = false;
/// <summary> /// <summary>

View File

@@ -15,6 +15,14 @@ namespace PARR.DAL.Models.Schedule
[Key] [Key]
public required string ResponseArea { get; set; } public required string ResponseArea { get; set; }
public required string TimeOffset { get; set; } /// <summary>
/// ЕСПП значение
/// </summary>
public required string EsppValue { get; set; }
/// <summary>
/// Смещение относительно UTC
/// </summary>
public required TimeSpan UtcTimeOffset { get; set; }
} }
} }

View File

@@ -62,5 +62,21 @@ namespace PARR.DAL.NextRunServices
/// <returns></returns> /// <returns></returns>
Task<HashSet<DateOnly>> GetWeekendsAsync(DateOnly startDate, DateOnly endDate, DateTimeOffset referenceDate); Task<HashSet<DateOnly>> GetWeekendsAsync(DateOnly startDate, DateOnly endDate, DateTimeOffset referenceDate);
/// <summary>
/// Получить NextRun со смещением УЗ ЕСПП и если надо, выполнить смещение для ЗО
/// </summary>
/// <param name="nextRun"></param>
/// <param name="isResponseAreaTimezone">Применить таймзону ЗО</param>
/// <param name="responseArea">ЗО</param>
/// <returns></returns>
DateTimeOffset GetNextRunWithTimezoneEsppAndResponseArea(DateTimeOffset nextRun, bool? isResponseAreaTimezone = null, string? responseArea = null);
/// <summary>
/// Получить NextRun согласно таймзоны ЗО
/// </summary>
/// <param name="nextRun"></param>
/// <param name="responseArea"></param>
/// <returns></returns>
DateTimeOffset GetNextRunWithResponseAreaOffset(DateTimeOffset nextRun, string responseArea);
} }
} }

View File

@@ -1,13 +1,17 @@
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using PARR.BLL.Helpers;
using PARR.Constants; using PARR.Constants;
using PARR.DAL.Contracts;
using PARR.DAL.DomainServices.Shortcodes; using PARR.DAL.DomainServices.Shortcodes;
using PARR.DAL.Models; using PARR.DAL.Models;
using PARR.DAL.Models.Job; using PARR.DAL.Models.Job;
using PARR.DAL.NextRunServices.Models; using PARR.DAL.NextRunServices.Models;
using PARR.DAL.NextRunServices.Subservices; using PARR.DAL.NextRunServices.Subservices;
using PARR.DAL.Services.Implementations.Schedule;
using PARR.DAL.Services.Interfaces; using PARR.DAL.Services.Interfaces;
using PARR.DAL.Services.Interfaces.Job; using PARR.DAL.Services.Interfaces.Job;
using PARR.DAL.Services.Interfaces.Schedule;
namespace PARR.DAL.NextRunServices namespace PARR.DAL.NextRunServices
{ {
@@ -19,6 +23,8 @@ namespace PARR.DAL.NextRunServices
private readonly IEsppScheduleTransformService esppScheduleTransformService; private readonly IEsppScheduleTransformService esppScheduleTransformService;
private readonly ITemplateDistributor templateDistributor; private readonly ITemplateDistributor templateDistributor;
private readonly IShortcodesService shortcodesService; private readonly IShortcodesService shortcodesService;
private readonly SettingsFromDb settingsFromDb;
private readonly IScheduleResponseAreaTimeOffsetService scheduleResponseAreaTimeOffsetService;
public NextRunService( public NextRunService(
ILogger<NextRunService> logger, ILogger<NextRunService> logger,
@@ -26,7 +32,9 @@ namespace PARR.DAL.NextRunServices
IJobGroupService jobGroupService, IJobGroupService jobGroupService,
IEsppScheduleTransformService esppScheduleTransformService, IEsppScheduleTransformService esppScheduleTransformService,
ITemplateDistributor templateDistributor, ITemplateDistributor templateDistributor,
IShortcodesService shortcodesService IShortcodesService shortcodesService,
SettingsFromDb settingsFromDb,
IScheduleResponseAreaTimeOffsetService scheduleResponseAreaTimeOffsetService
) )
{ {
this.logger = logger; this.logger = logger;
@@ -35,6 +43,8 @@ namespace PARR.DAL.NextRunServices
this.esppScheduleTransformService = esppScheduleTransformService; this.esppScheduleTransformService = esppScheduleTransformService;
this.templateDistributor = templateDistributor; this.templateDistributor = templateDistributor;
this.shortcodesService = shortcodesService; this.shortcodesService = shortcodesService;
this.settingsFromDb = settingsFromDb;
this.scheduleResponseAreaTimeOffsetService = scheduleResponseAreaTimeOffsetService;
} }
@@ -317,5 +327,58 @@ namespace PARR.DAL.NextRunServices
{ {
return await templateDistributor.GetWeekendsV2Async(startDate, endDate, referenceDate); return await templateDistributor.GetWeekendsV2Async(startDate, endDate, referenceDate);
} }
public DateTimeOffset GetNextRunWithTimezoneEsppAndResponseArea(DateTimeOffset nextRun, bool? isResponseAreaTimezone = null, string? responseArea = null)
{
logger.LogDebug("Начинаю получать nextRun с учетом УЗ ЕСПП и ЗО, входные параметры: nextRun: {nextRun}, isResponseAreaTimezone: {isResponseAreaTimezone}, responseArea: {responseArea}", nextRun, isResponseAreaTimezone, responseArea);
var esppOffset = GetEsppAccountOffset();
// смещение УЗ ЕСПП
var resultNextRun = nextRun.Add(esppOffset);
logger.LogDebug("Смещение nextRun с учетом смещения УЗ ЕСПП, новое значение: {resultNextRun}", resultNextRun);
// если включено использовать таймзону ЗО
if (isResponseAreaTimezone == true && !string.IsNullOrEmpty(responseArea))
{
// resultNextRun = офсет УЗ ЕСПП - offset ЗО
var responseAreaOffset = scheduleResponseAreaTimeOffsetService.GetByResponseAreaOrDefault(responseArea).UtcTimeOffset;
var resultOffset = esppOffset - responseAreaOffset;
resultNextRun = resultNextRun.Add(resultOffset);
logger.LogDebug("Смещение nextRun с учетом ЗО, смещение ЗО: {responseAreaOffset}, смещение с учетом смещения УЗ ЕСПП: {resultOffset}, новое значение: {resultNextRun}", responseAreaOffset, resultOffset, resultNextRun);
}
//var resulstStr = EsppScheduleHelpers.GetNextRun(resultNextRun);
//logger.LogDebug("Результат в формате ЕСПП: {resulstStr}", resulstStr);
return resultNextRun;
}
public DateTimeOffset GetNextRunWithResponseAreaOffset(DateTimeOffset nextRun, string responseArea)
{
var responseAreaOffset = scheduleResponseAreaTimeOffsetService.GetByResponseAreaOrDefault(responseArea).UtcTimeOffset;
var resulstNextRun = nextRun.Add(responseAreaOffset);
logger.LogDebug("Смещение nextRun для ЗО {responseArea}, входящий: {nextRun}, смещение: {offset}, результат: {result}", responseArea, nextRun, responseAreaOffset, resulstNextRun);
return resulstNextRun;
}
/// <summary>
/// Получить смещение УЗ ЕСПП
/// </summary>
/// <returns></returns>
private TimeSpan GetEsppAccountOffset()
{
var esppOffset = new TimeSpan(settingsFromDb.EsppRobotAccountTimeZoneHour, 0, 0);
logger.LogDebug("Оффсет УЗ ЕСПП: {esppOffset}", esppOffset);
return esppOffset;
}
} }
} }

View File

@@ -107,7 +107,6 @@ namespace PARR.DAL
services.AddTransient<IScheduleExcludeTypeService, ScheduleExcludeTypeService>(); services.AddTransient<IScheduleExcludeTypeService, ScheduleExcludeTypeService>();
services.AddTransient<IScheduleExcludeTypeCalendarService, ScheduleExcludeTypeCalendarService>(); services.AddTransient<IScheduleExcludeTypeCalendarService, ScheduleExcludeTypeCalendarService>();
services.AddTransient<IScheduleResponseAreaTimeOffsetService, ScheduleResponseAreaTimeOffsetService>();
#endregion #endregion
@@ -135,12 +134,11 @@ namespace PARR.DAL
#endregion #endregion
// TransformServices //services.AddTransient<INextRunModifierService, NextRunModifierService>();
services.AddTransient<IEsppScheduleTransformService, EsppScheduleTransformService>();
services.AddTransient<INextRunModifierService, NextRunModifierService>();
#region NextRun Services #region NextRun Services
services.AddTransient<IEsppScheduleTransformService, EsppScheduleTransformService>();
services.AddTransient<INextRunService, NextRunService>(); services.AddTransient<INextRunService, NextRunService>();
services.AddTransient<ITemplateDistributor, TemplateDistributor>(); services.AddTransient<ITemplateDistributor, TemplateDistributor>();
@@ -182,6 +180,16 @@ namespace PARR.DAL
services.AddSingleton(settingsFromDb); services.AddSingleton(settingsFromDb);
PrefixSettings.PrefixWithoutVariable = settingsFromDb.TemplatePrefixWithoutVariable; PrefixSettings.PrefixWithoutVariable = settingsFromDb.TemplatePrefixWithoutVariable;
// Сервис - Расписание в ЕСПП. Смещение часового пояса относительно МСК для зоны ответственности рабочей группы
services.AddSingleton<IScheduleResponseAreaTimeOffsetService>(provider =>
{
using var scope = provider.CreateScope();
var dbContext = scope.ServiceProvider.GetRequiredService<DataContext>();
var settingsFromDb = scope.ServiceProvider.GetRequiredService<SettingsFromDb>();
return new ScheduleResponseAreaTimeOffsetService(dbContext, settingsFromDb);
});
} }
} }

View File

@@ -1,29 +1,64 @@
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using PARR.DAL.Context; using PARR.DAL.Context;
using PARR.DAL.Contracts;
using PARR.DAL.Models.Schedule; using PARR.DAL.Models.Schedule;
using PARR.DAL.Services.Interfaces.Schedule; using PARR.DAL.Services.Interfaces.Schedule;
namespace PARR.DAL.Services.Implementations.Schedule namespace PARR.DAL.Services.Implementations.Schedule
{ {
internal class ScheduleResponseAreaTimeOffsetService : IScheduleResponseAreaTimeOffsetService internal sealed class ScheduleResponseAreaTimeOffsetService : IScheduleResponseAreaTimeOffsetService
{ {
private readonly DataContext dataContext; private readonly IReadOnlyDictionary<string, ScheduleResponseAreaTimeOffset> offsetList;
/// <summary>
/// ЗО по умолчанию
/// </summary>
private readonly string defaultResponseArea;
/// <summary>
/// Настройки, если не нашли в offsetList
/// </summary>
private readonly ScheduleResponseAreaTimeOffset defaultOffset;
public ScheduleResponseAreaTimeOffsetService(DataContext dataContext) public ScheduleResponseAreaTimeOffsetService(DataContext dataContext, SettingsFromDb settingsFromDb)
{ {
this.dataContext = dataContext; offsetList = dataContext.ScheduleResponseAreaTimeOffsets
.AsNoTracking()
.ToDictionary(t => t.ResponseArea, t => t, StringComparer.OrdinalIgnoreCase);
if (string.IsNullOrEmpty(settingsFromDb.DefaultResponseAreaToTimeOffset))
defaultResponseArea = "17-МСК";
else
defaultResponseArea = settingsFromDb.DefaultResponseAreaToTimeOffset;
defaultOffset = new ScheduleResponseAreaTimeOffset
{
ResponseArea = "17-МСК",
EsppValue = "",
UtcTimeOffset = new TimeSpan(3, 0, 0)
};
} }
public IQueryable<ScheduleResponseAreaTimeOffset> Get()
public IReadOnlyDictionary<string, ScheduleResponseAreaTimeOffset> GetAll => offsetList;
public ScheduleResponseAreaTimeOffset GetDefault => GetByResponseAreaOrDefault(defaultResponseArea);
public ScheduleResponseAreaTimeOffset GetByResponseAreaOrDefault(string responseArea)
{ {
return dataContext.ScheduleResponseAreaTimeOffsets; return offsetList.TryGetValue(responseArea, out var value) ? value : defaultOffset;
} }
public async Task<string?> GetTimeOffsetByResponseAreaAsync(string responseArea)
{
var result = await dataContext.ScheduleResponseAreaTimeOffsets.FirstOrDefaultAsync(t => t.ResponseArea == responseArea);
return result != null ? result.TimeOffset : null; //public IQueryable<ScheduleResponseAreaTimeOffset> Get()
} //{
// return dataContext.ScheduleResponseAreaTimeOffsets;
//}
//public async Task<string?> GetTimeOffsetByResponseAreaAsync(string responseArea)
//{
// var result = await dataContext.ScheduleResponseAreaTimeOffsets.FirstOrDefaultAsync(t => t.ResponseArea == responseArea);
// return result != null ? result.TimeOffset : null;
//}
} }
} }

View File

@@ -4,8 +4,21 @@ namespace PARR.DAL.Services.Interfaces.Schedule
{ {
public interface IScheduleResponseAreaTimeOffsetService public interface IScheduleResponseAreaTimeOffsetService
{ {
IQueryable<ScheduleResponseAreaTimeOffset> Get(); /// <summary>
/// Список всех значений
/// </summary>
IReadOnlyDictionary<string, ScheduleResponseAreaTimeOffset> GetAll { get; }
Task<string?> GetTimeOffsetByResponseAreaAsync(string responseArea); /// <summary>
/// Значение по умолчанию
/// </summary>
ScheduleResponseAreaTimeOffset GetDefault { get; }
/// <summary>
/// Получить значение по ЗО, если не найдет, то значение по умолчанию
/// </summary>
/// <param name="responseArea"></param>
/// <returns></returns>
ScheduleResponseAreaTimeOffset GetByResponseAreaOrDefault(string responseArea);
} }
} }

View File

@@ -2,23 +2,23 @@
namespace PARR.DAL.TransformServices namespace PARR.DAL.TransformServices
{ {
/// <summary> ///// <summary>
/// Сервис по изменению NextRun ///// Сервис по изменению NextRun
/// </summary> ///// </summary>
public interface INextRunModifierService //public interface INextRunModifierService
{ //{
/// <summary> // /// <summary>
/// Получить NextRun с учетом тайм зоны робота ЕСПП // /// Получить NextRun с учетом тайм зоны УЗ робота ЕСПП
/// </summary> // /// </summary>
/// <param name="nextRun"></param> // /// <param name="nextRun"></param>
/// <returns></returns> // /// <returns></returns>
DateTimeOffset GetNextRunByAccountRobotTimeZone(DateTimeOffset nextRun); // DateTimeOffset GetNextRunByAccountRobotTimeZone(DateTimeOffset nextRun);
///// <summary> // ///// <summary>
///// Получить РАБОЧИЙ день следующего срабатывания // ///// Получить РАБОЧИЙ день следующего срабатывания
///// </summary> // ///// </summary>
///// <param name="nextRun"></param> // ///// <param name="nextRun"></param>
///// <returns></returns> // ///// <returns></returns>
//Task<DateTimeOffset> GetWorkDayAsync(DateTimeOffset nextRun); // //Task<DateTimeOffset> GetWorkDayAsync(DateTimeOffset nextRun);
} //}
} }

View File

@@ -1,68 +1,32 @@
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using PARR.Common;
using PARR.DAL.Contracts; using PARR.DAL.Contracts;
using PARR.DAL.Services.Interfaces; using PARR.DAL.Services.Interfaces;
namespace PARR.DAL.TransformServices namespace PARR.DAL.TransformServices
{ {
internal class NextRunModifierService : INextRunModifierService //internal class NextRunModifierService : INextRunModifierService
{ //{
private readonly SettingsFromDb settingsFromDb; // private readonly SettingsFromDb settingsFromDb;
private readonly ILogger<NextRunModifierService> logger; // private readonly ILogger<NextRunModifierService> logger;
private readonly IWeekendDayService weekendDayService; // private readonly IWeekendDayService weekendDayService;
public NextRunModifierService( // public NextRunModifierService(
SettingsFromDb settingsFromDb, // SettingsFromDb settingsFromDb,
ILogger<NextRunModifierService> logger, // ILogger<NextRunModifierService> logger,
IWeekendDayService weekendDayService // IWeekendDayService weekendDayService
) // )
{ // {
this.settingsFromDb = settingsFromDb; // this.settingsFromDb = settingsFromDb;
this.logger = logger; // this.logger = logger;
this.weekendDayService = weekendDayService; // this.weekendDayService = weekendDayService;
} // }
public DateTimeOffset GetNextRunByAccountRobotTimeZone(DateTimeOffset nextRun) // public DateTimeOffset GetNextRunByAccountRobotTimeZone(DateTimeOffset nextRun)
{ // {
return nextRun.AddHours(settingsFromDb.EsppRobotAccountTimeZoneHour); // return nextRun.AddHours(settingsFromDb.EsppRobotAccountTimeZoneHour);
} // }
//public async Task<DateTimeOffset> GetWorkDayAsync(DateTimeOffset nextRun) //}
//{
// // получаем день относительно часового пояса МСК
// var date = DateOnly.FromDateTime(DateResolver.IsCurrentDayRelativeMskTime(nextRun) ? nextRun.Date : nextRun.Date.AddDays(1));
// if (await weekendDayService.IsWorkDayAsync(date, true))
// {
// //текущий nextRun рабочий день, возвращаем его
// return nextRun;
// }
// // ищем следующий рабочий день, максимум 20 итераций, если за их кол-во не нашли рабочий, берём последний не рабочий
// int count = 20;
// while (count > 0)
// {
// date = date.AddDays(1);
// var isWorkDay = await weekendDayService.IsWorkDayAsync(date, true);
// if (isWorkDay)
// break; // это рабочий день, выбираем его
// count--;
// if (!isWorkDay && count == 0)
// logger.LogWarning($"Не нашли рабочий день за 20 итераций, взяли последний нерабочий {date}");
// }
// // смотрим, если смещали из-за пояса МСК на день вперед, вычитаем этот день назад
// if (!DateResolver.IsCurrentDayRelativeMskTime(nextRun))
// date = date.AddDays(-1);
// // считаем новый NextRun
// var dayCount = date.DayNumber - DateOnly.FromDateTime(nextRun.Date).DayNumber;
// return nextRun.AddDays(dayCount);
//}
}
} }

View File

@@ -4,10 +4,11 @@ using Microsoft.Extensions.Logging;
using PARR.BLL.Helpers; using PARR.BLL.Helpers;
using PARR.BLL.Services.Interfaces; using PARR.BLL.Services.Interfaces;
using PARR.DAL.Contracts; using PARR.DAL.Contracts;
using PARR.DAL.DomainServices.Shortcodes;
using PARR.DAL.Models; using PARR.DAL.Models;
using PARR.DAL.NextRunServices;
using PARR.DAL.Services.Interfaces; using PARR.DAL.Services.Interfaces;
using PARR.DAL.Services.Interfaces.Schedule; using PARR.DAL.Services.Interfaces.Schedule;
using PARR.DAL.TransformServices;
using PARR.EsppScheduleSync.Domain; using PARR.EsppScheduleSync.Domain;
using PARR.EsppScheduleSync.Settings; using PARR.EsppScheduleSync.Settings;
using PARR.EsppSync; using PARR.EsppSync;
@@ -22,8 +23,9 @@ namespace PARR.EsppScheduleSync
private readonly ISyncService<EsppObjectSchedule> syncService; private readonly ISyncService<EsppObjectSchedule> syncService;
private readonly SettingsFromDb settingsFromDb; private readonly SettingsFromDb settingsFromDb;
private readonly IServiceProvider serviceProvider; private readonly IServiceProvider serviceProvider;
private readonly IScheduleResponseAreaTimeOffsetService scheduleResponseAreaTimeOffsetService;
private string noneExcludeCalendarEsppValue; private string noneExcludeCalendarEsppValue;
private Dictionary<string, string> responseAreaTimeOffsetDict; //private Dictionary<string, string> responseAreaTimeOffsetDict;
public ScheduleSyncher( public ScheduleSyncher(
@@ -32,7 +34,8 @@ namespace PARR.EsppScheduleSync
IMqService mqService, IMqService mqService,
ISyncService<EsppObjectSchedule> syncService, ISyncService<EsppObjectSchedule> syncService,
SettingsFromDb settingsFromDb, SettingsFromDb settingsFromDb,
IServiceProvider serviceProvider IServiceProvider serviceProvider,
IScheduleResponseAreaTimeOffsetService scheduleResponseAreaTimeOffsetService
) )
{ {
this.logger = logger; this.logger = logger;
@@ -41,8 +44,8 @@ namespace PARR.EsppScheduleSync
this.syncService = syncService; this.syncService = syncService;
this.settingsFromDb = settingsFromDb; this.settingsFromDb = settingsFromDb;
this.serviceProvider = serviceProvider; this.serviceProvider = serviceProvider;
this.scheduleResponseAreaTimeOffsetService = scheduleResponseAreaTimeOffsetService;
this.responseAreaTimeOffsetDict = new Dictionary<string, string>(); //this.responseAreaTimeOffsetDict = new Dictionary<string, string>();
this.noneExcludeCalendarEsppValue = string.Empty; this.noneExcludeCalendarEsppValue = string.Empty;
if (globalSettings.MqSettings == null) if (globalSettings.MqSettings == null)
@@ -62,8 +65,8 @@ namespace PARR.EsppScheduleSync
if (string.IsNullOrEmpty(noneExcludeCalendarEsppValue)) if (string.IsNullOrEmpty(noneExcludeCalendarEsppValue))
await GetNoneExcludeCalendarEsppValueAsync(); await GetNoneExcludeCalendarEsppValueAsync();
if (responseAreaTimeOffsetDict.Count == 0) //if (responseAreaTimeOffsetDict.Count == 0)
await GetResponseAreaTimeOffsetsAsync(); // await GetResponseAreaTimeOffsetsAsync();
var isConnected = await mqService.InitConsumerAsync(globalSettings!.MqSettings!, SyncScheduleAsync); var isConnected = await mqService.InitConsumerAsync(globalSettings!.MqSettings!, SyncScheduleAsync);
@@ -73,13 +76,13 @@ namespace PARR.EsppScheduleSync
logger.LogInformation("Запущена проверка очереди {QueueName}.", globalSettings.MqSettings!.QueueName); logger.LogInformation("Запущена проверка очереди {QueueName}.", globalSettings.MqSettings!.QueueName);
} }
private async Task GetResponseAreaTimeOffsetsAsync() //private async Task GetResponseAreaTimeOffsetsAsync()
{ //{
using var scope = serviceProvider.CreateScope(); // using var scope = serviceProvider.CreateScope();
var service = scope.ServiceProvider.GetRequiredService<IScheduleResponseAreaTimeOffsetService>(); // var service = scope.ServiceProvider.GetRequiredService<IScheduleResponseAreaTimeOffsetService>();
responseAreaTimeOffsetDict = await service.Get().ToDictionaryAsync(t => t.ResponseArea, t => t.TimeOffset); // responseAreaTimeOffsetDict = await service.Get().ToDictionaryAsync(t => t.ResponseArea, t => t.TimeOffset);
} //}
private async Task GetNoneExcludeCalendarEsppValueAsync() private async Task GetNoneExcludeCalendarEsppValueAsync()
{ {
@@ -226,15 +229,23 @@ namespace PARR.EsppScheduleSync
private EsppObjectSchedule ConvertDbObjToEsppObj(Template template) private EsppObjectSchedule ConvertDbObjToEsppObj(Template template)
{ {
//дефолтное значение, изменится в сервисе nextRunModifierService //дефолтное значение, изменится в сервисе nextRunModifierService
var nextRunByAccountRobotTimeZone = DateTimeOffset.MinValue; var nextRunWithTimeZone = DateTimeOffset.MinValue;
// дефолтное значение, изменится в ApplyShortcodesAsync
var responseArea = "%ЗО_РГ%";
using (var scope = serviceProvider.CreateScope()) using (var scope = serviceProvider.CreateScope())
{ {
var nextRunModifierService = scope.ServiceProvider.GetService<INextRunModifierService>(); //var nextRunModifierService = scope.ServiceProvider.GetService<INextRunModifierService>();
if (nextRunModifierService == null) //if (nextRunModifierService == null)
throw new Exception($"Не найден сервис: {nameof(INextRunModifierService)}"); // throw new Exception($"Не найден сервис: {nameof(INextRunModifierService)}");
nextRunByAccountRobotTimeZone = nextRunModifierService.GetNextRunByAccountRobotTimeZone(template.NextRun); //nextRunWithTimeZone = nextRunModifierService.GetNextRunByAccountRobotTimeZone(template.NextRun);
var nextRunService = scope.ServiceProvider.GetRequiredService<INextRunService>();
var shortcodeService = scope.ServiceProvider.GetRequiredService<IShortcodesService>();
responseArea = shortcodeService.ApplyShortcodesAsync(template.Job!.ResponseAreaMask, template).GetAwaiter().GetResult();
nextRunWithTimeZone = nextRunService.GetNextRunWithTimezoneEsppAndResponseArea(template.NextRun, template.Job?.Group?.IsResponseAreaTimezone, responseArea);
} }
var esppObjectFromDb = new EsppObjectSchedule var esppObjectFromDb = new EsppObjectSchedule
@@ -253,9 +264,9 @@ namespace PARR.EsppScheduleSync
//Scheduled = EsppScheduleHelpers.GetNextRun(template.NextRun), //Scheduled = EsppScheduleHelpers.GetNextRun(template.NextRun),
//Scheduled = EsppScheduleHelpers.GetNextRun(nextRunModifierService.GetNextRunByAccountRobotTimeZone(template.NextRun)), //Scheduled = EsppScheduleHelpers.GetNextRun(nextRunModifierService.GetNextRunByAccountRobotTimeZone(template.NextRun)),
//BasisTime = EsppScheduleHelpers.GetGenerationTime(nextRunModifierService.GetNextRunByAccountRobotTimeZone(template.NextRun)), //BasisTime = EsppScheduleHelpers.GetGenerationTime(nextRunModifierService.GetNextRunByAccountRobotTimeZone(template.NextRun)),
Scheduled = EsppScheduleHelpers.GetNextRun(nextRunByAccountRobotTimeZone), Scheduled = EsppScheduleHelpers.GetNextRun(nextRunWithTimeZone),
BasisTime = EsppScheduleHelpers.GetGenerationTime(nextRunByAccountRobotTimeZone), BasisTime = EsppScheduleHelpers.GetGenerationTime(nextRunWithTimeZone),
Timezone = GetTimezone(template), Timezone = GetTimezone(template, responseArea),
//Мы решили, что для всех расписаний "Отсутствует дата завершения", если что-то поменяется, тут нужно переделать //Мы решили, что для всех расписаний "Отсутствует дата завершения", если что-то поменяется, тут нужно переделать
TerminationType = settingsFromDb.ScheduleRepeatRange == "Отсутствует дата завершения" ? "forever" : "", TerminationType = settingsFromDb.ScheduleRepeatRange == "Отсутствует дата завершения" ? "forever" : "",
CompleteAfter = "" CompleteAfter = ""
@@ -265,29 +276,34 @@ namespace PARR.EsppScheduleSync
return ClearOptionalFields(esppObjectFromDb); return ClearOptionalFields(esppObjectFromDb);
} }
private string GetTimezone(Template template) private string GetTimezone(Template template, string responseArea)
{ {
if (template.Job?.Group?.IsWorkGroupTimezone != true) //if (template.Job?.Group?.IsWorkGroupTimezone != true)
return settingsFromDb.ScheduleTimezone; // return settingsFromDb.ScheduleTimezone;
var responseArea = template.Unit?.BaseFields?.ResponseArea; if (template.Job?.Group?.IsResponseAreaTimezone != true)
return scheduleResponseAreaTimeOffsetService.GetDefault.EsppValue;
if (string.IsNullOrEmpty(responseArea)) //var responseArea = template.Unit?.BaseFields?.ResponseArea;
{
throw new InvalidOperationException(
$"У шаблона Id={template.Id}, Name='{template.Name}' не задана ResponseArea в Unit.BaseFields, " +
"но включена настройка 'использовать часовой пояс рабочей группы'.");
}
if (!responseAreaTimeOffsetDict.TryGetValue(responseArea, out var offset)) //if (string.IsNullOrEmpty(responseArea))
{ //{
throw new InvalidOperationException( // throw new InvalidOperationException(
$"Не найдено временное смещение для ResponseArea '{responseArea}' у шаблона Id={template.Id}, Name='{template.Name}'. " + // $"У шаблона Id={template.Id}, Name='{template.Name}' не задана ResponseArea в Unit.BaseFields, " +
"Проверьте наличие записи в таблице ScheduleResponseAreaTimeOffset."); // "но включена настройка 'использовать часовой пояс рабочей группы'.");
} //}
return offset; //if (!responseAreaTimeOffsetDict.TryGetValue(responseArea, out var offset))
//{
// throw new InvalidOperationException(
// $"Не найдено временное смещение для ResponseArea '{responseArea}' у шаблона Id={template.Id}, Name='{template.Name}'. " +
// "Проверьте наличие записи в таблице ScheduleResponseAreaTimeOffset.");
//}
//return offset;
return scheduleResponseAreaTimeOffsetService.GetByResponseAreaOrDefault(responseArea).EsppValue;
} }

View File

@@ -4,14 +4,10 @@ using PARR.BLL.Services.Interfaces;
using PARR.Common.Domain; using PARR.Common.Domain;
using PARR.Constants; using PARR.Constants;
using PARR.DAL.DomainServices.Shortcodes; using PARR.DAL.DomainServices.Shortcodes;
using PARR.DAL.DomainServices.Shortcodes.Models;
using PARR.DAL.Models; using PARR.DAL.Models;
using PARR.DAL.Models.Job;
using PARR.DAL.Models.Unit;
using PARR.DAL.NextRunServices; using PARR.DAL.NextRunServices;
using PARR.DAL.Services.Interfaces; using PARR.DAL.Services.Interfaces;
using PARR.DAL.Services.Interfaces.Job; using PARR.DAL.Services.Interfaces.Job;
using PARR.DAL.TransformServices;
using PARR.TemplateGeneratorWorker.Services; using PARR.TemplateGeneratorWorker.Services;
namespace PARR.TemplateGeneratorWorker namespace PARR.TemplateGeneratorWorker