2025-07-01 17:20:48 +10:00
using AutoMapper ;
using FluentValidation ;
using Microsoft.AspNetCore.Authorization ;
using Microsoft.AspNetCore.Mvc ;
using Microsoft.EntityFrameworkCore ;
using PARR.API.Contracts.V1 ;
using PARR.API.Contracts.V1.Requests ;
using PARR.API.Contracts.V1.Requests.Queries ;
using PARR.API.Contracts.V1.Responses ;
using PARR.API.Contracts.V1.Responses.Base ;
using PARR.API.Controllers.V1.Base ;
using PARR.API.Extensions ;
using PARR.API.Services.Interfaces ;
2025-12-02 09:49:08 +10:00
using PARR.API.Settings ;
using PARR.BLL.Domain.Mq ;
using PARR.BLL.Services.Interfaces ;
using PARR.Common.Domain ;
2025-07-01 17:20:48 +10:00
using PARR.Constants ;
2026-01-16 11:04:26 +10:00
using PARR.DAL.Cache.Services ;
2025-07-01 17:20:48 +10:00
using PARR.DAL.Contracts ;
using PARR.DAL.DomainModels ;
2025-09-11 16:03:51 +10:00
using PARR.DAL.DomainServices.Interfaces ;
2026-01-21 18:25:09 +10:00
using PARR.DAL.DomainServices.UnitFilterService ;
2025-12-08 14:23:08 +10:00
using PARR.DAL.Extensions ;
2025-07-01 17:20:48 +10:00
using PARR.DAL.Models.Job ;
using PARR.DAL.Services.Interfaces ;
using PARR.DAL.Services.Interfaces.Job ;
2025-09-11 16:03:51 +10:00
using PARR.DAL.Services.Interfaces.Unit ;
2025-12-02 09:49:08 +10:00
using System.Text.Json ;
2025-07-01 17:20:48 +10:00
namespace PARR.API.Controllers.V1
{
/// <summary>
/// Управление работами
/// </summary>
[Authorize(Roles = ParrRoles.Administrator.Role)]
public class JobController : BaseApiController
{
private readonly ILogger < JobController > logger ;
private readonly IMapper mapper ;
private readonly IUriService uriService ;
private readonly IJobService jobService ;
private readonly ITemplateService templateService ;
2025-09-11 16:03:51 +10:00
private readonly IValidator < JobRequest > jobValidator ;
2025-12-02 09:49:08 +10:00
private readonly IMqService mqService ;
private readonly MqSettings mqSettings ;
private readonly IClientService clientService ;
2025-12-08 14:23:08 +10:00
private readonly IJobAutoControlService jobAutoControlService ;
2026-01-16 11:04:26 +10:00
private readonly IMatchingStatusService matchingStatusService ;
2025-07-01 17:20:48 +10:00
public JobController (
ILogger < JobController > logger ,
IMapper mapper ,
IUriService uriService ,
IJobService jobService ,
ITemplateService templateService ,
2025-09-11 16:03:51 +10:00
IJobGroupService jobGroupService ,
IValidator < JobRequest > jobValidator ,
IUnitFilterService unitFilterService ,
2025-12-02 09:49:08 +10:00
IUnitService unitService ,
IMqService mqService ,
MqSettings mqSettings ,
2025-12-08 14:23:08 +10:00
IClientService clientService ,
2026-01-16 11:04:26 +10:00
IJobAutoControlService jobAutoControlService ,
IMatchingStatusService matchingStatusService
2025-07-01 17:20:48 +10:00
)
{
this . logger = logger ;
this . mapper = mapper ;
this . uriService = uriService ;
this . jobService = jobService ;
this . templateService = templateService ;
2025-09-11 16:03:51 +10:00
this . jobValidator = jobValidator ;
2025-12-02 09:49:08 +10:00
this . mqService = mqService ;
this . mqSettings = mqSettings ;
this . clientService = clientService ;
2025-12-08 14:23:08 +10:00
this . jobAutoControlService = jobAutoControlService ;
2026-01-16 11:04:26 +10:00
this . matchingStatusService = matchingStatusService ;
2025-07-01 17:20:48 +10:00
}
/// <summary>
/// Получить список заданий на выполнение работ(Job) постранично
/// </summary>
/// <returns></returns>
[HttpGet(ApiRoutes.Job.GetAll)]
public async Task < IActionResult > GetAll ( [ FromQuery ] PaginationQuery paginationQuery , [ FromQuery ] JobQuery filter )
{
var paginationFilter = mapper . Map < PaginationFilter > ( paginationQuery ) ;
2025-12-08 14:23:08 +10:00
IQueryable < Job > query = jobService . Get ( ) . Include ( t = > t . AutoControl ) ;
2025-07-01 17:20:48 +10:00
query = query . OrderBy ( t = > t . Name ) ;
if ( ! string . IsNullOrEmpty ( filter . Name ) )
query = query . Where ( t = > t . Name . ToLower ( ) . Contains ( filter . Name . ToLower ( ) ) ) ;
if ( filter . GroupId . HasValue )
query = query . Where ( t = > t . GroupId = = filter . GroupId . Value ) ;
2025-12-09 16:00:38 +10:00
if ( filter . TnkId . HasValue )
query = query . Where ( t = > t . TnkId = = filter . TnkId . Value ) ;
2025-09-09 17:19:41 +10:00
if ( filter . IsFull )
{
query = query
. Include ( t = > t . Tnk )
2025-12-19 10:48:41 +10:00
. Include ( t = > t . Group ) . ThenInclude ( t = > t . GroupType )
. Include ( t = > t . Group ) . ThenInclude ( t = > t . GroupingUnitField ) ;
2025-09-09 17:19:41 +10:00
query = query
. Include ( t = > t . UnitFilters )
2025-09-24 12:34:46 +10:00
. ThenInclude ( t = > t . FieldFilters )
2025-09-22 15:25:17 +10:00
. ThenInclude ( t = > t . UnitField )
2025-09-09 17:19:41 +10:00
. Include ( t = > t . UnitFilters )
2025-09-24 12:34:46 +10:00
. ThenInclude ( t = > t . RelationshipFilters )
2025-09-09 17:19:41 +10:00
. ThenInclude ( t = > t . UnitField ) ;
}
2025-07-01 17:20:48 +10:00
var jobs = await jobService . GetPage ( query , paginationFilter ) . ToListAsync ( ) ;
if ( ! jobs . Any ( ) )
return NoContent ( ) ;
var response = mapper . Map < List < JobResponse > > ( jobs ) ; //TODO Migration to job
2025-09-10 11:01:54 +10:00
foreach ( var jobResponse in response )
{
2025-12-26 11:21:45 +10:00
//jobResponse.TemplatesCount = await templateService.Get().CountAsync(t => t.JobId == jobResponse.Id);
jobResponse . TemplatesCount = await GetCountTemplatesAsync ( jobResponse . Id ) ;
2026-01-16 11:04:26 +10:00
if ( filter . IsFull )
{
jobResponse . MatchingStatus = await GetMatchingStatusAsync ( jobResponse . Id ) ;
}
2025-09-10 11:01:54 +10:00
}
2025-07-01 17:20:48 +10:00
var paginationResponse = new PagedResponse < JobResponse > ( response , true ) . GetPaginatedProps ( paginationFilter , query ) ;
return Ok ( paginationResponse ) ;
}
/// <summary>
/// Получить задание на выполнение работ по id
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet(ApiRoutes.Job.Get)]
public async Task < IActionResult > GetById ( [ FromRoute ] Guid id )
{
2025-09-09 17:19:41 +10:00
var job = await jobService . Get ( )
. Include ( t = > t . Tnk )
2025-11-25 12:26:24 +10:00
. Include ( t = > t . Group ) . ThenInclude ( t = > t . GroupType )
2025-12-19 10:48:41 +10:00
. Include ( t = > t . Group ) . ThenInclude ( t = > t . GroupingUnitField )
2025-09-09 17:19:41 +10:00
. Include ( t = > t . UnitFilters )
2025-09-24 10:08:50 +10:00
. ThenInclude ( t = > t . FieldFilters )
2025-09-22 15:25:17 +10:00
. ThenInclude ( t = > t . UnitField )
2025-09-09 17:19:41 +10:00
. Include ( t = > t . UnitFilters )
2025-09-24 10:08:50 +10:00
. ThenInclude ( t = > t . RelationshipFilters )
2025-09-23 10:38:19 +10:00
. ThenInclude ( t = > t . UnitField )
2025-12-08 14:23:08 +10:00
. Include ( t = > t . AutoControl )
2025-09-09 17:19:41 +10:00
. FirstOrDefaultAsync ( t = > t . Id = = id ) ;
2025-07-01 17:20:48 +10:00
if ( job = = null )
return NotFound ( ) ;
var response = mapper . Map < JobResponse > ( job ) ;
2025-09-09 17:19:41 +10:00
2025-12-26 11:21:45 +10:00
response . TemplatesCount = await GetCountTemplatesAsync ( id ) ; //await templateService.Get().CountAsync(t => t.JobId == id);
2026-01-16 11:04:26 +10:00
response . MatchingStatus = await GetMatchingStatusAsync ( id ) ;
2025-07-01 17:20:48 +10:00
2025-12-26 11:21:45 +10:00
//var statistics = await GetStatisticsAsync(response.Id);
//BindStatistics(response, statistics);
2025-07-01 17:20:48 +10:00
return Ok ( new Response < JobResponse > ( response , true ) ) ;
}
/// <summary>
/// Создать задание на выполнение работ (Job)
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpPost(ApiRoutes.Job.Create)]
public async Task < IActionResult > Create ( [ FromBody ] JobRequest request )
{
2025-09-11 16:03:51 +10:00
#region В а л и д а ц и я
var jobValidateResult = await jobValidator . ValidateAsync ( request ) ; //Валидация параметров самого задания
2025-07-01 17:20:48 +10:00
2025-09-11 16:03:51 +10:00
if ( ! jobValidateResult . IsValid )
return BadRequest ( new Response ( jobValidateResult . Errors ) ) ;
#endregion
2025-07-01 17:20:48 +10:00
2025-12-19 10:48:41 +10:00
//TODO: !!!!!!! проверить, если тип ЗОНТИК или ГРУППИРОВКА, то обязательно должны быть заполнены поля min max
2025-09-16 15:27:26 +10:00
#region П р о в е р к а с у щ е с т в о в а н и я р а б о т ы с т а к и м и ж е п а р а м е т р а м и
2025-12-08 14:23:08 +10:00
2025-09-16 15:27:26 +10:00
var isExistTheSameLinks = await jobService . Get ( )
2025-11-25 12:26:24 +10:00
. Include ( t = > t . Group ) . ThenInclude ( t = > t . GroupType )
2025-09-16 15:27:26 +10:00
. CountAsync ( t = >
2025-12-19 10:48:41 +10:00
//t.Group!.GroupType!.Code == JobGroupTypesEnum.Umbrella
( t . Group ! . GroupType ! . Code = = JobGroupTypesEnum . Umbrella | | t . Group ! . GroupType ! . Code = = JobGroupTypesEnum . Group ) & &
2025-09-16 15:27:26 +10:00
t . GroupId = = request . GroupId & &
( t . MinValueRelationships = = request . MinValueRelationships | |
t . MaxValueRelationships = = request . MaxValueRelationships )
2025-11-25 12:26:24 +10:00
) ;
2025-09-16 15:27:26 +10:00
if ( isExistTheSameLinks > 0 )
return BadRequest ( new Response ( false , new List < ErrorModel > { new ErrorModel { FieldName = nameof ( request . Name ) , Message = $"Работа с указанным диапазоном связей пересекается с уже имеющейся в базе данных({request.MinValueRelationships}-{request.MaxValueRelationships})" } } ) ) ;
2025-12-08 14:23:08 +10:00
2025-09-16 15:27:26 +10:00
#endregion
2025-09-11 16:03:51 +10:00
var job = mapper . Map < Job > ( request ) ;
2025-07-01 17:20:48 +10:00
2025-12-08 14:23:08 +10:00
job . AutoControl = new JobAutoControl
{
JobId = job . Id ,
IsEnable = request . IsEnableAutoControl ,
InitUsedScheduleState = request . InitUsedScheduleState ,
InitUsedTemplateState = request . InitUsedTemplateState
} ;
2025-07-01 17:20:48 +10:00
if ( ! await jobService . CreateAsync ( job ) | | ! await jobService . CommitAsync ( ) )
return BadRequest ( new Response ( false , new List < ErrorModel > { new ErrorModel { Message = "Ошибка при созании задания на выполнение работ" } } ) ) ;
logger . LogInformation ( $"Пользователь {User.Identity?.Name} добавил задание на выполнение работ: {job.Id}, {job.Name}, {job.WorkName}" ) ;
2025-09-11 16:03:51 +10:00
var createdJob = await jobService . Get ( )
. Include ( t = > t . Tnk )
2025-11-25 12:26:24 +10:00
. Include ( t = > t . Group ) . ThenInclude ( t = > t . GroupType )
2025-12-19 10:48:41 +10:00
. Include ( t = > t . Group ) . ThenInclude ( t = > t . GroupingUnitField )
2025-09-11 16:03:51 +10:00
. Include ( t = > t . UnitFilters )
2025-09-24 12:34:46 +10:00
. ThenInclude ( t = > t . FieldFilters )
2025-09-22 15:25:17 +10:00
. ThenInclude ( t = > t . UnitField )
2025-09-11 16:03:51 +10:00
. Include ( t = > t . UnitFilters )
2025-09-24 12:34:46 +10:00
. ThenInclude ( t = > t . RelationshipFilters )
2025-12-08 14:23:08 +10:00
. Include ( t = > t . AutoControl )
2025-09-11 16:03:51 +10:00
. FirstOrDefaultAsync ( t = > t . Id = = job . Id ) ;
2025-07-01 17:20:48 +10:00
2025-09-11 16:03:51 +10:00
var locationUri = uriService . GetUri ( ApiRoutes . Job . Get , ApiRoutes . Job . getParam , createdJob ! . Id ) ;
2025-07-01 17:20:48 +10:00
var response = mapper . Map < JobResponse > ( createdJob ) ;
// так как мы только что создали Job, то у него нет шаблонов, смело ставим = 0 (ускоряем запрос)
response . TemplatesCount = 0 ;
2026-01-16 11:04:26 +10:00
response . MatchingStatus = await GetMatchingStatusAsync ( response . Id ) ;
2025-07-01 17:20:48 +10:00
return Created ( locationUri , new Response < JobResponse > ( response , true ) ) ;
}
/// <summary>
/// Обновить задание на выполнение работ (Job)
/// </summary>
/// <param name="id"></param>
/// <param name="request"></param>
/// <returns></returns>
[HttpPut(ApiRoutes.Job.Update)]
public async Task < IActionResult > Update ( [ FromRoute ] Guid id , [ FromBody ] JobRequest request )
{
2025-09-11 16:03:51 +10:00
var resultValidate = await jobValidator . ValidateAsync ( request ) ;
2025-07-01 17:20:48 +10:00
if ( ! resultValidate . IsValid )
return BadRequest ( new Response ( resultValidate . Errors ) ) ;
2025-09-16 15:27:26 +10:00
var orig = await jobService . Get ( )
. Include ( t = > t . Tnk )
2025-11-25 12:26:24 +10:00
. Include ( t = > t . Group ) . ThenInclude ( t = > t . GroupType )
2025-12-19 10:48:41 +10:00
. Include ( t = > t . Group ) . ThenInclude ( t = > t . GroupingUnitField )
2025-09-16 15:27:26 +10:00
. Include ( t = > t . UnitFilters )
. ThenInclude ( t = > t . FieldFilters )
. Include ( t = > t . UnitFilters )
. ThenInclude ( t = > t . RelationshipFilters )
2025-12-08 14:23:08 +10:00
. Include ( t = > t . AutoControl )
2025-09-16 15:27:26 +10:00
. AsSingleQuery ( )
2025-07-01 17:20:48 +10:00
. FirstOrDefaultAsync ( t = > t . Id = = id ) ;
if ( orig = = null )
return BadRequest ( new Response ( false , new List < ErrorModel > { new ErrorModel { Message = $"Ошибка при изменении задания на выполнение работ. Н е найдено задание с Id: {id}" } } ) ) ;
2025-12-02 09:49:08 +10:00
// если изменили маску шаблона, ниже отправим в очередь, на изменение связанных имен шаблонов
var isChangedTemplateNameMask = orig . TemplateNameMask ! = request . TemplateNameMask . Trim ( ) ;
2025-12-19 10:48:41 +10:00
//TODO: В О Т ЭТО ВООБЩЕ МЫ БУДЕМ ПРОВЕРЯТЬ, А А А А ???? - Проверка существования работы с такими же параметрами
//TODO: !!!!!!! проверить, если тип ЗОНТИК или ГРУППИРОВКА, то обязательно должны быть заполнены поля min max
2025-09-16 15:27:26 +10:00
#region о б н о в л е н и е п о л е й з а д а н и я н а р а б о т у
2025-12-02 09:49:08 +10:00
2025-12-08 14:23:08 +10:00
orig . Name = request . Name . Trim ( ) ;
orig . WorkName = request . WorkName . Trim ( ) ;
orig . MinValueRelationships = request . MinValueRelationships ;
orig . MaxValueRelationships = request . MaxValueRelationships ;
orig . IsParentRelationships = request . IsParentRelationships ;
orig . TemplateNameMask = request . TemplateNameMask . Trim ( ) ;
orig . WorkGroupMask = request . WorkGroupMask . Trim ( ) ;
orig . TnkId = request . TnkId ;
orig . GroupId = request . GroupId ;
2026-01-13 14:50:34 +10:00
orig . ResponseAreaMask = request . ResponseAreaMask . Trim ( ) ;
2025-12-08 14:23:08 +10:00
if ( orig . AutoControl ! = null )
2025-09-16 15:27:26 +10:00
{
2025-12-08 14:23:08 +10:00
orig . AutoControl . IsEnable = request . IsEnableAutoControl ;
orig . AutoControl . InitUsedScheduleState = request . InitUsedScheduleState ;
orig . AutoControl . InitUsedTemplateState = request . InitUsedTemplateState ;
2025-09-16 15:27:26 +10:00
}
2025-12-08 14:23:08 +10:00
else
2025-09-16 15:27:26 +10:00
{
2025-12-08 14:23:08 +10:00
// автоконтрол не загружен, проверяем есть ли он в бд, если нет, то создадим
var existAutoControl = await jobAutoControlService . Get ( ) . FirstOrDefaultAsync ( t = > t . JobId = = id ) ;
if ( existAutoControl ! = null )
{
logger . LogError ( $"При обновлении job {id}, не загрузась связь с JobAutoControl, но она есть. Н е стал обновлять Job, вернул ошибку." ) ;
return BadRequest ( new Response ( false , new List < ErrorModel > { new ErrorModel { Message = $"Ошибка при изменении задания на выполнение работ." } } ) ) ;
}
else
{
var autoControl = new JobAutoControl
{
JobId = id ,
InitUsedScheduleState = request . InitUsedScheduleState ,
InitUsedTemplateState = request . InitUsedTemplateState ,
IsEnable = request . IsEnableAutoControl
} ;
orig . AutoControl = autoControl ;
logger . LogWarning ( $"При обновлении job {id}, отсутствовала запись в таблице JobAutoControl, создал е е . {autoControl.ToJson()}" ) ;
}
2025-09-16 15:27:26 +10:00
}
2025-12-08 14:23:08 +10:00
orig . DateModified = DateTimeOffset . UtcNow ;
2025-09-16 15:27:26 +10:00
#endregion
var job = mapper . Map < Job > ( request ) ;
job . Id = id ; //Н а всякий. Пусть будет для чистоты
UpdateUnitFilters ( orig , job ) ; //Обновление вложенных дочерних элементов-фильтров
2025-07-01 17:20:48 +10:00
if ( ! await jobService . CommitAsync ( ) )
return BadRequest ( new Response ( false , new List < ErrorModel > { new ErrorModel { Message = "Ошибка при изменении задания на выполнение работ." } } ) ) ;
2025-12-02 09:49:08 +10:00
// если изменили маску, отправим задание на переименование связанных шаблонов
if ( isChangedTemplateNameMask )
{
var mqResult = await SendRequestToUpdateTemplates ( id ) ;
//todo: если ошибка. пользователя не предупреждаем... возможно ему это и не нужно знать...ну не переименуются шаблоны, может они переименуются позже...
}
2025-07-01 17:20:48 +10:00
logger . LogInformation ( $"Пользователь {User.Identity?.Name} обновил задание на выполнение работ: {orig.Id}," +
$" {orig.Name}, {orig.WorkName}, {orig.MinValueRelationships}, {orig.MaxValueRelationships}," +
$" {orig.TemplateNameMask}, {orig.TnkId}, {nameof(orig.GroupId)}" ) ;
2025-09-16 15:27:26 +10:00
var updatedJob = await jobService . Get ( )
. Include ( t = > t . Tnk )
2025-11-17 12:06:33 +10:00
. Include ( t = > t . Group ) . ThenInclude ( t = > t . GroupType )
2025-12-19 10:48:41 +10:00
. Include ( t = > t . Group ) . ThenInclude ( t = > t . GroupingUnitField )
2025-09-16 15:27:26 +10:00
. Include ( t = > t . UnitFilters )
. ThenInclude ( t = > t . FieldFilters )
2025-09-22 15:25:17 +10:00
. ThenInclude ( t = > t . UnitField )
2025-09-16 15:27:26 +10:00
. Include ( t = > t . UnitFilters )
. ThenInclude ( t = > t . RelationshipFilters )
2025-12-08 14:23:08 +10:00
. Include ( t = > t . AutoControl )
2025-07-01 17:20:48 +10:00
. FirstAsync ( t = > t . Id = = orig . Id ) ;
2025-09-16 15:27:26 +10:00
var response = mapper . Map < JobResponse > ( updatedJob ) ;
2025-12-26 11:21:45 +10:00
response . TemplatesCount = await GetCountTemplatesAsync ( id ) ; //await templateService.Get().CountAsync(t => t.JobId == id);
2026-01-16 11:04:26 +10:00
response . MatchingStatus = await GetMatchingStatusAsync ( id ) ;
2025-07-01 17:20:48 +10:00
2025-12-26 11:21:45 +10:00
//не используется
//var statistics = await GetStatisticsAsync(response.Id);
//BindStatistics(response, statistics);
2025-07-01 17:20:48 +10:00
return Ok ( new Response < JobResponse > ( response , true ) ) ;
2025-09-16 15:27:26 +10:00
}
private void UpdateUnitFilters ( Job orig , Job mappedRequest )
{
2025-09-23 10:38:19 +10:00
orig . UnitFilters . Clear ( ) ;
foreach ( var mappedUnitFilter in mappedRequest . UnitFilters )
{
var newUnitFilter = new JobUnitFilter
{
UnitFilter = mappedUnitFilter . UnitFilter ,
DateCreated = DateTimeOffset . UtcNow ,
JobId = orig . Id
} ;
foreach ( var newRequestFieldFilter in mappedUnitFilter . FieldFilters )
{
2025-12-26 15:44:39 +10:00
var newFieldFilter = CreateFieldFilter ( newUnitFilter . Id , newRequestFieldFilter . FieldId , newRequestFieldFilter . ValueMask , newRequestFieldFilter . IsInverse ) ;
2025-09-23 10:38:19 +10:00
newUnitFilter . FieldFilters . Add ( newFieldFilter ) ;
}
foreach ( var newRequestRelationshipFilter in mappedUnitFilter . RelationshipFilters )
{
var newRelationshipFilter = CreateRelationshipFilter ( newRequestRelationshipFilter . FieldId ,
newRequestRelationshipFilter . IsParent ,
newRequestRelationshipFilter . IsFullMatch ,
newRequestRelationshipFilter . IsInverse ,
newRequestRelationshipFilter . ValueMask ) ;
newUnitFilter . RelationshipFilters . Add ( newRelationshipFilter ) ;
}
orig . UnitFilters . Add ( newUnitFilter ) ;
}
2025-12-26 11:21:45 +10:00
#region old
/ * П и с а л п о л н о ц е н н ы й а п д е й т , н о М и ш а с к а з а л ч т о н а х р е н э т о - п р о с т о в с е у д а л я е м , а п о т о м с о з д а ё м з а н о в о . . . О х у ж э т о т М и ш а . . .
2025-09-24 10:08:50 +10:00
//Сразу удаляем UnitFilter которых нет
2025-09-16 15:27:26 +10:00
var toDelete = orig . UnitFilters . Where ( t = > ! mappedRequest . UnitFilters . Any ( e = > e . Id = = t . Id ) ) ;
foreach ( var item in toDelete )
orig . UnitFilters . Remove ( item ) ;
2025-07-01 17:20:48 +10:00
2025-09-16 15:27:26 +10:00
foreach ( var mappedUnitFilter in mappedRequest . UnitFilters )
{
var origUnitFilter = orig . UnitFilters . FirstOrDefault ( t = > t . Id = = mappedUnitFilter . Id ) ;
if ( origUnitFilter = = null )
{
var newUnitFilter = new JobUnitFilter
{
UnitFilter = mappedUnitFilter . UnitFilter ,
DateCreated = DateTimeOffset . UtcNow ,
JobId = orig . Id
} ;
foreach ( var newRequestFieldFilter in mappedUnitFilter . FieldFilters )
{
var newFieldFilter = CreateFieldFilter ( newUnitFilter . Id , newRequestFieldFilter . FieldId , newRequestFieldFilter . ValueMask ) ;
newUnitFilter . FieldFilters . Add ( newFieldFilter ) ;
}
foreach ( var newRequestRelationshipFilter in mappedUnitFilter . RelationshipFilters )
{
var newRelationshipFilter = CreateRelationshipFilter ( newRequestRelationshipFilter . FieldId ,
newRequestRelationshipFilter . IsParent ,
newRequestRelationshipFilter . IsFullMatch ,
newRequestRelationshipFilter . IsInverse ,
newRequestRelationshipFilter . ValueMask ) ;
newUnitFilter . RelationshipFilters . Add ( newRelationshipFilter ) ;
}
orig . UnitFilters . Add ( newUnitFilter ) ;
}
else
{
#region Н е п о с р е д с т в е н н о UnitFilter
if ( origUnitFilter . UnitFilter ! = mappedUnitFilter . UnitFilter )
{
origUnitFilter . UnitFilter = mappedUnitFilter . UnitFilter ;
origUnitFilter . DateModified = DateTimeOffset . UtcNow ;
}
#endregion
#region FieldFilters
//Сразу удаляем неактуальные
var fieldFiltersToDelete = origUnitFilter . FieldFilters . Where ( t = > ! mappedUnitFilter . FieldFilters . Any ( m = > m . FieldId = = t . FieldId ) ) ;
foreach ( var item in fieldFiltersToDelete )
origUnitFilter . FieldFilters . Remove ( item ) ;
//Перебираем FieldFilter
foreach ( var mappedFieldFilter in mappedUnitFilter . FieldFilters )
{
var origFieldFilter = origUnitFilter . FieldFilters . FirstOrDefault ( t = > t . FieldId = = mappedFieldFilter . FieldId ) ;
if ( origFieldFilter = = null ) //Нет в БД? не проблема - создадим
{
var newFieldFilter = CreateFieldFilter ( origUnitFilter . Id , mappedFieldFilter . FieldId , mappedFieldFilter . ValueMask ) ;
origUnitFilter . FieldFilters . Add ( newFieldFilter ) ;
}
else
{
if ( origFieldFilter . ValueMask ! = mappedFieldFilter . ValueMask )
{
origFieldFilter . ValueMask = mappedFieldFilter . ValueMask ;
origFieldFilter . DateModified = DateTimeOffset . UtcNow ;
}
}
}
#endregion
#region RelationshipFilters
//Сразу удаляем неактуальные
var relationshipFiltersToDelete = origUnitFilter . RelationshipFilters . Where ( t = > ! mappedUnitFilter . RelationshipFilters . Any ( m = > m . FieldId = = t . FieldId ) ) ;
foreach ( var item in relationshipFiltersToDelete )
origUnitFilter . RelationshipFilters . Remove ( item ) ;
//Перебираем RelationshipFilters
foreach ( var mappedRelationshipFilter in mappedUnitFilter . RelationshipFilters )
{
var origRelationshipFilter = origUnitFilter . RelationshipFilters . FirstOrDefault ( t = > t . FieldId = = mappedRelationshipFilter . FieldId ) ;
if ( origRelationshipFilter = = null ) //Нет в БД? не проблема - создадим
{
var newRelationshipFilter = CreateRelationshipFilter ( mappedRelationshipFilter . FieldId ,
mappedRelationshipFilter . IsParent ,
mappedRelationshipFilter . IsFullMatch ,
mappedRelationshipFilter . IsInverse ,
mappedRelationshipFilter . ValueMask ) ;
origUnitFilter . RelationshipFilters . Add ( newRelationshipFilter ) ;
}
else
{
if ( origRelationshipFilter . IsParent ! = mappedRelationshipFilter . IsParent )
origRelationshipFilter . IsParent = mappedRelationshipFilter . IsParent ;
if ( origRelationshipFilter . ValueMask ! = mappedRelationshipFilter . ValueMask )
origRelationshipFilter . ValueMask = mappedRelationshipFilter . ValueMask ;
if ( origRelationshipFilter . IsFullMatch ! = mappedRelationshipFilter . IsFullMatch )
origRelationshipFilter . IsFullMatch = mappedRelationshipFilter . IsFullMatch ;
if ( origRelationshipFilter . IsInverse ! = mappedRelationshipFilter . IsInverse )
origRelationshipFilter . IsInverse = mappedRelationshipFilter . IsInverse ;
}
}
#endregion
}
2025-09-23 10:38:19 +10:00
} * /
2025-12-26 11:21:45 +10:00
#endregion
2025-09-16 15:27:26 +10:00
}
private static JobRelationshipFilter CreateRelationshipFilter ( Guid fieldId , bool isParent , bool isFullMatch , bool isInverse , string valueMask )
{
return new JobRelationshipFilter
{
FieldId = fieldId ,
IsParent = isParent ,
IsFullMatch = isFullMatch ,
IsInverse = isInverse ,
ValueMask = valueMask
} ;
}
2025-12-26 15:44:39 +10:00
private static JobFieldFilter CreateFieldFilter ( Guid unitFilterId , Guid fieldId , string valueMask , bool isInverse )
2025-09-16 15:27:26 +10:00
{
2025-09-22 15:25:17 +10:00
return new JobFieldFilter
2025-09-16 15:27:26 +10:00
{
UnitFilterId = unitFilterId ,
DateCreated = DateTimeOffset . UtcNow ,
FieldId = fieldId ,
2025-12-26 15:44:39 +10:00
ValueMask = valueMask ,
IsInverse = isInverse
2025-09-16 15:27:26 +10:00
} ;
2025-07-01 17:20:48 +10:00
}
/// <summary>
/// Удалить задание на выполнение работ (только если нет связанных шаблонов)
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpDelete(ApiRoutes.Job.Delete)]
public async Task < IActionResult > Delete ( [ FromRoute ] Guid id )
{
var job = await jobService . Get ( ) . Include ( t = > t . Tnk )
. FirstOrDefaultAsync ( t = > t . Id = = id ) ;
if ( job = = null )
return BadRequest ( new Response ( false , new List < ErrorModel > { new ErrorModel {
Message = $"Ошибка при удалении задания на выполнение работ. Н е найдено задание на выполнение работ Id: {id}"
} } ) ) ;
var templateCount = await templateService . Get ( ) . CountAsync ( t = > t . JobId = = id ) ;
if ( templateCount > 0 )
return BadRequest ( new Response ( false , new List < ErrorModel > { new ErrorModel {
Message = $"Ошибка при удалении задания на выполнение работ. С данным заданием связаны шаблоны: {templateCount} шт."
} } ) ) ;
if ( ! jobService . Delete ( job ) | | ! await jobService . CommitAsync ( ) )
return BadRequest ( new Response ( false , new List < ErrorModel > { new ErrorModel {
Message = $"Ошибка при удалении задания на выполнение работ"
} } ) ) ;
logger . LogInformation ( $"Пользователь {User.Identity?.Name} удалил задание на выполнение работ: {job.Id},{job.Name}," +
$" {job.WorkName}, {job.MinValueRelationships}, {job.MaxValueRelationships}," +
$" {job.TemplateNameMask}, {job.TnkId}, {job.GroupId}" ) ;
return NoContent ( ) ;
}
/// <summary>
/// Загрузка статистики
/// </summary>
/// <param name="jobId"></param>
/// <returns></returns>
private async Task < JobStatModel > GetStatisticsAsync ( Guid jobId )
{
var statResult = await jobService . Get ( )
. Include ( t = > t . Templates )
. ThenInclude ( t = > t . RobotConfigurations )
. Where ( x = > x . Id = = jobId )
. 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 ( ) ;
return new JobStatModel
{
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 }
} ;
}
2025-12-02 09:49:08 +10:00
2025-07-01 17:20:48 +10:00
private void BindStatistics ( JobResponse job , JobStatModel statistics )
{
2025-09-09 17:19:41 +10:00
//job.TemplateStatistics = new TemplateStats { Activated = statistics.TemplateStatistics.Activated, Errors = statistics.TemplateStatistics.Errors, Synchronized = statistics.TemplateStatistics.Synchronized };
//job.ScheduleStatistics = new ScheduleStats { Activated = statistics.ScheduleStatistics.Activated, Errors = statistics.ScheduleStatistics.Errors, Synchronized = statistics.ScheduleStatistics.Synchronized };
2025-07-01 17:20:48 +10:00
}
2025-12-02 09:49:08 +10:00
private async Task < bool > SendRequestToUpdateTemplates ( Guid jobId )
{
var request = new TemplateMatcherMq
{
Id = jobId ,
EntityType = SyncTaskEntityTypeEnum . Job ,
Action = TemplateMatcherActionEnum . Update ,
Initiator = new HistoryInitiator
{
InitiatorIp = clientService . GetClientIp ( ) ? . ToString ( ) ,
InitiatorParrComponentId = ParrComponentsEnum . Api ,
InitiatorComment = $"В GUI изменено имя шаблона, при сохранении Job отправлен запрос на обновление связанных шаблонов"
}
} ;
2026-01-22 10:56:02 +10:00
//var msg = JsonSerializer.Serialize(request);
//var result = await mqService.SendAsync(mqSettings.TemplatesMatcher, new[] { msg });
var result = await mqService . SendAsync ( mqSettings . TemplatesMatcher , new List < object > { request } ) ;
2025-12-02 09:49:08 +10:00
logger . LogDebug ( "Получен код отпрвки: {IsSuccess}" , result . IsSuccess ) ;
if ( ! result . IsSuccess )
{
2026-01-22 10:56:02 +10:00
logger . LogError ( $"Ошибка при отправке запроса в очередь на обновление связанных шаблонов, после обновления маски шаблона. {request.ToJson()}" ) ;
2025-12-02 09:49:08 +10:00
return false ;
}
2026-01-22 10:56:02 +10:00
logger . LogInformation ( $"После изменения маски шаблона в jobId: {jobId}, отправлен запрос в очередь на переименование связанных шаблонов: {request.ToJson()}" ) ;
2025-12-02 09:49:08 +10:00
return true ;
}
2025-12-26 11:21:45 +10:00
/// <summary>
/// Получить кол-во шаблонов в Job
/// </summary>
/// <param name="jobId"></param>
/// <returns></returns>
private async Task < int > GetCountTemplatesAsync ( Guid jobId )
{
// Получаем только шаблоны в статусе used
return await templateService . Get ( ) . CountAsync ( t = > t . JobId = = jobId & & t . StatusTypeId = = TemplateStatusTypeEnum . Used ) ;
}
2026-01-16 11:04:26 +10:00
/// <summary>
/// Получить статус matching`a
/// </summary>
/// <param name="jobId"></param>
/// <returns></returns>
private async Task < MatchingStatusResponse ? > GetMatchingStatusAsync ( Guid jobId )
{
var statusMatching = await matchingStatusService . GetStatusAsync ( jobId , SyncTaskEntityTypeEnum . Job ) ;
return mapper . Map < MatchingStatusResponse > ( statusMatching ) ;
}
2025-07-01 17:20:48 +10:00
}
2025-09-24 10:08:50 +10:00
2025-07-01 17:20:48 +10:00
public class JobStatModel
{
2025-08-22 11:25:51 +10:00
public required TemplateStats TemplateStatistics { get ; set ; }
2025-07-01 17:20:48 +10:00
2025-08-22 11:25:51 +10:00
public required ScheduleStats ScheduleStatistics { get ; set ; }
2025-07-01 17:20:48 +10:00
}
2025-09-11 16:03:51 +10:00
2025-09-16 15:27:26 +10:00
2025-07-01 17:20:48 +10:00
}