diff --git a/PARR.API/Contracts/V1/Requests/Queries/TemplateQuery.cs b/PARR.API/Contracts/V1/Requests/Queries/TemplateQuery.cs
index a80721b6..5e15b38f 100644
--- a/PARR.API/Contracts/V1/Requests/Queries/TemplateQuery.cs
+++ b/PARR.API/Contracts/V1/Requests/Queries/TemplateQuery.cs
@@ -30,6 +30,11 @@ namespace PARR.API.Contracts.V1.Requests.Queries
/// Статус синхронизации шаблонов и расписаний
///
public TemplateQuerySyncStatusEnum? SyncStatus { get; set; }
+
+ ///
+ /// Применять шорткоды
+ ///
+ public bool? ApplyShortcode { get; set; }
}
///
diff --git a/PARR.API/Contracts/V1/Responses/TemplateResponse.cs b/PARR.API/Contracts/V1/Responses/TemplateResponse.cs
index a21d5af8..ba278d57 100644
--- a/PARR.API/Contracts/V1/Responses/TemplateResponse.cs
+++ b/PARR.API/Contracts/V1/Responses/TemplateResponse.cs
@@ -1,6 +1,6 @@
namespace PARR.API.Contracts.V1.Responses
{
- public class TemplateResponse
+ public class TemplateBaseResponse
{
public Guid Id { get; set; }
@@ -10,6 +10,46 @@
public bool IsActiveSchedule { get; set; }
+ public string? ScheduleEsppId { get; set; }
+
+ public DateTimeOffset? LastRun { get; set; }
+
+ public DateTimeOffset NextRun { get; set; }
+
+
+ ///
+ /// Рабочая группа (формируется из шорткода)
+ ///
+ public string? WorkGroup { get; set; }
+
+ ///
+ /// ЗО, формируется из шорткода
+ ///
+ public string? ResponseArea { get; set; }
+
+ public UnitWithAttributesResponse? Unit { get; set; }
+
+ public TemplateStatusTypeResponse? StatusType { get; set; }
+
+ public TemplateAgentResponse? Agent { get; set; }
+
+ public List? SyncStatus { get; set; }
+
+ public int OrderCount { get; set; }
+
+ public bool IsAutoDistributionEnabled { get; set; }
+ }
+
+
+ public class TemplateListResponse : TemplateBaseResponse
+ {
+
+ }
+
+
+
+ public class TemplateResponse : TemplateBaseResponse
+ {
public required string Category { get; set; }
public required string Initiator { get; set; }
@@ -24,29 +64,6 @@
public required string TemplateDuration { get; set; }
- ///
- /// Рабочая группа (формируется из шорткода)
- ///
- public required string WorkGroup { get; set; }
-
- ///
- /// ЗО, формируется из шорткода
- ///
- public required string ResponseArea { get; set; }
-
- public TemplateAgentResponse? Agent { get; set; }
-
- public DateTimeOffset? LastRun { get; set; }
-
- public DateTimeOffset NextRun { get; set; }
-
- public bool IsAutoDistributionEnabled { get; set; }
-
- public string? ScheduleEsppId { get; set; }
-
- //public UnitResponse? Unit { get; set; }
- public UnitWithAttributesResponse? Unit { get; set; }
-
public JobResponse? Job { get; set; }
public ProcessResponse? Process { get; set; }
@@ -55,8 +72,6 @@
public TnkResponse? Tnk { get; set; }
- public List? SyncStatus { get; set; }
-
///
/// Расписание
///
@@ -72,10 +87,6 @@
///
public ScheduleExcludeTypeCalendarResponse? ScheduleExcludeTypeCalendar { get; set; }
- public int OrderCount { get; set; }
-
- public TemplateStatusTypeResponse? StatusType { get; set; }
-
public JobGroupDistributionConfigResponse? DistributionConfig { get; set; }
}
}
diff --git a/PARR.API/Controllers/V1/TemplateController.cs b/PARR.API/Controllers/V1/TemplateController.cs
index 78e27fa7..8dcdb24f 100644
--- a/PARR.API/Controllers/V1/TemplateController.cs
+++ b/PARR.API/Controllers/V1/TemplateController.cs
@@ -18,6 +18,7 @@ using PARR.DAL.DomainModels;
using PARR.DAL.DomainServices.Shortcodes;
using PARR.DAL.Models;
using PARR.DAL.Services.Interfaces;
+using System.Diagnostics;
namespace PARR.API.Controllers.V1
{
@@ -33,6 +34,7 @@ namespace PARR.API.Controllers.V1
private readonly IClientService clientService;
private readonly ILogger logger;
private readonly IShortcodesService shortcodesService;
+ private readonly IOrderService orderService;
public TemplateController(
IMapper mapper,
@@ -40,7 +42,8 @@ namespace PARR.API.Controllers.V1
IRobotConfigurationService robotConfigurationService,
IClientService clientService,
ILogger logger,
- IShortcodesService shortcodesService
+ IShortcodesService shortcodesService,
+ IOrderService orderService
)
{
this.mapper = mapper;
@@ -49,6 +52,7 @@ namespace PARR.API.Controllers.V1
this.clientService = clientService;
this.logger = logger;
this.shortcodesService = shortcodesService;
+ this.orderService = orderService;
}
@@ -62,18 +66,31 @@ namespace PARR.API.Controllers.V1
{
var paginationFilter = mapper.Map(paginationQuery);
- IQueryable query = templateService.GetWithIncludes().AsNoTracking()
- .Include(t => t.Unit).ThenInclude(t => t!.UnitValues).ThenInclude(t => t.Field)
- .Include(t => t.Unit).ThenInclude(t => t!.UnitValues).ThenInclude(t => t.Value)
- .Include(t => t.RobotConfigurations).ThenInclude(t => t.Robot)
- .Include(t => t.RobotConfigurations).ThenInclude(t => t.TaskStatus)
- .Include(t => t.RobotConfigurations).ThenInclude(t => t.RobotStatus)
- .Include(t => t.Orders)
- .Include(t => t.StatusType)
- .Include(t => t.Job).ThenInclude(t => t.Group).ThenInclude(t => t.ScheduleExcludeType)
- .Include(t => t.Job).ThenInclude(t => t.Group).ThenInclude(t => t.ScheduleExcludeTypeCalendar)
- .OrderBy(t => t.Name)
- .AsSplitQuery();
+ //IQueryable query = templateService.GetWithIncludes().AsNoTracking()
+ // .Include(t => t.Unit).ThenInclude(t => t!.UnitValues).ThenInclude(t => t.Field)
+ // .Include(t => t.Unit).ThenInclude(t => t!.UnitValues).ThenInclude(t => t.Value)
+ // .Include(t => t.RobotConfigurations).ThenInclude(t => t.Robot)
+ // .Include(t => t.RobotConfigurations).ThenInclude(t => t.TaskStatus)
+ // .Include(t => t.RobotConfigurations).ThenInclude(t => t.RobotStatus)
+ // .Include(t => t.Orders)
+ // .Include(t => t.StatusType)
+ // .Include(t => t.Job).ThenInclude(t => t.Group).ThenInclude(t => t.ScheduleExcludeType)
+ // .Include(t => t.Job).ThenInclude(t => t.Group).ThenInclude(t => t.ScheduleExcludeTypeCalendar)
+ // .OrderBy(t => t.Name)
+ // .AsSplitQuery();
+
+ //var sw = Stopwatch.StartNew();
+
+ IQueryable query = templateService.Get()
+ .Include(t => t.Unit).ThenInclude(t => t!.UnitValues).ThenInclude(t => t.Field)
+ .Include(t => t.Unit).ThenInclude(t => t!.UnitValues).ThenInclude(t => t.Value)
+ .Include(t => t.StatusType)
+ .Include(t => t.Job).ThenInclude(t => t.Group)
+ .Include(t => t.RobotConfigurations).ThenInclude(t => t.Robot)
+ .Include(t => t.RobotConfigurations).ThenInclude(t => t.TaskStatus)
+ .Include(t => t.RobotConfigurations).ThenInclude(t => t.RobotStatus)
+ .OrderBy(t => t.Name)
+ .AsNoTracking();
if (!string.IsNullOrEmpty(filter.Mask))
@@ -106,16 +123,42 @@ namespace PARR.API.Controllers.V1
var templates = await templateService.GetPage(query, paginationFilter).ToListAsync();
+ //logger.LogDebug("Загрузка шаблонов из БД: {ElapsedMs} мс", sw.ElapsedMilliseconds);
+
+
if (!templates.Any())
return NoContent();
- var templateResponse = mapper.Map>(templates);
- foreach (var responseItem in templateResponse)
- {
- await ApplyTemplateShortcodesAsync(responseItem, templates.First(t => t.Id == responseItem.Id));
- }
+ var templateResponse = mapper.Map>(templates);
- var paginationResponse = new PagedResponse(templateResponse, true).GetPaginatedProps(paginationFilter, query);
+ // словари для быстрого поиска
+ var templatesDict = templates.ToDictionary(t => t.Id);
+ var templateResponseDict = templateResponse.ToDictionary(t => t.Id);
+
+ #region Заполняем шорткоды
+ if (filter.ApplyShortcode == true)
+ {
+ //sw.Restart();
+ foreach (var responseItem in templateResponse)
+ {
+ //await ApplyTemplateShortcodesAsync(responseItem, templates.First(t => t.Id == responseItem.Id));
+ await ApplyTemplateShortcodesAsync(responseItem, templatesDict[responseItem.Id]);
+ }
+ //logger.LogDebug("Получение шорткодов: {ElapsedMs} мс", sw.ElapsedMilliseconds);
+ //sw.Stop();
+ }
+ #endregion
+
+ #region заполнение OrdersCount
+ var templatesWithOrdersCount = await GetOrdersCountAsync(templates.Select(t => t.Id).ToList());
+ foreach (var (templateId, orderCount) in templatesWithOrdersCount)
+ {
+ if (templateResponseDict.TryGetValue(templateId, out var response))
+ response.OrderCount = orderCount;
+ }
+ #endregion
+
+ var paginationResponse = new PagedResponse(templateResponse, true).GetPaginatedProps(paginationFilter, query);
return Ok(paginationResponse);
}
@@ -129,12 +172,10 @@ namespace PARR.API.Controllers.V1
public async Task GetById([FromRoute] Guid id)
{
var template = await templateService.GetWithIncludes().AsNoTracking()
- .Include(t => t.Unit).ThenInclude(t => t!.UnitValues).ThenInclude(t => t.Field)
- .Include(t => t.Unit).ThenInclude(t => t!.UnitValues).ThenInclude(t => t.Value)
.Include(t => t.RobotConfigurations).ThenInclude(t => t.Robot)
.Include(t => t.RobotConfigurations).ThenInclude(t => t.TaskStatus)
.Include(t => t.RobotConfigurations).ThenInclude(t => t.RobotStatus)
- .Include(t => t.Orders)
+ //.Include(t => t.Orders)
.Include(t => t.StatusType)
.Include(t => t.Job).ThenInclude(t => t.Group).ThenInclude(t => t.ScheduleExcludeType)
.Include(t => t.Job).ThenInclude(t => t.Group).ThenInclude(t => t.ScheduleExcludeTypeCalendar)
@@ -147,6 +188,9 @@ namespace PARR.API.Controllers.V1
var response = mapper.Map(template);
await ApplyTemplateShortcodesAsync(response, template);
+ var ordersCountResult = await GetOrdersCountAsync(new List { response.Id });
+ response.OrderCount = ordersCountResult.Count > 0 ? ordersCountResult.First().Value : 0;
+
return Ok(new Response(response, true));
}
@@ -161,19 +205,24 @@ namespace PARR.API.Controllers.V1
{
//TODO:!!! Возможно тут не надо сразу менять, а отправить запрос в TemplateActivator и пусть он сам занимается своей работой!!!
+ #region old
+ //var template = await templateService.GetWithIncludes()
+ // //.Include(t => t.Unit).ThenInclude(t => t!.UnitValues).ThenInclude(t => t.Field)
+ // //.Include(t => t.Unit).ThenInclude(t => t!.UnitValues).ThenInclude(t => t.Value)
+ // .Include(t => t.RobotConfigurations).ThenInclude(t => t.Robot)
+ // .Include(t => t.RobotConfigurations).ThenInclude(t => t.TaskStatus)
+ // .Include(t => t.RobotConfigurations).ThenInclude(t => t.RobotStatus)
+ // .Include(t => t.Orders)
+ // .Include(t => t.StatusType)
+ // .Include(t => t.Job).ThenInclude(t => t.Group).ThenInclude(t => t.ScheduleExcludeType)
+ // .Include(t => t.Job).ThenInclude(t => t.Group).ThenInclude(t => t.ScheduleExcludeTypeCalendar)
+ // .AsSplitQuery()
+ // .FirstOrDefaultAsync(t => t.Id == id);
+ #endregion
- var template = await templateService.GetWithIncludes()
- .Include(t => t.Unit).ThenInclude(t => t!.UnitValues).ThenInclude(t => t.Field)
- .Include(t => t.Unit).ThenInclude(t => t!.UnitValues).ThenInclude(t => t.Value)
- .Include(t => t.RobotConfigurations).ThenInclude(t => t.Robot)
- .Include(t => t.RobotConfigurations).ThenInclude(t => t.TaskStatus)
- .Include(t => t.RobotConfigurations).ThenInclude(t => t.RobotStatus)
- .Include(t => t.Orders)
- .Include(t => t.StatusType)
- .Include(t => t.Job).ThenInclude(t => t.Group).ThenInclude(t => t.ScheduleExcludeType)
- .Include(t => t.Job).ThenInclude(t => t.Group).ThenInclude(t => t.ScheduleExcludeTypeCalendar)
- .AsSplitQuery()
- .FirstOrDefaultAsync(t => t.Id == id);
+ var template = await templateService.Get()
+ .Include(t => t.RobotConfigurations)
+ .FirstOrDefaultAsync(t => t.Id == id);
if (template == null)
return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Не найден шаблона с id: {id}" } }));
@@ -197,31 +246,83 @@ namespace PARR.API.Controllers.V1
if (!await templateService.CommitAsync(new HistoryInitiator { InitiatorComment = "Изменён статус шаблона/расписания", InitiatorIp = clientService.GetClientIp()?.ToString(), InitiatorParrComponentId = ParrComponentsEnum.Api }))
return BadRequest(new Response(false, new List { new ErrorModel { Message = "Ошибка при изменении шаблона." } }));
- var templateToResponse = await templateService.GetWithIncludes().AsNoTracking()
- .Include(t => t.Unit).ThenInclude(t => t.UnitValues).ThenInclude(t => t.Field)
- .Include(t => t.Unit).ThenInclude(t => t.UnitValues).ThenInclude(t => t.Value)
- .Include(t => t.RobotConfigurations).ThenInclude(t => t.Robot)
- .Include(t => t.RobotConfigurations).ThenInclude(t => t.TaskStatus)
- .Include(t => t.RobotConfigurations).ThenInclude(t => t.RobotStatus)
- .Include(t => t.Orders)
- .Include(t => t.StatusType)
- .Include(t => t.Job).ThenInclude(t => t.Group).ThenInclude(t => t.ScheduleExcludeType)
- .Include(t => t.Job).ThenInclude(t => t.Group).ThenInclude(t => t.ScheduleExcludeTypeCalendar)
- .AsSplitQuery()
- .FirstAsync(t => t.Id == id);
+ #region old
+ //var templateToResponse = await templateService.GetWithIncludes().AsNoTracking()
+ // //.Include(t => t.Unit).ThenInclude(t => t.UnitValues).ThenInclude(t => t.Field)
+ // //.Include(t => t.Unit).ThenInclude(t => t.UnitValues).ThenInclude(t => t.Value)
+ // .Include(t => t.RobotConfigurations).ThenInclude(t => t.Robot)
+ // .Include(t => t.RobotConfigurations).ThenInclude(t => t.TaskStatus)
+ // .Include(t => t.RobotConfigurations).ThenInclude(t => t.RobotStatus)
+ // .Include(t => t.Orders)
+ // .Include(t => t.StatusType)
+ // .Include(t => t.Job).ThenInclude(t => t.Group).ThenInclude(t => t.ScheduleExcludeType)
+ // .Include(t => t.Job).ThenInclude(t => t.Group).ThenInclude(t => t.ScheduleExcludeTypeCalendar)
+ // .AsSplitQuery()
+ // .FirstAsync(t => t.Id == id);
+
+ //var response = mapper.Map(templateToResponse);
+ //await ApplyTemplateShortcodesAsync(response, templateToResponse);
+
+ //return Ok(new Response(response, true));
+ #endregion
+
+ var templateToResponse = await templateService.Get()
+ .AsNoTracking()
+ .Include(t => t.Unit).ThenInclude(t => t!.UnitValues).ThenInclude(t => t.Field)
+ .Include(t => t.Unit).ThenInclude(t => t!.UnitValues).ThenInclude(t => t.Value)
+ .Include(t => t.StatusType)
+ .Include(t => t.Job).ThenInclude(t => t.Group)
+ .Include(t => t.RobotConfigurations).ThenInclude(t => t.Robot)
+ .Include(t => t.RobotConfigurations).ThenInclude(t => t.TaskStatus)
+ .Include(t => t.RobotConfigurations).ThenInclude(t => t.RobotStatus)
+ .FirstAsync(t => t.Id == id);
+
+ var response = mapper.Map(templateToResponse);
- var response = mapper.Map(templateToResponse);
await ApplyTemplateShortcodesAsync(response, templateToResponse);
- return Ok(new Response(response, true));
+ var ordersCountResult = await GetOrdersCountAsync(new List { response.Id });
+ response.OrderCount = ordersCountResult.Count > 0 ? ordersCountResult.First().Value : 0;
+
+ return Ok(new Response(response, true));
}
- private async Task ApplyTemplateShortcodesAsync(TemplateResponse response, Template template)
+ ///
+ /// Применить шорткоды
+ ///
+ ///
+ ///
+ ///
+ private async Task ApplyTemplateShortcodesAsync(TemplateBaseResponse response, Template template)
{
response.WorkGroup = await shortcodesService.ApplyShortcodesAsync(template.Job.WorkGroupMask, template);
response.ResponseArea = await shortcodesService.ApplyShortcodesAsync(template.Job.ResponseAreaMask, template);
}
+
+ ///
+ /// Получить кол-во нарядов для шаблонов
+ ///
+ ///
+ ///
+ private async Task> GetOrdersCountAsync(List templateIdList)
+ {
+ if (!templateIdList.Any())
+ return new Dictionary();
+
+ var templateWithOrders = await orderService.Get()
+ .Where(t => t.TemplateId.HasValue && templateIdList.Contains(t.TemplateId.Value))
+ .GroupBy(t => t.TemplateId)
+ .Select(t => new { TemplateId = t.Key, OrderCount = t.Count() })
+ .AsNoTracking()
+ .ToListAsync();
+
+ if (templateWithOrders == null)
+ return new Dictionary();
+
+ return templateWithOrders.ToDictionary(t => t.TemplateId!.Value, t => t.OrderCount);
+ }
+
}
}
diff --git a/PARR.API/MappingProfiles/DomainToResponseProfile.cs b/PARR.API/MappingProfiles/DomainToResponseProfile.cs
index e21ca359..01ac6038 100644
--- a/PARR.API/MappingProfiles/DomainToResponseProfile.cs
+++ b/PARR.API/MappingProfiles/DomainToResponseProfile.cs
@@ -18,9 +18,21 @@ namespace PARR.API.MappingProfiles
#region Template
// --- Template ---
+ CreateMap()
+ .Include()
+ .Include()
+ .ForMember(d => d.Unit, o => o.MapFrom(s => s.Unit))
+ .ForMember(d => d.StatusType, o => o.MapFrom(s => s.StatusType))
+ .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.OrderCount, o => o.MapFrom(s => s.Orders.Count()))
+ .ForMember(d => d.IsAutoDistributionEnabled, o => o.MapFrom(s => s.Job!.Group!.IsAutoDistributionEnabled));
+
+ CreateMap();
+
CreateMap()
.ForMember(d => d.Job, o => o.MapFrom(s => s.Job))
- .ForMember(d => d.Unit, o => o.MapFrom(s => s.Unit))
+ //.ForMember(d => d.Unit, o => o.MapFrom(s => s.Unit))
.ForMember(d => d.Process, o => o.MapFrom(s => s.Job!.Tnk!.Subprocess!.Process))
.ForMember(d => d.Subprocess, o => o.MapFrom(s => s.Job!.Tnk!.Subprocess))
.ForMember(d => d.Tnk, o => o.MapFrom(s => s.Job!.Tnk))
@@ -31,16 +43,14 @@ namespace PARR.API.MappingProfiles
.ForMember(d => d.Initiator, o => o.MapFrom())
.ForMember(d => d.ClosingCode, o => o.MapFrom())
.ForMember(d => d.Category, o => o.MapFrom())
- .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.Schedule, o => o.MapFrom())
- .ForMember(d => d.Agent, o => o.MapFrom(s => s.Job!.Group!))
- //.ForMember(d => d.NextRun, o => o.MapFrom(s => s.ApplicationsInWork!.NextRun))
- //.ForMember(d => d.LastRun, o => o.MapFrom(s => s.ApplicationsInWork!.LastRun))
- .ForMember(d => d.NextRun, o => o.MapFrom(s => s.NextRun))
- .ForMember(d => d.LastRun, o => o.MapFrom(s => s.LastRun))
- .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.StatusType, o => o.MapFrom(s => s.StatusType))
+ //.ForMember(d => d.Agent, o => o.MapFrom(s => s.Job!.Group!))
+ //.ForMember(d => d.NextRun, o => o.MapFrom(s => s.NextRun))
+ //.ForMember(d => d.LastRun, o => o.MapFrom(s => s.LastRun))
+ //.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.StatusType, o => o.MapFrom(s => s.StatusType))
.ForMember(d => d.ScheduleExcludeType, o => o.MapFrom(s => s.Job!.Group!.ScheduleExcludeType))
.ForMember(d => d.ScheduleExcludeTypeCalendar, o => o.MapFrom(s => s.Job!.Group!.ScheduleExcludeTypeCalendar))
.ForMember(d => d.DistributionConfig, o => o.MapFrom(s => s.Job.Group.DistributionConfig))