feat(all): ! Критические изменения логики работы всех сервисорв, База Данных имееет неокончательную версию. Template, Scheduler переведены на работу с Unit+Job+JobGroup вместо Host+ApplicationsInWork

This commit is contained in:
Mikhail Kuznetsov
2025-06-25 14:17:34 +10:00
parent 1b867585d8
commit 03c7852378
54 changed files with 5176 additions and 989 deletions

View File

@@ -0,0 +1,17 @@
namespace PARR.API.Contracts.V1.Responses
{
public class JobBaseResponse
{
public Guid Id { get; set; }
public required string Name { get; set; }
public required string TemplateNameMask { get; set; }
public TnkResponse? Tnk { get; set; }
}
public class JobResponse : JobBaseResponse
{
}
}

View File

@@ -31,7 +31,7 @@
public required string TnkEsppId { get; set; }
public required string WorkName { get; set; }
public required string WorkEsppId { get; set; }
//public required string WorkEsppId { get; set; }
}

View File

@@ -2,7 +2,7 @@
{
public class StatHostTemplateResponse
{
public int AllHosts { get; set; }
public int AllUnits { get; set; }
public int HostsInTemplates { get; set; }
}
}

View File

@@ -25,9 +25,12 @@
public bool IsAutoDistributionEnabled { get; set; }
public HostTemplateResponse? Host { get; set; }
//public HostTemplateResponse? Host { get; set; }
public UnitBaseResponse? Unit { get; set; }
public WorkResponse? Work { get; set; }
public JobBaseResponse? Job { get; set; }
//public WorkResponse? Work { get; set; }
public ProcessResponse? Process { get; set; }
public SubprocessResponse? Subprocess { get; set; }
public TnkResponse? Tnk { get; set; }

View File

@@ -22,15 +22,4 @@
public List<AttributeResponse>? Attributes { get; set; }
}
}

View File

@@ -15,6 +15,7 @@ using PARR.Constants;
using PARR.DAL.DomainModels;
using PARR.DAL.Models;
using PARR.DAL.Services.Interfaces;
using PARR.DAL.Services.Interfaces.Unit;
namespace PARR.API.Controllers.V1
{
@@ -29,6 +30,7 @@ namespace PARR.API.Controllers.V1
private readonly IMapper mapper;
private readonly ITemplateService templateService;
private readonly IClientService clientService;
private readonly IUnitService unitService;
private readonly ILogger<AgentHistoryController> logger;
public AgentHistoryController(
@@ -38,6 +40,7 @@ namespace PARR.API.Controllers.V1
IMapper mapper,
ITemplateService templateService,
IClientService clientService,
IUnitService unitService,
ILogger<AgentHistoryController> logger
)
{
@@ -47,6 +50,7 @@ namespace PARR.API.Controllers.V1
this.mapper = mapper;
this.templateService = templateService;
this.clientService = clientService;
this.unitService = unitService;
this.logger = logger;
}
@@ -121,16 +125,22 @@ namespace PARR.API.Controllers.V1
var clientIp = clientService.GetClientIp()?.ToString();
var template = await templateService.Get().Include(t => t.Host).FirstOrDefaultAsync(t => t.Id == request.TemplateId);
var template = await templateService.Get()
.Include(t => t.Unit)
.ThenInclude(t => t!.UnitValues)
.FirstOrDefaultAsync(t => t.Id == request.TemplateId);
if (template == null)
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { FieldName = nameof(request.TemplateId), Message = $"Не найден шаблон с Id: {request.TemplateId}" } }));
//проверять что этот этот шаблон привязан к этому серверу по ip
if (template.Host?.IP != clientIp)
var unit = await unitService.GetWithIncludes().AsNoTracking().FirstOrDefaultAsync(t => t.Id == template.UnitId);
var unitIp = unit?.UnitValues.FirstOrDefault(t => t.Field!.AihitName == "IP_АДРЕС")!.Value!.Value;
if (unitIp != clientIp)
{
logger.LogWarning($"Клиент с ip: {clientIp} пытается записать историю агента для templateId: {request.TemplateId}, " +
$"но у шаблона ip: {template.Host?.IP}, доступ запрещен так как их ip не равны.");
$"но у шаблона ip: {unitIp}, доступ запрещен так как их ip не равны.");
return Forbid();
}

View File

@@ -10,6 +10,7 @@ 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
@@ -22,18 +23,21 @@ namespace PARR.API.Controllers.V1
{
private readonly IClientService clientService;
private readonly ITemplateService templateService;
private readonly IUnitService unitService;
private readonly IEsppScheduleTransformService esppScheduleTransformService;
private readonly ILogger<AgentTaskController> logger;
public AgentTaskController(
IClientService clientService,
ITemplateService templateService,
IUnitService unitService,
IEsppScheduleTransformService esppScheduleTransformService,
ILogger<AgentTaskController> logger
)
{
this.clientService = clientService;
this.templateService = templateService;
this.unitService = unitService;
this.esppScheduleTransformService = esppScheduleTransformService;
this.logger = logger;
}
@@ -62,19 +66,21 @@ namespace PARR.API.Controllers.V1
//Агент получает задания, если `IsAgent = true`, шаблон и расписания активны, и статус синхронизации шаблона и расписания `= Ok`, и `NextRun = сегодня`, так же если у ApplicationInWork есть расписание.
// С одним IP может быть несколько информационных систем, так что может быть несколько хостов
var units = await unitService.GetWithIncludes().AsNoTracking().Where(t => t.UnitValues.Any(v => v.Field!.AihitName == "IP_АДРЕС" && v.Value!.Value == ip)).ToListAsync();
var templates = await templateService.Get()
.Include(t => t.RobotConfigurations)
.Include(t => t.ApplicationsInWork)
.Include(t => t.Job)
.ThenInclude(t=>t!.Group)
.ThenInclude(t => t!.EsppSchValues)
.Include(t => t.Host)
.Where(t => t.Host!.IP == ip
&& t.ApplicationsInWork!.IsAgent == true
.Include(t => t.Unit)
.Where(t => units.Any(u=>u.Id == t.UnitId)
//&& t.ApplicationsInWork!.IsAgent == true//TODO Migration to job
&& t.IsActiveTemplate == true
&& t.IsActiveSchedule == true
//&& t.ApplicationsInWork!.NextRun.DateTime.Date == date.Date.Date
&& t.NextRun.DateTime.Date == date.Date.Date
&& t.RobotConfigurations.All(c => c.TaskStatusCode == (int)TaskStatusEnum.Ok)
&& t.ApplicationsInWork.EsppSchValues.Any()
&& t.Job!.Group!.EsppSchValues.Any()//.ApplicationsInWork.EsppSchValues.Any()
).ToListAsync();
if (!templates.Any())
@@ -88,26 +94,26 @@ namespace PARR.API.Controllers.V1
foreach (var template in templates)
{
//var templateSchedule = await esppScheduleTransformService.GetNextScheduleAsync(template.ApplicationInWorkId, template.ApplicationsInWork!.LastRun ?? template.ApplicationsInWork!.NextRun);
var templateSchedule = await esppScheduleTransformService.GetNextScheduleAsync(template.ApplicationInWorkId, template.NextRun);
var templateSchedule = await esppScheduleTransformService.GetNextScheduleAsync(template.Job!.GroupId, template.NextRun);
if (!templateSchedule.Any())
{
logger.LogWarning($"Запросили раписание для агента по NextRun и вернулся пустой список! Такого не должно быть! " +
$"ApplicationInWorkId: {template.ApplicationInWorkId}, latRun: {template.LastRun}, NextRun: {template.NextRun}, ip: {ip}, date: {date}");
$"JobGroupId: {template.Job.GroupId}, latRun: {template.LastRun}, NextRun: {template.NextRun}, ip: {ip}, date: {date}");
continue;
}
if (string.IsNullOrEmpty(template.ApplicationsInWork.AgentName) && string.IsNullOrEmpty(template.ApplicationsInWork.AgentScript))
if (string.IsNullOrEmpty(template.Job.Group!.AgentName) && string.IsNullOrEmpty(template.Job.Group!.AgentScript))
{
logger.LogWarning($"Запросили задание для агента с пустыми значениями AgentName && AgentScript. Такого не должно быть! " +
$"ApplicationInWorkId: {template.ApplicationInWorkId}, AgentName: {template.ApplicationsInWork.AgentName}, AgentScript: {template.ApplicationsInWork.AgentScript} , ip: {ip}, date: {date}");
$"JobGroupId: {template.Job.GroupId}, AgentName: {template.Job.Group.AgentName}, AgentScript: {template.Job.Group.AgentScript} , ip: {ip}, date: {date}");
continue;
}
templateSchedule.ForEach(item => response.Scheduled.Add(new AgentTaskMinScheduleResponse
{
Name = template.ApplicationsInWork!.AgentName ?? "",
Script = template.ApplicationsInWork!.AgentScript ?? "",
Name = template.Job.Group.AgentName ?? "",
Script = template.Job.Group.AgentScript ?? "",
StartAt = item,
TemplateId = template.Id
}));

View File

@@ -62,53 +62,53 @@ namespace PARR.API.Controllers.V1
/// Получить список заданий на выполнение работ(ApplicationInWork) постранично
/// </summary>
/// <returns></returns>
[HttpGet(ApiRoutes.Job.GetAll)]
public async Task<IActionResult> GetAll([FromQuery] PaginationQuery paginationQuery, [FromQuery] ApplicationInWorkQuery filter)
{
var paginationFilter = mapper.Map<PaginationFilter>(paginationQuery);
//[HttpGet(ApiRoutes.Job.GetAll)]
//public async Task<IActionResult> GetAll([FromQuery] PaginationQuery paginationQuery, [FromQuery] ApplicationInWorkQuery filter)
//{
// var paginationFilter = mapper.Map<PaginationFilter>(paginationQuery);
IQueryable<ApplicationsInWork> query = applicationsInWorkService.Get().Include(t => t.Application).ThenInclude(t => t!.ApplicationType);
// IQueryable<ApplicationsInWork> query = applicationsInWorkService.Get().Include(t => t.Application).ThenInclude(t => t!.ApplicationType);
if (filter.IsLight != true)
{
query = query
.Include(t => t.Work)
//.Include(t => t.Templates) - большой запрос, делаем его отдельно
.Include(t => t.WorkGroups).ThenInclude(t => t.WorkGroup)
.Include(t => t.JobAutoControl);
}
// if (filter.IsLight != true)
// {
// query = query
// .Include(t => t.Work)
// //.Include(t => t.Templates) - большой запрос, делаем его отдельно
// .Include(t => t.WorkGroups).ThenInclude(t => t.WorkGroup)
// .Include(t => t.JobAutoControl);
// }
query = query.OrderBy(t => t.ShortDescription).ThenBy(t => t.Application!.Name);
// query = query.OrderBy(t => t.ShortDescription).ThenBy(t => t.Application!.Name);
if (!string.IsNullOrEmpty(filter.ShortDescription))
query = query.Where(t => t.ShortDescription.ToLower().Contains(filter.ShortDescription.ToLower()));
// if (!string.IsNullOrEmpty(filter.ShortDescription))
// query = query.Where(t => t.ShortDescription.ToLower().Contains(filter.ShortDescription.ToLower()));
if (filter.WorkId.HasValue)
query = query.Where(t => t.WorkId == filter.WorkId.Value);
// if (filter.WorkId.HasValue)
// query = query.Where(t => t.WorkId == filter.WorkId.Value);
var appInWorks = await applicationsInWorkService.GetPage(query, paginationFilter).ToListAsync();
// var appInWorks = await applicationsInWorkService.GetPage(query, paginationFilter).ToListAsync();
if (!appInWorks.Any())
return NoContent();
// if (!appInWorks.Any())
// return NoContent();
var response = mapper.Map<List<ApplicationInWorkResponse>>(appInWorks);
// var response = mapper.Map<List<ApplicationInWorkResponse>>(appInWorks);//TODO Migration to job
if (filter.IsLight != true)
{
//Если запрос не легкий, загружаем кол-во шаблонов отдельно, это значительно ускоряет запрос
foreach (var item in response)
{
item.TemplatesCount = await templateService.Get().CountAsync(t => t.ApplicationInWorkId == item.Id);
// if (filter.IsLight != true)
// {
// //Если запрос не легкий, загружаем кол-во шаблонов отдельно, это значительно ускоряет запрос
// foreach (var item in response)
// {
// item.TemplatesCount = await templateService.Get().CountAsync(t => t.JobId == item.Id);
var statistics = await GetStatisticsAsync(item.Id);
BindStatistics(item, statistics);
}
}
// var statistics = await GetStatisticsAsync(item.Id);
// BindStatistics(item, statistics);
// }
// }
var paginationResponse = new PagedResponse<ApplicationInWorkResponse>(response, true).GetPaginatedProps(paginationFilter, query);
// var paginationResponse = new PagedResponse<ApplicationInWorkResponse>(response, true).GetPaginatedProps(paginationFilter, query);
return Ok(paginationResponse);
}
// return Ok(paginationResponse);
//}
/// <summary>
@@ -116,28 +116,28 @@ namespace PARR.API.Controllers.V1
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet(ApiRoutes.Job.Get)]
public async Task<IActionResult> GetById([FromRoute] Guid id)
{
var applicationInWork = await applicationsInWorkService.Get()
.Include(t => t.Application).ThenInclude(t => t!.ApplicationType)
.Include(t => t.Work)
//.Include(t => t.Templates)
.Include(t => t.WorkGroups).ThenInclude(t => t.WorkGroup)
.Include(t => t.JobAutoControl)
.FirstOrDefaultAsync(t => t.Id == id);
//[HttpGet(ApiRoutes.Job.Get)]
//public async Task<IActionResult> GetById([FromRoute] Guid id)
//{
// var applicationInWork = await applicationsInWorkService.Get()
// .Include(t => t.Application).ThenInclude(t => t!.ApplicationType)
// .Include(t => t.Work)
// //.Include(t => t.Templates)
// .Include(t => t.WorkGroups).ThenInclude(t => t.WorkGroup)
// .Include(t => t.JobAutoControl)
// .FirstOrDefaultAsync(t => t.Id == id);
if (applicationInWork == null)
return NotFound();
// if (applicationInWork == null)
// return NotFound();
var response = mapper.Map<ApplicationInWorkResponse>(applicationInWork);
response.TemplatesCount = await templateService.Get().CountAsync(t => t.ApplicationInWorkId == id);
// var response = mapper.Map<ApplicationInWorkResponse>(applicationInWork);
// response.TemplatesCount = await templateService.Get().CountAsync(t => t.ApplicationInWorkId == id);
var statistics = await GetStatisticsAsync(response.Id);
BindStatistics(response, statistics);
// var statistics = await GetStatisticsAsync(response.Id);
// BindStatistics(response, statistics);
return Ok(new Response<ApplicationInWorkResponse>(response, true));
}
// return Ok(new Response<ApplicationInWorkResponse>(response, true));
//}
/// <summary>
@@ -145,80 +145,80 @@ namespace PARR.API.Controllers.V1
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpPost(ApiRoutes.Job.Create)]
public async Task<IActionResult> Create([FromBody] ApplicationInWorkRequest request)
{
var resultValidate = await validator.ValidateAsync(request);
//[HttpPost(ApiRoutes.Job.Create)]
//public async Task<IActionResult> Create([FromBody] ApplicationInWorkRequest request)
//{
// var resultValidate = await validator.ValidateAsync(request);
if (!resultValidate.IsValid)
return BadRequest(new Response(resultValidate.Errors));
// if (!resultValidate.IsValid)
// return BadRequest(new Response(resultValidate.Errors));
//уникальная запись по полям ApplicationId, WorkId
var existSameAiW = await applicationsInWorkService.GetAsync(request.ApplicationId, request.WorkId);
if (existSameAiW != null)
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Задание на выполнение работ с такими ПО и работой уже существует" } }));
// //уникальная запись по полям ApplicationId, WorkId
// var existSameAiW = await applicationsInWorkService.GetAsync(request.ApplicationId, request.WorkId);
// if (existSameAiW != null)
// return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Задание на выполнение работ с такими ПО и работой уже существует" } }));
var applicationInWork = new ApplicationsInWork
{
Id = Guid.NewGuid(),
WorkId = request.WorkId,
ApplicationId = request.ApplicationId,
TemplateDuration = request.TemplateDuration,
ShortDescription = request.ShortDescription.Trim(),
FullDescription = request.FullDescription.Trim(),
Solution = request.Solution.Trim(),
//NextRun = request.NextRun,
IsAutoDistributionEnabled = request.IsAutoDistributionEnabled,
ReferenceDate = request.ReferenceDate,
IsAgent = request.IsAgent,
AgentName = request.AgentName?.Trim(),
AgentTimeOutSec = request.AgentTimeOutSec,
AgentScript = request.AgentScript?.Trim()
};
// var applicationInWork = new ApplicationsInWork
// {
// Id = Guid.NewGuid(),
// WorkId = request.WorkId,
// ApplicationId = request.ApplicationId,
// TemplateDuration = request.TemplateDuration,
// ShortDescription = request.ShortDescription.Trim(),
// FullDescription = request.FullDescription.Trim(),
// Solution = request.Solution.Trim(),
// //NextRun = request.NextRun,
// IsAutoDistributionEnabled = request.IsAutoDistributionEnabled,
// ReferenceDate = request.ReferenceDate,
// IsAgent = request.IsAgent,
// AgentName = request.AgentName?.Trim(),
// AgentTimeOutSec = request.AgentTimeOutSec,
// AgentScript = request.AgentScript?.Trim()
// };
//Добавляем настройки планировщика
request.Schedule.ForEach(item =>
{
applicationInWork.EsppSchValues.Add(new EsppSchValue
{
ApplicationsInWorkId = applicationInWork.Id,
TypeConfigId = item.TypeConfigId,
TypeValueId = item.TypeValueId
});
});
// //Добавляем настройки планировщика
// request.Schedule.ForEach(item =>
// {
// applicationInWork.EsppSchValues.Add(new EsppSchValue
// {
// ApplicationsInWorkId = applicationInWork.Id,
// TypeConfigId = item.TypeConfigId,
// TypeValueId = item.TypeValueId
// });
// });
//Добавляем рабочие группы
request.WorkGroups.ForEach(workGroupId =>
{
applicationInWork.WorkGroups.Add(new AppInWorkInWorkGroup
{
ApplicationsInWorkId = applicationInWork.Id,
WorkGroupId = workGroupId
});
});
// //Добавляем рабочие группы
// request.WorkGroups.ForEach(workGroupId =>
// {
// applicationInWork.WorkGroups.Add(new AppInWorkInWorkGroup
// {
// ApplicationsInWorkId = applicationInWork.Id,
// WorkGroupId = workGroupId
// });
// });
if (!await applicationsInWorkService.CreateAsync(applicationInWork) || !await applicationsInWorkService.CommitAsync())
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Ошибка при созании задания на выполнение работ" } }));
// if (!await applicationsInWorkService.CreateAsync(applicationInWork) || !await applicationsInWorkService.CommitAsync())
// return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Ошибка при созании задания на выполнение работ" } }));
logger.LogInformation($"Пользователь {User.Identity?.Name} добавил задание на выполнение работ: {applicationInWork.Id}, {applicationInWork.ShortDescription}, {applicationInWork.Solution}");
// logger.LogInformation($"Пользователь {User.Identity?.Name} добавил задание на выполнение работ: {applicationInWork.Id}, {applicationInWork.ShortDescription}, {applicationInWork.Solution}");
var createdApplicationInWork = await applicationsInWorkService.Get()
.Include(t => t.Application).ThenInclude(t => t!.ApplicationType)
.Include(t => t.Work)
//.Include(t => t.Templates)
.Include(t => t.WorkGroups).ThenInclude(t => t.WorkGroup)
.Include(t => t.JobAutoControl)
.FirstAsync(t => t.Id == applicationInWork.Id);
// var createdApplicationInWork = await applicationsInWorkService.Get()
// .Include(t => t.Application).ThenInclude(t => t!.ApplicationType)
// .Include(t => t.Work)
// //.Include(t => t.Templates)
// .Include(t => t.WorkGroups).ThenInclude(t => t.WorkGroup)
// .Include(t => t.JobAutoControl)
// .FirstAsync(t => t.Id == applicationInWork.Id);
var locationUri = uriService.GetUri(ApiRoutes.Job.Get, ApiRoutes.Job.getParam, createdApplicationInWork.Id);
// var locationUri = uriService.GetUri(ApiRoutes.Job.Get, ApiRoutes.Job.getParam, createdApplicationInWork.Id);
var response = mapper.Map<ApplicationInWorkResponse>(createdApplicationInWork);
// так как мы только что создали AppInW, то у него нет шаблонов, смело ставим = 0 (ускоряем запрос)
response.TemplatesCount = 0;
// var response = mapper.Map<ApplicationInWorkResponse>(createdApplicationInWork);
// // так как мы только что создали AppInW, то у него нет шаблонов, смело ставим = 0 (ускоряем запрос)
// response.TemplatesCount = 0;
return Created(locationUri, new Response<ApplicationInWorkResponse>(response, true));
}
// return Created(locationUri, new Response<ApplicationInWorkResponse>(response, true));
//}
/// <summary>
@@ -227,114 +227,114 @@ namespace PARR.API.Controllers.V1
/// <param name="id"></param>
/// <param name="request"></param>
/// <returns></returns>
[HttpPut(ApiRoutes.Job.Update)]
public async Task<IActionResult> Update([FromRoute] Guid id, [FromBody] ApplicationInWorkRequest request)
{
var resultValidate = await validator.ValidateAsync(request);
if (!resultValidate.IsValid)
return BadRequest(new Response(resultValidate.Errors));
//[HttpPut(ApiRoutes.Job.Update)]
//public async Task<IActionResult> Update([FromRoute] Guid id, [FromBody] ApplicationInWorkRequest request)
//{
// var resultValidate = await validator.ValidateAsync(request);
// if (!resultValidate.IsValid)
// return BadRequest(new Response(resultValidate.Errors));
//уникальная запись по полям ApplicationId, WorkId у которой id!=[FromRoute]id
var existSameAiW = await applicationsInWorkService.Get()
.FirstOrDefaultAsync(t => t.Id != id && t.ApplicationId == request.ApplicationId && t.WorkId == request.WorkId);
if (existSameAiW != null)
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Задание на выполнение работ с такими ПО и работой уже существует" } }));
// //уникальная запись по полям ApplicationId, WorkId у которой id!=[FromRoute]id
// var existSameAiW = await applicationsInWorkService.Get()
// .FirstOrDefaultAsync(t => t.Id != id && t.ApplicationId == request.ApplicationId && t.WorkId == request.WorkId);
// if (existSameAiW != null)
// return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Задание на выполнение работ с такими ПО и работой уже существует" } }));
var orig = await applicationsInWorkService.Get()
.Include(t => t.WorkGroups)
.Include(t => t.EsppSchValues)
.FirstOrDefaultAsync(t => t.Id == id);
// var orig = await applicationsInWorkService.Get()
// .Include(t => t.WorkGroups)
// .Include(t => t.EsppSchValues)
// .FirstOrDefaultAsync(t => t.Id == id);
if (orig == null)
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = $"Ошибка при изменении задания на выполнение работ. Не найдено задание с Id: {id}" } }));
// if (orig == null)
// return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = $"Ошибка при изменении задания на выполнение работ. Не найдено задание с Id: {id}" } }));
//Расписание было изменено, ниже добавим задание в очередь на обновление расписаний у связанных шаблонов
var isScheduleChanged = IsScheduleChanged(orig, request);
// //Расписание было изменено, ниже добавим задание в очередь на обновление расписаний у связанных шаблонов
// var isScheduleChanged = IsScheduleChanged(orig, request);
orig.WorkId = request.WorkId;
orig.ApplicationId = request.ApplicationId;
orig.TemplateDuration = request.TemplateDuration;
orig.ShortDescription = request.ShortDescription.Trim();
orig.FullDescription = request.FullDescription.Trim();
orig.Solution = request.Solution.Trim();
//orig.NextRun = request.NextRun;
orig.ReferenceDate = request.ReferenceDate;
orig.IsAutoDistributionEnabled = request.IsAutoDistributionEnabled;
orig.IsAgent = request.IsAgent;
orig.AgentName = request.AgentName?.Trim();
orig.AgentTimeOutSec = request.AgentTimeOutSec;
orig.AgentScript = request.AgentScript?.Trim();
orig.DateModified = DateTimeOffset.UtcNow;
// orig.WorkId = request.WorkId;
// orig.ApplicationId = request.ApplicationId;
// orig.TemplateDuration = request.TemplateDuration;
// orig.ShortDescription = request.ShortDescription.Trim();
// orig.FullDescription = request.FullDescription.Trim();
// orig.Solution = request.Solution.Trim();
// //orig.NextRun = request.NextRun;
// orig.ReferenceDate = request.ReferenceDate;
// orig.IsAutoDistributionEnabled = request.IsAutoDistributionEnabled;
// orig.IsAgent = request.IsAgent;
// orig.AgentName = request.AgentName?.Trim();
// orig.AgentTimeOutSec = request.AgentTimeOutSec;
// orig.AgentScript = request.AgentScript?.Trim();
// orig.DateModified = DateTimeOffset.UtcNow;
//обновляем планировщик
orig.EsppSchValues.Clear();
request.Schedule.ForEach(item =>
{
orig.EsppSchValues.Add(new EsppSchValue
{
ApplicationsInWorkId = orig.Id,
TypeConfigId = item.TypeConfigId,
TypeValueId = item.TypeValueId
});
});
// //обновляем планировщик
// orig.EsppSchValues.Clear();
// request.Schedule.ForEach(item =>
// {
// orig.EsppSchValues.Add(new EsppSchValue
// {
// ApplicationsInWorkId = orig.Id,
// TypeConfigId = item.TypeConfigId,
// TypeValueId = item.TypeValueId
// });
// });
//Обновляем рабочие группы
orig.WorkGroups.Clear();
request.WorkGroups.ForEach(workGroupId =>
{
orig.WorkGroups.Add(new AppInWorkInWorkGroup
{
ApplicationsInWorkId = orig.Id,
WorkGroupId = workGroupId
});
});
// //Обновляем рабочие группы
// orig.WorkGroups.Clear();
// request.WorkGroups.ForEach(workGroupId =>
// {
// orig.WorkGroups.Add(new AppInWorkInWorkGroup
// {
// ApplicationsInWorkId = orig.Id,
// WorkGroupId = workGroupId
// });
// });
if (!await applicationsInWorkService.CommitAsync())
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Ошибка при изменении задания на выполнение работ." } }));
// if (!await applicationsInWorkService.CommitAsync())
// return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Ошибка при изменении задания на выполнение работ." } }));
logger.LogInformation($"Пользователь {User.Identity?.Name} обновил задание на выполнение работ: {orig.Id}," +
$" {orig.WorkId}, {orig.ApplicationId}, {orig.TemplateDuration}, {orig.ShortDescription}," +
$" {orig.FullDescription}, {orig.Solution}, {nameof(orig.IsAutoDistributionEnabled)}: {orig.IsAutoDistributionEnabled}, {orig.IsAgent}, {orig.AgentName}, {orig.AgentTimeOutSec}, {orig.AgentScript}");
// logger.LogInformation($"Пользователь {User.Identity?.Name} обновил задание на выполнение работ: {orig.Id}," +
// $" {orig.WorkId}, {orig.ApplicationId}, {orig.TemplateDuration}, {orig.ShortDescription}," +
// $" {orig.FullDescription}, {orig.Solution}, {nameof(orig.IsAutoDistributionEnabled)}: {orig.IsAutoDistributionEnabled}, {orig.IsAgent}, {orig.AgentName}, {orig.AgentTimeOutSec}, {orig.AgentScript}");
if (isScheduleChanged)
{
//расписание было обновлено, отправим задание в очередь на перерасчет NextRun
var requestToMq = new TemplateDistributorMq
{
ApplicationInWorkId = id
};
// if (isScheduleChanged)
// {
// //расписание было обновлено, отправим задание в очередь на перерасчет NextRun
// var requestToMq = new TemplateDistributorMq
// {
// ApplicationInWorkId = id
// };
var msg = JsonSerializer.Serialize(requestToMq);
// var msg = JsonSerializer.Serialize(requestToMq);
logger.LogDebug($"Расписание в РР applicationInWorkId: {id} было изменено. Отправляем задание в очередь на перерасчет NextRun");
// logger.LogDebug($"Расписание в РР applicationInWorkId: {id} было изменено. Отправляем задание в очередь на перерасчет NextRun");
var sendResult = mqService.Send(mqSettings.TemplateDistributor, new[] { msg });
// var sendResult = mqService.Send(mqSettings.TemplateDistributor, new[] { msg });
if (sendResult.IsSuccess)
logger.LogInformation($"Задание на перерасчет NextRun успешно отправлено в очередь MQ {mqSettings.TemplateDistributor.QueueName}");
else
logger.LogError($"Ошибка при отправке задания на перерасчет NextRun в очередь MQ {mqSettings.TemplateDistributor.QueueName}");
}
// if (sendResult.IsSuccess)
// logger.LogInformation($"Задание на перерасчет NextRun успешно отправлено в очередь MQ {mqSettings.TemplateDistributor.QueueName}");
// else
// logger.LogError($"Ошибка при отправке задания на перерасчет NextRun в очередь MQ {mqSettings.TemplateDistributor.QueueName}");
// }
var updatedApplicationInWork = await applicationsInWorkService.Get()
.Include(t => t.Application).ThenInclude(t => t!.ApplicationType)
.Include(t => t.Work)
//.Include(t => t.Templates)
.Include(t => t.WorkGroups).ThenInclude(t => t.WorkGroup)
.Include(t => t.JobAutoControl)
.FirstAsync(t => t.Id == orig.Id);
// var updatedApplicationInWork = await applicationsInWorkService.Get()
// .Include(t => t.Application).ThenInclude(t => t!.ApplicationType)
// .Include(t => t.Work)
// //.Include(t => t.Templates)
// .Include(t => t.WorkGroups).ThenInclude(t => t.WorkGroup)
// .Include(t => t.JobAutoControl)
// .FirstAsync(t => t.Id == orig.Id);
var response = mapper.Map<ApplicationInWorkResponse>(updatedApplicationInWork);
response.TemplatesCount = await templateService.Get().CountAsync(t => t.ApplicationInWorkId == id);
// var response = mapper.Map<ApplicationInWorkResponse>(updatedApplicationInWork);
// response.TemplatesCount = await templateService.Get().CountAsync(t => t.ApplicationInWorkId == id);
var statistics = await GetStatisticsAsync(response.Id);
BindStatistics(response, statistics);
// var statistics = await GetStatisticsAsync(response.Id);
// BindStatistics(response, statistics);
return Ok(new Response<ApplicationInWorkResponse>(response, true));
// return Ok(new Response<ApplicationInWorkResponse>(response, true));
}
//}
/// <summary>
@@ -342,38 +342,38 @@ namespace PARR.API.Controllers.V1
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpDelete(ApiRoutes.Job.Delete)]
public async Task<IActionResult> Delete([FromRoute] Guid id)
{
var applicationsInWork = await applicationsInWorkService.Get()
//.Include(t => t.Templates)
.FirstOrDefaultAsync(t => t.Id == id);
//[HttpDelete(ApiRoutes.Job.Delete)]
//public async Task<IActionResult> Delete([FromRoute] Guid id)
//{
// var applicationsInWork = await applicationsInWorkService.Get()
// //.Include(t => t.Templates)
// .FirstOrDefaultAsync(t => t.Id == id);
if (applicationsInWork == null)
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel {
Message = $"Ошибка при удалении задания на выполнение работ. Не найдено задание на выполнение работ Id: {id}"
} }));
// if (applicationsInWork == null)
// return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel {
// Message = $"Ошибка при удалении задания на выполнение работ. Не найдено задание на выполнение работ Id: {id}"
// } }));
var templateCount = await templateService.Get().CountAsync(t => t.ApplicationInWorkId == id);
// var templateCount = await templateService.Get().CountAsync(t => t.ApplicationInWorkId == id);
//if (applicationsInWork.Templates.Any())
if (templateCount > 0)
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel {
Message = $"Ошибка при удалении задания на выполнение работ. С данным заданием связаны шаблоны: {templateCount} шт."
} }));
// //if (applicationsInWork.Templates.Any())
// if (templateCount > 0)
// return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel {
// Message = $"Ошибка при удалении задания на выполнение работ. С данным заданием связаны шаблоны: {templateCount} шт."
// } }));
if (!applicationsInWorkService.Delete(applicationsInWork) || !await applicationsInWorkService.CommitAsync())
return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel {
Message = $"Ошибка при удалении задания на выполнение работ"
} }));
// if (!applicationsInWorkService.Delete(applicationsInWork) || !await applicationsInWorkService.CommitAsync())
// return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel {
// Message = $"Ошибка при удалении задания на выполнение работ"
// } }));
logger.LogInformation($"Пользователь {User.Identity?.Name} удалил задание на выполнение работ: {applicationsInWork.Id},{applicationsInWork.WorkId}," +
$" {applicationsInWork.ApplicationId}, {applicationsInWork.TemplateDuration}, {applicationsInWork.ShortDescription}," +
$" {applicationsInWork.FullDescription}, {applicationsInWork.Solution}, {nameof(applicationsInWork.IsAutoDistributionEnabled)}: {applicationsInWork.IsAutoDistributionEnabled}, {applicationsInWork.IsAgent}," +
$" {applicationsInWork.AgentName}, {applicationsInWork.AgentTimeOutSec}, {applicationsInWork.AgentScript}");
// logger.LogInformation($"Пользователь {User.Identity?.Name} удалил задание на выполнение работ: {applicationsInWork.Id},{applicationsInWork.WorkId}," +
// $" {applicationsInWork.ApplicationId}, {applicationsInWork.TemplateDuration}, {applicationsInWork.ShortDescription}," +
// $" {applicationsInWork.FullDescription}, {applicationsInWork.Solution}, {nameof(applicationsInWork.IsAutoDistributionEnabled)}: {applicationsInWork.IsAutoDistributionEnabled}, {applicationsInWork.IsAgent}," +
// $" {applicationsInWork.AgentName}, {applicationsInWork.AgentTimeOutSec}, {applicationsInWork.AgentScript}");
return NoContent();
}
// return NoContent();
//}
/// <summary>
@@ -382,31 +382,31 @@ namespace PARR.API.Controllers.V1
/// <param name="orig"></param>
/// <param name="request"></param>
/// <returns></returns>
private bool IsScheduleChanged(ApplicationsInWork orig, ApplicationInWorkRequest request)
{
var isScheduleChanged = false;
//private bool IsScheduleChanged(ApplicationsInWork orig, ApplicationInWorkRequest request)
//{
// var isScheduleChanged = false;
if (orig.ReferenceDate != request.ReferenceDate)
isScheduleChanged = true;
// if (orig.ReferenceDate != request.ReferenceDate)
// isScheduleChanged = true;
if (request.Schedule.Count() != orig.EsppSchValues.Count())
isScheduleChanged = true;
// if (request.Schedule.Count() != orig.EsppSchValues.Count())
// isScheduleChanged = true;
if (request.IsAutoDistributionEnabled != orig.IsAutoDistributionEnabled)
isScheduleChanged = true;
// if (request.IsAutoDistributionEnabled != orig.IsAutoDistributionEnabled)
// isScheduleChanged = true;
request.Schedule.ForEach(requestSchedule =>
{
var schExist = orig.EsppSchValues.FirstOrDefault(t => t.ApplicationsInWorkId == orig.Id
&& t.TypeValueId == requestSchedule.TypeValueId
&& t.TypeConfigId == requestSchedule.TypeConfigId);
// request.Schedule.ForEach(requestSchedule =>
// {
// var schExist = orig.EsppSchValues.FirstOrDefault(t => t.ApplicationsInWorkId == orig.Id
// && t.TypeValueId == requestSchedule.TypeValueId
// && t.TypeConfigId == requestSchedule.TypeConfigId);
if (schExist == null)
isScheduleChanged = true;
});
// if (schExist == null)
// isScheduleChanged = true;
// });
return isScheduleChanged;
}
// return isScheduleChanged;
//}
/// <summary>
@@ -414,28 +414,28 @@ namespace PARR.API.Controllers.V1
/// </summary>
/// <param name="applicationInWorkId"></param>
/// <returns></returns>
private async Task<AppInWorkStatModel> GetStatisticsAsync(Guid applicationInWorkId)
{
var statResult = await applicationsInWorkService.Get()
.Include(t => t.Templates).ThenInclude(t => t.RobotConfigurations)
.Where(x => x.Id == applicationInWorkId)
.Select(t => new
{
TemplateActivated = t.Templates.Count(x => x.IsActiveTemplate),
TemplateSynchronized = t.Templates.Count(x => x.RobotConfigurations.Any(c => c.TaskStatusCode == (int)TaskStatusEnum.Ok && c.RobotCode == (int)RobotsEnum.TemplateOrder)),
TemplateErrors = t.Templates.Count(x => x.RobotConfigurations.Any(c => c.RobotStatusCode == (int)RobotStatusEnum.Error && c.RobotCode == (int)RobotsEnum.TemplateOrder)),
ScheduleActivated = t.Templates.Count(x => x.IsActiveSchedule),
ScheduleSynchronized = t.Templates.Count(x => x.RobotConfigurations.Any(c => c.TaskStatusCode == (int)TaskStatusEnum.Ok && c.RobotCode == (int)RobotsEnum.ScheduleOrder)),
ScheduleErrors = t.Templates.Count(x => x.RobotConfigurations.Any(c => c.RobotStatusCode == (int)RobotStatusEnum.Error && c.RobotCode == (int)RobotsEnum.ScheduleOrder))
//private async Task<AppInWorkStatModel> GetStatisticsAsync(Guid applicationInWorkId)
//{
// var statResult = await applicationsInWorkService.Get()
// .Include(t => t.Templates).ThenInclude(t => t.RobotConfigurations)
// .Where(x => x.Id == applicationInWorkId)
// .Select(t => new
// {
// TemplateActivated = t.Templates.Count(x => x.IsActiveTemplate),
// TemplateSynchronized = t.Templates.Count(x => x.RobotConfigurations.Any(c => c.TaskStatusCode == (int)TaskStatusEnum.Ok && c.RobotCode == (int)RobotsEnum.TemplateOrder)),
// TemplateErrors = t.Templates.Count(x => x.RobotConfigurations.Any(c => c.RobotStatusCode == (int)RobotStatusEnum.Error && c.RobotCode == (int)RobotsEnum.TemplateOrder)),
// ScheduleActivated = t.Templates.Count(x => x.IsActiveSchedule),
// ScheduleSynchronized = t.Templates.Count(x => x.RobotConfigurations.Any(c => c.TaskStatusCode == (int)TaskStatusEnum.Ok && c.RobotCode == (int)RobotsEnum.ScheduleOrder)),
// ScheduleErrors = t.Templates.Count(x => x.RobotConfigurations.Any(c => c.RobotStatusCode == (int)RobotStatusEnum.Error && c.RobotCode == (int)RobotsEnum.ScheduleOrder))
}).FirstOrDefaultAsync();
// }).FirstOrDefaultAsync();
return new AppInWorkStatModel
{
ScheduleStatistics = new ScheduleStats { Activated = statResult?.ScheduleActivated ?? 0, Errors = statResult?.ScheduleErrors ?? 0, Synchronized = statResult?.ScheduleSynchronized ?? 0 },
TemplateStatistics = new TemplateStats { Activated = statResult?.TemplateActivated ?? 0, Errors = statResult?.TemplateErrors ?? 0, Synchronized = statResult?.TemplateSynchronized ?? 0 }
};
}
// return new AppInWorkStatModel
// {
// ScheduleStatistics = new ScheduleStats { Activated = statResult?.ScheduleActivated ?? 0, Errors = statResult?.ScheduleErrors ?? 0, Synchronized = statResult?.ScheduleSynchronized ?? 0 },
// TemplateStatistics = new TemplateStats { Activated = statResult?.TemplateActivated ?? 0, Errors = statResult?.TemplateErrors ?? 0, Synchronized = statResult?.TemplateSynchronized ?? 0 }
// };
//}
private void BindStatistics(ApplicationInWorkResponse applicationsInWork, AppInWorkStatModel statistics)

View File

@@ -71,11 +71,11 @@ namespace PARR.API.Controllers.V1
case RobotsEnum.TemplateOrder:
// шаблоны
query = query.Include(t => t.Template)
.ThenInclude(t => t!.Host).ThenInclude(t => t!.ResponseArea)
.ThenInclude(t => t!.Hosts).ThenInclude(t => t.WorkGroup).ThenInclude(t => t!.ResponseArea)
.ThenInclude(t => t!.Unit)
//.ThenInclude(t => t!.Hosts).ThenInclude(t => t.WorkGroup).ThenInclude(t => t!.ResponseArea)
.Include(t => t.Template)
.ThenInclude(a => a!.ApplicationsInWork)
.ThenInclude(w => w!.Work)
.ThenInclude(a => a!.Job)
//.ThenInclude(w => w!.Work)
.ThenInclude(t => t!.Tnk)
.ThenInclude(s => s!.Subprocess)
.ThenInclude(p => p!.Process);
@@ -84,10 +84,12 @@ namespace PARR.API.Controllers.V1
//расписание
// тут не делаем AsSplitQuery, не может подтянуть все таблицы
query = query.Include(t => t.Template)
.ThenInclude(t => t!.Host).ThenInclude(t => t!.ResponseArea)
.ThenInclude(t => t!.Hosts).ThenInclude(t => t.WorkGroup)
.ThenInclude(t => t!.Unit)//.ThenInclude(t => t!.ResponseArea)
//.ThenInclude(t => t!.Hosts).ThenInclude(t => t.WorkGroup)
.Include(t => t.Template)
.ThenInclude(t => t!.ApplicationsInWork)
.ThenInclude(t => t!.Job)
.ThenInclude(t => t!.Group)
//.ThenInclude(t => t!.ApplicationsInWork)
.ThenInclude(t => t!.EsppSchValues)
.ThenInclude(t => t!.EsppSchTypeConfig)
.ThenInclude(t => t!.EsppSchTypeSchedule);
@@ -169,7 +171,7 @@ namespace PARR.API.Controllers.V1
// передаем LastRun, если его нет, то NextRun
//var nextRun = await esppScheduleTransformService.GetNextDateAsync(task.Template!.ApplicationInWorkId, task.Template.ApplicationsInWork!.LastRun ?? task.Template.ApplicationsInWork.NextRun);
// всегда считаем по nextRun
var nextRun = await esppScheduleTransformService.GetNextDateAsync(template.ApplicationInWorkId, template.NextRun);
var nextRun = await esppScheduleTransformService.GetNextDateAsync(template.Job!.GroupId, template.NextRun);
if (nextRun != template.NextRun)
{

View File

@@ -9,6 +9,7 @@ using PARR.API.Controllers.V1.Base;
using PARR.BLL.Services.Interfaces;
using PARR.Constants;
using PARR.DAL.Services.Interfaces;
using PARR.DAL.Services.Interfaces.Unit;
namespace PARR.API.Controllers.V1.Statistics
{
@@ -19,11 +20,17 @@ namespace PARR.API.Controllers.V1.Statistics
public class StatHostController : BaseApiController
{
private readonly IHostService hostService;
private readonly IUnitService unitService;
private readonly ICalendarService calendarService;
public StatHostController(IHostService hostService, ICalendarService calendarService)
public StatHostController(
IHostService hostService,
IUnitService unitService,
ICalendarService calendarService
)
{
this.hostService = hostService;
this.unitService = unitService;
this.calendarService = calendarService;
}
@@ -103,8 +110,8 @@ namespace PARR.API.Controllers.V1.Statistics
var response = new StatHostTemplateResponse
{
AllHosts = await hostService.Get().CountAsync(),
HostsInTemplates = await hostService.Get().Include(t => t.Templates).CountAsync(t => t.Templates.Any())
AllUnits = await unitService.Get().CountAsync(),
HostsInTemplates = await unitService.Get().Include(t => t.Templates).CountAsync(t => t.Templates.Any())
};
return Ok(new Response<StatHostTemplateResponse>(response, true));

View File

@@ -40,88 +40,88 @@ namespace PARR.API.Controllers.V1.Statistics
}
/// <summary>
/// Статистика загрузки РР по всем ЗО
/// </summary>
/// <returns></returns>
[HttpGet(ApiRoutes.StatResponseAreaWorkLoad.GetAll)]
public async Task<IActionResult> GetAll([FromQuery] WorkloadBaseQuery requestQuery)
{
var response = await GetStatisticsAsync(requestQuery);
///// <summary>
///// Статистика загрузки РР по всем ЗО
///// </summary>
///// <returns></returns>
//[HttpGet(ApiRoutes.StatResponseAreaWorkLoad.GetAll)]
//public async Task<IActionResult> GetAll([FromQuery] WorkloadBaseQuery requestQuery)
//{
// var response = await GetStatisticsAsync(requestQuery);
return Ok(new Response<List<StatResponseAreaWorkLoadResponse>>(response, true));
}
// return Ok(new Response<List<StatResponseAreaWorkLoadResponse>>(response, true));
//}
/// <summary>
/// Статистика загрузки РР по списку ЗО
/// </summary>
/// <returns></returns>
[HttpPost(ApiRoutes.StatResponseAreaWorkLoad.GetByResponseAreas)]
public async Task<IActionResult> GetByResponseAreas([FromBody] StatResponseAreaWorkloadRequest request)
{
var response = await GetStatisticsAsync(request.Filter, request.ResponseAreas);
///// <summary>
///// Статистика загрузки РР по списку ЗО
///// </summary>
///// <returns></returns>
//[HttpPost(ApiRoutes.StatResponseAreaWorkLoad.GetByResponseAreas)]
//public async Task<IActionResult> GetByResponseAreas([FromBody] StatResponseAreaWorkloadRequest request)
//{
// var response = await GetStatisticsAsync(request.Filter, request.ResponseAreas);
return Ok(new Response<List<StatResponseAreaWorkLoadResponse>>(response, true));
}
// return Ok(new Response<List<StatResponseAreaWorkLoadResponse>>(response, true));
//}
private async Task<List<StatResponseAreaWorkLoadResponse>> GetStatisticsAsync(WorkloadBaseQuery requestQuery, List<int>? responseAreas = null)
{
var daysList = workLoadService.GetDatesForPeriod(requestQuery);
//private async Task<List<StatResponseAreaWorkLoadResponse>> GetStatisticsAsync(WorkloadBaseQuery requestQuery, List<int>? responseAreas = null)
//{
// var daysList = workLoadService.GetDatesForPeriod(requestQuery);
IQueryable<DAL.Models.Template> query = templateService.Get()
.Include(t => t.Host).ThenInclude(t => t.WorkGroup);
// IQueryable<DAL.Models.Template> query = templateService.Get()
// .Include(t => t.Host).ThenInclude(t => t.WorkGroup);
query = workLoadService.FilterTemplatesQuery(query, requestQuery);
// query = workLoadService.FilterTemplatesQuery(query, requestQuery);
if (responseAreas != null && responseAreas.Count() > 0)
query = query.Where(t => responseAreas.Any(x => x == t.Host.WorkGroup.ResponseAreaCode));
// if (responseAreas != null && responseAreas.Count() > 0)
// query = query.Where(t => responseAreas.Any(x => x == t.Host.WorkGroup.ResponseAreaCode));
//var groupedQuery = query.GroupBy(t => new { t.NextRun.DateTime.Date, t.Host!.WorkGroup!.ResponseAreaCode })
var groupedQuery = query.GroupBy(t => new { t.NextRun.AddHours(requestQuery.TimeZoneOffsetHours).DateTime.Date, t.Host!.WorkGroup!.ResponseAreaCode })
.Select(t => new
{
ResponseAreaCode = t.Key.ResponseAreaCode,
Date = t.Key.Date,
TemplateCount = t.Count()
// //var groupedQuery = query.GroupBy(t => new { t.NextRun.DateTime.Date, t.Host!.WorkGroup!.ResponseAreaCode })
// var groupedQuery = query.GroupBy(t => new { t.NextRun.AddHours(requestQuery.TimeZoneOffsetHours).DateTime.Date, t.Host!.WorkGroup!.ResponseAreaCode })
// .Select(t => new
// {
// ResponseAreaCode = t.Key.ResponseAreaCode,
// Date = t.Key.Date,
// TemplateCount = t.Count()
});
// });
var queryResult = await groupedQuery.ToListAsync();
// var queryResult = await groupedQuery.ToListAsync();
var responseAreaQuery = responseAreaService.Get();
// var responseAreaQuery = responseAreaService.Get();
if (responseAreas != null && responseAreas.Count() > 0)
responseAreaQuery = responseAreaQuery.Where(t => responseAreas.Any(x => x == t.Code));
// if (responseAreas != null && responseAreas.Count() > 0)
// responseAreaQuery = responseAreaQuery.Where(t => responseAreas.Any(x => x == t.Code));
var allResponseArea = await responseAreaQuery.ToListAsync();
// var allResponseArea = await responseAreaQuery.ToListAsync();
//if (!allResponseArea.Any())
// return NoContent();
// //if (!allResponseArea.Any())
// // return NoContent();
var response = new List<StatResponseAreaWorkLoadResponse>();
// var response = new List<StatResponseAreaWorkLoadResponse>();
allResponseArea.ForEach(respArea =>
{
var workLoads = daysList.Select(t => new StatWorkLoadDataResponse
{
Date = t,
TemplateCount = queryResult.FirstOrDefault(x => x.ResponseAreaCode == respArea.Code && DateOnly.FromDateTime(x.Date) == t)?.TemplateCount ?? 0
}).OrderBy(t => t.Date).ToList();
// allResponseArea.ForEach(respArea =>
// {
// var workLoads = daysList.Select(t => new StatWorkLoadDataResponse
// {
// Date = t,
// TemplateCount = queryResult.FirstOrDefault(x => x.ResponseAreaCode == respArea.Code && DateOnly.FromDateTime(x.Date) == t)?.TemplateCount ?? 0
// }).OrderBy(t => t.Date).ToList();
response.Add(
new StatResponseAreaWorkLoadResponse
{
ResponseArea = mapper.Map<ResponseAreaResponse>(respArea),
WorkLoad = workLoads
});
});
// response.Add(
// new StatResponseAreaWorkLoadResponse
// {
// ResponseArea = mapper.Map<ResponseAreaResponse>(respArea),
// WorkLoad = workLoads
// });
// });
response = response.OrderBy(t => t.ResponseArea.Code).ToList();
// response = response.OrderBy(t => t.ResponseArea.Code).ToList();
return response;
}
// return response;
//}
}
}

View File

@@ -32,66 +32,66 @@ namespace PARR.API.Controllers.V1.Statistics
this.calendarService = calendarService;
}
/// <summary>
/// Статистика по шаблонам
/// </summary>
/// <returns></returns>
[HttpGet(ApiRoutes.StatTemplate.Get)]
public async Task<IActionResult> Get()
{
var response = new StatTemplateResponse
{
ActivateScheduleCount = await templateService.Get().CountAsync(t => t.IsActiveSchedule),
ActivateTemplateCount = await templateService.Get().CountAsync(t => t.IsActiveTemplate),
TemplateAgentCount = await templateService.Get().Include(t => t.ApplicationsInWork).CountAsync(t => t.ApplicationsInWork!.IsAgent),
TemplateCount = await templateService.Get().CountAsync(),
SyncEsppScheduleCount = await templateService.Get().Include(t => t.RobotConfigurations).CountAsync(t => t.RobotConfigurations.Any(c => c.RobotCode == (int)RobotsEnum.ScheduleOrder && c.TaskStatusCode == (int)TaskStatusEnum.Ok)),
SyncEsppTemplatesCount = await templateService.Get().Include(t => t.RobotConfigurations).CountAsync(t => t.RobotConfigurations.Any(c => c.RobotCode == (int)RobotsEnum.TemplateOrder && c.TaskStatusCode == (int)TaskStatusEnum.Ok))
};
///// <summary>
///// Статистика по шаблонам
///// </summary>
///// <returns></returns>
//[HttpGet(ApiRoutes.StatTemplate.Get)]
//public async Task<IActionResult> Get()
//{
// var response = new StatTemplateResponse
// {
// ActivateScheduleCount = await templateService.Get().CountAsync(t => t.IsActiveSchedule),
// ActivateTemplateCount = await templateService.Get().CountAsync(t => t.IsActiveTemplate),
// TemplateAgentCount = await templateService.Get().Include(t => t.ApplicationsInWork).CountAsync(t => t.ApplicationsInWork!.IsAgent),
// TemplateCount = await templateService.Get().CountAsync(),
// SyncEsppScheduleCount = await templateService.Get().Include(t => t.RobotConfigurations).CountAsync(t => t.RobotConfigurations.Any(c => c.RobotCode == (int)RobotsEnum.ScheduleOrder && c.TaskStatusCode == (int)TaskStatusEnum.Ok)),
// SyncEsppTemplatesCount = await templateService.Get().Include(t => t.RobotConfigurations).CountAsync(t => t.RobotConfigurations.Any(c => c.RobotCode == (int)RobotsEnum.TemplateOrder && c.TaskStatusCode == (int)TaskStatusEnum.Ok))
// };
return Ok(new Response<StatTemplateResponse>(response, true));
}
// return Ok(new Response<StatTemplateResponse>(response, true));
//}
/// <summary>
/// Получить статистику созданных шаблонов (расписаний) в БД ПАРР
/// </summary>
/// <param name="timeZoneQuery"></param>
/// <param name="startPeriodDays"></param>
/// <returns></returns>
[HttpGet(ApiRoutes.StatTemplate.GetForPeriod)]
public async Task<IActionResult> GetForPeriod([FromQuery] TimeZoneOffsetClient timeZoneQuery, [FromQuery] int startPeriodDays = 3)
{
var endPeriod = calendarService.GetDateWithTimeZoneOffset(DateTimeOffset.UtcNow, timeZoneQuery.TimeZoneOffsetHours);
var startPeriod = endPeriod.AddDays(-startPeriodDays);
///// <summary>
///// Получить статистику созданных шаблонов (расписаний) в БД ПАРР
///// </summary>
///// <param name="timeZoneQuery"></param>
///// <param name="startPeriodDays"></param>
///// <returns></returns>
//[HttpGet(ApiRoutes.StatTemplate.GetForPeriod)]
//public async Task<IActionResult> GetForPeriod([FromQuery] TimeZoneOffsetClient timeZoneQuery, [FromQuery] int startPeriodDays = 3)
//{
// var endPeriod = calendarService.GetDateWithTimeZoneOffset(DateTimeOffset.UtcNow, timeZoneQuery.TimeZoneOffsetHours);
// var startPeriod = endPeriod.AddDays(-startPeriodDays);
var query = templateService.Get()
.Where(t =>
t.DateCreated.DateTime.AddHours(timeZoneQuery.TimeZoneOffsetHours).Date >= startPeriod.Date
&& t.DateCreated.DateTime.AddHours(timeZoneQuery.TimeZoneOffsetHours).Date <= endPeriod.Date
).GroupBy(t => t.DateCreated.AddHours(timeZoneQuery.TimeZoneOffsetHours).Date)
.Select(t => new
{
Date = t.Key,
CreatedObjs = t.Count()
});
// var query = templateService.Get()
// .Where(t =>
// t.DateCreated.DateTime.AddHours(timeZoneQuery.TimeZoneOffsetHours).Date >= startPeriod.Date
// && t.DateCreated.DateTime.AddHours(timeZoneQuery.TimeZoneOffsetHours).Date <= endPeriod.Date
// ).GroupBy(t => t.DateCreated.AddHours(timeZoneQuery.TimeZoneOffsetHours).Date)
// .Select(t => new
// {
// Date = t.Key,
// CreatedObjs = t.Count()
// });
var result = await query.ToListAsync();
// var result = await query.ToListAsync();
var daysList = calendarService.GetDatesForPeriod(startPeriod, endPeriod);
// var daysList = calendarService.GetDatesForPeriod(startPeriod, endPeriod);
var response = new List<StatTemplatePeriodResponse>();
// var response = new List<StatTemplatePeriodResponse>();
daysList.ForEach(date => response.Add(new StatTemplatePeriodResponse
{
Date = date,
CreatedTemplatesCount = result.FirstOrDefault(t => DateOnly.FromDateTime(t.Date) == date)?.CreatedObjs ?? 0
}));
// daysList.ForEach(date => response.Add(new StatTemplatePeriodResponse
// {
// Date = date,
// CreatedTemplatesCount = result.FirstOrDefault(t => DateOnly.FromDateTime(t.Date) == date)?.CreatedObjs ?? 0
// }));
response = response.OrderBy(t => t.Date).ToList();
// response = response.OrderBy(t => t.Date).ToList();
return Ok(new Response<List<StatTemplatePeriodResponse>>(response, true));
}
// return Ok(new Response<List<StatTemplatePeriodResponse>>(response, true));
//}
}

View File

@@ -37,20 +37,20 @@ namespace PARR.API.Controllers.V1.Statistics
/// <summary>
/// Статистика распределения шаблонов по JobId (ApplicationInWorkId)
/// </summary>
/// <param name="applicationInWorkId"></param>
/// <param name="JobId"></param>
/// <returns></returns>
[HttpGet(ApiRoutes.StatTemplateDistribution.Get)]
public async Task<IActionResult> Get([FromRoute] Guid applicationInWorkId)
public async Task<IActionResult> Get([FromRoute] Guid jobId)
{
// f87dbe9f-cabf-4108-9c93-12068d4b48a5
var query = templateService.Get()
.Include(t => t.Host)
.Where(t => t.ApplicationInWorkId == applicationInWorkId)
.GroupBy(t => t.Host!.WorkGroupId)
.Include(t => t.Unit)
.Where(t => t.JobId == jobId)
.GroupBy(t => t.Unit!.BaseFields!.WorkGroup)
.Select(x => new
{
WorkGroupId = x.Key,
WorkGroup = x.Key,
CountTemplates = x.Count(),
IsActivatedAllCount = x.Count(t => t.IsActiveTemplate && t.IsActiveSchedule),
IsDeactivatedAllCount = x.Count(t => !t.IsActiveTemplate || !t.IsActiveSchedule || (!t.IsActiveTemplate && !t.IsActiveSchedule)),
@@ -73,13 +73,13 @@ namespace PARR.API.Controllers.V1.Statistics
var workGroups = await workGroupService.Get()
.Include(t => t.ResponseArea)
.Where(t => statResult.Select(x => x.WorkGroupId).Any(w => w == t.Id))
.Where(t => statResult.Select(x => x.WorkGroup).Any(w => w == t.Name))
.ToListAsync();
var response = statResult.Select(stat => new StatTemplateDistributorResponse
{
WorkGroup = mapper.Map<WorkGroupResponse>(workGroups.FirstOrDefault(x => x.Id == stat.WorkGroupId)),
WorkGroup = mapper.Map<WorkGroupResponse>(workGroups.FirstOrDefault(x => x.Name == stat.WorkGroup)),//TODO Migration to job
AllCount = stat.CountTemplates,
IsActivatedAllCount = stat.IsActivatedAllCount,
IsDeactivatedAllCount = stat.IsDeactivatedAllCount,

View File

@@ -39,7 +39,7 @@ namespace PARR.API.Controllers.V1.Statistics
this.logger = logger;
}
/*
/// <summary>
/// Статистика загрузки регламентными работами рабочих групп по ЗО
/// </summary>
@@ -137,6 +137,6 @@ namespace PARR.API.Controllers.V1.Statistics
return response;
}
*/
}
}

View File

@@ -41,131 +41,131 @@ namespace PARR.API.Controllers.V1.Statistics
}
/// <summary>
/// Статистика загрузки регламентными работами по Видам работ(ApplicationInWorks)
/// </summary>
/// <param name="workGroupId"></param>
/// <param name="requestQuery"></param>
/// <returns></returns>
[HttpGet(ApiRoutes.StatWorkWorkLoad.Get)]
public async Task<IActionResult> Get([FromRoute] Guid workGroupId, [FromQuery] WorkloadBaseQuery requestQuery)
{
var response = await GetStatisticsAsync(workGroupId, requestQuery);
///// <summary>
///// Статистика загрузки регламентными работами по Видам работ(ApplicationInWorks)
///// </summary>
///// <param name="workGroupId"></param>
///// <param name="requestQuery"></param>
///// <returns></returns>
//[HttpGet(ApiRoutes.StatWorkWorkLoad.Get)]
//public async Task<IActionResult> Get([FromRoute] Guid workGroupId, [FromQuery] WorkloadBaseQuery requestQuery)
//{
// var response = await GetStatisticsAsync(workGroupId, requestQuery);
return Ok(new Response<List<StatWorkWorkLoadResponse>>(response, true));
}
// return Ok(new Response<List<StatWorkWorkLoadResponse>>(response, true));
//}
/// <summary>
/// Статистика загрузки РР по списку РР
/// </summary>
/// <param name="requestBody"></param>
/// <returns></returns>
[HttpPost(ApiRoutes.StatWorkWorkLoad.GetByApplicationInWork)]
public async Task<IActionResult> GetByApplicationInWork([FromBody] StatWorkWorkLoadRequest requestBody)
{
var response = await GetStatisticsAsync(null, requestBody.Filter, requestBody.JobsRequests);
///// <summary>
///// Статистика загрузки РР по списку РР
///// </summary>
///// <param name="requestBody"></param>
///// <returns></returns>
//[HttpPost(ApiRoutes.StatWorkWorkLoad.GetByApplicationInWork)]
//public async Task<IActionResult> GetByApplicationInWork([FromBody] StatWorkWorkLoadRequest requestBody)
//{
// var response = await GetStatisticsAsync(null, requestBody.Filter, requestBody.JobsRequests);
return Ok(new Response<List<StatWorkWorkLoadResponse>>(response, true));
}
// return Ok(new Response<List<StatWorkWorkLoadResponse>>(response, true));
//}
private async Task<List<StatWorkWorkLoadResponse>> GetStatisticsAsync(Guid? workGroupId, WorkloadBaseQuery requestQuery, List<StatWorkWorkLoadJobRequest>? jobsRequests = null)
{
//защита от дурака, чтоб не выгрузить всю БД
if (workGroupId == null && (jobsRequests == null || jobsRequests.Count() == 0))
{
logger.LogWarning($"Пытались выполнить запрос получения статситики с нулевыми параметрами {nameof(workGroupId)}, {nameof(jobsRequests)}. Controller {nameof(StatWorkWorkLoadController)}");
return new List<StatWorkWorkLoadResponse>();
}
//private async Task<List<StatWorkWorkLoadResponse>> GetStatisticsAsync(Guid? workGroupId, WorkloadBaseQuery requestQuery, List<StatWorkWorkLoadJobRequest>? jobsRequests = null)
//{
// //защита от дурака, чтоб не выгрузить всю БД
// if (workGroupId == null && (jobsRequests == null || jobsRequests.Count() == 0))
// {
// logger.LogWarning($"Пытались выполнить запрос получения статситики с нулевыми параметрами {nameof(workGroupId)}, {nameof(jobsRequests)}. Controller {nameof(StatWorkWorkLoadController)}");
// return new List<StatWorkWorkLoadResponse>();
// }
var daysList = workLoadService.GetDatesForPeriod(requestQuery);
// var daysList = workLoadService.GetDatesForPeriod(requestQuery);
IQueryable<DAL.Models.Template> query = templateService.Get()
.Include(t => t.Host);
// IQueryable<DAL.Models.Template> query = templateService.Get()
// .Include(t => t.Host);
query = workLoadService.FilterTemplatesQuery(query, requestQuery);
// query = workLoadService.FilterTemplatesQuery(query, requestQuery);
if (workGroupId.HasValue)
query = query.Where(t => t.Host!.WorkGroupId == workGroupId.Value);
// if (workGroupId.HasValue)
// query = query.Where(t => t.Host!.WorkGroupId == workGroupId.Value);
if (jobsRequests != null && jobsRequests.Count() > 0)
//query = query.Where(t => jobsRequests.Any(x => x.JobId == t.ApplicationInWorkId && x.WorkGroupId == t.Host!.WorkGroupId.Value)); /*&& x.WorkGroupId == t.Host!.WorkGroupId.Value*/
query = query.Where(t => jobsRequests.Select(t => t.JobId).Any(x => x == t.ApplicationInWorkId) && jobsRequests.Select(t => t.WorkGroupId).Any(x => x == t.Host!.WorkGroupId.Value));
// if (jobsRequests != null && jobsRequests.Count() > 0)
// //query = query.Where(t => jobsRequests.Any(x => x.JobId == t.ApplicationInWorkId && x.WorkGroupId == t.Host!.WorkGroupId.Value)); /*&& x.WorkGroupId == t.Host!.WorkGroupId.Value*/
// query = query.Where(t => jobsRequests.Select(t => t.JobId).Any(x => x == t.ApplicationInWorkId) && jobsRequests.Select(t => t.WorkGroupId).Any(x => x == t.Host!.WorkGroupId.Value));
//var groupedQuery = query.GroupBy(t => new { t.NextRun.DateTime.Date, t.ApplicationInWorkId, t.Host.WorkGroupId })
var groupedQuery = query.GroupBy(t => new { t.NextRun.AddHours(requestQuery.TimeZoneOffsetHours).DateTime.Date, t.ApplicationInWorkId, t.Host.WorkGroupId })
.Select(t => new
{
ApplicationInWorkId = t.Key.ApplicationInWorkId,
WorkGroupId = t.Key.WorkGroupId,
Date = t.Key.Date,
TemplateCount = t.Count()
});
// //var groupedQuery = query.GroupBy(t => new { t.NextRun.DateTime.Date, t.ApplicationInWorkId, t.Host.WorkGroupId })
// var groupedQuery = query.GroupBy(t => new { t.NextRun.AddHours(requestQuery.TimeZoneOffsetHours).DateTime.Date, t.ApplicationInWorkId, t.Host.WorkGroupId })
// .Select(t => new
// {
// ApplicationInWorkId = t.Key.ApplicationInWorkId,
// WorkGroupId = t.Key.WorkGroupId,
// Date = t.Key.Date,
// TemplateCount = t.Count()
// });
var queryResult = await groupedQuery.ToListAsync();
// var queryResult = await groupedQuery.ToListAsync();
// получаем только работы по которым есть шаблоны (активированные/деакт) и за любой период
IQueryable<DAL.Models.Template> appInWorksQuery = templateService.Get()
.Include(t => t.Host)
.Include(t => t.ApplicationsInWork).ThenInclude(t => t.Application).ThenInclude(t => t.ApplicationType);
// // получаем только работы по которым есть шаблоны (активированные/деакт) и за любой период
// IQueryable<DAL.Models.Template> appInWorksQuery = templateService.Get()
// .Include(t => t.Host)
// .Include(t => t.ApplicationsInWork).ThenInclude(t => t.Application).ThenInclude(t => t.ApplicationType);
IQueryable<WorkGroup> workGroupsQuery = workGroupService.Get()
.Include(t => t.ResponseArea);
// IQueryable<WorkGroup> workGroupsQuery = workGroupService.Get()
// .Include(t => t.ResponseArea);
if (workGroupId.HasValue)
{
appInWorksQuery = appInWorksQuery.Where(t => t.Host.WorkGroupId == workGroupId);
workGroupsQuery = workGroupsQuery.Where(t => t.Id == workGroupId.Value);
}
// if (workGroupId.HasValue)
// {
// appInWorksQuery = appInWorksQuery.Where(t => t.Host.WorkGroupId == workGroupId);
// workGroupsQuery = workGroupsQuery.Where(t => t.Id == workGroupId.Value);
// }
if (jobsRequests != null && jobsRequests.Count() > 0)
{
//appInWorksQuery = appInWorksQuery.Where(t => jobsRequests.Any(x => x.JobId == t.ApplicationInWorkId));
appInWorksQuery = appInWorksQuery.Where(t => jobsRequests.Select(j => j.JobId).Any(x => x == t.ApplicationInWorkId));
workGroupsQuery = workGroupsQuery.Where(t => jobsRequests.Select(w => w.WorkGroupId).Any(x => x == t.Id));
}
// if (jobsRequests != null && jobsRequests.Count() > 0)
// {
// //appInWorksQuery = appInWorksQuery.Where(t => jobsRequests.Any(x => x.JobId == t.ApplicationInWorkId));
// appInWorksQuery = appInWorksQuery.Where(t => jobsRequests.Select(j => j.JobId).Any(x => x == t.ApplicationInWorkId));
// workGroupsQuery = workGroupsQuery.Where(t => jobsRequests.Select(w => w.WorkGroupId).Any(x => x == t.Id));
// }
var appInWorks = await appInWorksQuery.Select(t => t.ApplicationsInWork)
.Distinct()
.ToListAsync();
// var appInWorks = await appInWorksQuery.Select(t => t.ApplicationsInWork)
// .Distinct()
// .ToListAsync();
var workGroups = await workGroupsQuery.Distinct().ToListAsync();
// var workGroups = await workGroupsQuery.Distinct().ToListAsync();
var response = new List<StatWorkWorkLoadResponse>();
// var response = new List<StatWorkWorkLoadResponse>();
appInWorks.ForEach(appInWork =>
{
workGroups.ForEach(workGroup =>
{
var workLoads = daysList.Select(t => new StatWorkLoadDataResponse
{
Date = t,
TemplateCount = queryResult.FirstOrDefault(x => x.ApplicationInWorkId == appInWork.Id && DateOnly.FromDateTime(x.Date) == t && x.WorkGroupId == workGroup.Id)?.TemplateCount ?? 0
}).OrderBy(t => t.Date).ToList();
// appInWorks.ForEach(appInWork =>
// {
// workGroups.ForEach(workGroup =>
// {
// var workLoads = daysList.Select(t => new StatWorkLoadDataResponse
// {
// Date = t,
// TemplateCount = queryResult.FirstOrDefault(x => x.ApplicationInWorkId == appInWork.Id && DateOnly.FromDateTime(x.Date) == t && x.WorkGroupId == workGroup.Id)?.TemplateCount ?? 0
// }).OrderBy(t => t.Date).ToList();
response.Add(new StatWorkWorkLoadResponse
{
Job = mapper.Map<ApplicationInWorkBaseResponse>(appInWork),
WorkGroup = mapper.Map<WorkGroupResponse>(workGroup),
WorkLoad = workLoads
});
});
});
// response.Add(new StatWorkWorkLoadResponse
// {
// Job = mapper.Map<ApplicationInWorkBaseResponse>(appInWork),
// WorkGroup = mapper.Map<WorkGroupResponse>(workGroup),
// WorkLoad = workLoads
// });
// });
// });
// убираем не нужные значения так как запрос в SQL (query) был с несколькими Any
if (jobsRequests != null && jobsRequests.Count() > 0)
response = response.Where(t => jobsRequests.Any(x => x.WorkGroupId == t.WorkGroup.Id && x.JobId == t.Job.Id)).ToList();
// // убираем не нужные значения так как запрос в SQL (query) был с несколькими Any
// if (jobsRequests != null && jobsRequests.Count() > 0)
// response = response.Where(t => jobsRequests.Any(x => x.WorkGroupId == t.WorkGroup.Id && x.JobId == t.Job.Id)).ToList();
response = response.OrderBy(t => t.Job.ShortDescription).ThenBy(t => t.Job.Application?.Name).ThenBy(t => t.WorkGroup.Name).ToList();
// response = response.OrderBy(t => t.Job.ShortDescription).ThenBy(t => t.Job.Application?.Name).ThenBy(t => t.WorkGroup.Name).ToList();
return response;
}
// return response;
//}
}
}

View File

@@ -71,7 +71,7 @@ namespace PARR.API.Controllers.V1
query = query.Where(t => EF.Functions.Like(t.Name.ToLower(), SqlHelpers.RegexToLike(filter.Mask)));
if (filter.AppInWorkId.HasValue)
query = query.Where(t => t.ApplicationInWorkId == filter.AppInWorkId.Value);
query = query.Where(t => t.JobId == filter.AppInWorkId.Value);//TODO Migration to job
var templates = await templateService.GetPage(query, paginationFilter).ToListAsync();

View File

@@ -23,7 +23,7 @@ namespace PARR.API.Controllers.V1
private readonly IUnitService unitService;
private readonly IFieldFilterService fieldFilterService;
private readonly IJobService jobService;
private readonly IJobDetailsService jobDetailsService;
private readonly IJobUnitFilterService jobUnitFilterService;
public TestController(
IClientService clientService,
@@ -33,7 +33,7 @@ namespace PARR.API.Controllers.V1
IUnitService unitService,
IFieldFilterService fieldFilterService,
IJobService jobService,
IJobDetailsService jobDetailsService
IJobUnitFilterService jobUnitFilterService
)
{
this.clientService = clientService;
@@ -43,7 +43,7 @@ namespace PARR.API.Controllers.V1
this.unitService = unitService;
this.fieldFilterService = fieldFilterService;
this.jobService = jobService;
this.jobDetailsService = jobDetailsService;
this.jobUnitFilterService = jobUnitFilterService;
}

View File

@@ -7,6 +7,7 @@ using PARR.Constants.Shortcodes;
using PARR.DAL.DomainModels;
using PARR.DAL.Extensions;
using PARR.DAL.Models;
using PARR.DAL.Models.Job;
using PARR.DAL.Models.Unit;
namespace PARR.API.MappingProfiles
@@ -19,27 +20,27 @@ namespace PARR.API.MappingProfiles
// --- Template ---
CreateMap<Template, TemplateResponse>()
.ForMember(d => d.Work, o => o.MapFrom(s => s.ApplicationsInWork!.Work))
.ForMember(d => d.Host, o => o.MapFrom(s => s.Host))
.ForMember(d => d.Process, o => o.MapFrom(s => s.ApplicationsInWork!.Work!.Tnk!.Subprocess!.Process))
.ForMember(d => d.Subprocess, o => o.MapFrom(s => s.ApplicationsInWork!.Work!.Tnk!.Subprocess))
.ForMember(d => d.Tnk, o => o.MapFrom(s => s.ApplicationsInWork!.Work!.Tnk))
.ForMember(d => d.ShortDescription, o => o.MapFrom(s => s.ApplicationsInWork!.ShortDescription))
.ForMember(d => d.FullDescription, o => o.MapFrom(s => s.ApplicationsInWork!.FullDescription))
.ForMember(d => d.Solution, o => o.MapFrom(s => s.ApplicationsInWork!.Solution))
.ForMember(d => d.TemplateDuration, o => o.MapFrom(s => s.ApplicationsInWork!.TemplateDuration))
.ForMember(d => d.Job, o => o.MapFrom(s => s.Job))
.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))
.ForMember(d => d.ShortDescription, o => o.MapFrom(s => s.Job!.Group!.ShortDescription))
.ForMember(d => d.FullDescription, o => o.MapFrom(s => s.Job!.Group!.FullDescription))
.ForMember(d => d.Solution, o => o.MapFrom(s => s.Job!.Group!.Solution))
.ForMember(d => d.TemplateDuration, o => o.MapFrom(s => s.Job!.Group!.TemplateDuration))
.ForMember(d => d.Initiator, o => o.MapFrom<TemplateInitiatorResolver>())
.ForMember(d => d.ClosingCode, o => o.MapFrom<TemplateClosingCodeResolver>())
.ForMember(d => d.Category, o => o.MapFrom<TemplateCategoryResolver>())
.ForMember(d => d.SyncStatus, o => o.MapFrom(s => s.RobotConfigurations.OrderBy(t => t.RobotCode)))
.ForMember(d => d.Schedule, o => o.MapFrom<TemplateScheduleResolver>())
.ForMember(d => d.Agent, o => o.MapFrom(s => s.ApplicationsInWork))
.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.ApplicationsInWork!.IsAutoDistributionEnabled));
.ForMember(d => d.IsAutoDistributionEnabled, o => o.MapFrom(s => s.Job!.Group!.IsAutoDistributionEnabled));
// === Template ===
@@ -156,36 +157,36 @@ namespace PARR.API.MappingProfiles
CreateMap<RobotConfiguration, RobotTaskTemplateResponse>()
.ForMember(d => d.IsActive, o => o.MapFrom(s => s.Template!.IsActiveTemplate))
.ForMember(d => d.ClosingCode, o => o.MapFrom<RobotTaskTemplateClosingCodeResolver>())
.ForMember(d => d.FullDescription, o => o.MapFrom(s => s.Template!.ApplicationsInWork!.FullDescription))
.ForMember(d => d.ShortDescription, o => o.MapFrom(s => s.Template!.ApplicationsInWork!.ShortDescription.ApplyShortcode(ShortcodeEnum.EK, s.Template!.Host!.Ek)))
.ForMember(d => d.Solution, o => o.MapFrom(s => s.Template!.ApplicationsInWork!.Solution))
.ForMember(d => d.FullDescription, o => o.MapFrom(s => s.Template!.Job!.Group!.FullDescription))
.ForMember(d => d.ShortDescription, o => o.MapFrom(s => s.Template!.Job!.Group!.ShortDescription.ApplyShortcode(ShortcodeEnum.EK, s.Template!.Unit!.Name)))
.ForMember(d => d.Solution, o => o.MapFrom(s => s.Template!.Job!.Group!.Solution))
//.ForMember(d => d.ResponseArea, o => o.MapFrom(s => s.Template!.Host!.ResponseArea!.Name))
//ЗО берем у группы а не у хоста
.ForMember(d => d.ResponseArea, o => o.MapFrom(s => s.Template!.Host!.WorkGroup!.ResponseArea!.Name))
.ForMember(d => d.TemplateDuration, o => o.MapFrom(s => s.Template!.ApplicationsInWork!.TemplateDuration))
.ForMember(d => d.ResponseArea, o => o.MapFrom(s => s.Template!.Unit.BaseFields.ResponseArea))
.ForMember(d => d.TemplateDuration, o => o.MapFrom(s => s.Template!.Job!.Group!.TemplateDuration))
.ForMember(d => d.Initiator, o => o.MapFrom<RobotTaskTemplateInitiatorResolver>())
.ForMember(d => d.Category, o => o.MapFrom<RobotTaskTemplateCategoryResolver>())
.ForMember(d => d.WorkGroup, o => o.MapFrom(s => s.Template!.Host!.WorkGroup!.Name))
.ForMember(d => d.Ek, o => o.MapFrom(s => s.Template!.Host!.Ek))
.ForMember(d => d.WorkGroup, o => o.MapFrom(s => s.Template!.Unit.BaseFields.WorkGroup))
.ForMember(d => d.Ek, o => o.MapFrom(s => s.Template!.Unit.Name))
.ForMember(d => d.Name, o => o.MapFrom(s => s.Template!.Name))
.ForMember(d => d.ProcessName, o => o.MapFrom(s => s.Template!.ApplicationsInWork!.Work!.Tnk!.Subprocess!.Process!.Name))
.ForMember(d => d.ProcessEsppId, o => o.MapFrom(s => s.Template!.ApplicationsInWork!.Work!.Tnk!.Subprocess!.Process!.EsppId))
.ForMember(d => d.SubprocessName, o => o.MapFrom(s => s.Template!.ApplicationsInWork!.Work!.Tnk!.Subprocess!.Name))
.ForMember(d => d.SubprocessEsppId, o => o.MapFrom(s => s.Template!.ApplicationsInWork!.Work!.Tnk!.Subprocess!.EsppId))
.ForMember(d => d.TnkName, o => o.MapFrom(s => s.Template!.ApplicationsInWork!.Work!.Tnk!.Name.ApplyShortcode(ShortcodeEnum.EK, s.Template!.Host!.Ek)))
.ForMember(d => d.TnkEsppId, o => o.MapFrom(s => s.Template!.ApplicationsInWork!.Work!.Tnk!.EsppId))
.ForMember(d => d.WorkName, o => o.MapFrom(s => s.Template!.ApplicationsInWork!.Work!.Name.ApplyShortcode(ShortcodeEnum.EK, s.Template!.Host!.Ek)))
.ForMember(d => d.WorkEsppId, o => o.MapFrom(s => s.Template!.ApplicationsInWork!.Work!.EsppId))
.ForMember(d => d.ProcessName, o => o.MapFrom(s => s.Template!.Job!.Tnk!.Subprocess!.Process!.Name))
.ForMember(d => d.ProcessEsppId, o => o.MapFrom(s => s.Template!.Job!.Tnk!.Subprocess!.Process!.EsppId))
.ForMember(d => d.SubprocessName, o => o.MapFrom(s => s.Template!.Job!.Tnk!.Subprocess!.Name))
.ForMember(d => d.SubprocessEsppId, o => o.MapFrom(s => s.Template!.Job!.Tnk!.Subprocess!.EsppId))
.ForMember(d => d.TnkName, o => o.MapFrom(s => s.Template!.Job!.Tnk!.Name.ApplyShortcode(ShortcodeEnum.EK, s.Template!.Unit!.Name)))
.ForMember(d => d.TnkEsppId, o => o.MapFrom(s => s.Template!.Job!.Tnk!.EsppId))
.ForMember(d => d.WorkName, o => o.MapFrom(s => s.Template!.Job!.Name.ApplyShortcode(ShortcodeEnum.EK, s.Template!.Unit!.Name)))
//.ForMember(d => d.WorkEsppId, o => o.MapFrom(s => s.Template!.Job!.EsppId))
.ForMember(d => d.ScheduleEsppId, o => o.MapFrom(s => s.Template!.ScheduleEsppId));
CreateMap<RobotConfiguration, RobotTaskScheduleResponse>()
.ForMember(d => d.EsppId, o => o.MapFrom(s => s.Template!.ScheduleEsppId))
.ForMember(d => d.ScheduleName, o => o.MapFrom(s => s.Template!.Name))
.ForMember(d => d.IsActive, o => o.MapFrom(s => s.Template!.IsActiveSchedule))
.ForMember(d => d.ResponseArea, o => o.MapFrom(s => s.Template!.Host!.ResponseArea!.Name))
.ForMember(d => d.ResponseArea, o => o.MapFrom(s => s.Template!.Unit!.BaseFields!.ResponseArea))
.ForMember(d => d.TemplateName, o => o.MapFrom(s => s.Template!.Name))
.ForMember(d => d.TemplateId, o => o.MapFrom(s => s.Template!.Id))
.ForMember(d => d.WorkGroup, o => o.MapFrom(s => s.Template!.Host!.WorkGroup!.Name))
.ForMember(d => d.WorkGroup, o => o.MapFrom(s => s.Template!.Unit!.BaseFields!.WorkGroup))
.ForMember(d => d.Exclude, o => o.MapFrom<RobotTaskScheduleExcludeResolver>())
.ForMember(d => d.Timezone, o => o.MapFrom<RobotTaskScheduleTimezoneResolver>())
.ForMember(d => d.RepeatRange, o => o.MapFrom<RobotTaskScheduleRepeatRangeResolver>())
@@ -195,9 +196,9 @@ namespace PARR.API.MappingProfiles
//.ForMember(d => d.NextStart, o => o.MapFrom(s => EsppScheduleHelpers.GetNextRun(s.Template!.NextRun)))
.ForMember(d => d.NextStart, o => o.MapFrom<RobotTaskScheduleNextStartResolver>())
.ForMember(d => d.ScheduleType, o => o.MapFrom(s =>
s.Template!.ApplicationsInWork!.EsppSchValues!.First()!.EsppSchTypeConfig!.EsppSchTypeSchedule!.Description))
s.Template!.Job!.Group!.EsppSchValues!.First()!.EsppSchTypeConfig!.EsppSchTypeSchedule!.Description))
.ForMember(d => d.ScheduleTypeCode, o => o.MapFrom(s =>
s.Template!.ApplicationsInWork!.EsppSchValues!.First()!.EsppSchTypeConfig!.EsppSchTypeSchedule!.Id))
s.Template!.Job!.Group!.EsppSchValues!.First()!.EsppSchTypeConfig!.EsppSchTypeSchedule!.Id))
.ForMember(d => d.Schedule, o => o.MapFrom<RobotTaskScheduleSchResolver>());
// === RobotConfiguration ===
#endregion
@@ -291,13 +292,20 @@ namespace PARR.API.MappingProfiles
CreateMap<ApplicationsInWork, ApplicationInWorkResponse>()
.ForMember(d => d.Work, o => o.MapFrom(s => s.Work))
.ForMember(d => d.TemplatesCount, o => o.MapFrom(s => s.Templates.Count()))
//.ForMember(d => d.TemplatesCount, o => o.MapFrom(s => s.Templates.Count()))
.ForMember(d => d.Schedule, o => o.MapFrom<ApplicationInWorkScheduleResolver>())
.ForMember(d => d.WorkGroups, o => o.MapFrom(s => s.WorkGroups.OrderBy(t => t.WorkGroup.Name).Select(t => t.WorkGroup)))
.ForMember(d => d.WorkGroups, o => o.MapFrom(s => s.WorkGroups.OrderBy(t => t.WorkGroup!.Name).Select(t => t.WorkGroup)))
.ForMember(d => d.AutoControl, o => o.MapFrom(s => s.JobAutoControl));
#endregion
#region Job
CreateMap<Job, JobBaseResponse>()
.Include<Job, JobResponse>();
CreateMap<Job, JobResponse>();
#endregion
#region JobAutoControl
CreateMap<JobAutoControl, JobAutoControlBaseResponse>()
@@ -306,7 +314,7 @@ namespace PARR.API.MappingProfiles
CreateMap<JobAutoControl, JobAutoControlResponse>()
.ForMember(d => d.EkMasks, o => o.MapFrom(s => s.JobEkMasks.OrderBy(t => t.Name)))
.ForMember(d => d.EnabledEkStatuses, o => o.MapFrom(s => s.JobAutoControlInEkStatuses.Select(t => t.EkStatus).OrderBy(t => t.Name)))
.ForMember(d => d.WorkGroups, o => o.MapFrom(s => s.ApplicationsInWork.WorkGroups.Select(t => t.WorkGroup).OrderBy(t => t.Name)));
.ForMember(d => d.WorkGroups, o => o.MapFrom(s => s.ApplicationsInWork!.WorkGroups.Select(t => t.WorkGroup).OrderBy(t => t.Name)));
#endregion

View File

@@ -26,7 +26,7 @@ namespace PARR.API.MappingProfiles.Resolvers
public List<RobotTaskScheduleSchResponse>? Resolve(RobotConfiguration source, RobotTaskScheduleResponse destination, List<RobotTaskScheduleSchResponse>? destMember, ResolutionContext context)
{
var appInWorksId = source.Template!.ApplicationInWorkId;
var appInWorksId = source.Template!.JobId;
var schedule = esppConfigService.GetEsppScheduleDto(appInWorksId);
@@ -45,7 +45,7 @@ namespace PARR.API.MappingProfiles.Resolvers
}).OrderBy(t => t.Order).ToList();
//Если задача относится к распределенной модели исполнения за период месяц устанавливаем день равный NextRun
if (source.Template!.ApplicationsInWork!.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);

View File

@@ -28,11 +28,11 @@ namespace PARR.API.MappingProfiles.Resolvers
public EsppScheduleResponse? Resolve(Template source, TemplateResponse destination, EsppScheduleResponse? destMember, ResolutionContext context)
{
var schedule = esppConfigService.GetEsppScheduleDto(source.ApplicationInWorkId);
var schedule = esppConfigService.GetEsppScheduleDto(source.Job!.GroupId);
if (schedule == null)
{
logger.LogError($"TemplateScheduleResolver: Не смог замапить расписание для робота, так как оно null. appInWorksId: {source.ApplicationInWorkId}");
logger.LogError($"TemplateScheduleResolver: Не смог замапить расписание для робота, так как оно null. appInWorksId: {source.Job!.GroupId}");
return null;
}

View File

@@ -91,7 +91,11 @@ namespace PARR.DAL.Context
public DbSet<Job> Jobs { get; set; }
public DbSet<JobUnitFilter> JobDetails { get; set; }
public DbSet<JobUnitFilter> JobUnitFilters { get; set; }
public DbSet<JobGroup> JobGroups { get; set; }
#endregion

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,192 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace PARR.DAL.Migrations
{
/// <inheritdoc />
public partial class tblTemplatesMigrationFormApplicationInWork : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_EsppSchValues_ApplicationsInWorks_ApplicationsInWorkId",
table: "EsppSchValues");
migrationBuilder.DropForeignKey(
name: "FK_Templates_ApplicationsInWorks_ApplicationInWorkId",
table: "Templates");
migrationBuilder.DropForeignKey(
name: "FK_Templates_Hosts_HostId",
table: "Templates");
migrationBuilder.DropIndex(
name: "IX_Templates_ApplicationInWorkId",
table: "Templates");
migrationBuilder.DropIndex(
name: "IX_Templates_HostId",
table: "Templates");
migrationBuilder.DropColumn(
name: "ApplicationInWorkId",
table: "Templates");
migrationBuilder.DropColumn(
name: "HostId",
table: "Templates");
migrationBuilder.RenameColumn(
name: "Duration",
schema: "job",
table: "Groups",
newName: "TemplateDuration");
migrationBuilder.RenameColumn(
name: "ApplicationsInWorkId",
table: "EsppSchValues",
newName: "JobGroupId");
migrationBuilder.AddColumn<string>(
name: "AgentName",
schema: "job",
table: "Groups",
type: "text",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "AgentScript",
schema: "job",
table: "Groups",
type: "text",
nullable: true);
migrationBuilder.AddColumn<int>(
name: "AgentTimeOutSec",
schema: "job",
table: "Groups",
type: "integer",
nullable: true);
migrationBuilder.AddColumn<bool>(
name: "IsAgent",
schema: "job",
table: "Groups",
type: "boolean",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<bool>(
name: "IsAutoDistributionEnabled",
schema: "job",
table: "Groups",
type: "boolean",
nullable: false,
defaultValue: false);
migrationBuilder.AddForeignKey(
name: "FK_EsppSchValues_Groups_JobGroupId",
table: "EsppSchValues",
column: "JobGroupId",
principalSchema: "job",
principalTable: "Groups",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_EsppSchValues_Groups_JobGroupId",
table: "EsppSchValues");
migrationBuilder.DropColumn(
name: "AgentName",
schema: "job",
table: "Groups");
migrationBuilder.DropColumn(
name: "AgentScript",
schema: "job",
table: "Groups");
migrationBuilder.DropColumn(
name: "AgentTimeOutSec",
schema: "job",
table: "Groups");
migrationBuilder.DropColumn(
name: "IsAgent",
schema: "job",
table: "Groups");
migrationBuilder.DropColumn(
name: "IsAutoDistributionEnabled",
schema: "job",
table: "Groups");
migrationBuilder.RenameColumn(
name: "TemplateDuration",
schema: "job",
table: "Groups",
newName: "Duration");
migrationBuilder.RenameColumn(
name: "JobGroupId",
table: "EsppSchValues",
newName: "ApplicationsInWorkId");
migrationBuilder.AddColumn<Guid>(
name: "ApplicationInWorkId",
table: "Templates",
type: "uuid",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));
migrationBuilder.AddColumn<Guid>(
name: "HostId",
table: "Templates",
type: "uuid",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"));
migrationBuilder.CreateIndex(
name: "IX_Templates_ApplicationInWorkId",
table: "Templates",
column: "ApplicationInWorkId");
migrationBuilder.CreateIndex(
name: "IX_Templates_HostId",
table: "Templates",
column: "HostId");
migrationBuilder.AddForeignKey(
name: "FK_EsppSchValues_ApplicationsInWorks_ApplicationsInWorkId",
table: "EsppSchValues",
column: "ApplicationsInWorkId",
principalTable: "ApplicationsInWorks",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_Templates_ApplicationsInWorks_ApplicationInWorkId",
table: "Templates",
column: "ApplicationInWorkId",
principalTable: "ApplicationsInWorks",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_Templates_Hosts_HostId",
table: "Templates",
column: "HostId",
principalTable: "Hosts",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
}
}

View File

@@ -1477,7 +1477,7 @@ namespace PARR.DAL.Migrations
modelBuilder.Entity("PARR.DAL.Models.EsppSchValue", b =>
{
b.Property<Guid>("ApplicationsInWorkId")
b.Property<Guid>("JobGroupId")
.HasColumnType("uuid");
b.Property<Guid>("TypeValueId")
@@ -1486,7 +1486,7 @@ namespace PARR.DAL.Migrations
b.Property<Guid>("TypeConfigId")
.HasColumnType("uuid");
b.HasKey("ApplicationsInWorkId", "TypeValueId", "TypeConfigId");
b.HasKey("JobGroupId", "TypeValueId", "TypeConfigId");
b.HasIndex("TypeConfigId");
@@ -1629,16 +1629,21 @@ namespace PARR.DAL.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("AgentName")
.HasColumnType("text");
b.Property<string>("AgentScript")
.HasColumnType("text");
b.Property<int?>("AgentTimeOutSec")
.HasColumnType("integer");
b.Property<DateTimeOffset>("DateCreated")
.HasColumnType("timestamp with time zone");
b.Property<DateTimeOffset?>("DateModified")
.HasColumnType("timestamp with time zone");
b.Property<string>("Duration")
.IsRequired()
.HasColumnType("text");
b.Property<string>("FullDescription")
.IsRequired()
.HasColumnType("text");
@@ -1647,6 +1652,12 @@ namespace PARR.DAL.Migrations
.IsRequired()
.HasColumnType("text");
b.Property<bool>("IsAgent")
.HasColumnType("boolean");
b.Property<bool>("IsAutoDistributionEnabled")
.HasColumnType("boolean");
b.Property<bool?>("IsUmbrella")
.HasColumnType("boolean");
@@ -1661,6 +1672,10 @@ namespace PARR.DAL.Migrations
.IsRequired()
.HasColumnType("text");
b.Property<string>("TemplateDuration")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Groups", "job", t =>
@@ -2559,18 +2574,12 @@ namespace PARR.DAL.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<Guid>("ApplicationInWorkId")
.HasColumnType("uuid");
b.Property<DateTimeOffset>("DateCreated")
.HasColumnType("timestamp with time zone");
b.Property<DateTimeOffset?>("DateModified")
.HasColumnType("timestamp with time zone");
b.Property<Guid>("HostId")
.HasColumnType("uuid");
b.Property<string>("InitiatorComment")
.HasColumnType("text");
@@ -2607,10 +2616,6 @@ namespace PARR.DAL.Migrations
b.HasKey("Id");
b.HasIndex("ApplicationInWorkId");
b.HasIndex("HostId");
b.HasIndex("JobId");
b.HasIndex("Name")
@@ -3143,9 +3148,9 @@ namespace PARR.DAL.Migrations
modelBuilder.Entity("PARR.DAL.Models.EsppSchValue", b =>
{
b.HasOne("PARR.DAL.Models.ApplicationsInWork", "ApplicationsInWork")
b.HasOne("PARR.DAL.Models.Job.JobGroup", "JobGroup")
.WithMany("EsppSchValues")
.HasForeignKey("ApplicationsInWorkId")
.HasForeignKey("JobGroupId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
@@ -3161,11 +3166,11 @@ namespace PARR.DAL.Migrations
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ApplicationsInWork");
b.Navigation("EsppSchTypeConfig");
b.Navigation("EsppSchTypeValue");
b.Navigation("JobGroup");
});
modelBuilder.Entity("PARR.DAL.Models.Host", b =>
@@ -3215,7 +3220,7 @@ namespace PARR.DAL.Migrations
modelBuilder.Entity("PARR.DAL.Models.Job.Job", b =>
{
b.HasOne("PARR.DAL.Models.Job.JobGroup", "Group")
.WithMany("Job")
.WithMany("Jobs")
.HasForeignKey("GroupId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
@@ -3381,18 +3386,6 @@ namespace PARR.DAL.Migrations
modelBuilder.Entity("PARR.DAL.Models.Template", b =>
{
b.HasOne("PARR.DAL.Models.ApplicationsInWork", "ApplicationsInWork")
.WithMany("Templates")
.HasForeignKey("ApplicationInWorkId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("PARR.DAL.Models.Host", "Host")
.WithMany("Templates")
.HasForeignKey("HostId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("PARR.DAL.Models.Job.Job", "Job")
.WithMany()
.HasForeignKey("JobId")
@@ -3400,15 +3393,11 @@ namespace PARR.DAL.Migrations
.IsRequired();
b.HasOne("PARR.DAL.Models.Unit.Unit", "Unit")
.WithMany()
.WithMany("Templates")
.HasForeignKey("UnitId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("ApplicationsInWork");
b.Navigation("Host");
b.Navigation("Job");
b.Navigation("Unit");
@@ -3580,12 +3569,8 @@ namespace PARR.DAL.Migrations
modelBuilder.Entity("PARR.DAL.Models.ApplicationsInWork", b =>
{
b.Navigation("EsppSchValues");
b.Navigation("JobAutoControl");
b.Navigation("Templates");
b.Navigation("WorkGroups");
});
@@ -3631,8 +3616,6 @@ namespace PARR.DAL.Migrations
modelBuilder.Entity("PARR.DAL.Models.Host", b =>
{
b.Navigation("ApplicationsInHosts");
b.Navigation("Templates");
});
modelBuilder.Entity("PARR.DAL.Models.Job.Job", b =>
@@ -3642,7 +3625,9 @@ namespace PARR.DAL.Migrations
modelBuilder.Entity("PARR.DAL.Models.Job.JobGroup", b =>
{
b.Navigation("Job");
b.Navigation("EsppSchValues");
b.Navigation("Jobs");
});
modelBuilder.Entity("PARR.DAL.Models.Job.JobUnitFilter", b =>
@@ -3740,6 +3725,8 @@ namespace PARR.DAL.Migrations
b.Navigation("ParentUnits");
b.Navigation("Templates");
b.Navigation("UnitFields");
b.Navigation("UnitValues");

View File

@@ -111,9 +111,9 @@ namespace PARR.DAL.Models
[ForeignKey(nameof(ApplicationId))]
public Application? Application { get; set; }
public ICollection<Template> Templates { get; set; } = new HashSet<Template>();
// public ICollection<Template> Templates { get; set; } = new HashSet<Template>();
public ICollection<EsppSchValue> EsppSchValues { get; set; } = new HashSet<EsppSchValue>();
//public ICollection<EsppSchValue> EsppSchValues { get; set; } = new HashSet<EsppSchValue>();
public ICollection<AppInWorkInWorkGroup> WorkGroups { get; set; } = new HashSet<AppInWorkInWorkGroup>();

View File

@@ -1,4 +1,5 @@
using Microsoft.EntityFrameworkCore;
using PARR.DAL.Models.Job;
using System.ComponentModel.DataAnnotations.Schema;
namespace PARR.DAL.Models
@@ -8,22 +9,28 @@ namespace PARR.DAL.Models
/// </summary>
[Table("EsppSchValues")]
//[Index(nameof(ApplicationsInWorkId), nameof(TypeValueId), nameof(TypeConfigId), IsUnique = true)]
[PrimaryKey(nameof(ApplicationsInWorkId), nameof(TypeValueId), nameof(TypeConfigId))]
//[PrimaryKey(nameof(ApplicationsInWorkId), nameof(TypeValueId), nameof(TypeConfigId))]
[PrimaryKey(nameof(JobGroupId), nameof(TypeValueId), nameof(TypeConfigId))]
public class EsppSchValue
{
public Guid ApplicationsInWorkId { get; set; }
//public Guid ApplicationsInWorkId { get; set; }
public Guid TypeValueId { get; set; }
public Guid TypeConfigId { get; set; }
[ForeignKey(nameof(ApplicationsInWorkId))]
public ApplicationsInWork? ApplicationsInWork { get; set; }
public Guid JobGroupId { get; set; }
//[ForeignKey(nameof(ApplicationsInWorkId))]
//public ApplicationsInWork? ApplicationsInWork { get; set; }
[ForeignKey(nameof(TypeValueId))]
public EsppSchTypeValue? EsppSchTypeValue { get; set; }
[ForeignKey(nameof(TypeConfigId))]
public EsppSchTypeConfig? EsppSchTypeConfig { get; set; }
[ForeignKey(nameof(JobGroupId))]
public JobGroup? JobGroup { get; set; }
}
}

View File

@@ -43,7 +43,7 @@ namespace PARR.DAL.Models
public ICollection<ApplicationInHost> ApplicationsInHosts { get; set; } = new HashSet<ApplicationInHost>();
public ICollection<Template> Templates { get; set; } = new HashSet<Template>();
//public ICollection<Template> Templates { get; set; } = new HashSet<Template>();
[ForeignKey(nameof(EkStatusCode))]

View File

@@ -45,14 +45,61 @@ namespace PARR.DAL.Models.Job
/// <summary>
/// Поле Длительность описания шаблона АСУ ЕСПП
/// </summary>
public required string Duration { get; set; }
public required string TemplateDuration { get; set; }
/// <summary>
/// TemplateDuration в формате TimeSpan
/// </summary>
public TimeSpan? TemplateDurationTimeSpan
{
get
{
try
{
//ЕСПП кривоногие, они почему-то таймспан пишут так "7 00:00:00", а правильно так: "7:00:00:00"
var durationWithTimeSpanFormat = TemplateDuration.Replace(" ", ":");
return TimeSpan.Parse(durationWithTimeSpanFormat);
}
catch
{
return null;
}
}
}
/// <summary>
/// Дата начала работ или дата для отсчёта периода следующего выполнения
/// </summary>
public DateTimeOffset ReferenceDate { get; set; }
/// <summary>
/// Включить автораспределение
/// </summary>
public bool IsAutoDistributionEnabled { get; set; }
public ICollection<Job> Job { get; set; } = new HashSet<Job>();
/// <summary>
/// Выполняет агент
/// </summary>
public bool IsAgent { get; set; }
/// <summary>
/// Какое-то имя которое мы передаем агенту, пока непонятно что это такое.
/// </summary>
public string? AgentName { get; set; }
/// <summary>
/// Сколько времени ожидать выполнение скрипта агентом (секунд)
/// </summary>
public int? AgentTimeOutSec { get; set; }
/// <summary>
/// Скрипт для автоматического выполнения
/// </summary>
public string? AgentScript { get; set; }
public ICollection<Job> Jobs { get; set; } = new HashSet<Job>();
public ICollection<EsppSchValue> EsppSchValues { get; set; } = new HashSet<EsppSchValue>();
}
}

View File

@@ -48,13 +48,13 @@ namespace PARR.DAL.Models
public DateTimeOffset NextRun { get; set; }
public Guid ApplicationInWorkId { get; set; }
//public Guid ApplicationInWorkId { get; set; }
public Guid JobId { get; set; }//TODO Вернуть не NULL!!!
public Guid UnitId { get; set; }//TODO Вернуть не NULL!!!
public Guid HostId { get; set; }
//public Guid HostId { get; set; }
#region Initiator
public string? InitiatorIp { get; set; }
@@ -64,11 +64,11 @@ namespace PARR.DAL.Models
public string? InitiatorComment { get; set; }
#endregion
[ForeignKey(nameof(ApplicationInWorkId))]
public ApplicationsInWork? ApplicationsInWork { get; set; }
//[ForeignKey(nameof(ApplicationInWorkId))]
//public ApplicationsInWork? ApplicationsInWork { get; set; }
[ForeignKey(nameof(HostId))]
public Host? Host { get; set; }
//[ForeignKey(nameof(HostId))]
//public Host? Host { get; set; }
[ForeignKey(nameof(JobId))]
public Job.Job? Job { get; set; }

View File

@@ -28,6 +28,28 @@ namespace PARR.DAL.Models.Unit
// todo: добавить еще поля??? (которые есть у всех ЭК)
[NotMapped]
public BaseFields? BaseFields
{
get
{
if (UnitValues.Any())
{
var result = new BaseFields();
result.IP = UnitValues.FirstOrDefault(t => t.Field?.AihitName == "IP_АДРЕС")?.Value?.Value;
result.ResponseArea = UnitValues.FirstOrDefault(t => t.Field?.AihitName == "ЗО_РГ")?.Value?.Value;
result.WorkGroup = UnitValues.FirstOrDefault(t => t.Field?.AihitName == "РАБОЧАЯ_ГР_ОТВ_ЗАК")?.Value?.Value;
result.Status = UnitValues.FirstOrDefault(t => t.Field?.AihitName == "СТАТУС")?.Value?.Value;
return result;
}
return null;
}
}
public ICollection<UnitInField> UnitFields { get; set; } = new HashSet<UnitInField>();
public ICollection<UnitInValue> UnitValues { get; set; } = new HashSet<UnitInValue>();
@@ -44,5 +66,19 @@ namespace PARR.DAL.Models.Unit
/// </summary>
[InverseProperty(nameof(UnitInUnit.ParentUnit))]
public ICollection<UnitInUnit> ChildUnits { get; set; } = new HashSet<UnitInUnit>();
public ICollection<Template> Templates { get; set; } = new HashSet<Template>();
}
public class BaseFields
{
public string? IP { get; set; }
public string? ResponseArea { get; set; }
public string? WorkGroup { get; set; }
public string? Status { get; set; }
}
}

View File

@@ -105,8 +105,10 @@ namespace PARR.DAL
#region Job
services.AddTransient<IJobService, JobService>();
services.AddTransient<IJobDetailsService, JobDetailsService>();
services.AddTransient<IJobGroupService, JobGroupService>();
services.AddTransient<IJobUnitFilterService, JobUnitFilterService>();
services.AddTransient<IFieldFilterService, FieldFilterService>();
services.AddTransient<IJobUnitFilterService, JobUnitFilterService>();
#endregion

View File

@@ -31,17 +31,27 @@ namespace PARR.DAL.Services.Implementations
.ThenInclude(t => t!.EsppSchValues);
}
public async Task<EsppScheduleDto?> GetEsppScheduleDtoAsync(Guid applicationInWorksId)
public async Task<EsppScheduleDto?> GetEsppScheduleDtoAsync(Guid jobGroupId)
{
//Формирует расписание в нормальном понятном виде из БД
var test = await dataContext.EsppSchValues
//.Include(t => t.JobGroup)
//.Include(t => t.EsppSchTypeConfig)
// .ThenInclude(t => t!.EsppSchTypeSchedule)
//.Include(t => t.EsppSchTypeConfig)
// .ThenInclude(t => t.EsppSchType)
//.Include(t => t.EsppSchTypeValue)
.ToListAsync();
var schValues = await dataContext.EsppSchValues
.Include(t => t.EsppSchTypeConfig)
.ThenInclude(t => t!.EsppSchTypeSchedule)
.Include(t => t.EsppSchTypeConfig)
.ThenInclude(t=>t.EsppSchType)
.ThenInclude(t => t.EsppSchType)
.Include(t => t.EsppSchTypeValue)
.Where(t => t.ApplicationsInWorkId == applicationInWorksId)
.Include(t => t.JobGroup)
.Where(t => t.JobGroup!.Id == jobGroupId)//TODO Migration to job
.OrderBy(t => t.EsppSchTypeConfig!.Order)
.ToListAsync();
@@ -94,11 +104,11 @@ namespace PARR.DAL.Services.Implementations
return dto;
}
public EsppScheduleDto? GetEsppScheduleDto(Guid applicationInWorksId)
public EsppScheduleDto? GetEsppScheduleDto(Guid jobGroupId)
{
var result = Task.Run(async () =>
{
return await GetEsppScheduleDtoAsync(applicationInWorksId);
return await GetEsppScheduleDtoAsync(jobGroupId);
}).Result;
return result;

View File

@@ -7,15 +7,15 @@ using PARR.DAL.Services.Interfaces.Job;
namespace PARR.DAL.Services.Implementations.Job
{
internal class JobDetailsService : BaseService<Models.Job.JobUnitFilter>, IJobDetailsService
internal class JobUnitFilterService : BaseService<JobUnitFilter>, IJobUnitFilterService
{
private readonly DataContext dataContext;
protected override DbSet<JobUnitFilter> EntitySet => dataContext.JobDetails;
protected override DbSet<JobUnitFilter> EntitySet => dataContext.JobUnitFilters;
protected override DataContext EntitiContext => dataContext;
public JobDetailsService(DataContext dataContext, ILogger<JobDetailsService> logger) : base(logger)
public JobUnitFilterService(DataContext dataContext, ILogger<JobUnitFilterService> logger) : base(logger)
{
this.dataContext = dataContext;
}

View File

@@ -0,0 +1,22 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using PARR.DAL.Context;
using PARR.DAL.Models.Job;
using PARR.DAL.Services.Abstracts;
using PARR.DAL.Services.Interfaces.Job;
namespace PARR.DAL.Services.Implementations.Job
{
internal class JobGroupService : BaseService<Models.Job.JobGroup>, IJobGroupService
{
private readonly DataContext dataContext;
public JobGroupService(DataContext dataContext, ILogger<JobGroupService> logger) : base(logger)
{
this.dataContext = dataContext;
}
protected override DbSet<JobGroup> EntitySet => dataContext.JobGroups;
protected override DataContext EntitiContext => dataContext;
}
}

View File

@@ -34,18 +34,24 @@ namespace PARR.DAL.Services.Implementations
public IQueryable<Template> GetWithIncludes()
{
return Get()
.Include(h => h.Host)
.ThenInclude(t => t!.ResponseArea)
.Include(h => h.Host)
.ThenInclude(t => t!.WorkGroup)
.ThenInclude(t => t!.ResponseArea)
.Include(h => h.Host)
.ThenInclude(t => t!.EkStatus)
.Include(a => a.ApplicationsInWork)
.ThenInclude(w => w!.Work)
.Include(h => h.Unit)
.Include(a => a.Job)
.ThenInclude(t => t!.Tnk)
.ThenInclude(s => s!.Subprocess)
.ThenInclude(p => p!.Process);
//return Get()
// .Include(h => h.Host)
// .ThenInclude(t => t!.ResponseArea)
// .Include(h => h.Host)
// .ThenInclude(t => t!.WorkGroup)
// .ThenInclude(t => t!.ResponseArea)
// .Include(h => h.Host)
// .ThenInclude(t => t!.EkStatus)
// .Include(a => a.ApplicationsInWork)
// .ThenInclude(w => w!.Work)
// .ThenInclude(t => t!.Tnk)
// .ThenInclude(s => s!.Subprocess)
// .ThenInclude(p => p!.Process);
}
public override Task<bool> CreateAsync(Template obj)

View File

@@ -18,5 +18,15 @@ namespace PARR.DAL.Services.Implementations.Unit
{
this.dataContext = dataContext;
}
public IQueryable<Models.Unit.Unit> GetWithIncludes()
{
return Get()
.Include(t => t.UnitValues)
.ThenInclude(t => t.Field)
.Include(t => t.UnitValues)
.ThenInclude(t => t.Value);
}
}
}

View File

@@ -9,16 +9,16 @@ namespace PARR.DAL.Services.Interfaces
/// <summary>
/// Формирует расписание в нормальном понятном виде из БД синхронно
/// </summary>
/// <param name="applicationInWorksId"></param>
/// <param name="jobGroupId"></param>
/// <returns></returns>
EsppScheduleDto? GetEsppScheduleDto(Guid applicationInWorksId);
EsppScheduleDto? GetEsppScheduleDto(Guid jobGroupId);
/// <summary>
/// Формирует расписание в нормальном понятном виде из БД асинхронно
/// </summary>
/// <param name="applicationInWorksId"></param>
/// <param name="jobGroupId"></param>
/// <returns></returns>
Task<EsppScheduleDto?> GetEsppScheduleDtoAsync(Guid applicationInWorksId);
Task<EsppScheduleDto?> GetEsppScheduleDtoAsync(Guid jobGroupId);
IQueryable<EsppSchTypeConfig> GetWithSchIncludes();
}

View File

@@ -2,7 +2,7 @@
namespace PARR.DAL.Services.Interfaces.Job
{
public interface IJobDetailsService : IBaseService<Models.Job.JobUnitFilter>
public interface IJobUnitFilterService : IBaseService<Models.Job.JobUnitFilter>
{
}
}

View File

@@ -0,0 +1,8 @@
using PARR.DAL.Services.Interfaces.Base;
namespace PARR.DAL.Services.Interfaces.Job
{
public interface IJobGroupService : IBaseService<Models.Job.JobGroup>
{
}
}

View File

@@ -4,5 +4,6 @@ namespace PARR.DAL.Services.Interfaces.Unit
{
public interface IUnitService : IBaseService<Models.Unit.Unit>
{
IQueryable<Models.Unit.Unit> GetWithIncludes();
}
}

View File

@@ -6,6 +6,7 @@ using PARR.DAL.Contracts;
using PARR.DAL.DomainModels;
using PARR.DAL.Extensions;
using PARR.DAL.Services.Interfaces;
using PARR.DAL.Services.Interfaces.Job;
namespace PARR.DAL.TransformServices
{
@@ -15,6 +16,7 @@ namespace PARR.DAL.TransformServices
private readonly IApplicationsInWorkService applicationsInWorkService;
private readonly IWeekendDayService weekendDayService;
private readonly INextRunModifierService nextRunModifierService;
private readonly IJobGroupService jobGroupService;
private readonly ILogger<EsppScheduleTransformService> logger;
private readonly Dictionary<string, int> monthDict = new Dictionary<string, int>()
@@ -59,13 +61,15 @@ namespace PARR.DAL.TransformServices
IEsppSchTypeConfigService esppSchTypeConfigService,
IApplicationsInWorkService applicationsInWorkService,
IWeekendDayService weekendDayService,
INextRunModifierService nextRunModifierService
INextRunModifierService nextRunModifierService,
IJobGroupService jobGroupService
)
{
this.esppSchTypeConfigService = esppSchTypeConfigService;
this.applicationsInWorkService = applicationsInWorkService;
this.weekendDayService = weekendDayService;
this.nextRunModifierService = nextRunModifierService;
this.jobGroupService = jobGroupService;
this.logger = logger;
}
@@ -157,23 +161,28 @@ namespace PARR.DAL.TransformServices
}
public async Task<DateTimeOffset> GetNextDateAsync(Guid applicationInWorkId, DateTimeOffset lastRun)
public async Task<DateTimeOffset> GetNextDateAsync(Guid jobGroupId, DateTimeOffset lastRun)
{
//если больше текущего вернуть lastRun. Это и есть следующая дата
if (lastRun > DateTimeOffset.UtcNow)
return await nextRunModifierService.GetWorkDayAsync(lastRun);
var appInWork = await applicationsInWorkService.Get()
.Include(aiw => aiw.EsppSchValues)
//var appInWork = await applicationsInWorkService.Get()
// .Include(aiw => aiw.EsppSchValues)
// .ThenInclude(esv => esv.EsppSchTypeValue)
// .ThenInclude(etv => etv!.DistributionPeriod)
// .FirstOrDefaultAsync(t => t.Id == applicationInWorkId);
var jobGroup = await jobGroupService.Get()
.Include(t=>t.EsppSchValues)
.ThenInclude(esv => esv.EsppSchTypeValue)
.ThenInclude(etv => etv!.DistributionPeriod)
.FirstOrDefaultAsync(t => t.Id == applicationInWorkId);
.FirstOrDefaultAsync(t => t.Id == jobGroupId);
var esppSchedule = await GetEsppScheduleAsync(applicationInWorkId);
var esppSchedule = await GetEsppScheduleAsync(jobGroupId);
if (appInWork!.IsAutoDistributionEnabled)
if (jobGroup!.IsAutoDistributionEnabled)
{
var period = appInWork.EsppSchValues.FirstOrDefault()?.EsppSchTypeValue?.DistributionPeriod;
var period = jobGroup.EsppSchValues.FirstOrDefault()?.EsppSchTypeValue?.DistributionPeriod;
var periodType = ParseDistributionPeriodType(period!.Type);
return GetNextDateForDistributionRun(lastRun, periodType, period.Duration);
@@ -183,24 +192,24 @@ namespace PARR.DAL.TransformServices
}
public async Task<List<DateTimeOffset>> GetNextScheduleAsync(Guid applicationInWorkId, DateTimeOffset lastRun)
public async Task<List<DateTimeOffset>> GetNextScheduleAsync(Guid jobGroupId, DateTimeOffset lastRun)
{
//TODO: тут не проверен переход через выходные дни!!! Переход не используется, так как тут не рассчитываем NextRun.
//В общем проверить, когда будем тестировать агента, что с датами все ок
var esppSchedule = await GetEsppScheduleAsync(applicationInWorkId);
var esppSchedule = await GetEsppScheduleAsync(jobGroupId);
var nextSchedule = GetNextSchedule(esppSchedule, lastRun);
return nextSchedule;
}
private async Task<EsppScheduleDto> GetEsppScheduleAsync(Guid applicationInWorkId)
private async Task<EsppScheduleDto> GetEsppScheduleAsync(Guid jobGroupId)
{
var esppSchedule = await esppSchTypeConfigService.GetEsppScheduleDtoAsync(applicationInWorkId);
var esppSchedule = await esppSchTypeConfigService.GetEsppScheduleDtoAsync(jobGroupId);
if (esppSchedule == null)
{
logger.LogError($"Не найдено расписание в БД, applicationInWorkId: {applicationInWorkId}");
throw new Exception($"Не найдено расписание в БД, applicationInWorkId: {applicationInWorkId}");
logger.LogError($"Не найдено расписание в БД, jobId: {jobGroupId}");
throw new Exception($"Не найдено расписание в БД, jobId: {jobGroupId}");
}
return esppSchedule;
@@ -427,9 +436,9 @@ namespace PARR.DAL.TransformServices
}
public async Task<DateOnly> GetStartPeriodForDateAsync(Guid applicationInWorkId, DateTimeOffset date, DateTimeOffset referenceDate, DistributionPeriodTypeEnum periodType, string distributionPeriod)
public async Task<DateOnly> GetStartPeriodForDateAsync(Guid jobGroupId, DateTimeOffset date, DateTimeOffset referenceDate, DistributionPeriodTypeEnum periodType, string distributionPeriod)
{
var esppSchedule = await GetEsppScheduleAsync(applicationInWorkId);
var esppSchedule = await GetEsppScheduleAsync(jobGroupId);
var currentStartPeriod = referenceDate;
var currentEndPeriod = GetNextDateForDistributionRun(currentStartPeriod, periodType, distributionPeriod);

View File

@@ -25,20 +25,20 @@ namespace PARR.DAL.TransformServices
//List<DateTimeOffset> GetNextSchedule(EsppScheduleDto esppSchedule, DateTimeOffset lastRun);
/// <summary>
/// Получить следующую дату по applicationInWorkId
/// Получить следующую дату по jobGroupId
/// </summary>
/// <param name="applicationInWorkId"></param>
/// <param name="jobGroupId"></param>
/// <param name="lastRun"></param>
/// <returns></returns>
Task<DateTimeOffset> GetNextDateAsync(Guid applicationInWorkId, DateTimeOffset lastRun);
Task<DateTimeOffset> GetNextDateAsync(Guid jobGroupId, DateTimeOffset lastRun);
/// <summary>
/// Получить расписание по applicationInWorkId
/// Получить расписание по jobGroupId
/// </summary>
/// <param name="applicationInWorkId"></param>
/// <param name="jobGroupId"></param>
/// <param name="lastRun"></param>
/// <returns></returns>
Task<List<DateTimeOffset>> GetNextScheduleAsync(Guid applicationInWorkId, DateTimeOffset lastRun);
Task<List<DateTimeOffset>> GetNextScheduleAsync(Guid jobGroupId, DateTimeOffset lastRun);
/// <summary>
@@ -54,9 +54,9 @@ namespace PARR.DAL.TransformServices
/// <summary>
/// Получить дату начала периода распределения относительно опорной даты (Reference Date)
/// </summary>
/// <param name="applicationInWorkId"></param>
/// <param name="jobGroupId"></param>
/// <param name="date"></param>
/// <returns></returns>
Task<DateOnly> GetStartPeriodForDateAsync(Guid applicationInWorkId, DateTimeOffset date, DateTimeOffset refrenceDate, DistributionPeriodTypeEnum periodType, string distributionPeriod);
Task<DateOnly> GetStartPeriodForDateAsync(Guid jobGroupId, DateTimeOffset date, DateTimeOffset refrenceDate, DistributionPeriodTypeEnum periodType, string distributionPeriod);
}
}

View File

@@ -37,7 +37,7 @@ namespace PARR.EsppOrderLoader.Services
}
var template = await templateService.Get()
.Include(t => t.ApplicationsInWork)
.Include(t => t.Job)
.FirstOrDefaultAsync(t => t.Name.ToLower() == esppOrder.TemplateName.ToLower());
if (template == null)

View File

@@ -86,7 +86,7 @@ namespace PARR.EsppOrderManager
.Include(t => t.AgentHistories).ThenInclude(t => t.AgentHistoryLevel)
.Include(t => t.OrderStatus)
.Include(t => t.NextStatus)
.Include(t => t.Template).ThenInclude(t => t!.ApplicationsInWork).ThenInclude(t => t!.Work).ThenInclude(t => t!.Tnk)
.Include(t => t.Template).ThenInclude(t => t!.Job).ThenInclude(t => t!.Tnk)
.FirstOrDefaultAsync(t => t.Id == objFromQuery.OrderId);
if (!IsValidOrder(ref order, ref objFromQuery))
@@ -162,7 +162,7 @@ namespace PARR.EsppOrderManager
var template = resultTemplateSettings.Template;
//Поле решение из ApplicationsInWork
var baseMsg = order.Template!.ApplicationsInWork!.Solution;
var baseMsg = order.Template!.Job!.Group!.Solution;
//Формируем сообщения от Агента
var msgAgent = agentHistory.Any()

View File

@@ -71,7 +71,7 @@ namespace PARR.EsppOrderManager.Services
// заполняем ТНК
var tnk = new AddMtnkQuery
{
JobOperation = order!.Template!.ApplicationsInWork!.Work!.Name,
JobOperation = order!.Template!.Job!.WorkName,
RecordId = order.Number,
Time = duration.ToString("hh\\:mm")
};

View File

@@ -86,9 +86,9 @@ namespace PARR.EsppScheduleSync
Code = template.ScheduleEsppId ?? "",
ScheduleName = template.Name,
IsActive = template.IsActiveSchedule,
ResponseArea = template.Host!.ResponseArea!.Name,
//ResponseArea = template.Host!.ResponseArea!.Name,//TODO Migration to job
//WorkGroup = template.Host!.WorkGroup!,
WorkGroup = template.Host!.WorkGroup!.Name,
//WorkGroup = template.Host!.WorkGroup!.Name,//TODO Migration to job
//Мы решили, что для всех расписаний "Нет исключений", если что-то поменяется, тут нужно переделать
TypeV60calendar = settingsFromDb.ScheduleExclude == "Нет исключений" ? "NONE" : "",
//Scheduled = EsppScheduleHelpers.GetNextRun(template.NextRun),
@@ -119,7 +119,7 @@ namespace PARR.EsppScheduleSync
if (esppSchTypeConfigService == null)
throw new Exception($"Не найден сервис: {nameof(IEsppSchTypeConfigService)}");
var esppSchedule = esppSchTypeConfigService.GetEsppScheduleDto(template.ApplicationInWorkId);
var esppSchedule = esppSchTypeConfigService.GetEsppScheduleDto(template.JobId);
if (esppSchedule == null)
{
logger.LogError($"Не смог получить расписание из БД для шаблона templateId: {template.Id}, {template.Name}");
@@ -144,16 +144,16 @@ namespace PARR.EsppScheduleSync
break;
case EsppSchTypeScheduleEnum.Monthly:
//если включено автораспределение, подставляем дату месяца из NextRun
if (template.ApplicationsInWork?.IsAutoDistributionEnabled == true)
{
var nextRunByRobotTimeZone = nextRunModifierService.GetNextRunByAccountRobotTimeZone(template.NextRun);
esppObject.Dayofmonth = nextRunByRobotTimeZone.Day.ToString();
// esppObject.Dayofmonth = template.NextRun.Day.ToString();
}
else
{
//if (template.ApplicationsInWork?.IsAutoDistributionEnabled == true)//TODO Migration to job
//{
// var nextRunByRobotTimeZone = nextRunModifierService.GetNextRunByAccountRobotTimeZone(template.NextRun);
// esppObject.Dayofmonth = nextRunByRobotTimeZone.Day.ToString();
// // esppObject.Dayofmonth = template.NextRun.Day.ToString();
//}
//else
//{
esppObject.Dayofmonth = esppSchedule.Values.First(t => t.Order == 0).Value.EsppExportValue;
}
//}
break;
case EsppSchTypeScheduleEnum.Monthly2:
esppObject.Md1 = esppSchedule.Values.First(t => t.Order == 0).Value.EsppExportValue;

View File

@@ -74,19 +74,19 @@ namespace PARR.EsppTemplateSync
TemplateName = template.Name,
IsActive = template.IsActiveTemplate,
//WorkGroup = template.Host!.WorkGroup!,
WorkGroup = template.Host!.WorkGroup!.Name,
ShortDescription = Normalize(template.ApplicationsInWork!.ShortDescription.ApplyShortcode(Constants.Shortcodes.ShortcodeEnum.EK,template.Host.Ek)),
WorkGroup = template.Unit!.BaseFields!.WorkGroup!,
ShortDescription = Normalize(template.Job.Group.ShortDescription.ApplyShortcode(Constants.Shortcodes.ShortcodeEnum.EK,template.Unit.Name)),
//ResponseArea = template.Host!.ResponseArea!.Name,
//ЗО берем РГ а не хоста
ResponseArea = template.Host!.WorkGroup!.ResponseArea!.Name,
Duration = template.ApplicationsInWork.TemplateDuration,
EK = template.Host.Ek,
FullDescription = Normalize(template.ApplicationsInWork.FullDescription),
Solution = Normalize(template.ApplicationsInWork.Solution),
Process = template.ApplicationsInWork.Work!.Tnk!.Subprocess!.Process!.Name,
SubProcess = template.ApplicationsInWork.Work.Tnk.Subprocess.Name,
TNK = template.ApplicationsInWork.Work.Tnk.Name.ApplyShortcode(Constants.Shortcodes.ShortcodeEnum.EK, template.Host.Ek),
Work = template.ApplicationsInWork.Work.Name.ApplyShortcode(Constants.Shortcodes.ShortcodeEnum.EK, template.Host.Ek),
ResponseArea = template.Unit.BaseFields.ResponseArea,
Duration = template.Job.Group.TemplateDuration,
EK = template.Unit.Name,
FullDescription = Normalize(template.Job.Group.FullDescription),
Solution = Normalize(template.Job.Group.Solution),
Process = template.Job.Tnk!.Subprocess!.Process!.Name,
SubProcess = template.Job.Tnk.Subprocess.Name,
TNK = template.Job.Tnk.Name.ApplyShortcode(Constants.Shortcodes.ShortcodeEnum.EK, template.Unit.Name),
Work = template.Job.WorkName.ApplyShortcode(Constants.Shortcodes.ShortcodeEnum.EK, template.Unit.Name),
Initiator = settingsFromDb.Initiator
};

View File

@@ -43,93 +43,94 @@ namespace PARR.GeneratorTemplates.Services
public async Task CreateTemplates(GeneratorTemplateMq query)
{
//В таблице AppInWork находим РР, и смотрим ее рабочие группы. Затем по ним будем фильтровать хосты
var appInWorkWg = await applicationsInWorkService.Get()
.Include(t => t.WorkGroups)
.FirstAsync(t => t.ApplicationId == query.ApplicationId && t.WorkId == query.WorkId);
//TODO Migratin to Job
////В таблице AppInWork находим РР, и смотрим ее рабочие группы. Затем по ним будем фильтровать хосты
//var appInWorkWg = await applicationsInWorkService.Get()
// .Include(t => t.WorkGroups)
// .FirstAsync(t => t.ApplicationId == query.ApplicationId && t.WorkId == query.WorkId);
if (!appInWorkWg.WorkGroups.Any())
{
logger.LogWarning($"Не генерирую шаблоны. Нет рабочих групп у ApplicationInWork с id: {appInWorkWg.Id}");
return;
}
//if (!appInWorkWg.WorkGroups.Any())
//{
// logger.LogWarning($"Не генерирую шаблоны. Нет рабочих групп у ApplicationInWork с id: {appInWorkWg.Id}");
// return;
//}
var workGroups = appInWorkWg.WorkGroups.ToList();
//var workGroups = appInWorkWg.WorkGroups.ToList();
//Согласно параметрам, находит все ЭК в таблице Hosts.
//Далее проверяет есть ли такие шаблоны в таблице Templates, если нет, то создает, активирует и ставит статус Creating.
//Если такие шаблоны уже есть, ничего с ними не делает.
////Согласно параметрам, находит все ЭК в таблице Hosts.
////Далее проверяет есть ли такие шаблоны в таблице Templates, если нет, то создает, активирует и ставит статус Creating.
////Если такие шаблоны уже есть, ничего с ними не делает.
string ekPattern = SqlHelpers.RegexToLike(query.Ek);
//string ekPattern = SqlHelpers.RegexToLike(query.Ek);
// список хостов для создания шаблонов
var queryHosts = hostService.Get()
//.Include(t => t.WorkGroupItem)
.Include(t => t.ApplicationsInHosts)
.ThenInclude(t => t.Application).ThenInclude(t => t!.ApplicationsInWorks).ThenInclude(w => w.Work)
.Include(t => t.Templates)
.ThenInclude(w => w.ApplicationsInWork)
.Include(t => t.ResponseArea)
.Where(t =>
t.ApplicationsInHosts.Any(h =>
h.ApplicationId == query.ApplicationId
&& h.Application!.ApplicationsInWorks.Any(w => w.WorkId == query.WorkId)
)
&& EF.Functions.Like(t.Ek.ToLower(), ekPattern)
// смотрим что нет такого шаблона
&& t.Templates.Any(templ => templ.ApplicationsInWork!.WorkId == query.WorkId && templ.ApplicationsInWork.ApplicationId == query.ApplicationId) == false
// смотрим что у этих хостов есть нужные группы
//&& workGroups.Any(x => x.WorkGroupId == t.WorkGroupId)
);
//// список хостов для создания шаблонов
//var queryHosts = hostService.Get()
// //.Include(t => t.WorkGroupItem)
// .Include(t => t.ApplicationsInHosts)
// .ThenInclude(t => t.Application).ThenInclude(t => t!.ApplicationsInWorks).ThenInclude(w => w.Work)
// .Include(t => t.Templates)
// .ThenInclude(w => w.ApplicationsInWork)
// .Include(t => t.ResponseArea)
// .Where(t =>
// t.ApplicationsInHosts.Any(h =>
// h.ApplicationId == query.ApplicationId
// && h.Application!.ApplicationsInWorks.Any(w => w.WorkId == query.WorkId)
// )
// && EF.Functions.Like(t.Ek.ToLower(), ekPattern)
// // смотрим что нет такого шаблона
// && t.Templates.Any(templ => templ.ApplicationsInWork!.WorkId == query.WorkId && templ.ApplicationsInWork.ApplicationId == query.ApplicationId) == false
// // смотрим что у этих хостов есть нужные группы
// //&& workGroups.Any(x => x.WorkGroupId == t.WorkGroupId)
// );
// статус ЭК
if (query.StatusEk > 0)
queryHosts = queryHosts.Where(t => t.EkStatusCode == query.StatusEk);
//// статус ЭК
//if (query.StatusEk > 0)
// queryHosts = queryHosts.Where(t => t.EkStatusCode == query.StatusEk);
var hosts = await queryHosts
.AsSplitQuery()
.ToListAsync();
//var hosts = await queryHosts
// .AsSplitQuery()
// .ToListAsync();
// Исключаем хосты у которых нет нужных групп
hosts = hosts.Where(t => workGroups.Any(x => x.WorkGroupId == t.WorkGroupId)).ToList();
if (!hosts.Any())
{
logger.LogInformation($"Не найдено ЭК попадающих под условие: ${JsonSerializer.Serialize(query)}");
return;
}
//// Исключаем хосты у которых нет нужных групп
//hosts = hosts.Where(t => workGroups.Any(x => x.WorkGroupId == t.WorkGroupId)).ToList();
//if (!hosts.Any())
//{
// logger.LogInformation($"Не найдено ЭК попадающих под условие: ${JsonSerializer.Serialize(query)}");
// return;
//}
// хосты группируем по РГ, чтоб потом распределить/рассчитать NextRun
var groupingHostByWg = hosts.GroupBy(t => t.WorkGroupId);
//// хосты группируем по РГ, чтоб потом распределить/рассчитать NextRun
//var groupingHostByWg = hosts.GroupBy(t => t.WorkGroupId);
foreach (var group in groupingHostByWg)
{
var groupingHosts = group.ToList();
//foreach (var group in groupingHostByWg)
//{
// var groupingHosts = group.ToList();
var templates = CreateQueryTemplates(groupingHosts, query);
// var templates = CreateQueryTemplates(groupingHosts, query);
//проверяем, что нет шаблонов с такими именами, исключаем их
templates = await ExcludeExistTemplatesAsync(templates);
if (!templates.Any())
continue;
// //проверяем, что нет шаблонов с такими именами, исключаем их
// templates = await ExcludeExistTemplatesAsync(templates);
// if (!templates.Any())
// continue;
//заполняем NextRun
templates = await templateDistributor.DistributeTemplateAsync(templates, appInWorkWg.Id, (Guid)group.Key!);
// //заполняем NextRun
// templates = await templateDistributor.DistributeTemplateAsync(templates, appInWorkWg.Id, (Guid)group.Key!);
// сохраняем
foreach (var template in templates)
{
if (!await templateService.CreateAsync(template) || !await templateService.CommitAsync(query.HistoryInitiator))
{
logger.LogError($"Ошибка при создании шаблона: Name: {template.Name}, ApplicationInWorkId: {template.ApplicationInWorkId}, HostId: {template.HostId}");
}
else
{
logger.LogInformation($"Создан шаблон: Name: {template.Name}, ApplicationInWorkId: {template.ApplicationInWorkId}, " +
$"HostId: {template.HostId}");
}
}
}
// // сохраняем
// foreach (var template in templates)
// {
// if (!await templateService.CreateAsync(template) || !await templateService.CommitAsync(query.HistoryInitiator))
// {
// logger.LogError($"Ошибка при создании шаблона: Name: {template.Name}, ApplicationInWorkId: {template.ApplicationInWorkId}, HostId: {template.HostId}");
// }
// else
// {
// logger.LogInformation($"Создан шаблон: Name: {template.Name}, ApplicationInWorkId: {template.ApplicationInWorkId}, " +
// $"HostId: {template.HostId}");
// }
// }
//}
#region создавали шаблоны до того, как стали группировать по РГ
////Создаем шаблоны
@@ -231,8 +232,8 @@ namespace PARR.GeneratorTemplates.Services
),
IsActiveTemplate = query.IsActiveTemplate ?? false,
IsActiveSchedule = query.IsActiveSchedule ?? false,
ApplicationInWorkId = appInWork.Id,
HostId = host.Id,
JobId = appInWork.Id,//TODO Migratin to Job
UnitId = host.Id,//TODO Migratin to Job
// NextRun не задаем значение, его рассчитаем позже
//NextRun = ???,
LastRun = null
@@ -270,26 +271,26 @@ namespace PARR.GeneratorTemplates.Services
string ekPattern = SqlHelpers.RegexToLike(query.Ek);
var queryTemplates = templateService.Get()
.Include(t => t.Host)
.Include(t => t.ApplicationsInWork)
.Include(t => t.Unit)//TODO Migratin to Job
.Include(t => t.Job)//TODO Migratin to Job
.Include(t => t.RobotConfigurations)
.Where(t =>
(t.IsActiveTemplate == true || t.IsActiveSchedule == true)
&& t.ApplicationsInWork!.ApplicationId == query.ApplicationId
&& t.ApplicationsInWork!.WorkId == query.WorkId
&& EF.Functions.Like(t.Host!.Ek.ToLower(), ekPattern)
//&& t.ApplicationsInWork!.ApplicationId == query.ApplicationId//TODO Migratin to Job
//&& t.ApplicationsInWork!.WorkId == query.WorkId//TODO Migratin to Job
&& EF.Functions.Like(t.Unit!.Name.ToLower(), ekPattern)
);
// статус ЭК
if (query.StatusEk > 0)
queryTemplates = queryTemplates.Where(t => t.Host!.EkStatusCode == query.StatusEk);
queryTemplates = queryTemplates;//.Where(t => t.Unit!.BaseFields.Status == query.StatusEk);//TODO Migratin to Job
var existTemplates = await queryTemplates
.AsSplitQuery()
.ToListAsync();
// Исключаем хосты у которых нет нужных групп
existTemplates = existTemplates.Where(t => workGroups.Any(x => x.WorkGroupId == t.Host.WorkGroupId)).ToList();
existTemplates = existTemplates.Where(t => workGroups.Any(x => x.WorkGroup.Name == t.Unit.BaseFields.WorkGroup)).ToList();
if (!existTemplates.Any())
{

View File

@@ -121,7 +121,7 @@ namespace PARR.Master.Services
if (isAgentStarted == true && isAgentEnded == false)
{
var lastStrartDate = allHistory.Last(t => t.HistoryLevelId == (int)AgentHistoryLevelEnum.Start).DateCreated;
var timeout = (double)order.Template!.ApplicationsInWork!.AgentTimeOutSec!;
var timeout = (double)order.Template!.Job!.Group!.AgentTimeOutSec!;
if (lastStrartDate.AddSeconds(timeout) <= DateTimeOffset.UtcNow)
{
@@ -182,7 +182,7 @@ namespace PARR.Master.Services
t.TemplateId == order.TemplateId
&& t.DateCreated > order.GenerateDate!.Value.Add(-orderManageSettings.FindAgentHistoryStartOffset)
//&& t.DateCreated <= order.GenerateDate!.Value.AddSeconds(order.Template!.ApplicationsInWork!.AgentTimeOutSec!.Value)
&& t.DateCreated <= order.GenerateDate!.Value.Add(order.Template!.ApplicationsInWork!.TemplateDurationTimeSpan!.Value)
&& t.DateCreated <= order.GenerateDate!.Value.Add(order.Template!.Job!.Group!.TemplateDurationTimeSpan!.Value)
&& t.OrderId == null
)
.OrderBy(t => t.DateCreated)
@@ -244,14 +244,14 @@ namespace PARR.Master.Services
private IQueryable<Order> GetOrdres()
{
return orderService.Get()
.Include(t => t.Template).ThenInclude(t => t!.ApplicationsInWork)
.Include(t => t.Template).ThenInclude(t => t!.Job)
.Include(t => t.AgentHistories)
.Where(t =>
t.TemplateId.HasValue
&& t.Template!.ApplicationsInWork!.IsAgent == true
&& t.Template!.Job!.Group!.IsAgent == true
&& t.GenerateDate.HasValue
&& t.Template!.ApplicationsInWork!.AgentTimeOutSec.HasValue
&& string.IsNullOrEmpty(t.Template!.ApplicationsInWork!.TemplateDuration) == false
&& t.Template!.Job!.Group!.AgentTimeOutSec.HasValue
&& string.IsNullOrEmpty(t.Template!.Job!.Group!.TemplateDuration) == false
&& t.ExpirationDate > DateTimeOffset.UtcNow
).OrderBy(t => t.DateCreated);
}

View File

@@ -64,7 +64,7 @@ namespace PARR.NextRun
foreach (var template in templates)
{
var nextRun = await esppScheduleTransformService.GetNextDateAsync(template.ApplicationInWorkId, template.NextRun);
var nextRun = await esppScheduleTransformService.GetNextDateAsync(template.JobId, template.NextRun);
template.LastRun = template.NextRun;
template.NextRun = nextRun;

View File

@@ -35,11 +35,11 @@ internal class TemplateActivator : ITemplateActivator
}
public async Task ChangeStateAsync(Guid applicationInWorkId, TemplateActivatorActionsEnum action, IHistoryInitiator? historyInitiator)
public async Task ChangeStateAsync(Guid applicationInWorkId, TemplateActivatorActionsEnum action, IHistoryInitiator? historyInitiator)//TODO Migratin to Job
{
var query = templateService.Get()
.Include(t => t.RobotConfigurations).ThenInclude(t => t.Robot)
.Where(t => t.ApplicationInWorkId == applicationInWorkId);
.Where(t => t.JobId == applicationInWorkId);//TODO Migratin to Job
var changes = 0;
switch (action)
{
@@ -121,7 +121,7 @@ internal class TemplateActivator : ITemplateActivator
var changes = 0;
//Добавляем информацию о рабочих группах для возможности их фильтрации
query = query.Include(t => t.Host).ThenInclude(h => h!.WorkGroup);
query = query.Include(t => t.Unit);//TODO Migratin to Job
//Получаем настройки авто-контроля
var jobAutoControlSettings = await GetJobAutoControlSettingsAsync(applicationInWorkId);
@@ -149,7 +149,7 @@ internal class TemplateActivator : ITemplateActivator
//Фильтруем по рабочим группам
var appInWorkWorkGroups = GetApplicationInWorkWorkGroups(applicationInWorkId);
if (appInWorkWorkGroups.Any())
templates = templates.Where(t => appInWorkWorkGroups.Any(awg => t.Host!.WorkGroupId == awg.WorkGroupId)).ToList();
templates = templates.Where(t => appInWorkWorkGroups.Any(awg => t.Unit!.BaseFields!.WorkGroup == awg.WorkGroup!.Name)).ToList();//TODO Migratin to Job
//Фильтруем соответствие статусов ЭК условиям автоконтроля
var checkEkStatus = FilterTemplatesByWrongEkStatus(templates, trueEkStatuses, isActivate);
@@ -177,9 +177,9 @@ internal class TemplateActivator : ITemplateActivator
private List<Template> FilterTemplatesByWrongEkStatus(List<Template> templates, ICollection<JobAutoControlInEkStatus> trueEkStatuses, bool isActivate)
{
if (isActivate)
return templates.Where(t => trueEkStatuses.Any(tes => tes.EkStatusCode == t.Host!.EkStatusCode)).ToList();
return templates.Where(t => trueEkStatuses.Any(tes => tes.EkStatus!.Name == t.Unit!.BaseFields!.Status)).ToList();//TODO Migratin to Job
return templates.Where(t => !trueEkStatuses.Any(tes => tes.EkStatusCode == t.Host!.EkStatusCode)).ToList();
return templates.Where(t => !trueEkStatuses.Any(tes => tes.EkStatus!.Name == t.Unit!.BaseFields!.Status)).ToList();//TODO Migratin to Job
}
private List<Template> FilterTemplatesByNameNotMatchToMasks(IQueryable<Template> query, ICollection<JobEkMask> trueMasks)
@@ -187,7 +187,7 @@ internal class TemplateActivator : ITemplateActivator
var result = new List<Template>();
foreach (var mask in trueMasks)
{
var templates = query.Where(t => EF.Functions.Like(t.Host!.Ek.ToLower(), SqlHelpers.RegexToLike(mask.Name))).ToList();
var templates = query.Where(t => EF.Functions.Like(t.Unit!.Name.ToLower(), SqlHelpers.RegexToLike(mask.Name))).ToList();
result.AddRange(templates);
}

View File

@@ -21,27 +21,28 @@ namespace PARR.TemplateDistributor.Services
{
using (var scope = serviceProvider.CreateScope())
{
var service = scope.ServiceProvider.GetService<IApplicationsInWorkService>();
//TODO Migratin to Job
//var service = scope.ServiceProvider.GetService<IApplicationsInWorkService>();
if (service == null)
throw new Exception($"Не найден сервис: {nameof(IApplicationsInWorkService)}");
//if (service == null)
// throw new Exception($"Не найден сервис: {nameof(IApplicationsInWorkService)}");
var appInWork = await service.Get()
.Include(aiw => aiw.EsppSchValues)
.FirstOrDefaultAsync(t => t.Id == applicationInWorkId);
//var appInWork = await service.Get()//TODO Migratin to Job
// //.Include(aiw => aiw.EsppSchValues)
// .FirstOrDefaultAsync(t => t.Id == applicationInWorkId);
if (appInWork == null)
{
logger.LogError($"Не найдена регалментная работа {nameof(applicationInWorkId)}: {applicationInWorkId}");
return false;
}
//if (appInWork == null)
//{
// logger.LogError($"Не найдена регалментная работа {nameof(applicationInWorkId)}: {applicationInWorkId}");
// return false;
//}
if (appInWork.IsAutoDistributionEnabled && appInWork.EsppSchValues.Count !=1)
{
logger.LogError($"Регалментная работа {nameof(applicationInWorkId)}: {applicationInWorkId} должна иметь только одно значение EsppSchTypeValue" +
$", соответствующее режиму равномерного распределения по периоду");
return false;
}
//if (appInWork.IsAutoDistributionEnabled && appInWork.EsppSchValues.Count !=1)
//{
// logger.LogError($"Регалментная работа {nameof(applicationInWorkId)}: {applicationInWorkId} должна иметь только одно значение EsppSchTypeValue" +
// $", соответствующее режиму равномерного распределения по периоду");
// return false;
//}
return true;
}

View File

@@ -5,6 +5,7 @@ using PARR.Constants;
using PARR.DAL.Models;
using PARR.DAL.Services.Interfaces;
using PARR.DAL.TransformServices;
using System.Reflection.Metadata.Ecma335;
namespace PARR.TemplateDistributor
{
@@ -38,20 +39,20 @@ namespace PARR.TemplateDistributor
}
public async Task UpdateScheduleAsync(Guid applicationInWorkId)
public async Task UpdateScheduleAsync(Guid applicationInWorkId)//TODO Migratin to Job
{
var appInWork = await applicationsInWorkService.GetAsync(applicationInWorkId);
var templates = await templateService.Get()
.Include(t => t.Host)
.ThenInclude(h => h!.WorkGroup)
.Where(t => t.ApplicationInWorkId == applicationInWorkId && t.Host!.WorkGroupId != null)
.Include(t => t.Unit)//TODO Migratin to Job
//.ThenInclude(h => h!.WorkGroup)
.Where(t => t.JobId == applicationInWorkId && t.Unit!.BaseFields!.WorkGroup != null)//TODO Migratin to Job
.ToListAsync();
//Группируем шаблоны по рабочим группам
var workGroupsWithTemplates = templates.GroupBy(t => t.Host!.WorkGroupId);
var workGroupsWithTemplates = templates.GroupBy(t => t.Unit!.BaseFields!.WorkGroup);
foreach (var workGroupWithTemplates in workGroupsWithTemplates)
/*foreach (var workGroupWithTemplates in workGroupsWithTemplates)
{
var wgId = (Guid)workGroupWithTemplates.Key!;
var values = workGroupWithTemplates.ToList();
@@ -79,163 +80,167 @@ namespace PARR.TemplateDistributor
if (distrTemplates.Any())
if (!await templateService.CommitAsync())
logger.LogError($"Ошибка записи изменений в БД при перераспределении NextRun шаблонов РР({applicationInWorkId})");
}
}*/
// TODO Migratin to Job
}
public async Task<List<Template>> DistributeTemplateAsync(List<Template> templates, Guid applicationInWorkId, Guid workGroupId)
{
var appInWork = await applicationsInWorkService.Get()
.Include(aiw => aiw.EsppSchValues)
.ThenInclude(esv => esv.EsppSchTypeValue)
.ThenInclude(etv => etv!.DistributionPeriod)
.FirstAsync(t => t.Id == applicationInWorkId);
// var appInWork = await applicationsInWorkService.Get()
// .Include(aiw => aiw.EsppSchValues)
// .ThenInclude(esv => esv.EsppSchTypeValue)
// .ThenInclude(etv => etv!.DistributionPeriod)
// .FirstAsync(t => t.Id == applicationInWorkId);
var refDate = appInWork.ReferenceDate;
// var refDate = appInWork.ReferenceDate;
//Проверяем наличие распределения РР на период
if (appInWork.IsAutoDistributionEnabled)
{
var existingTemplates = await templateService.Get()
.Include(t => t.Host)
.Where(t => t.ApplicationInWorkId == applicationInWorkId && t.Host!.WorkGroupId == workGroupId)
.ToListAsync();
//Удалим из входных шаблонов уже существующие в БД (по идее, такого никогда не должно случиться)
var duplicates = templates.Select(t => t.Id).Where(t => existingTemplates.Any(et => et.Id == t)).ToList();
if (duplicates.Count > 0)
{
duplicates.ForEach(t =>
{
logger.LogWarning($"Для распределения AiW({applicationInWorkId}),workGroupId({workGroupId}) передан существующий в базе данных шаблон {t}");
});
templates.RemoveAll(t => duplicates.Any(dt => dt == t.Id));
}
existingTemplates.AddRange(templates);
//Если распределенная РР получаем начало
var period = appInWork.EsppSchValues.First()!.EsppSchTypeValue!.DistributionPeriod;
var periodType = ParseDistributionPeriodType(period!.Type);
var workDays = await GetWorkDaysAsync(appInWork);
var result = new List<Template>();
//распределяем РР отдельно активированные
var activatedTemplates = existingTemplates.Where(t => t.IsActiveTemplate && t.IsActiveSchedule).ToList();
if (activatedTemplates.Count > 0)
{
Distribute(ref activatedTemplates, refDate, period, periodType, workDays);
// result.AddRange(activatedTemplates);
}
//распределяем РР отдельно деактивированные
var deactivatedTemplates = existingTemplates.Where(t =>
!t.IsActiveTemplate || !t.IsActiveSchedule || (
!t.IsActiveTemplate && !t.IsActiveSchedule
)).ToList();
if (deactivatedTemplates.Count > 0)
{
Distribute(ref deactivatedTemplates, refDate, period, periodType, workDays);
// result.AddRange(deactivatedTemplates);
}
if (templates.Any())
{
// это была генерация шаблонов, не нужны все шаблоны, нужны только те которые передал для получения NextRun
result.AddRange(templates);
}
else
{
// это было распределение шаблонов, добавляем активированные и деактивированные
result.AddRange(activatedTemplates);
result.AddRange(deactivatedTemplates);
}
return result;
#region comments
//var d = new Dictionary<DateOnly, List<Template>>();
//foreach (var wd in workDays)
//{
// var wrokDateTimeOffset = new DateTimeOffset(
// wd.Year, wd.Month, wd.Day,
// refDate.Hour, refDate.Minute, refDate.Second,
// new TimeSpan(0, 0, 0));
// if (wrokDateTimeOffset < DateTimeOffset.UtcNow)
// wrokDateTimeOffset = esppScheduleTransformService.GetNextDateForDistributionRun(wrokDateTimeOffset, periodType, period.Duration);
// var assignedTemplates = existingTemplates.Where(t => t.NextRun == wrokDateTimeOffset).ToList();
// d.Add(wd, assignedTemplates);
//}
//var templatesPerStep = (double)templates.Count() / workDays.Count();//
//var currentTemplateStep = (int)Math.Ceiling(templatesPerStep);
//var delta = templatesPerStep - currentTemplateStep;
////templates.First().NextRun = currentDay;
//var templateDistributed = 0;
////Отталкиваясь от количества
//while (templateDistributed < templates.Count())
//{
// var wdCounts = d.Select(wd => wd.Value).OrderBy(count => count).ToArray();
// var templateCountDelta = d.Max(t => t.Value.Count()) - d.Min(t => t.Value.Count());
// var addingTemplatesCount = wdCounts.Length > 1 ?
// (templateCountDelta == 0) ? (int)Math.Ceiling(templatesPerStep) : templateCountDelta :
// (int)Math.Ceiling(templatesPerStep);
// var workDaysWithMinTemplates = d.Where(wd => wd.Value == wdCounts[0]).ToArray();
// if (workDaysWithMinTemplates.Length * addingTemplatesCount < templates.Count())
// //Проверяем наличие распределения РР на период
// if (appInWork.IsAutoDistributionEnabled)
// {
// foreach (var wd in workDaysWithMinTemplates)
// {
// //Считаем DateTimeOffset, потому что у нас только дата пока
// var currentDay = new DateTimeOffset(
// wd.Key.Year, wd.Key.Month, wd.Key.Day,
// refDate.Hour, refDate.Minute, refDate.Second,
// new TimeSpan(0, 0, 0));
// var existingTemplates = await templateService.Get()
// .Include(t => t.Unit)
// .Where(t => t.JobId == applicationInWorkId
// //&& t.Host!.WorkGroupId == workGroupId//TODO Migratin to Job
// )
// .ToListAsync();
// templates.Skip(templateDistributed).Take(addingTemplatesCount).ToList().ForEach(t =>
// //Удалим из входных шаблонов уже существующие в БД (по идее, такого никогда не должно случиться)
// var duplicates = templates.Select(t => t.Id).Where(t => existingTemplates.Any(et => et.Id == t)).ToList();
// if (duplicates.Count > 0)
// {
// t.NextRun = currentDay;
// d[wd.Key].Add(t);
// duplicates.ForEach(t =>
// {
// logger.LogWarning($"Для распределения AiW({applicationInWorkId}),workGroupId({workGroupId}) передан существующий в базе данных шаблон {t}");
// });
// templateDistributed += addingTemplatesCount;
// templates.RemoveAll(t => duplicates.Any(dt => dt == t.Id));
// }
// existingTemplates.AddRange(templates);
// //Если распределенная РР получаем начало
// var period = appInWork.EsppSchValues.First()!.EsppSchTypeValue!.DistributionPeriod;
// var periodType = ParseDistributionPeriodType(period!.Type);
// var workDays = await GetWorkDaysAsync(appInWork);
// var result = new List<Template>();
// //распределяем РР отдельно активированные
// var activatedTemplates = existingTemplates.Where(t => t.IsActiveTemplate && t.IsActiveSchedule).ToList();
// if (activatedTemplates.Count > 0)
// {
// Distribute(ref activatedTemplates, refDate, period, periodType, workDays);
// // result.AddRange(activatedTemplates);
// }
// //распределяем РР отдельно деактивированные
// var deactivatedTemplates = existingTemplates.Where(t =>
// !t.IsActiveTemplate || !t.IsActiveSchedule || (
// !t.IsActiveTemplate && !t.IsActiveSchedule
// )).ToList();
// if (deactivatedTemplates.Count > 0)
// {
// Distribute(ref deactivatedTemplates, refDate, period, periodType, workDays);
// // result.AddRange(deactivatedTemplates);
// }
// if (templates.Any())
// {
// // это была генерация шаблонов, не нужны все шаблоны, нужны только те которые передал для получения NextRun
// result.AddRange(templates);
// }
// else
// {
// while (templateDistributed < templates.Count())
// {
// var wd = d.Where(wd => wd.Value == d.Min(t => t.Value)).First();
// //Считаем DateTimeOffset, потому что у нас только дата пока
// var currentDay = new DateTimeOffset(
// wd.Key.Year, wd.Key.Month, wd.Key.Day,
// refDate.Hour, refDate.Minute, refDate.Second,
// new TimeSpan(0, 0, 0));
// templates.Skip(templateDistributed).Take(addingTemplatesCount).ToList().ForEach(t =>
// {
// t.NextRun = currentDay;
// d[wd.Key].Add(t);
// });
// templateDistributed += addingTemplatesCount;
// // это было распределение шаблонов, добавляем активированные и деактивированные
// result.AddRange(activatedTemplates);
// result.AddRange(deactivatedTemplates);
// }
// return result;
// #region comments
// //var d = new Dictionary<DateOnly, List<Template>>();
// //foreach (var wd in workDays)
// //{
// // var wrokDateTimeOffset = new DateTimeOffset(
// // wd.Year, wd.Month, wd.Day,
// // refDate.Hour, refDate.Minute, refDate.Second,
// // new TimeSpan(0, 0, 0));
// // if (wrokDateTimeOffset < DateTimeOffset.UtcNow)
// // wrokDateTimeOffset = esppScheduleTransformService.GetNextDateForDistributionRun(wrokDateTimeOffset, periodType, period.Duration);
// // var assignedTemplates = existingTemplates.Where(t => t.NextRun == wrokDateTimeOffset).ToList();
// // d.Add(wd, assignedTemplates);
// //}
// //var templatesPerStep = (double)templates.Count() / workDays.Count();//
// //var currentTemplateStep = (int)Math.Ceiling(templatesPerStep);
// //var delta = templatesPerStep - currentTemplateStep;
// ////templates.First().NextRun = currentDay;
// //var templateDistributed = 0;
// ////Отталкиваясь от количества
// //while (templateDistributed < templates.Count())
// //{
// // var wdCounts = d.Select(wd => wd.Value).OrderBy(count => count).ToArray();
// // var templateCountDelta = d.Max(t => t.Value.Count()) - d.Min(t => t.Value.Count());
// // var addingTemplatesCount = wdCounts.Length > 1 ?
// // (templateCountDelta == 0) ? (int)Math.Ceiling(templatesPerStep) : templateCountDelta :
// // (int)Math.Ceiling(templatesPerStep);
// // var workDaysWithMinTemplates = d.Where(wd => wd.Value == wdCounts[0]).ToArray();
// // if (workDaysWithMinTemplates.Length * addingTemplatesCount < templates.Count())
// // {
// // foreach (var wd in workDaysWithMinTemplates)
// // {
// // //Считаем DateTimeOffset, потому что у нас только дата пока
// // var currentDay = new DateTimeOffset(
// // wd.Key.Year, wd.Key.Month, wd.Key.Day,
// // refDate.Hour, refDate.Minute, refDate.Second,
// // new TimeSpan(0, 0, 0));
// // templates.Skip(templateDistributed).Take(addingTemplatesCount).ToList().ForEach(t =>
// // {
// // t.NextRun = currentDay;
// // d[wd.Key].Add(t);
// // });
// // templateDistributed += addingTemplatesCount;
// // }
// // }
// // else
// // {
// // while (templateDistributed < templates.Count())
// // {
// // var wd = d.Where(wd => wd.Value == d.Min(t => t.Value)).First();
// // //Считаем DateTimeOffset, потому что у нас только дата пока
// // var currentDay = new DateTimeOffset(
// // wd.Key.Year, wd.Key.Month, wd.Key.Day,
// // refDate.Hour, refDate.Minute, refDate.Second,
// // new TimeSpan(0, 0, 0));
// // templates.Skip(templateDistributed).Take(addingTemplatesCount).ToList().ForEach(t =>
// // {
// // t.NextRun = currentDay;
// // d[wd.Key].Add(t);
// // });
// // templateDistributed += addingTemplatesCount;
// // }
// // }
// //}
// #endregion
// }
//}
// else
// // templates.ForEach(t => t.NextRun = appInWork!.ReferenceDate);
// // это не автораспределение, по ReferenceDate получаем ближайший рабочий день
// templates.ForEach(async t => t.NextRun = await nextRunModifierService.GetWorkDayAsync(appInWork!.ReferenceDate));
#endregion
}
else
// templates.ForEach(t => t.NextRun = appInWork!.ReferenceDate);
// это не автораспределение, по ReferenceDate получаем ближайший рабочий день
templates.ForEach(async t => t.NextRun = await nextRunModifierService.GetWorkDayAsync(appInWork!.ReferenceDate));
return templates;
// return templates;
return new List<Template>();
}
private void Distribute(ref List<Template> templates, DateTimeOffset refDate, DistributionPeriod period, DistributionPeriodTypeEnum periodType, List<DateOnly> workDays)
@@ -246,9 +251,9 @@ namespace PARR.TemplateDistributor
//Проверяем шаблоны уже распределённые, чтобы не перемещать лишний раз
var templateToDistrib = GetTemplatesToDistribute(ref distrPlan, templates);
//logger.LogInformation($"{GetType().Name}(AppInWId:{templates.Select(t => t.ApplicationInWorkId).First()}, WorkGroup:{templates.Select(t => t.Host!.WorkGroup!.Name).First()}) запланировал изменение даты следующего срабатывания у {templateToDistrib.Count()} существующих шаблона(ов), {templates.Count() - templateToDistrib.Count()} остались без изменений");
string? loggerWorkGroup = templates.FirstOrDefault()?.Host?.WorkGroup != null ? templates.FirstOrDefault()?.Host?.WorkGroup?.Name : templates.FirstOrDefault()?.Host?.WorkGroupId?.ToString();
logger.LogInformation($"{GetType().Name}(AppInWId:{templates.Select(t => t.ApplicationInWorkId).First()}, " +
string? loggerWorkGroup = templates.FirstOrDefault()?.Unit?.BaseFields?.WorkGroup != null ? templates.FirstOrDefault()?.Unit.BaseFields.WorkGroup : templates.FirstOrDefault()?.Unit?.BaseFields?.WorkGroup?.ToString();
logger.LogInformation($"{GetType().Name}(AppInWId:{templates.Select(t => t.JobId).First()}, " +
$"WorkGroup:{loggerWorkGroup}) " +
$"запланировал изменение даты следующего срабатывания у {templateToDistrib.Count()} существующих шаблона(ов), {templates.Count() - templateToDistrib.Count()} остались без изменений");
@@ -288,47 +293,49 @@ namespace PARR.TemplateDistributor
/// <returns></returns>
private async Task<List<DateOnly>> GetWorkDaysAsync(ApplicationsInWork appInWork)
{
var period = appInWork.EsppSchValues.FirstOrDefault()?.EsppSchTypeValue?.DistributionPeriod;
var periodType = ParseDistributionPeriodType(period!.Type);
//var period = appInWork.EsppSchValues.FirstOrDefault()?.EsppSchTypeValue?.DistributionPeriod;
//var periodType = ParseDistributionPeriodType(period!.Type);
//старт период, берем сейчас, будем получать рабочие дни с вычетом выходных на весь период сразу.
var startPeriod = DateOnly.FromDateTime(DateTimeOffset.UtcNow.Date);
// старт период считаем относительно refDate
//var startPeriod = await esppScheduleTransformService.GetStartPeriodForDateAsync(appInWork.Id, appInWork.ReferenceDate, appInWork.ReferenceDate, periodType, period.Duration);
////старт период, берем сейчас, будем получать рабочие дни с вычетом выходных на весь период сразу.
//var startPeriod = DateOnly.FromDateTime(DateTimeOffset.UtcNow.Date);
//// старт период считаем относительно refDate
////var startPeriod = await esppScheduleTransformService.GetStartPeriodForDateAsync(appInWork.Id, appInWork.ReferenceDate, appInWork.ReferenceDate, periodType, period.Duration);
var workDays = calendarService.GetWorkDatesForPeriod(startPeriod, TimeOnly.FromDateTime(appInWork.ReferenceDate.DateTime), periodType, period.Duration, weekendDayService.GetWeekends);
//var workDays = calendarService.GetWorkDatesForPeriod(startPeriod, TimeOnly.FromDateTime(appInWork.ReferenceDate.DateTime), periodType, period.Duration, weekendDayService.GetWeekends);
#region старая логика
//var resultWorkDays = new List<DateOnly>();
//#region старая логика
////var resultWorkDays = new List<DateOnly>();
//workDays.ForEach(wd =>
//{
// var wrokDateTimeOffset = new DateTimeOffset(
// wd.Year, wd.Month, wd.Day,
// appInWork.ReferenceDate.Hour, appInWork.ReferenceDate.Minute, appInWork.ReferenceDate.Second,
// new TimeSpan(0, 0, 0));
////workDays.ForEach(wd =>
////{
//// var wrokDateTimeOffset = new DateTimeOffset(
//// wd.Year, wd.Month, wd.Day,
//// appInWork.ReferenceDate.Hour, appInWork.ReferenceDate.Minute, appInWork.ReferenceDate.Second,
//// new TimeSpan(0, 0, 0));
// if (wrokDateTimeOffset < DateTimeOffset.UtcNow)
// {
// wrokDateTimeOffset = esppScheduleTransformService.GetNextDateForDistributionRun(wrokDateTimeOffset, periodType, period.Duration);
// //wd = DateOnly.FromDateTime(wrokDateTimeOffset.DateTime);
// resultWorkDays.Add(DateOnly.FromDateTime(wrokDateTimeOffset.DateTime));
// }
// else
// {
// resultWorkDays.Add(wd);
// }
//});
//// if (wrokDateTimeOffset < DateTimeOffset.UtcNow)
//// {
//// wrokDateTimeOffset = esppScheduleTransformService.GetNextDateForDistributionRun(wrokDateTimeOffset, periodType, period.Duration);
//// //wd = DateOnly.FromDateTime(wrokDateTimeOffset.DateTime);
//// resultWorkDays.Add(DateOnly.FromDateTime(wrokDateTimeOffset.DateTime));
//// }
//// else
//// {
//// resultWorkDays.Add(wd);
//// }
////});
////----- убираем даты, которые могли выйти за конец периода (из-за сдвига NextRun по рабочим дням)
//var endPeriod = calendarService.GetEndPeriodDate(DateOnly.FromDateTime(DateTimeOffset.UtcNow.Date), periodType, period.Duration);
//resultWorkDays = resultWorkDays.Where(t => t <= endPeriod).Distinct().OrderBy(t => t).ToList();
////-----
//////----- убираем даты, которые могли выйти за конец периода (из-за сдвига NextRun по рабочим дням)
////var endPeriod = calendarService.GetEndPeriodDate(DateOnly.FromDateTime(DateTimeOffset.UtcNow.Date), periodType, period.Duration);
////resultWorkDays = resultWorkDays.Where(t => t <= endPeriod).Distinct().OrderBy(t => t).ToList();
//////-----
//return resultWorkDays;
#endregion
////return resultWorkDays;
//#endregion
return workDays;
//return workDays;
return new List<DateOnly>();
}
/// <summary>

View File

@@ -41,6 +41,28 @@ namespace PARR.Test
#region test
using (var scope = serviceProvider.CreateScope())
{
var unitService = scope.ServiceProvider.GetService<IUnitService>();
var unitsQuery = unitService!.Get()
.Include(t => t.UnitValues)
.ThenInclude(t => t.Field)
.Include(t => t.UnitValues)
.ThenInclude(t => t.Value)
.Include(t => t.ParentUnits)
.Include(t => t.ChildUnits)
.Where(t => EF.Functions.Like(t.Name, "%-ГВЦ") &&
t.UnitValues.Any(v =>
v.Field!.AihitName == ОДКАТЕГОРИЯ_ЭК" && v.Value!.Value == "система хранения данных (схд)")
&& t.UnitValues.Any(v =>
v.Field!.AihitName == "ТИП_ЭК" && v.Value!.Value == "коммутатор")
//&& t.UnitValues.Any(v =>
// v.Field!.AihitName == "АКТИВЕН" && v.Value!.Value == "1")
// && t.UnitValues.Any(v =>
// v.Field!.AihitName == "НЕУНИКАЛЬНЫЙ_ЭК" && v.Value!.Value == "0")
);
var v1 = await unitsQuery.Where(t => t.UnitValues.Any(v =>
v.Field!.AihitName == "НЕУНИКАЛЬНЫЙ_ЭК" && v.Value!.Value == "0")).ToListAsync();
/*var service = scope.ServiceProvider.GetService<ITemplateNameGeneratorService>();
var ttt = await service.GetTemplateNameAsync(Guid.Parse("ba05948b-b040-48cc-ab77-0accc9c223a0"), Guid.Parse("d4a86f24-6975-4614-98ab-431f26e3eb69"));*/