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

@@ -1,17 +1,12 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using PARR.API.Contracts.V1;
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.Services.Interfaces;
using PARR.Constants;
using PARR.DAL.Contracts;
using PARR.DAL.Services.Interfaces;
using PARR.DAL.Services.Interfaces.Unit;
using PARR.DAL.TransformServices;
namespace PARR.API.Controllers.V1
{

View File

@@ -18,8 +18,10 @@ using PARR.DAL.DomainModels;
using PARR.DAL.DomainServices.Interfaces;
using PARR.DAL.Models;
using PARR.DAL.Models.Job;
using PARR.DAL.NextRunServices;
using PARR.DAL.Services.Interfaces;
using PARR.DAL.Services.Interfaces.Job;
using PARR.DAL.Services.Interfaces.Schedule;
namespace PARR.API.Controllers.V1
{
@@ -39,6 +41,7 @@ namespace PARR.API.Controllers.V1
private readonly IJobGroupTypeService jobGroupTypeService;
private readonly SettingsFromDb settingsFromDb;
private readonly IMatchingStatusService matchingStatusService;
private readonly IScheduleResponseAreaTimeOffsetService scheduleResponseAreaTimeOffsetService;
public JobGroupController(
ILogger<JobController> logger,
@@ -50,7 +53,8 @@ namespace PARR.API.Controllers.V1
IValidator<JobGroupRequest> validator,
IJobGroupTypeService jobGroupTypeService,
SettingsFromDb settingsFromDb,
IMatchingStatusService matchingStatusService
IMatchingStatusService matchingStatusService,
IScheduleResponseAreaTimeOffsetService scheduleResponseAreaTimeOffsetService
)
{
this.logger = logger;
@@ -63,6 +67,7 @@ namespace PARR.API.Controllers.V1
this.jobGroupTypeService = jobGroupTypeService;
this.settingsFromDb = settingsFromDb;
this.matchingStatusService = matchingStatusService;
this.scheduleResponseAreaTimeOffsetService = scheduleResponseAreaTimeOffsetService;
}
@@ -166,7 +171,7 @@ namespace PARR.API.Controllers.V1
ScheduleExcludeTypeId = request.ScheduleExcludeTypeId,
ScheduleExcludeTypeCalendarId = request.ScheduleExcludeTypeCalendarId,
IsAutoDistributionEnabled = request.IsAutoDistributionEnabled,
IsWorkGroupTimezone = request.IsWorkGroupTimezone
IsResponseAreaTimezone = request.IsWorkGroupTimezone
//IsAgent = request.IsAgent,
//AgentName = request.AgentName,
//AgentTimeOutSec = request.AgentTimeOutSec,
@@ -260,7 +265,7 @@ namespace PARR.API.Controllers.V1
orig.ScheduleExcludeTypeId = request.ScheduleExcludeTypeId;
orig.ScheduleExcludeTypeCalendarId = request.ScheduleExcludeTypeCalendarId;
orig.IsAutoDistributionEnabled = request.IsAutoDistributionEnabled;
orig.IsWorkGroupTimezone = request.IsWorkGroupTimezone;
orig.IsResponseAreaTimezone = request.IsWorkGroupTimezone;
//orig.IsAgent = request.IsAgent;
//orig.AgentName = request.AgentName;
//orig.AgentTimeOutSec = request.AgentTimeOutSec;
@@ -445,7 +450,8 @@ namespace PARR.API.Controllers.V1
var scheduleResponse = new JobGroupScheduleResponse
{
Timezone = settingsFromDb.ScheduleTimezone,
//Timezone = settingsFromDb.ScheduleTimezone,
Timezone = scheduleResponseAreaTimeOffsetService.GetDefault.EsppValue,
TypeSchedule = mapper.Map<EsppScheduleTypeScheduleResponse>(schedule.TypeSchedule),
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.Controllers.V1.Base;
using PARR.API.Services.Interfaces;
using PARR.BLL.Helpers;
using PARR.Common.Domain;
using PARR.Constants;
using PARR.DAL.Contracts;
@@ -200,17 +201,11 @@ namespace PARR.API.Controllers.V1
{ //RobotTaskTemplateResponse
var robotTaskTemplateResponse = mapper.Map<RobotTaskTemplateResponse>(task);
//if (shortcodesService.IsAnyShortcodes(robotTaskTemplateResponse.FullDescription))
robotTaskTemplateResponse.FullDescription = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.FullDescription, task.Template!);
//if (shortcodesService.IsAnyShortcodes(robotTaskTemplateResponse.ShortDescription))
robotTaskTemplateResponse.ShortDescription = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.ShortDescription, task.Template!);
//if (shortcodesService.IsAnyShortcodes(robotTaskTemplateResponse.Solution))
robotTaskTemplateResponse.Solution = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.Solution, task.Template!);
//if (shortcodesService.IsAnyShortcodes(robotTaskTemplateResponse.TnkName))
robotTaskTemplateResponse.TnkName = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.TnkName, task.Template!);
//if (shortcodesService.IsAnyShortcodes(robotTaskTemplateResponse.WorkName))
robotTaskTemplateResponse.WorkName = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.WorkName, task.Template!);
//if (shortcodesService.IsAnyShortcodes(robotTaskTemplateResponse.WorkGroup))
robotTaskTemplateResponse.WorkGroup = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.WorkGroup, task.Template!);
robotTaskTemplateResponse.ResponseArea = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.ResponseArea, task.Template!);
@@ -223,12 +218,15 @@ namespace PARR.API.Controllers.V1
//RobotTaskScheduleResponse
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.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));
}
@@ -240,6 +238,11 @@ namespace PARR.API.Controllers.V1
}
/// <summary>
/// Обоновить NextRun если он устарел
/// </summary>
/// <param name="task"></param>
/// <returns></returns>
private async Task UpdateLastNextRunDate(RobotConfiguration task)
{
var template = task.Template!;
@@ -251,9 +254,6 @@ namespace PARR.API.Controllers.V1
//var nextRun = await esppScheduleTransformService.GetNextDateAsync(template.Job!.GroupId, template.NextRun);
#endregion
//пока у нас выключено автораспределение, считает по refDate
//TODO: когда заработает автораспределение, будем думать!!!!!
//var nextRun = await esppScheduleTransformService.GetNextDateAsync(template.Job!.GroupId, template!.Job!.Group!.ReferenceDate);
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}");
//if (template.NextRun < DateTimeOffset.UtcNow)
//{
// logger.LogDebug($"Для шаблона id {template.Id} обновляю lastRun, новое значение {template.NextRun}, старое значение {template.LastRun}");
// template.LastRun = template.NextRun;
//}
template.LastRun = template.NextRun;
template.NextRun = nextRun;
@@ -331,10 +326,17 @@ namespace PARR.API.Controllers.V1
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)
return settingsFromDb.ScheduleTimezone;
if (template.Job?.Group?.IsResponseAreaTimezone != true)
return scheduleResponseAreaTimeOffsetService.GetDefault.EsppValue;
var responseArea = template.Unit?.BaseFields?.ResponseArea;
@@ -345,18 +347,7 @@ namespace PARR.API.Controllers.V1
"но включена настройка 'использовать часовой пояс рабочей группы'.");
}
var offsets = await scheduleResponseAreaTimeOffsetService
.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;
return scheduleResponseAreaTimeOffsetService.GetByResponseAreaOrDefault(responseArea).EsppValue;
}
}

View File

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