Files
parr_api/PARR.API/Controllers/V1/Statistics/StatTemplateDistributionController.cs

208 lines
9.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using AutoMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using PARR.API.Contracts.V1;
using PARR.API.Contracts.V1.Responses;
using PARR.API.Contracts.V1.Responses.Base;
using PARR.API.Contracts.V1.Responses.Statistics;
using PARR.API.Controllers.V1.Base;
using PARR.Constants;
using PARR.DAL.DomainServices.Shortcodes;
using PARR.DAL.Models;
using PARR.DAL.Models.Job;
using PARR.DAL.NextRunServices;
using PARR.DAL.Services.Interfaces;
using PARR.DAL.Services.Interfaces.Job;
namespace PARR.API.Controllers.V1.Statistics
{
/// <summary>
/// Статистика распределения шаблонов
/// </summary>
[Authorize(Roles = ParrRoles.Administrator.Role)]
public class StatTemplateDistributionController : BaseApiController
{
private readonly ITemplateService templateService;
private readonly IJobGroupService jobGroupService;
private readonly IMapper mapper;
private readonly IShortcodesService shortcodesService;
private readonly INextRunService nextRunService;
private readonly ILogger<StatTemplateDistributionController> logger;
public StatTemplateDistributionController(
ITemplateService templateService,
IJobGroupService jobGroupService,
IMapper mapper,
IShortcodesService shortcodesService,
INextRunService nextRunService,
ILogger<StatTemplateDistributionController> logger
)
{
this.templateService = templateService;
this.jobGroupService = jobGroupService;
this.mapper = mapper;
this.shortcodesService = shortcodesService;
this.nextRunService = nextRunService;
this.logger = logger;
}
/// <summary>
/// Статистика распределения шаблонов по jobGroupId, только для Used
/// </summary>
/// <param name="jobGroupId"></param>
/// <returns></returns>
[HttpGet(ApiRoutes.StatTemplateDistribution.Get)]
public async Task<IActionResult> Get([FromRoute] Guid jobGroupId)
{
// eadc5498-dba6-4f10-9b4b-a1653e3c3e61
var jobGroup = await jobGroupService.Get()
.Include(t => t.DistributionConfig)
.ThenInclude(t => t.DistributionPeriod)
.AsNoTracking()
.FirstOrDefaultAsync(t => t.Id == jobGroupId);
if (jobGroup == null)
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Не найдена группа работ" } }));
if (!jobGroup.IsAutoDistributionEnabled || jobGroup.DistributionConfig == null)
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Для группы работ не включено автораспределение" } }));
var items = await templateService.Get()
.Where(t => t.Job!.GroupId == jobGroupId && t.StatusTypeId == TemplateStatusTypeEnum.Used)
.Select(t => new
{
WorkGroup = t.Job!.WorkGroupMask,
Template = t
})
.AsNoTracking()
.ToListAsync();
if (!items.Any())
return Ok(new Response<StatTemplateDistributorResponse>(new StatTemplateDistributorResponse
{
JobGroup = mapper.Map<JobGroupWithDistributionConfigResponse>(jobGroup),
ItemsList = null
}, true));
// получаем список рабочих дней
var workDays = await GetWorkDaysAsync(jobGroup, items.Max(t => t.Template.NextRun));
var responseItemsList = new List<StatDistributorItemResponse>();
if (jobGroup.DistributionConfig.IsGroupingByWorkGroup)
{
// тут группируем по рабочим группам
// Получаем список пар (WorkGroupName, Template)
var templatesWithWorkGroupNames = new List<(string WorkGroupName, Template Template)>();
// получаем названия рабочих групп
foreach (var item in items)
{
var workGroupName = await shortcodesService.ApplyShortcodesAsync(item.WorkGroup, item.Template);
templatesWithWorkGroupNames.Add((workGroupName, item.Template));
}
// Группируем по WorkGroupName
var grouped = templatesWithWorkGroupNames
.GroupBy(x => x.WorkGroupName)
.ToDictionary(g => g.Key, g => g.Select(x => x.Template).ToList());
foreach (var groupedItem in grouped)
{
var statResult = GetResponseByWorkGroup(groupedItem.Key, groupedItem.Value, workDays);
responseItemsList.Add(statResult);
}
}
else
{
// не нужно группировать по рабочим группам
// сразу формируем response
responseItemsList.Add(GetResponseByWorkGroup(null, items.Select(t => t.Template).ToList(), workDays));
}
var response = new StatTemplateDistributorResponse
{
JobGroup = mapper.Map<JobGroupWithDistributionConfigResponse>(jobGroup),
ItemsList = responseItemsList.OrderBy(t => t.WorkGroupName).ToList()
};
return Ok(new Response<StatTemplateDistributorResponse>(response, true));
}
private async Task<List<DateOnly>> GetWorkDaysAsync(JobGroup jobGroup, DateTimeOffset maxNextRunTemplate)
{
var durationDays = nextRunService.GetDurationDays(jobGroup.DistributionConfig!);
var dateStart = DateOnly.FromDateTime(DateTime.UtcNow);
// последний день, не может быть меньше чем durationDays
var dateEnd = dateStart.AddDays(durationDays);
// последний день, не может быть меньше чем refDate+durationDays
var sumRefDuration = DateOnly.FromDateTime(jobGroup.ReferenceDate.AddDays(durationDays).Date);
if (dateEnd < sumRefDuration)
dateEnd = sumRefDuration;
// с DateEnd вообще какая-то шурпатня :(
// как наглядно понять ок не ок распределяется, если на каком-то графике dateEnd может ухеать за период распределения
// последний день, не может быть меньше чем дата последнего шаблона maxNextRunTemplate
var lastTempalteDate = DateOnly.FromDateTime(maxNextRunTemplate.Date);
if (dateEnd < lastTempalteDate)
dateEnd = lastTempalteDate;
return await nextRunService.GetWorkDaysAsync(dateStart, dateEnd, jobGroup.DistributionConfig!.IsExcludeWeekends);
}
private StatDistributorItemResponse GetResponseByWorkGroup(string? workGroupName, List<Template> templates, List<DateOnly> workDays)
{
var result = new StatDistributorItemResponse
{
WorkGroupName = workGroupName,
Statistics = workDays.OrderBy(t => t).Select(t => new StatTemplateDistributorDateStat
{
AllCount = 0,
Date = t,
IsActivatedCount = 0,
IsDeactivatedCount = 0,
Templates = new List<StatTempleteDistribItem>()
}).ToList()
};
foreach (var templatesFromDate in templates.GroupBy(t => DateOnly.FromDateTime(t.NextRun.Date)))
{
var statisticsForDate = result.Statistics.FirstOrDefault(t => t.Date == templatesFromDate.Key);
if (statisticsForDate == null)
{
logger.LogWarning("В списке рабочих дней, нет дня для шаблонов {count} шт. выполняющихся в {date}", templatesFromDate.Count(), templatesFromDate.Key);
continue;
}
statisticsForDate.AllCount = templatesFromDate.Count();
statisticsForDate.IsDeactivatedCount = templatesFromDate.Count(t => !t.IsActiveTemplate || !t.IsActiveSchedule);
statisticsForDate.IsActivatedCount = templatesFromDate.Count(t => t.IsActiveTemplate && t.IsActiveSchedule);
statisticsForDate.Templates = templatesFromDate.Select(t => new StatTempleteDistribItem
{
Name = t.Name,
IsActiveSchedular = t.IsActiveSchedule,
IsActiveTemplate = t.IsActiveTemplate,
NextRun = t.NextRun
})
.OrderBy(t => t.Name)
.ToList();
}
return result;
}
}
}