From 8151ea89b9a78ac5a0802de4ed3b029c2c337f45 Mon Sep 17 00:00:00 2001 From: Mikhail Trubnikov Date: Thu, 18 Jun 2026 16:39:35 +1000 Subject: [PATCH 1/4] =?UTF-8?q?feat(api,core,dal):=20=D0=93=D1=80=D1=83?= =?UTF-8?q?=D0=BF=D0=BF=D1=8B=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=20-=20?= =?UTF-8?q?=D1=83=D0=BF=D1=80=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20?= =?UTF-8?q?=D0=B0=D0=B2=D1=82=D0=BE=D0=BA=D0=BD=D0=BE=D1=82=D1=80=D0=BE?= =?UTF-8?q?=D0=BB=D0=B5=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../V1/Requests/JobAutoControlRequest.cs | 54 +- .../Contracts/V1/Requests/JobGroupRequest.cs | 55 +- .../V1/Responses/JobGroupResponse.cs | 11 + .../V1/Responses/JobGroupTypeResponse.cs | 16 +- PARR.API/Controllers/V1/JobGroupController.cs | 175 +- .../Controllers/V1/JobGroupTypeController.cs | 14 +- .../V1/ShortcodeApplyController.cs | 2 +- .../Controllers/V1/ShortcodeController.cs | 2 +- .../DomainToResponseProfile.cs | 4 +- .../JobAutoControlRequestValidator.cs | 33 - PARR.API/Validators/JobGroupValidator.cs | 43 +- .../Job/IJobAutoControlRepository.cs | 1 + PARR.DAL/Context/DataContext.cs | 6 +- ...pTypesAddRelationshipsSettings.Designer.cs | 4021 +++++++++++++++++ ...1_tblGroupTypesAddRelationshipsSettings.cs | 57 + .../Migrations/DataContextModelSnapshot.cs | 7 + .../Job/JobAutoControlRepository.cs | 5 + .../Entities/JobGroupEntities/JobGroupType.cs | 6 + 18 files changed, 4326 insertions(+), 186 deletions(-) delete mode 100644 PARR.API/Validators/JobAutoControlRequestValidator.cs create mode 100644 PARR.DAL/Migrations/20260615235401_tblGroupTypesAddRelationshipsSettings.Designer.cs create mode 100644 PARR.DAL/Migrations/20260615235401_tblGroupTypesAddRelationshipsSettings.cs diff --git a/PARR.API/Contracts/V1/Requests/JobAutoControlRequest.cs b/PARR.API/Contracts/V1/Requests/JobAutoControlRequest.cs index 8f2f3113..3d144acf 100644 --- a/PARR.API/Contracts/V1/Requests/JobAutoControlRequest.cs +++ b/PARR.API/Contracts/V1/Requests/JobAutoControlRequest.cs @@ -1,52 +1,14 @@ -using PARR.Domain.Enums; - -namespace PARR.API.Contracts.V1.Requests +namespace PARR.API.Contracts.V1.Requests { - public class JobAutoControlRequest + /// + /// Часть реквеста по управлению авто контролем для Job, JobGroup + /// + public record JobAutoControlRequest { - /// - /// Создавать новые РР (из настроке РР) - /// - public bool CreateNew { get; set; } + public bool IsEnable { get; init; } - /// - /// Деактивировать не актуальные согласно ЭК (обратные статусы ЭК) - /// - public bool Deactivate { get; set; } + public bool InitUsedTemplateState { get; init; } - /// - /// Активировать РР после смены ЭК (согласно настройкам статусов ЭК) - /// - public bool Activate { get; set; } - - /// - /// Состояние для активированных РР, шаблоны - /// - public bool OnTemplateIsActive { get; set; } - - /// - /// Состояние для активированных РР, расписания - /// - public bool OnScheduleIsActive { get; set; } - - /// - /// Состояние для деактивированных РР, шаблоны - /// - public bool OffTemplateIsActive { get; set; } - - /// - /// Состояние для деактивированных РР, расписания - /// - public bool OffScheduleIsActive { get; set; } - - /// - /// Маски ЭК - /// - public required List EkMasks { get; set; } - - /// - /// Статусы ЭК для которых включена генерация РР и активация - /// - public required List EnabledEkStatuses { get; set; } + public bool InitUsedScheduleState { get; init; } } } diff --git a/PARR.API/Contracts/V1/Requests/JobGroupRequest.cs b/PARR.API/Contracts/V1/Requests/JobGroupRequest.cs index de37af25..672ae79f 100644 --- a/PARR.API/Contracts/V1/Requests/JobGroupRequest.cs +++ b/PARR.API/Contracts/V1/Requests/JobGroupRequest.cs @@ -1,47 +1,47 @@ namespace PARR.API.Contracts.V1.Requests { - public class JobGroupRequest + public record JobGroupRequest { - public required string Name { get; set; } + public required string Name { get; init; } //public bool? IsUmbrella { get; set; } - public Guid GroupTypeId { get; set; } + public Guid GroupTypeId { get; init; } /// /// Поле по которому групиируем, если тип - ГРУППА /// - public Guid? GroupingUnitFieldId { get; set; } + public Guid? GroupingUnitFieldId { get; init; } - public bool? IsGroupByResponsible { get; set; } + public bool? IsGroupByResponsible { get; init; } - public required string ShortDescription { get; set; } + public required string ShortDescription { get; init; } - public required string FullDescription { get; set; } + public required string FullDescription { get; init; } - public required string Solution { get; set; } + public required string Solution { get; init; } - public required string TemplateDuration { get; set; } + public required string TemplateDuration { get; init; } - public DateTimeOffset ReferenceDate { get; set; } + public DateTimeOffset ReferenceDate { get; init; } - public int? UserTimeZoneOffsetMinutes { get; set; } + public int? UserTimeZoneOffsetMinutes { get; init; } /// /// Использовать таймзону рабочей группы ответственного за ЭК шаблона /// - public bool IsWorkGroupTimezone { get; set; } + public bool IsWorkGroupTimezone { get; init; } - public Guid ScheduleExcludeTypeId { get; set; } + public Guid ScheduleExcludeTypeId { get; init; } - public Guid? ScheduleExcludeTypeCalendarId { get; set; } + public Guid? ScheduleExcludeTypeCalendarId { get; init; } - public bool IsAutoDistributionEnabled { get; set; } + public bool IsAutoDistributionEnabled { get; init; } /// /// Настройки автораспределения /// - public DistributionConfigRequest? DistributionConfig { get; set; } + public DistributionConfigRequest? DistributionConfig { get; init; } //public bool IsAgent { get; set; } @@ -51,28 +51,35 @@ //public string? AgentScript { get; set; } - public List Schedule { get; set; } = new List(); + public List Schedule { get; init; } = new List(); + + /// + /// Настройки автоконтроля (возможны только в случае, если JobGroupType.IsJobGroupAutocontrol==true) + /// + public JobAutoControlRequest? AutoControl { get; init; } } - public class EsppSchValueRequest + public record EsppSchValueRequest { - public Guid TypeValueId { get; set; } + public Guid TypeValueId { get; init; } - public Guid TypeConfigId { get; set; } + public Guid TypeConfigId { get; init; } } - public class DistributionConfigRequest + public record DistributionConfigRequest { - public Guid DistributionPeriodId { get; set; } + public Guid DistributionPeriodId { get; init; } /// /// Исключать выходные и праздники /// - public bool IsExcludeWeekends { get; set; } + public bool IsExcludeWeekends { get; init; } /// /// Группировать по рабочей группе /// - public bool IsGroupingByWorkGroup { get; set; } + public bool IsGroupingByWorkGroup { get; init; } } + + } diff --git a/PARR.API/Contracts/V1/Responses/JobGroupResponse.cs b/PARR.API/Contracts/V1/Responses/JobGroupResponse.cs index 40e0550f..449c40a4 100644 --- a/PARR.API/Contracts/V1/Responses/JobGroupResponse.cs +++ b/PARR.API/Contracts/V1/Responses/JobGroupResponse.cs @@ -68,12 +68,23 @@ /// public ScheduleExcludeTypeCalendarResponse? ScheduleExcludeTypeCalendar { get; set; } + public JobGroupAutoControlResponse? AutoControl { get; set; } + ///// ///// Настройки автораспределения ///// //public JobGroupDistributionConfigResponse? DistributionConfig { get; set; } } + public class JobGroupAutoControlResponse + { + public bool IsEnable { get; set; } + + public bool InitUsedTemplateState { get; set; } + + public bool InitUsedScheduleState { get; set; } + } + public class JobGroupScheduleResponse { public string Timezone { get; set; } = string.Empty; diff --git a/PARR.API/Contracts/V1/Responses/JobGroupTypeResponse.cs b/PARR.API/Contracts/V1/Responses/JobGroupTypeResponse.cs index ab36b909..f00e7eef 100644 --- a/PARR.API/Contracts/V1/Responses/JobGroupTypeResponse.cs +++ b/PARR.API/Contracts/V1/Responses/JobGroupTypeResponse.cs @@ -2,14 +2,20 @@ namespace PARR.API.Contracts.V1.Responses { - public class JobGroupTypeResponse + public record JobGroupTypeResponse { - public Guid Id { get; set; } + public Guid Id { get; init; } - public required JobGroupTypesEnum Code { get; set; } + public required JobGroupTypesEnum Code { get; init; } - public required string Name { get; set; } + public required string Name { get; init; } - public required string Description { get; set; } + public required string Description { get; init; } + + public bool IsAllowJobUnitFilter { get; init; } + + public bool IsJobGroupAutoControl { get; init; } + + public bool IsRelationshipsAllowed { get; init; } } } diff --git a/PARR.API/Controllers/V1/JobGroupController.cs b/PARR.API/Controllers/V1/JobGroupController.cs index 44446685..c4aac721 100644 --- a/PARR.API/Controllers/V1/JobGroupController.cs +++ b/PARR.API/Controllers/V1/JobGroupController.cs @@ -36,13 +36,13 @@ namespace PARR.API.Controllers.V1 private readonly ILogger logger; private readonly IMapper mapper; private readonly IUriService uriService; - private readonly IJobGroupRepository groupService; - private readonly IJobRepository jobService; - private readonly IEsppSchTypeConfigRepository esppConfigService; - //private readonly IValidator validator; - private readonly IJobGroupTypeRepository jobGroupTypeService; - private readonly IMatchingStatusService matchingStatusService; - private readonly IScheduleResponseAreaTimeOffsetRepository scheduleResponseAreaTimeOffsetService; + private readonly IJobGroupRepository _groupRepository; + private readonly IJobRepository _jobRepository; + private readonly IEsppSchTypeConfigRepository _esppConfigRepository; + private readonly IJobGroupTypeRepository _jobGroupTypeRepository; + private readonly IMatchingStatusService _matchingStatusRepository; + private readonly IScheduleResponseAreaTimeOffsetRepository _scheduleResponseAreaTimeOffsetRepository; + private readonly IJobAutoControlRepository _jobAutoControlRepository; private readonly IRabbitService mqService; private readonly MqSettings mqSettings; @@ -50,13 +50,13 @@ namespace PARR.API.Controllers.V1 ILogger logger, IMapper mapper, IUriService uriService, - IJobGroupRepository groupService, - IJobRepository jobService, - IEsppSchTypeConfigRepository esppConfigService, - //IValidator validator, - IJobGroupTypeRepository jobGroupTypeService, - IMatchingStatusService matchingStatusService, - IScheduleResponseAreaTimeOffsetRepository scheduleResponseAreaTimeOffsetService, + IJobGroupRepository groupRepository, + IJobRepository jobRepository, + IEsppSchTypeConfigRepository esppConfigRepository, + IJobGroupTypeRepository jobGroupTypeRepository, + IMatchingStatusService matchingStatusRepository, + IScheduleResponseAreaTimeOffsetRepository scheduleResponseAreaTimeOffsetRepository, + IJobAutoControlRepository jobAutoControlRepository, IRabbitService mqService, MqSettings mqSettings ) @@ -64,20 +64,20 @@ namespace PARR.API.Controllers.V1 this.logger = logger; this.mapper = mapper; this.uriService = uriService; - this.groupService = groupService; - this.jobService = jobService; - this.esppConfigService = esppConfigService; - //this.validator = validator; - this.jobGroupTypeService = jobGroupTypeService; - this.matchingStatusService = matchingStatusService; - this.scheduleResponseAreaTimeOffsetService = scheduleResponseAreaTimeOffsetService; + _groupRepository = groupRepository; + _jobRepository = jobRepository; + _esppConfigRepository = esppConfigRepository; + _jobGroupTypeRepository = jobGroupTypeRepository; + _matchingStatusRepository = matchingStatusRepository; + _scheduleResponseAreaTimeOffsetRepository = scheduleResponseAreaTimeOffsetRepository; + _jobAutoControlRepository = jobAutoControlRepository; this.mqService = mqService; this.mqSettings = mqSettings; } /// - /// Получить список групп заданий на выполнение работ постранично + /// Получить список групп работ постранично /// /// [HttpGet(ApiRoutes.JobGroup.GetAll)] @@ -85,11 +85,12 @@ namespace PARR.API.Controllers.V1 { var paginationFilter = mapper.Map(paginationQuery); - IQueryable query = groupService.Get() + IQueryable query = _groupRepository.Get() .Include(t => t.GroupType) .Include(t => t.GroupingUnitField) .Include(t => t.ScheduleExcludeType) - .Include(t => t.ScheduleExcludeTypeCalendar); + .Include(t => t.ScheduleExcludeTypeCalendar) + .Include(t => t.AutoControl); query = query.OrderBy(t => t.GroupName); @@ -104,7 +105,7 @@ namespace PARR.API.Controllers.V1 .Include(t => t.Jobs).ThenInclude(t => t.Tnk) .Include(t => t.DistributionConfig).ThenInclude(t => t.DistributionPeriod); - var jobGroups = await groupService.GetPage(query, paginationFilter).ToListAsync(); + var jobGroups = await _groupRepository.GetPage(query, paginationFilter).ToListAsync(); if (!jobGroups.Any()) return NoContent(); @@ -122,20 +123,21 @@ namespace PARR.API.Controllers.V1 /// - /// Получить группу заданий на выполнение работ по id + /// Получить группу работ по id /// /// /// [HttpGet(ApiRoutes.JobGroup.Get)] public async Task GetById([FromRoute] Guid id) { - var jobGroup = await groupService.Get() + var jobGroup = await _groupRepository.Get() .Include(t => t.Jobs).ThenInclude(t => t.Tnk) .Include(t => t.GroupType) .Include(t => t.GroupingUnitField) .Include(t => t.ScheduleExcludeType) .Include(t => t.ScheduleExcludeTypeCalendar) .Include(t => t.DistributionConfig).ThenInclude(t => t.DistributionPeriod) + .Include(t => t.AutoControl) .FirstOrDefaultAsync(t => t.Id == id); if (jobGroup == null) @@ -149,18 +151,13 @@ namespace PARR.API.Controllers.V1 /// - /// Создать группу заданий на выполнение работ (JobGroup) + /// Создать группу работ (JobGroup) /// /// /// [HttpPost(ApiRoutes.JobGroup.Create)] public async Task Create([FromBody] JobGroupRequest request) { - //var resultValidate = await validator.ValidateAsync(request); - - //if (!resultValidate.IsValid) - // return BadRequest(new Response(resultValidate.Errors)); - var jobGroup = new JobGroup { Id = Guid.NewGuid(), @@ -199,6 +196,22 @@ namespace PARR.API.Controllers.V1 } #endregion + #region Настройки автоконтроля + + // Корректность проверяется в валидаторе + if (request.AutoControl != null) + { + jobGroup.AutoControl = new JobGroupAutoControl + { + InitUsedScheduleState = request.AutoControl.InitUsedScheduleState, + InitUsedTemplateState = request.AutoControl.InitUsedTemplateState, + IsEnable = request.AutoControl.IsEnable, + JobGroupId = jobGroup.Id + }; + } + + #endregion + //Добавляем настройки планировщика request.Schedule.ForEach(item => { @@ -210,18 +223,19 @@ namespace PARR.API.Controllers.V1 }); }); - if (!await groupService.CreateAsync(jobGroup) || !await groupService.CommitAsync()) + if (!await _groupRepository.CreateAsync(jobGroup) || !await _groupRepository.CommitAsync()) return BadRequest(new Response(false, new List { new ErrorModel { Message = "Ошибка при создании группы заданий на выполнение работ" } })); logger.LogInformation($"Пользователь {User.Identity?.Name} добавил группу заданий на выполнение работ: {jobGroup.Id}, {jobGroup.GroupName}, {jobGroup.ShortDescription}"); - var createdJobGroup = await groupService.Get().Include(t => t.Jobs).ThenInclude(t => t.Tnk) + var createdJobGroup = await _groupRepository.Get().Include(t => t.Jobs).ThenInclude(t => t.Tnk) .Include(t => t.GroupType) .Include(t => t.GroupingUnitField) .Include(t => t.ScheduleExcludeType) .Include(t => t.ScheduleExcludeTypeCalendar) .Include(t => t.DistributionConfig).ThenInclude(t => t.DistributionPeriod) + .Include(t => t.AutoControl) .FirstAsync(t => t.Id == jobGroup.Id); var locationUri = uriService.GetUri(ApiRoutes.JobGroup.Get, ApiRoutes.JobGroup.getParam, createdJobGroup.Id); @@ -234,7 +248,7 @@ namespace PARR.API.Controllers.V1 /// - /// Обновить группу заданий на выполнение работ (JobGroup) + /// Обновить группу работ (JobGroup) /// /// /// @@ -242,15 +256,11 @@ namespace PARR.API.Controllers.V1 [HttpPut(ApiRoutes.JobGroup.Update)] public async Task Update([FromRoute] Guid id, [FromBody] JobGroupRequest request) { - //var resultValidate = await validator.ValidateAsync(request); - - //if (!resultValidate.IsValid) - // return BadRequest(new Response(resultValidate.Errors)); - - var orig = await groupService.Get() + var orig = await _groupRepository.Get() .Include(t => t.Jobs) .ThenInclude(t => t.Tnk) .Include(t => t.EsppSchValues) + .Include(t => t.AutoControl) .Include(t => t.DistributionConfig).ThenInclude(t => t.DistributionPeriod) .FirstOrDefaultAsync(t => t.Id == id); @@ -309,12 +319,50 @@ namespace PARR.API.Controllers.V1 // удаляем настройки распределения если они были if (orig.DistributionConfig != null) { - groupService.DeleteDistributionConfig(orig.DistributionConfig); + _groupRepository.DeleteDistributionConfig(orig.DistributionConfig); } } #endregion + #region Настройки автоконтроля + + // валидатор проверяет корректность + if (request.AutoControl != null) + { + // автоконтролем управляет JobGroup + if (orig.AutoControl != null) + { + // обновляем + orig.AutoControl.IsEnable = request.AutoControl.IsEnable; + orig.AutoControl.InitUsedScheduleState = request.AutoControl.InitUsedScheduleState; + orig.AutoControl.InitUsedTemplateState = request.AutoControl.InitUsedTemplateState; + // удалить настройки автоконтроля для job + await RemoveJobAutoControlSettingsAsync(orig.Id); + } + else + { + // создаем новую запись + orig.AutoControl = new JobGroupAutoControl + { + InitUsedScheduleState = request.AutoControl.InitUsedScheduleState, + InitUsedTemplateState = request.AutoControl.InitUsedTemplateState, + IsEnable = request.AutoControl.IsEnable, + JobGroupId = orig.Id + }; + // удалить настройки автоконтроля для job + await RemoveJobAutoControlSettingsAsync(orig.Id); + } + } + else + { + // автоконтролем управляет каждый job отдельно + // удаляем настройки, если они были + orig.AutoControl = null; + } + + #endregion + //обновляем планировщик orig.EsppSchValues.Clear(); request.Schedule.ForEach(item => @@ -327,7 +375,7 @@ namespace PARR.API.Controllers.V1 }); }); - if (!await groupService.CommitAsync()) + if (!await _groupRepository.CommitAsync()) return BadRequest(new Response(false, new List { new ErrorModel { Message = "Ошибка при изменении группы заданий на выполнение работ." } })); logger.LogInformation($"Пользователь {User.Identity?.Name} обновил группу заданий на выполнение работ: {orig.Id}," + @@ -355,7 +403,7 @@ namespace PARR.API.Controllers.V1 #endregion - var updatedJobGroup = await groupService.Get() + var updatedJobGroup = await _groupRepository.Get() .Include(t => t.Jobs) .ThenInclude(t => t.Tnk) .Include(t => t.GroupType) @@ -363,6 +411,7 @@ namespace PARR.API.Controllers.V1 .Include(t => t.ScheduleExcludeType) .Include(t => t.ScheduleExcludeTypeCalendar) .Include(t => t.DistributionConfig).ThenInclude(t => t.DistributionPeriod) + .Include(t => t.AutoControl) .FirstAsync(t => t.Id == orig.Id); var response = mapper.Map(updatedJobGroup); @@ -373,14 +422,14 @@ namespace PARR.API.Controllers.V1 /// - /// Удалить группу заданий на выполнение работ (только если нет связанных заданий) + /// Удалить группу работ (только если нет связанных работ) /// /// /// [HttpDelete(ApiRoutes.JobGroup.Delete)] public async Task Delete([FromRoute] Guid id) { - var jobGroup = await groupService.Get() + var jobGroup = await _groupRepository.Get() .FirstOrDefaultAsync(t => t.Id == id); if (jobGroup == null) @@ -388,13 +437,13 @@ namespace PARR.API.Controllers.V1 Message = $"Ошибка при удалении группы заданий на выполнение работ. Не найдена группа заданий на выполнение работ Id: {id}" } })); - var jobCount = await jobService.Get().CountAsync(t => t.GroupId == id); + var jobCount = await _jobRepository.Get().CountAsync(t => t.GroupId == id); if (jobCount > 0) return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Ошибка при удалении группы заданий на выполнение работ. С данным группой связаны задания: {jobCount} шт." } })); - if (!groupService.Delete(jobGroup) || !await groupService.CommitAsync()) + if (!_groupRepository.Delete(jobGroup) || !await _groupRepository.CommitAsync()) return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Ошибка при удалении группы заданий на выполнение работ" } })); @@ -408,6 +457,22 @@ namespace PARR.API.Controllers.V1 return NoContent(); } + /// + /// Удалить настройки автоконтроля для связанных Job + /// + /// + /// + private async Task RemoveJobAutoControlSettingsAsync(Guid jobGroupId) + { + var jobAutoControlsToRemove = await _jobAutoControlRepository.Get() + .Where(t => t.Job!.GroupId == jobGroupId) + .ToListAsync(); + + if (!jobAutoControlsToRemove.Any()) + return; + + _jobAutoControlRepository.RemoveRange(jobAutoControlsToRemove); + } /// /// Проверка, были ли изменения в расписании @@ -471,7 +536,7 @@ namespace PARR.API.Controllers.V1 /// private async Task AppendMissingDataAsync(JobGroupResponse jobGroupResponse) { - var schedule = await esppConfigService.GetEsppScheduleDtoAsync(jobGroupResponse.Id); + var schedule = await _esppConfigRepository.GetEsppScheduleDtoAsync(jobGroupResponse.Id); if (schedule == null) { @@ -482,14 +547,14 @@ namespace PARR.API.Controllers.V1 var scheduleResponse = new JobGroupScheduleResponse { //Timezone = settingsFromDb.ScheduleTimezone, - Timezone = scheduleResponseAreaTimeOffsetService.GetDefault.EsppValue, + Timezone = _scheduleResponseAreaTimeOffsetRepository.GetDefault.EsppValue, TypeSchedule = mapper.Map(schedule.TypeSchedule), Values = mapper.Map>(schedule.Values).OrderBy(t => t.Order).ToList() }; jobGroupResponse.Schedule = scheduleResponse; - jobGroupResponse.JobsCount = await jobService.Get().CountAsync(t => t.GroupId == jobGroupResponse.Id); + jobGroupResponse.JobsCount = await _jobRepository.Get().CountAsync(t => t.GroupId == jobGroupResponse.Id); jobGroupResponse.MatchingStatus = await GetMatchingStatusAsync(jobGroupResponse.Id); } @@ -506,7 +571,7 @@ namespace PARR.API.Controllers.V1 return null; // Если есть значение, смотрим, групповой ли тип работ, и если нет, то вернем null - var groupingType = await jobGroupTypeService.Get().FirstAsync(t => t.Code == JobGroupTypesEnum.Group); + var groupingType = await _jobGroupTypeRepository.Get().FirstAsync(t => t.Code == JobGroupTypesEnum.Group); if (request.GroupTypeId == groupingType.Id) { // это групповой тип работ, все ок @@ -534,7 +599,7 @@ namespace PARR.API.Controllers.V1 return request.GroupingUnitFieldId; - var groupingType = await jobGroupTypeService.Get().FirstAsync(t => t.Code == JobGroupTypesEnum.Group); + var groupingType = await _jobGroupTypeRepository.Get().FirstAsync(t => t.Code == JobGroupTypesEnum.Group); if (request.GroupTypeId == groupingType.Id) { @@ -558,7 +623,7 @@ namespace PARR.API.Controllers.V1 /// private async Task GetMatchingStatusAsync(Guid jobGroupId) { - var statusMatching = await matchingStatusService.GetStatusAsync(jobGroupId, SyncTaskEntityTypeEnum.JobGroup); + var statusMatching = await _matchingStatusRepository.GetStatusAsync(jobGroupId, SyncTaskEntityTypeEnum.JobGroup); return mapper.Map(statusMatching); } diff --git a/PARR.API/Controllers/V1/JobGroupTypeController.cs b/PARR.API/Controllers/V1/JobGroupTypeController.cs index 24f4797a..91f2547f 100644 --- a/PARR.API/Controllers/V1/JobGroupTypeController.cs +++ b/PARR.API/Controllers/V1/JobGroupTypeController.cs @@ -17,23 +17,29 @@ namespace PARR.API.Controllers.V1 [Authorize(Roles = ParrRoles.Administrator.Role)] public class JobGroupTypeController : BaseApiController { - private readonly IJobGroupTypeRepository jobGroupTypeService; + private readonly IJobGroupTypeRepository jobGroupTypeRepository; private readonly IMapper mapper; public JobGroupTypeController( - IJobGroupTypeRepository jobGroupTypeService, + IJobGroupTypeRepository jobGroupTypeRepository, IMapper mapper ) { - this.jobGroupTypeService = jobGroupTypeService; + this.jobGroupTypeRepository = jobGroupTypeRepository; this.mapper = mapper; } + /// + /// Получить список типов групп работ + /// + /// [HttpGet(ApiRoutes.JobGroupType.GetAll)] public async Task GetAll() { - var query = jobGroupTypeService.Get().OrderBy(t => t.Description); + var query = jobGroupTypeRepository.Get() + .AsNoTracking() + .OrderBy(t => t.Description); var types = await query.ToListAsync(); diff --git a/PARR.API/Controllers/V1/ShortcodeApplyController.cs b/PARR.API/Controllers/V1/ShortcodeApplyController.cs index 205eda63..688ba9b4 100644 --- a/PARR.API/Controllers/V1/ShortcodeApplyController.cs +++ b/PARR.API/Controllers/V1/ShortcodeApplyController.cs @@ -32,7 +32,7 @@ namespace PARR.API.Controllers.V1 /// - /// Получить список всех переменных составляющих + /// Применить шорткод /// /// [HttpPost(ApiRoutes.ShortcodeApply.Apply)] diff --git a/PARR.API/Controllers/V1/ShortcodeController.cs b/PARR.API/Controllers/V1/ShortcodeController.cs index cd67aac1..316eff0b 100644 --- a/PARR.API/Controllers/V1/ShortcodeController.cs +++ b/PARR.API/Controllers/V1/ShortcodeController.cs @@ -33,7 +33,7 @@ namespace PARR.API.Controllers.V1 /// - /// Получить список всех переменных составляющих + /// Получить список всех переменных составляющих (список шорткодов) /// /// [HttpGet(ApiRoutes.Shortcode.GetAll)] diff --git a/PARR.API/MappingProfiles/DomainToResponseProfile.cs b/PARR.API/MappingProfiles/DomainToResponseProfile.cs index 238a25fa..802340d3 100644 --- a/PARR.API/MappingProfiles/DomainToResponseProfile.cs +++ b/PARR.API/MappingProfiles/DomainToResponseProfile.cs @@ -379,9 +379,11 @@ namespace PARR.API.MappingProfiles CreateMap() .ForMember(d => d.ScheduleExcludeType, o => o.MapFrom(s => s.ScheduleExcludeType)) - .ForMember(d => d.ScheduleExcludeTypeCalendar, o => o.MapFrom(s => s.ScheduleExcludeTypeCalendar)); + .ForMember(d => d.ScheduleExcludeTypeCalendar, o => o.MapFrom(s => s.ScheduleExcludeTypeCalendar)) + .ForMember(d => d.AutoControl, o => o.MapFrom(s => s.AutoControl)); //.ForMember(d => d.DistributionConfig, o => o.MapFrom(s => s.DistributionConfig)); + CreateMap(); #endregion diff --git a/PARR.API/Validators/JobAutoControlRequestValidator.cs b/PARR.API/Validators/JobAutoControlRequestValidator.cs deleted file mode 100644 index 826f1e5a..00000000 --- a/PARR.API/Validators/JobAutoControlRequestValidator.cs +++ /dev/null @@ -1,33 +0,0 @@ -using FluentValidation; -using PARR.API.Contracts.V1.Requests; -using PARR.Domain.Enums; - -namespace PARR.API.Validators -{ - public class JobAutoControlRequestValidator : AbstractValidator - { - public JobAutoControlRequestValidator() - { - RuleFor(t => t.EkMasks).Must(items => - items.Count(t => t.Trim().Length > 0) > 0 - ).WithMessage("Должна быть указана хотя бы одна маска ЭК"); - - RuleFor(t => t.EnabledEkStatuses).Must( - items => items.Distinct().Count() == items.Count() - ).WithMessage("Статусы ЭК не должны повторяться"); - - RuleFor(t => t.EnabledEkStatuses).Must(items => - { - return !items.Any(item => !Enum.IsDefined(typeof(EkStatusEnum), item)) && !items.Any(t => t == 0); - }) - .WithMessage($"Допустимые значения: {(int)EkStatusEnum.New} ({EkStatusEnum.New}), " + - $"{(int)EkStatusEnum.Preapre} ({EkStatusEnum.Preapre}), " + - $"{(int)EkStatusEnum.Exploitation} ({EkStatusEnum.Exploitation}), " + - $"{(int)EkStatusEnum.Repair} ({EkStatusEnum.Repair}), " + - $"{(int)EkStatusEnum.Reserve} ({EkStatusEnum.Reserve}), " + - $"{(int)EkStatusEnum.OutOfService} ({EkStatusEnum.OutOfService}), " + - $"{(int)EkStatusEnum.Test} ({EkStatusEnum.Test}), " + - $"{(int)EkStatusEnum.Development} ({EkStatusEnum.Development})"); - } - } -} diff --git a/PARR.API/Validators/JobGroupValidator.cs b/PARR.API/Validators/JobGroupValidator.cs index fd96b693..2c68cda9 100644 --- a/PARR.API/Validators/JobGroupValidator.cs +++ b/PARR.API/Validators/JobGroupValidator.cs @@ -12,11 +12,11 @@ namespace PARR.API.Validators public class JobGroupValidator : AbstractValidator { public JobGroupValidator( - IJobGroupTypeRepository jobGroupTypeService, - IUnitFieldRepository unitFieldService, - IScheduleExcludeTypeRepository scheduleExcludeTypeService, - IScheduleExcludeTypeCalendarRepository scheduleExcludeTypeCalendarService, - IDistributionPeriodRepository distributionPeriodService + IJobGroupTypeRepository jobGroupTypeRepository, + IUnitFieldRepository unitFieldRepository, + IScheduleExcludeTypeRepository scheduleExcludeTypeRepository, + IScheduleExcludeTypeCalendarRepository scheduleExcludeTypeCalendarRepository, + IDistributionPeriodRepository distributionPeriodRepository ) { RuleFor(t => t.Name) @@ -35,7 +35,7 @@ namespace PARR.API.Validators .NotNull().NotEmpty(); RuleFor(t => t.GroupTypeId) - .MustAsync(async (entity, value, c) => await jobGroupTypeService.GetAsync(value) != null) + .MustAsync(async (entity, value, c) => await jobGroupTypeRepository.GetAsync(value) != null) .WithMessage("Указан несуществующий Id типа"); //Проверяем существует ли такой GroupingUnitFieldId в unitField @@ -47,7 +47,7 @@ namespace PARR.API.Validators return true; } - return await unitFieldService.GetAsync(value.Value) != null; + return await unitFieldRepository.GetAsync(value.Value) != null; }) .WithMessage("Указано несуществующий Id поля"); @@ -55,7 +55,7 @@ namespace PARR.API.Validators RuleFor(t => t.GroupingUnitFieldId) .MustAsync(async (entity, value, c) => { - var groupingJobType = await jobGroupTypeService.Get().FirstAsync(t => t.Code == JobGroupTypesEnum.Group); + var groupingJobType = await jobGroupTypeRepository.Get().FirstAsync(t => t.Code == JobGroupTypesEnum.Group); // Если это сгруппированный тип, то у него обязательно должно быть заполнено поле GroupingUnitFieldId if (entity.GroupTypeId == groupingJobType.Id) @@ -68,14 +68,14 @@ namespace PARR.API.Validators RuleFor(t => t.ScheduleExcludeTypeId) .NotNull() .NotEmpty() - .MustAsync(async (entity, value, c) => await scheduleExcludeTypeService.GetAsync(value) != null) + .MustAsync(async (entity, value, c) => await scheduleExcludeTypeRepository.GetAsync(value) != null) .WithMessage("Некорректное значение"); RuleFor(t => t.ScheduleExcludeTypeCalendarId) .MustAsync(async (entity, value, c) => { // Если выбрано "Нет исключений", то это поле должно быть пустое, иначе, должно быть валидное значение - var type = await scheduleExcludeTypeService.GetAsync(entity.ScheduleExcludeTypeId); + var type = await scheduleExcludeTypeRepository.GetAsync(entity.ScheduleExcludeTypeId); if (type == null) return false; @@ -89,7 +89,7 @@ namespace PARR.API.Validators if (!value.HasValue) return false; - return await scheduleExcludeTypeCalendarService.GetAsync(value.Value) != null; + return await scheduleExcludeTypeCalendarRepository.GetAsync(value.Value) != null; }) .WithMessage("Некорректное значение"); @@ -115,7 +115,7 @@ namespace PARR.API.Validators if (periodId.HasValue) { - var exist = await distributionPeriodService.GetAsync(periodId.Value); + var exist = await distributionPeriodRepository.GetAsync(periodId.Value); return exist != null; } @@ -129,7 +129,24 @@ namespace PARR.API.Validators // если IsResponseAreaTimezone == true, то поле UserTimeZoneOffsetMinutes обязательно. // если IsResponseAreaTimezone == false, то UserTimeZoneOffsetMinutes должно быть null return (entity.IsWorkGroupTimezone && value != null) || (!entity.IsWorkGroupTimezone && value == null); - }).WithMessage("Некорректное значение."); ; + }).WithMessage("Некорректное значение."); + + RuleFor(t => t.AutoControl) + .MustAsync(async (entity, value, c) => + { + // Автоконтроль разрешен только типам работ у которых включен IsJobGroupAutoControl + var isAllowedAutocontrol = await jobGroupTypeRepository.Get().AsNoTracking().AnyAsync(t => t.Id == entity.GroupTypeId && t.IsJobGroupAutoControl == true); + // Разрешен автоконтроль и есть значение + if (isAllowedAutocontrol && value != null) + return true; + + // Запрещен автоконтроль и нет значения + if (!isAllowedAutocontrol && value == null) + return true; + + return false; + }) + .WithMessage("Не верные параметры автоконтроля"); } } diff --git a/PARR.Core/Repositories/Interfaces/Job/IJobAutoControlRepository.cs b/PARR.Core/Repositories/Interfaces/Job/IJobAutoControlRepository.cs index 79823486..e0937825 100644 --- a/PARR.Core/Repositories/Interfaces/Job/IJobAutoControlRepository.cs +++ b/PARR.Core/Repositories/Interfaces/Job/IJobAutoControlRepository.cs @@ -5,5 +5,6 @@ namespace PARR.Core.Repositories.Interfaces.Job public interface IJobAutoControlRepository { IQueryable Get(); + void RemoveRange(List autoControlList); } } diff --git a/PARR.DAL/Context/DataContext.cs b/PARR.DAL/Context/DataContext.cs index a2b46824..971db050 100644 --- a/PARR.DAL/Context/DataContext.cs +++ b/PARR.DAL/Context/DataContext.cs @@ -179,9 +179,9 @@ namespace PARR.DAL.Context modelBuilder.Entity(f => { f.HasData( - new() { Id = new Guid("4FA62E79-86BB-47C2-BE1A-72A716A170FA"), DateCreated = dateCreated, DateModified = null, Name = JobGroupTypesEnum.Simple.ToString(), Code = JobGroupTypesEnum.Simple, Description = "Обычный", IsAllowJobUnitFilter = true, IsJobGroupAutoControl = false }, - new() { Id = new Guid("6EC58B1A-5C40-47B9-B036-4FA490E8D503"), DateCreated = dateCreated, DateModified = null, Name = JobGroupTypesEnum.Umbrella.ToString(), Code = JobGroupTypesEnum.Umbrella, Description = "Зонтик", IsAllowJobUnitFilter = false, IsJobGroupAutoControl = true }, - new() { Id = new Guid("318625E5-F833-436A-99DF-2A382A1E71C7"), DateCreated = dateCreated, DateModified = null, Name = JobGroupTypesEnum.Group.ToString(), Code = JobGroupTypesEnum.Group, Description = "Сгруппированный", IsAllowJobUnitFilter = false, IsJobGroupAutoControl = true } + new() { Id = new Guid("4FA62E79-86BB-47C2-BE1A-72A716A170FA"), DateCreated = dateCreated, DateModified = null, Name = JobGroupTypesEnum.Simple.ToString(), Code = JobGroupTypesEnum.Simple, Description = "Обычный", IsAllowJobUnitFilter = true, IsJobGroupAutoControl = false, IsRelationshipsAllowed = false }, + new() { Id = new Guid("6EC58B1A-5C40-47B9-B036-4FA490E8D503"), DateCreated = dateCreated, DateModified = null, Name = JobGroupTypesEnum.Umbrella.ToString(), Code = JobGroupTypesEnum.Umbrella, Description = "Зонтик", IsAllowJobUnitFilter = false, IsJobGroupAutoControl = true, IsRelationshipsAllowed = true }, + new() { Id = new Guid("318625E5-F833-436A-99DF-2A382A1E71C7"), DateCreated = dateCreated, DateModified = null, Name = JobGroupTypesEnum.Group.ToString(), Code = JobGroupTypesEnum.Group, Description = "Сгруппированный", IsAllowJobUnitFilter = false, IsJobGroupAutoControl = true, IsRelationshipsAllowed = true } ); }); #endregion diff --git a/PARR.DAL/Migrations/20260615235401_tblGroupTypesAddRelationshipsSettings.Designer.cs b/PARR.DAL/Migrations/20260615235401_tblGroupTypesAddRelationshipsSettings.Designer.cs new file mode 100644 index 00000000..04f559df --- /dev/null +++ b/PARR.DAL/Migrations/20260615235401_tblGroupTypesAddRelationshipsSettings.Designer.cs @@ -0,0 +1,4021 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using PARR.DAL.Context; + +#nullable disable + +namespace PARR.DAL.Migrations +{ + [DbContext(typeof(DataContext))] + [Migration("20260615235401_tblGroupTypesAddRelationshipsSettings")] + partial class tblGroupTypesAddRelationshipsSettings + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "9.0.16") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("PARR.Domain.Entities.AgentHistory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("HistoryLevelId") + .HasColumnType("integer"); + + b.Property("Message") + .HasColumnType("text"); + + b.Property("OrderId") + .HasColumnType("uuid"); + + b.Property("TemplateId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("HistoryLevelId"); + + b.HasIndex("OrderId"); + + b.HasIndex("TemplateId"); + + b.ToTable("AgentHistories"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.AgentHistoryLevel", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("AgentHistoryLevels"); + + b.HasData( + new + { + Id = 1, + Description = "Агент начал выполнять задание", + Name = "Start" + }, + new + { + Id = 5, + Description = "Агент завершил выполнение задания", + Name = "End" + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.DistributionPeriod", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Duration") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Type"); + + b.ToTable("DistributionPeriods", "schedule"); + + b.HasData( + new + { + Id = new Guid("9bd0bfa8-c316-480b-a001-e09ffe8c9340"), + Duration = "7", + Name = "Еженедельно", + Type = "Day" + }, + new + { + Id = new Guid("3a7341a8-085c-461c-babc-6b78dd5d2c67"), + Duration = "30", + Name = "Ежемесячно", + Type = "Day" + }, + new + { + Id = new Guid("0ad2dfdb-3833-46d9-979a-c408b7eadc6c"), + Duration = "90", + Name = "Каждые 90 дней", + Type = "Day" + }, + new + { + Id = new Guid("31dd3947-8471-4f09-852c-a4f075f1ba7f"), + Duration = "182", + Name = "Каждые пол года", + Type = "Day" + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.DistributionPeriodType", b => + { + b.Property("Type") + .HasColumnType("text"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Type"); + + b.ToTable("DistributionPeriodTypes", "schedule"); + + b.HasData( + new + { + Type = "Day", + Description = "День" + }, + new + { + Type = "Month", + Description = "Месяц" + }, + new + { + Type = "Year", + Description = "Год" + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Job.Job", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateModified") + .HasColumnType("timestamp with time zone"); + + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("IsParentRelationships") + .HasColumnType("boolean"); + + b.Property("MaxValueRelationships") + .HasColumnType("integer"); + + b.Property("MinValueRelationships") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("ResponseAreaMask") + .IsRequired() + .HasColumnType("text"); + + b.Property("TemplateNameMask") + .IsRequired() + .HasColumnType("text"); + + b.Property("TnkId") + .HasColumnType("uuid"); + + b.Property("WorkGroupMask") + .IsRequired() + .HasColumnType("text"); + + b.Property("WorkName") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("GroupId"); + + b.HasIndex("TnkId"); + + b.ToTable("Jobs", "job", t => + { + t.HasComment("Таблица видов работ"); + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Job.JobAutoControl", b => + { + b.Property("JobId") + .HasColumnType("uuid"); + + b.Property("InitUsedScheduleState") + .HasColumnType("boolean"); + + b.Property("InitUsedTemplateState") + .HasColumnType("boolean"); + + b.Property("IsEnable") + .HasColumnType("boolean"); + + b.HasKey("JobId"); + + b.ToTable("AutoControls", "job", t => + { + t.HasComment("Таблица управления автоконтролем для работ"); + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Job.JobFieldFilter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("FieldId") + .HasColumnType("uuid"); + + b.Property("IsInverse") + .HasColumnType("boolean"); + + b.Property("UnitFilterId") + .HasColumnType("uuid"); + + b.Property("ValueMask") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("FieldId"); + + b.HasIndex("UnitFilterId"); + + b.ToTable("FieldFilters", "job", t => + { + t.HasComment("Таблица описания критериев выборки аттрибутов ЭК"); + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Job.JobRelationshipFilter", b => + { + b.Property("UnitFilterId") + .HasColumnType("uuid"); + + b.Property("FieldId") + .HasColumnType("uuid"); + + b.Property("IsFullMatch") + .HasColumnType("boolean"); + + b.Property("IsInverse") + .HasColumnType("boolean"); + + b.Property("IsParent") + .HasColumnType("boolean"); + + b.Property("ValueMask") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("UnitFilterId", "FieldId"); + + b.HasIndex("FieldId"); + + b.ToTable("RelationshipFilters", "job", t => + { + t.HasComment("Таблица фильтров связей ЭК"); + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Job.JobUnitFilter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("JobId") + .HasColumnType("uuid"); + + b.Property("UnitFilter") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("JobId"); + + b.ToTable("UnitFilters", "job", t => + { + t.HasComment("Таблица описания критериев выборки ЭК, описание полей в АСУ ЕСПП"); + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Job.UnitsInTemplate", b => + { + b.Property("TemplateId") + .HasColumnType("uuid"); + + b.Property("UnitId") + .HasColumnType("uuid"); + + b.Property("UnitFieldValueId") + .HasColumnType("uuid"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("TemplateId", "UnitId", "UnitFieldValueId"); + + b.HasIndex("UnitFieldValueId"); + + b.HasIndex("UnitId"); + + b.ToTable("UnitsInTemplates", "job", t => + { + t.HasComment("Таблица связи ЭК в шаблонах"); + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.JobGroupEntities.JobGroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AgentName") + .HasColumnType("text"); + + b.Property("AgentScript") + .HasColumnType("text"); + + b.Property("AgentTimeOutSec") + .HasColumnType("integer"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateModified") + .HasColumnType("timestamp with time zone"); + + b.Property("FullDescription") + .IsRequired() + .HasColumnType("text"); + + b.Property("GroupName") + .IsRequired() + .HasColumnType("text"); + + b.Property("GroupTypeId") + .HasColumnType("uuid"); + + b.Property("GroupingUnitFieldId") + .HasColumnType("uuid"); + + b.Property("IsAgent") + .HasColumnType("boolean"); + + b.Property("IsAutoDistributionEnabled") + .HasColumnType("boolean"); + + b.Property("IsGroupByResponsible") + .HasColumnType("boolean"); + + b.Property("IsResponseAreaTimezone") + .HasColumnType("boolean"); + + b.Property("ReferenceDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ScheduleExcludeTypeCalendarId") + .HasColumnType("uuid"); + + b.Property("ScheduleExcludeTypeId") + .HasColumnType("uuid"); + + b.Property("ShortDescription") + .IsRequired() + .HasColumnType("text"); + + b.Property("Solution") + .IsRequired() + .HasColumnType("text"); + + b.Property("TemplateDuration") + .IsRequired() + .HasColumnType("text"); + + b.Property("UserTimeZoneOffsetMinutes") + .HasColumnType("integer") + .HasComment("Смещение часового пояса пользователя в минутах относительно UTC на момент ReferenceDate"); + + b.HasKey("Id"); + + b.HasIndex("GroupTypeId"); + + b.HasIndex("GroupingUnitFieldId"); + + b.HasIndex("ScheduleExcludeTypeCalendarId"); + + b.HasIndex("ScheduleExcludeTypeId"); + + b.ToTable("Groups", "jobGroup", t => + { + t.HasComment("Таблица описания групп работ, для реализации зонтиков"); + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.JobGroupEntities.JobGroupAutoControl", b => + { + b.Property("JobGroupId") + .HasColumnType("uuid"); + + b.Property("InitUsedScheduleState") + .HasColumnType("boolean"); + + b.Property("InitUsedTemplateState") + .HasColumnType("boolean"); + + b.Property("IsEnable") + .HasColumnType("boolean"); + + b.HasKey("JobGroupId"); + + b.ToTable("AutoControls", "jobGroup", t => + { + t.HasComment("Таблица управления автоконтролем для группы работ"); + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.JobGroupEntities.JobGroupDistributionConfig", b => + { + b.Property("GroupId") + .HasColumnType("uuid"); + + b.Property("DistributionPeriodId") + .HasColumnType("uuid"); + + b.Property("IsExcludeWeekends") + .HasColumnType("boolean"); + + b.Property("IsGroupingByWorkGroup") + .HasColumnType("boolean"); + + b.HasKey("GroupId"); + + b.HasIndex("DistributionPeriodId"); + + b.ToTable("GroupDistributionConfigs", "jobGroup", t => + { + t.HasComment("Настройки автораспределения для группы работ"); + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.JobGroupEntities.JobGroupFieldFilter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("FieldId") + .HasColumnType("uuid"); + + b.Property("IsInverse") + .HasColumnType("boolean"); + + b.Property("UnitFilterId") + .HasColumnType("uuid"); + + b.Property("ValueMask") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("FieldId") + .HasDatabaseName("IX_FieldFilters_FieldId1"); + + b.HasIndex("UnitFilterId") + .HasDatabaseName("IX_FieldFilters_UnitFilterId1"); + + b.ToTable("FieldFilters", "jobGroup", t => + { + t.HasComment("Таблица описания критериев выборки аттрибутов ЭК"); + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.JobGroupEntities.JobGroupRelationshipFilter", b => + { + b.Property("UnitFilterId") + .HasColumnType("uuid"); + + b.Property("FieldId") + .HasColumnType("uuid"); + + b.Property("IsFullMatch") + .HasColumnType("boolean"); + + b.Property("IsInverse") + .HasColumnType("boolean"); + + b.Property("IsParent") + .HasColumnType("boolean"); + + b.Property("ValueMask") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("UnitFilterId", "FieldId"); + + b.HasIndex("FieldId") + .HasDatabaseName("IX_RelationshipFilters_FieldId1"); + + b.ToTable("RelationshipFilters", "jobGroup", t => + { + t.HasComment("Таблица фильтров связей ЭК"); + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.JobGroupEntities.JobGroupType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Code") + .HasColumnType("integer"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsAllowJobUnitFilter") + .HasColumnType("boolean") + .HasComment("Разрешить Job фильтры. Влияет только на интерфейс. Мэтчер собирает все фильтры из группы и работ всегда."); + + b.Property("IsJobGroupAutoControl") + .HasColumnType("boolean") + .HasComment("Автоконтролем управляет JobGroup? true - да JobGroup, false - Job. Влияет на интерфейс и на логику работы автоконтроля."); + + b.Property("IsRelationshipsAllowed") + .HasColumnType("boolean") + .HasComment("Разрешена настройка кол-ва связей"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("GroupTypes", "jobGroup", t => + { + t.HasComment("Таблица типов групп работ"); + }); + + b.HasData( + new + { + Id = new Guid("4fa62e79-86bb-47c2-be1a-72a716a170fa"), + Code = 0, + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Description = "Обычный", + IsAllowJobUnitFilter = true, + IsJobGroupAutoControl = false, + IsRelationshipsAllowed = false, + Name = "Simple" + }, + new + { + Id = new Guid("6ec58b1a-5c40-47b9-b036-4fa490e8d503"), + Code = 1, + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Description = "Зонтик", + IsAllowJobUnitFilter = false, + IsJobGroupAutoControl = true, + IsRelationshipsAllowed = true, + Name = "Umbrella" + }, + new + { + Id = new Guid("318625e5-f833-436a-99df-2a382a1e71c7"), + Code = 2, + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Description = "Сгруппированный", + IsAllowJobUnitFilter = false, + IsJobGroupAutoControl = true, + IsRelationshipsAllowed = true, + Name = "Group" + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.JobGroupEntities.JobGroupUnitFilter", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("JobGroupId") + .HasColumnType("uuid"); + + b.Property("UnitFilter") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("JobGroupId"); + + b.ToTable("UnitFilters", "jobGroup", t => + { + t.HasComment("Таблица описания критериев выборки ЭК, описание полей в АСУ ЕСПП"); + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Order", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateModified") + .HasColumnType("timestamp with time zone"); + + b.Property("ExpirationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("GenerateDate") + .HasColumnType("timestamp with time zone"); + + b.Property("NextStatusCode") + .HasColumnType("integer"); + + b.Property("Number") + .IsRequired() + .HasColumnType("text"); + + b.Property("ShortName") + .IsRequired() + .HasColumnType("text"); + + b.Property("StatusCode") + .HasColumnType("integer"); + + b.Property("TemplateId") + .HasColumnType("uuid"); + + b.Property("WorkGroup") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("NextStatusCode"); + + b.HasIndex("Number") + .IsUnique(); + + b.HasIndex("StatusCode"); + + b.HasIndex("TemplateId"); + + b.ToTable("Orders"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.OrderStatus", b => + { + b.Property("Code") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Code")); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Code"); + + b.ToTable("OrderStatuses"); + + b.HasData( + new + { + Code = 1, + Description = "1-Направлен в группу", + Name = "New" + }, + new + { + Code = 2, + Description = "2-В работе", + Name = "InWork" + }, + new + { + Code = 3, + Description = "3-Приостановлен", + Name = "Stop" + }, + new + { + Code = 4, + Description = "4-Выполнен", + Name = "Complete" + }, + new + { + Code = 5, + Description = "5-Закрыт", + Name = "Closed" + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.ParrComponent", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("ParrComponents"); + + b.HasData( + new + { + Id = 0, + Description = "API", + Name = "Api" + }, + new + { + Id = 1, + Description = "Загрузчик из АИХИТ", + Name = "AihitLoader" + }, + new + { + Id = 2, + Description = "Синхронизатор АИХИТ", + Name = "AihitSyncer" + }, + new + { + Id = 3, + Description = "Загрузчик нарядов из ЕСПП", + Name = "EsppOrderLoader" + }, + new + { + Id = 4, + Description = "Управление нарядами ЕСПП", + Name = "EsppOrderManager" + }, + new + { + Id = 5, + Description = "Синхронизатор расписаний", + Name = "EsppScheduleSync" + }, + new + { + Id = 6, + Description = "Синхронизатор шаблонов", + Name = "EsppTemplateSync" + }, + new + { + Id = 7, + Description = "Генератор шаблонов", + Name = "GeneratorTemplates" + }, + new + { + Id = 8, + Description = "Авто-контроль РР", + Name = "JobAutoControl" + }, + new + { + Id = 9, + Description = "Связывание нарядов ЕСПП с ПАРР (шаблонами, агентами)", + Name = "Master" + }, + new + { + Id = 10, + Description = "Рассчет даты следующего срабатывания", + Name = "NextRun" + }, + new + { + Id = 11, + Description = "Активатор шаблонов / расписаний", + Name = "TemplateActivator" + }, + new + { + Id = 12, + Description = "Автораспределение РР", + Name = "TemplateDistributor" + }, + new + { + Id = 13, + Description = "Генератор шаблонов", + Name = "TemplateTaskGenerator" + }, + new + { + Id = 14, + Description = "Генератор кэша отчетов workload", + Name = "WorkloadBuilder" + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Process", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateModified") + .HasColumnType("timestamp with time zone"); + + b.Property("EsppId") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("EsppId") + .IsUnique(); + + b.ToTable("Processes"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Robot", b => + { + b.Property("Code") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Code")); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Code"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Robots"); + + b.HasData( + new + { + Code = 1, + Description = "Робот по созданию/изменению шаблона наряда ЕСПП", + Name = "TemplateOrder" + }, + new + { + Code = 2, + Description = "Робот по созданию/изменению расписания шаблона наряда в ЕСПП", + Name = "ScheduleOrder" + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.RobotConfiguration", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AttemptsNumber") + .HasColumnType("integer"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("LastRobotStatusUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("RobotCode") + .HasColumnType("integer"); + + b.Property("RobotStatusCode") + .HasColumnType("integer"); + + b.Property("TaskStatusCode") + .HasColumnType("integer"); + + b.Property("TemplateId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("RobotCode"); + + b.HasIndex("RobotStatusCode"); + + b.HasIndex("TaskStatusCode"); + + b.HasIndex("TemplateId", "RobotCode") + .IsUnique(); + + b.HasIndex("TemplateId", "RobotStatusCode"); + + b.HasIndex("TemplateId", "TaskStatusCode"); + + b.ToTable("RobotConfigurations"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.RobotEntities.RobotSnapshot", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("Ip") + .IsRequired() + .HasMaxLength(45) + .HasColumnType("character varying(45)") + .HasComment("Текущий IP-адрес сервера"); + + b.Property("MaxRobots") + .HasColumnType("integer") + .HasComment("Максимально разрешенное количество роботов на сервере"); + + b.Property("ScheduleRobotsCount") + .HasColumnType("integer") + .HasComment("Количество запущенных роботов по расписаниям"); + + b.Property("TemplateRobotsCount") + .HasColumnType("integer") + .HasComment("Количество запущенных роботов по шаблонам"); + + b.HasKey("Id"); + + b.HasIndex("Ip", "DateCreated"); + + b.ToTable("Snapshots", "robot", t => + { + t.HasComment("Снимки роботов"); + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.RobotHistory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("EsppMessage") + .HasColumnType("text"); + + b.Property("HistoryLevel") + .HasColumnType("integer"); + + b.Property("RobotConfigurationId") + .HasColumnType("uuid"); + + b.Property("RobotId") + .HasColumnType("text") + .HasComment("Идентификатор робота. Форматы: H20-R1-T, H20-R1-S, H20-R1-ET, H20-R1-ES."); + + b.Property("RobotIp") + .HasColumnType("text"); + + b.Property("RobotMessage") + .HasColumnType("text"); + + b.Property("TaskStatusCode") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("DateCreated"); + + b.HasIndex("TaskStatusCode"); + + b.HasIndex("HistoryLevel", "DateCreated") + .IsDescending(false, true); + + b.HasIndex("RobotConfigurationId", "DateCreated"); + + b.ToTable("RobotHistories"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.RobotHistoryLevel", b => + { + b.Property("Level") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Level")); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Level"); + + b.ToTable("RobotHistoryLevels"); + + b.HasData( + new + { + Level = 1, + Description = "Робот начал работу ", + Name = "Start" + }, + new + { + Level = 5, + Description = "Информация", + Name = "Information" + }, + new + { + Level = 10, + Description = "Ошибка", + Name = "Error" + }, + new + { + Level = 15, + Description = "Успешно завершил работу", + Name = "Complete" + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.RobotStatus", b => + { + b.Property("Code") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Code")); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Code"); + + b.ToTable("RobotStatuses"); + + b.HasData( + new + { + Code = 11, + Description = "Ожидание, ждет пока робот возьмет в работу.", + Name = "Wait" + }, + new + { + Code = 22, + Description = "Робот взял в работу.", + Name = "InProgress" + }, + new + { + Code = 33, + Description = "Ошибка отработки роботом. Требует ручного вмешательства.", + Name = "Error" + }, + new + { + Code = 44, + Description = "Робот успешно отработал.", + Name = "Complete" + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Role", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Roles"); + + b.HasData( + new + { + Id = new Guid("c8f2f144-e6c2-45d7-ba66-5e9bbd376376"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Description = "Администратор", + Name = "administrator" + }, + new + { + Id = new Guid("13bca225-7fa4-42fa-9d80-d2d46de261fe"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Description = "Робот ЕСПП", + Name = "espp-robot" + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Schedule.EsppSchType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("EsppSchTypes", "schedule"); + + b.HasData( + new + { + Id = 1, + Description = "Через интервал", + Name = "Interval" + }, + new + { + Id = 2, + Description = "День недели: пнд, вт...", + Name = "DayOfWeek" + }, + new + { + Id = 3, + Description = "Число месяца: 1,2,3,4", + Name = "DayOfMonth" + }, + new + { + Id = 4, + Description = "Каждый: первый, второй, третий, четвертый, последний", + Name = "Order" + }, + new + { + Id = 5, + Description = "Месяц: январь, февраль...", + Name = "Month" + }, + new + { + Id = 6, + Description = "Месяц (родительный падеж): января, февраля...", + Name = "MonthGenitive" + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Schedule.EsppSchTypeConfig", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateModified") + .HasColumnType("timestamp with time zone"); + + b.Property("Order") + .HasColumnType("integer"); + + b.Property("TypeId") + .HasColumnType("integer"); + + b.Property("TypeScheduleId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("TypeId"); + + b.HasIndex("TypeScheduleId", "TypeId") + .IsUnique(); + + b.ToTable("EsppSchTypeConfigs", "schedule"); + + b.HasData( + new + { + Id = new Guid("d2693562-b3eb-41e9-97db-c6b5d2ef1bea"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Order = 0, + TypeId = 1, + TypeScheduleId = 1 + }, + new + { + Id = new Guid("06b2e7aa-6927-4fbf-99fb-67c92a4fce8a"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Order = 0, + TypeId = 2, + TypeScheduleId = 2 + }, + new + { + Id = new Guid("78079071-ff80-417e-9bb0-d928cec853e7"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Order = 0, + TypeId = 3, + TypeScheduleId = 3 + }, + new + { + Id = new Guid("accb1d46-e1c1-4396-9182-4c0766155921"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Order = 0, + TypeId = 4, + TypeScheduleId = 4 + }, + new + { + Id = new Guid("162ffe73-2428-4abe-8f83-235c2593664c"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Order = 1, + TypeId = 2, + TypeScheduleId = 4 + }, + new + { + Id = new Guid("8470d1ef-165d-42fc-ab05-8203e4d263cf"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Order = 0, + TypeId = 5, + TypeScheduleId = 5 + }, + new + { + Id = new Guid("006900b5-f65c-413e-bc67-09e6dae60b7c"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Order = 1, + TypeId = 3, + TypeScheduleId = 5 + }, + new + { + Id = new Guid("85635bc8-f17a-46b8-9c15-8615761be3d9"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Order = 0, + TypeId = 4, + TypeScheduleId = 6 + }, + new + { + Id = new Guid("439460c2-deca-4b54-80e7-2f20806696ec"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Order = 1, + TypeId = 2, + TypeScheduleId = 6 + }, + new + { + Id = new Guid("5c63ad8c-e9b4-43fd-9d24-5c2eed80dadd"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + Order = 2, + TypeId = 6, + TypeScheduleId = 6 + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Schedule.EsppSchTypeSchedule", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("EsppSchTypeSchedules", "schedule"); + + b.HasData( + new + { + Id = 1, + Description = "Регулярно", + Name = "Regularly" + }, + new + { + Id = 2, + Description = "Еженедельно", + Name = "Weekly" + }, + new + { + Id = 3, + Description = "Ежемесячно", + Name = "Monthly" + }, + new + { + Id = 4, + Description = "Ежемесячно-2", + Name = "Monthly2" + }, + new + { + Id = 5, + Description = "Ежегодно", + Name = "Annually" + }, + new + { + Id = 6, + Description = "Ежегодно-2", + Name = "Annually2" + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Schedule.EsppSchTypeValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("EsppExportValue") + .IsRequired() + .HasColumnType("text"); + + b.Property("Order") + .HasColumnType("integer"); + + b.Property("TypeId") + .HasColumnType("integer"); + + b.Property("Value") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("TypeId"); + + b.ToTable("EsppSchTypeValues", "schedule"); + + b.HasData( + new + { + Id = new Guid("6e3b5dd2-b2f7-40bc-bace-15bfa6bbd4ff"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "01:00:00", + Order = 0, + TypeId = 1, + Value = "Каждый час" + }, + new + { + Id = new Guid("4df04834-f14f-43d9-8984-334f080f4107"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "02:00:00", + Order = 1, + TypeId = 1, + Value = "Каждые 2 часа" + }, + new + { + Id = new Guid("dab6e3f9-2385-4966-b77c-133ad233c592"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "03:00:00", + Order = 2, + TypeId = 1, + Value = "Каждые 3 часа" + }, + new + { + Id = new Guid("035f485d-8451-47df-bfaa-ba4dd36cf146"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "04:00:00", + Order = 3, + TypeId = 1, + Value = "Каждые 4 часа" + }, + new + { + Id = new Guid("d627daa7-3eed-4571-acae-ffbb3c5bedb9"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "06:00:00", + Order = 4, + TypeId = 1, + Value = "Каждые 6 часов" + }, + new + { + Id = new Guid("ae0a0015-0f1e-4496-b71e-6244f7e321e7"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "12:00:00", + Order = 5, + TypeId = 1, + Value = "Каждые 12 часов" + }, + new + { + Id = new Guid("8df097aa-9860-4a62-9675-a8eecd3f2ce7"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "1 00:00:00", + Order = 6, + TypeId = 1, + Value = "Ежедневно" + }, + new + { + Id = new Guid("dee32e60-c1a1-4206-98bc-aa03deabfdf6"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "3 00:00:00", + Order = 7, + TypeId = 1, + Value = "Каждые 72 часа" + }, + new + { + Id = new Guid("e0465fbf-e3a5-4486-9f53-5bb85c6feeca"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "4 00:00:00", + Order = 8, + TypeId = 1, + Value = "Каждые 96 часов" + }, + new + { + Id = new Guid("4e3f73d1-a0f3-4dd1-bca9-68ada0dd5ce2"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "14 00:00:00", + Order = 9, + TypeId = 1, + Value = "Каждые 2 недели" + }, + new + { + Id = new Guid("55833417-6a24-42f6-bcc2-5d032f883202"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "60 00:00:00", + Order = 10, + TypeId = 1, + Value = "Каждые 60 дней" + }, + new + { + Id = new Guid("7fefa052-29db-4ce5-9c57-2fd9ff855f21"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "80 00:00:00", + Order = 11, + TypeId = 1, + Value = "Каждые 80 дней" + }, + new + { + Id = new Guid("b0ca99f9-5ee0-45b3-bb80-948f82b1fcb1"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "90 00:00:00", + Order = 12, + TypeId = 1, + Value = "Каждые 90 дней" + }, + new + { + Id = new Guid("086f7a37-9848-423a-a3cc-36dbb5ad43e3"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "182 00:00:00", + Order = 13, + TypeId = 1, + Value = "Каждые полгода" + }, + new + { + Id = new Guid("f2da9e02-d619-4517-a598-374880a8c8e8"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "540 00:00:00", + Order = 14, + TypeId = 1, + Value = "Каждые 1,5 года" + }, + new + { + Id = new Guid("f38d7d30-8923-4ea0-aa7c-5b251e19ab61"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "1095 00:00:00", + Order = 15, + TypeId = 1, + Value = "Каждые 3 года" + }, + new + { + Id = new Guid("b7303461-9a30-43fa-8e55-305aa13f186f"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "1", + Order = 0, + TypeId = 2, + Value = "Понедельник" + }, + new + { + Id = new Guid("e951135e-71f2-4262-9342-df4d5315ab6c"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "2", + Order = 1, + TypeId = 2, + Value = "Вторник" + }, + new + { + Id = new Guid("c34d5375-70e7-4632-b3af-30e279a0621a"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "3", + Order = 2, + TypeId = 2, + Value = "Среда" + }, + new + { + Id = new Guid("ec9540df-c2de-4bda-a063-34d02d4b6e03"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "4", + Order = 3, + TypeId = 2, + Value = "Четверг" + }, + new + { + Id = new Guid("2ed85534-4684-4eb2-9ccb-e264d212c945"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "5", + Order = 4, + TypeId = 2, + Value = "Пятница" + }, + new + { + Id = new Guid("a6804315-96ef-484e-82ee-c5795694468b"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "6", + Order = 5, + TypeId = 2, + Value = "Суббота" + }, + new + { + Id = new Guid("eb71e699-937f-4894-9688-f7a7f95e5e58"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "7", + Order = 6, + TypeId = 2, + Value = "Воскресенье" + }, + new + { + Id = new Guid("e86adbfb-3345-4e0c-aa3b-b4418f9cfe88"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "1", + Order = 0, + TypeId = 3, + Value = "1" + }, + new + { + Id = new Guid("5b4d7ca6-31e7-475b-b7c8-13c6680c3dc3"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "2", + Order = 1, + TypeId = 3, + Value = "2" + }, + new + { + Id = new Guid("0da03db0-9404-425d-bea1-5da0c9b60b59"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "3", + Order = 2, + TypeId = 3, + Value = "3" + }, + new + { + Id = new Guid("199474c8-0a77-47e5-aab8-ba33c216cc9e"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "4", + Order = 3, + TypeId = 3, + Value = "4" + }, + new + { + Id = new Guid("e6619da1-f7e8-45b9-bbd3-9c17bec2ccd3"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "5", + Order = 4, + TypeId = 3, + Value = "5" + }, + new + { + Id = new Guid("a8708763-c838-49a5-95fe-bf4f73518d71"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "6", + Order = 5, + TypeId = 3, + Value = "6" + }, + new + { + Id = new Guid("7ec056aa-820c-4900-96cb-4564d2ea6398"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "7", + Order = 6, + TypeId = 3, + Value = "7" + }, + new + { + Id = new Guid("554d7d0c-91b1-4b81-b94d-1ee864192962"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "8", + Order = 7, + TypeId = 3, + Value = "8" + }, + new + { + Id = new Guid("8b7847a4-23de-4199-8aad-3b5c0323b5a2"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "9", + Order = 8, + TypeId = 3, + Value = "9" + }, + new + { + Id = new Guid("fb7f41ca-950b-4dc1-a0a6-bd9a221ab2ad"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "10", + Order = 9, + TypeId = 3, + Value = "10" + }, + new + { + Id = new Guid("a28b530f-ea38-4a2c-a16b-0b7fa3770d3c"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "11", + Order = 10, + TypeId = 3, + Value = "11" + }, + new + { + Id = new Guid("7a004a11-32e1-40ae-ab35-0d3dc3a69785"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "12", + Order = 11, + TypeId = 3, + Value = "12" + }, + new + { + Id = new Guid("e0f2f4d1-4a5e-4997-8336-83c3c35f38df"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "13", + Order = 12, + TypeId = 3, + Value = "13" + }, + new + { + Id = new Guid("9c5aaf48-88ec-4c67-b936-2be45550f8bf"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "14", + Order = 13, + TypeId = 3, + Value = "14" + }, + new + { + Id = new Guid("8dbd680c-ce49-4d2e-8a1a-05619685e240"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "15", + Order = 14, + TypeId = 3, + Value = "15" + }, + new + { + Id = new Guid("2f476f70-b1ef-419d-aad5-3911f1e3231f"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "16", + Order = 15, + TypeId = 3, + Value = "16" + }, + new + { + Id = new Guid("2c635ce2-fc18-47be-b3e9-98c211abf312"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "17", + Order = 16, + TypeId = 3, + Value = "17" + }, + new + { + Id = new Guid("f9d5b03b-624a-4f9f-8da3-1490ea5d2914"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "18", + Order = 17, + TypeId = 3, + Value = "18" + }, + new + { + Id = new Guid("4f4b249c-db60-4582-86ed-75cfee4edd0c"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "19", + Order = 18, + TypeId = 3, + Value = "19" + }, + new + { + Id = new Guid("220a1464-4d39-416c-b4b2-3093eb007298"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "20", + Order = 19, + TypeId = 3, + Value = "20" + }, + new + { + Id = new Guid("c887ca60-b05d-4d3c-ad1f-223c879b1a6d"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "21", + Order = 20, + TypeId = 3, + Value = "21" + }, + new + { + Id = new Guid("2905765d-63fb-41fe-a111-ee2f1d03d62e"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "22", + Order = 21, + TypeId = 3, + Value = "22" + }, + new + { + Id = new Guid("dbbe704a-8d6d-40e7-bd30-6974035b1fab"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "23", + Order = 22, + TypeId = 3, + Value = "23" + }, + new + { + Id = new Guid("cf7b9645-52ed-43a2-8267-267e0aed19b1"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "24", + Order = 23, + TypeId = 3, + Value = "24" + }, + new + { + Id = new Guid("454788d6-d0ad-4c07-878c-da3fd3cd05e1"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "25", + Order = 24, + TypeId = 3, + Value = "25" + }, + new + { + Id = new Guid("40d70d73-8582-4be6-a9e6-503b96ae3d49"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "26", + Order = 25, + TypeId = 3, + Value = "26" + }, + new + { + Id = new Guid("8f6610dc-ef46-4842-a57e-18d7aaa75931"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "27", + Order = 26, + TypeId = 3, + Value = "27" + }, + new + { + Id = new Guid("03858472-d4ce-47fd-9497-8051728766e4"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "28", + Order = 27, + TypeId = 3, + Value = "28" + }, + new + { + Id = new Guid("b1018e07-e90e-42ee-b399-19f3d0c14dd6"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "29", + Order = 28, + TypeId = 3, + Value = "29" + }, + new + { + Id = new Guid("a1669207-aa31-40fe-98d0-d941008d1655"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "30", + Order = 29, + TypeId = 3, + Value = "30" + }, + new + { + Id = new Guid("0936aa99-73e0-43de-b6df-334c1228a226"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "31", + Order = 30, + TypeId = 3, + Value = "31" + }, + new + { + Id = new Guid("626ca076-f09e-4a7a-8610-b7de6337b24a"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "1", + Order = 0, + TypeId = 4, + Value = "Первый" + }, + new + { + Id = new Guid("032fbd02-67d0-4b8c-bed0-42629ab7113b"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "2", + Order = 1, + TypeId = 4, + Value = "Второй" + }, + new + { + Id = new Guid("fa8a8f60-e41e-495e-ac86-35174d9976bf"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "3", + Order = 2, + TypeId = 4, + Value = "Третий" + }, + new + { + Id = new Guid("d2f90168-2b49-42f2-820b-79db2c522adf"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "4", + Order = 3, + TypeId = 4, + Value = "Четвертый" + }, + new + { + Id = new Guid("12bb8db2-cf7f-4113-baff-6883770f1ba5"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "5", + Order = 4, + TypeId = 4, + Value = "Последний" + }, + new + { + Id = new Guid("18260e91-3fbe-4401-9edc-78dbc419370e"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "1", + Order = 0, + TypeId = 5, + Value = "Январь" + }, + new + { + Id = new Guid("361526aa-3e1c-452e-bb44-0ade8521830d"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "2", + Order = 1, + TypeId = 5, + Value = "Февраль" + }, + new + { + Id = new Guid("fad4bdb0-6c51-4810-a30b-6d031a0d4c46"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "3", + Order = 2, + TypeId = 5, + Value = "Март" + }, + new + { + Id = new Guid("06ab835d-3d3e-4057-8422-a553b6b40995"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "4", + Order = 3, + TypeId = 5, + Value = "Апрель" + }, + new + { + Id = new Guid("83f56b5d-b16b-4aa5-89d7-a253fee4e4ad"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "5", + Order = 4, + TypeId = 5, + Value = "Май" + }, + new + { + Id = new Guid("e679ec84-a9ee-4bed-a051-2b14edddcb18"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "6", + Order = 5, + TypeId = 5, + Value = "Июнь" + }, + new + { + Id = new Guid("d439808a-6a10-409b-8809-a755b7cca60b"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "7", + Order = 6, + TypeId = 5, + Value = "Июль" + }, + new + { + Id = new Guid("6e9972c4-6bf7-4fe4-b4ea-bbb333fb69c8"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "8", + Order = 7, + TypeId = 5, + Value = "Август" + }, + new + { + Id = new Guid("0883aac2-9d5b-4098-b672-c684d2a3a0c9"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "9", + Order = 8, + TypeId = 5, + Value = "Сентябрь" + }, + new + { + Id = new Guid("5e6592bc-acb2-45a4-979b-fdecf8457453"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "10", + Order = 9, + TypeId = 5, + Value = "Октябрь" + }, + new + { + Id = new Guid("edd7cb49-d6a0-4969-b2d6-1967da69b336"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "11", + Order = 10, + TypeId = 5, + Value = "Ноябрь" + }, + new + { + Id = new Guid("dd695fb2-4ad0-4cda-a4df-e15059c56b24"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "12", + Order = 11, + TypeId = 5, + Value = "Декабрь" + }, + new + { + Id = new Guid("2f473624-4eb3-49b4-a4b9-cc7fc08a50f5"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "1", + Order = 0, + TypeId = 6, + Value = "Января" + }, + new + { + Id = new Guid("f0003490-a249-44bd-814f-4566999915d8"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "2", + Order = 1, + TypeId = 6, + Value = "Февраля" + }, + new + { + Id = new Guid("f4c3fe38-aeaa-42f7-a9ba-190ea2dfe339"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "3", + Order = 2, + TypeId = 6, + Value = "Марта" + }, + new + { + Id = new Guid("06a8bd2f-68e1-42f5-961c-ac3b98a2181e"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "4", + Order = 3, + TypeId = 6, + Value = "Апреля" + }, + new + { + Id = new Guid("963b9c41-d607-444a-9fe0-fe429590e326"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "5", + Order = 4, + TypeId = 6, + Value = "Мая" + }, + new + { + Id = new Guid("ec8554c8-dee4-49a1-b1b7-474ad8ec1473"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "6", + Order = 5, + TypeId = 6, + Value = "Июня" + }, + new + { + Id = new Guid("e15c7c63-e29f-41a3-9c82-f70eb6c24fde"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "7", + Order = 6, + TypeId = 6, + Value = "Июля" + }, + new + { + Id = new Guid("0b1f3cea-301a-4d74-9ce1-2cd93b41897d"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "8", + Order = 7, + TypeId = 6, + Value = "Августа" + }, + new + { + Id = new Guid("e2fa3769-f66f-4753-a161-35adad7717a5"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "9", + Order = 8, + TypeId = 6, + Value = "Сентября" + }, + new + { + Id = new Guid("c1de4aca-9f49-48ae-9279-cf9ec4092112"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "10", + Order = 9, + TypeId = 6, + Value = "Октября" + }, + new + { + Id = new Guid("a74b9ebd-bcd8-4537-b371-194de2fe0a4d"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "11", + Order = 10, + TypeId = 6, + Value = "Ноября" + }, + new + { + Id = new Guid("852a5ebd-4545-494b-bc69-c27409a41adc"), + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppExportValue = "12", + Order = 11, + TypeId = 6, + Value = "Декабря" + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Schedule.EsppSchValue", b => + { + b.Property("JobGroupId") + .HasColumnType("uuid"); + + b.Property("TypeValueId") + .HasColumnType("uuid"); + + b.Property("TypeConfigId") + .HasColumnType("uuid"); + + b.HasKey("JobGroupId", "TypeValueId", "TypeConfigId"); + + b.HasIndex("TypeConfigId"); + + b.HasIndex("TypeValueId"); + + b.ToTable("EsppSchValues", "schedule"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Schedule.ScheduleExcludeType", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Code") + .IsRequired() + .HasColumnType("text"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("EsppName") + .IsRequired() + .HasColumnType("text"); + + b.Property("EsppValue") + .IsRequired() + .HasColumnType("text"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("ExcludeTypes", "schedule", t => + { + t.HasComment("Расписание регламентной работы - Тип исключения"); + }); + + b.HasData( + new + { + Id = new Guid("0595b8e0-f322-4661-b5e3-064af8fbe7cd"), + Code = "None", + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppName = "Нет исключений", + EsppValue = "NONE", + Title = "Нет исключений" + }, + new + { + Id = new Guid("2b7a4356-9aaf-4e00-b444-42f0b5010e25"), + Code = "Only", + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppName = "Выполнить ТОЛЬКО В указанном календаре", + EsppValue = "ONLY", + Title = "Выполнить ТОЛЬКО В указанном календаре" + }, + new + { + Id = new Guid("38cd9e64-27c1-4672-a805-2211952a48bd"), + Code = "Except", + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppName = "Выполнить везде, КРОМЕ указанного календаря", + EsppValue = "EXCEPT", + Title = "Выполнить везде, КРОМЕ указанного календаря" + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Schedule.ScheduleExcludeTypeCalendar", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Code") + .IsRequired() + .HasColumnType("text"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("EsppName") + .IsRequired() + .HasColumnType("text"); + + b.Property("EsppValue") + .IsRequired() + .HasColumnType("text"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("ExcludeTypeCalendars", "schedule", t => + { + t.HasComment("Расписание регламентной работы, исключение - Календарь"); + }); + + b.HasData( + new + { + Id = new Guid("a26edb88-0267-4fbf-b7ec-d172b0a86c9c"), + Code = "24x5", + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppName = "24x5", + EsppValue = "24x5", + Title = "24x5" + }, + new + { + Id = new Guid("6834f1d5-ac51-43d5-974e-4c759d7bbf9f"), + Code = "24x7", + DateCreated = new DateTimeOffset(new DateTime(2023, 5, 1, 0, 0, 0, 0, DateTimeKind.Unspecified), new TimeSpan(0, 0, 0, 0, 0)), + EsppName = "24x7", + EsppValue = "24x7", + Title = "24x7" + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Schedule.ScheduleResponseAreaTimeOffset", b => + { + b.Property("ResponseArea") + .HasColumnType("text"); + + b.Property("EsppValue") + .IsRequired() + .HasColumnType("text"); + + b.Property("UtcTimeOffset") + .HasColumnType("interval"); + + b.HasKey("ResponseArea"); + + b.ToTable("ResponseAreaTimeOffsets", "schedule", t => + { + t.HasComment("Расписание в ЕСПП. Смещение часового пояса относительно МСК для зоны ответственности рабочей группы"); + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Setting", b => + { + b.Property("Name") + .HasColumnType("text"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("Value") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Name"); + + b.ToTable("Settings"); + + b.HasData( + new + { + Name = "Initiator", + Description = "Инициатор регламентной работы, указывается при создании шаблона в ЕСПП.", + Value = "АКСЕНОВ АЛЕКСАНДР ЕВГЕНЬЕВИЧ (AKSENOVAE@GVC.OAO.RZD)" + }, + new + { + Name = "ClosingCode", + Description = "Код закрытия регламентной работы, указывается при создании шаблона в ЕСПП.", + Value = "выполнен" + }, + new + { + Name = "Category", + Description = "Категория создаваемого объекта в ЕСПП", + Value = "регламентная работа" + }, + new + { + Name = "TemplatePrefixName", + Description = "Префикс имени шаблона в ЕСПП", + Value = "%PREFIX%-ЭИТИ-ПТК-ПАРР" + }, + new + { + Name = "RobotAttemptsNumber", + Description = "Количество попыток выполнения задания роботом", + Value = "3" + }, + new + { + Name = "RobotWaitTime", + Description = "Время ожидания выполнения роботом задания", + Value = "00:10:00" + }, + new + { + Name = "EsppScheduleTimezone", + Description = "Расписание регламентной работы - В каком часовом поясе", + Value = "MSK" + }, + new + { + Name = "ScheduleRepeatRange", + Description = "Расписание регламентной работы - Диапазн повторов", + Value = "Отсутствует дата завершения" + }, + new + { + Name = "OrderSearchDeltaDate", + Description = "Промежуток времени для поиска нарядов в ЕСПП", + Value = "01:30:00" + }, + new + { + Name = "EsppRobotAccountTimeZoneHour", + Description = "Таймзона УЗ роботов в ЕСПП, в часах (может быть положительная и отрицательная)", + Value = "3" + }, + new + { + Name = "WeekendCacheTtl", + Description = "Время хранения в кэше данных о выходных и рабочих днях", + Value = "01:00:00" + }, + new + { + Name = "TemplateNameConstantParts", + Description = "Список неизменных частей имени шаблона", + Value = "[{\"Name\":\"П-1\",\"Value\":\"ЭИТИ-ПАРР\"}]" + }, + new + { + Name = "EsppUnitTag", + Description = "Префикс тега в поле ЭК \"Дополнительная информация\"", + Value = "ПАРР_" + }, + new + { + Name = "JobIdForUnusedTemplates", + Description = "Job в который перемещаем ниспользованные шаблоны", + Value = "8f85a91c-a223-4686-bb69-1f0ee73624f2" + }, + new + { + Name = "DefaultResponseAreaToTimeOffset", + Description = "Зона ответственности для получения тайм зоны по умолчанию для расписаний", + Value = "17-МСК" + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Subprocess", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateModified") + .HasColumnType("timestamp with time zone"); + + b.Property("EsppId") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("ProcessId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("EsppId") + .IsUnique(); + + b.HasIndex("ProcessId"); + + b.ToTable("Subprocesses"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.TaskEntities.TaskError", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AttemptNumber") + .HasColumnType("integer"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("ErrorMessage") + .IsRequired() + .HasColumnType("text"); + + b.Property("StackTrace") + .HasColumnType("text"); + + b.Property("TaskId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("TaskId"); + + b.ToTable("Errors", "task", t => + { + t.HasComment("Таблица ошибок заданий"); + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.TaskEntities.TaskItem", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateModified") + .HasColumnType("timestamp with time zone"); + + b.Property("InitiatorComment") + .HasColumnType("text"); + + b.Property("InitiatorIp") + .HasColumnType("text"); + + b.Property("InitiatorParrComponentId") + .HasColumnType("integer"); + + b.Property("Payload") + .HasColumnType("text"); + + b.Property("ProcessedAt") + .HasColumnType("timestamp with time zone"); + + b.Property("ProgressPercent") + .HasColumnType("integer") + .HasComment("Процент выполнения задачи"); + + b.Property("RetryCount") + .HasColumnType("integer"); + + b.Property("StatusCode") + .HasColumnType("integer"); + + b.Property("TypeCode") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("StatusCode"); + + b.HasIndex("TypeCode"); + + b.ToTable("Tasks", "task", t => + { + t.HasComment("Таблица заданий"); + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.TaskEntities.TaskStatus", b => + { + b.Property("Code") + .HasColumnType("integer"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Code"); + + b.ToTable("Statuses", "task", t => + { + t.HasComment("Таблица статусов заданий"); + }); + + b.HasData( + new + { + Code = 0, + Description = "Ожидание", + Name = "Pending" + }, + new + { + Code = 1, + Description = "В работе", + Name = "Processing" + }, + new + { + Code = 2, + Description = "Выполнено успешно", + Name = "Success" + }, + new + { + Code = 3, + Description = "Ошибка", + Name = "Failed" + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.TaskEntities.TaskType", b => + { + b.Property("Code") + .HasColumnType("integer"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsSingleton") + .HasColumnType("boolean"); + + b.Property("MaxExecutionTimeMinutes") + .HasColumnType("integer"); + + b.Property("MaxRetries") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("RetentionDays") + .HasColumnType("integer"); + + b.HasKey("Code"); + + b.ToTable("Types", "task", t => + { + t.HasComment("Таблица типов заданий"); + }); + + b.HasData( + new + { + Code = 0, + Description = "Формирование данных для отчетности - Загруженность", + IsSingleton = true, + MaxExecutionTimeMinutes = 90, + MaxRetries = 2, + Name = "Workload", + RetentionDays = 90 + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.TaskStatus", b => + { + b.Property("Code") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Code")); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Code"); + + b.ToTable("TaskStatuses"); + + b.HasData( + new + { + Code = 10, + Description = "Требуется создание объекта в ЕСПП", + Name = "Creating" + }, + new + { + Code = 20, + Description = "Требуется обновление объекта в ЕСПП", + Name = "Updating" + }, + new + { + Code = 30, + Description = "Нормальное состояние объекта в ЕСПП и ПАРР. Объект в ПАРР соответствует объекту в ЕСПП", + Name = "Ok" + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Template", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateModified") + .HasColumnType("timestamp with time zone"); + + b.Property("Index") + .HasColumnType("integer"); + + b.Property("InitiatorComment") + .HasColumnType("text"); + + b.Property("InitiatorIp") + .HasColumnType("text"); + + b.Property("InitiatorParrComponentId") + .HasColumnType("integer"); + + b.Property("IsActiveSchedule") + .HasColumnType("boolean"); + + b.Property("IsActiveTemplate") + .HasColumnType("boolean"); + + b.Property("JobId") + .HasColumnType("uuid"); + + b.Property("LastRun") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("NextRun") + .HasColumnType("timestamp with time zone"); + + b.Property("ScheduleEsppId") + .HasColumnType("text"); + + b.Property("StatusTypeId") + .HasColumnType("integer"); + + b.Property("UnitId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("JobId"); + + b.HasIndex("StatusTypeId"); + + b.HasIndex("UnitId"); + + b.HasIndex("Name", "Index") + .IsUnique(); + + b.ToTable("Templates"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.TemplateHistory", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DateAddedToHistory") + .HasColumnType("timestamp with time zone"); + + b.Property("DateModified") + .HasColumnType("timestamp with time zone"); + + b.Property("InitiatorComment") + .HasColumnType("text"); + + b.Property("InitiatorIp") + .HasColumnType("text"); + + b.Property("InitiatorParrComponentId") + .HasColumnType("integer"); + + b.Property("IsActiveSchedule") + .HasColumnType("boolean"); + + b.Property("IsActiveTemplate") + .HasColumnType("boolean"); + + b.Property("LastRun") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("NextRun") + .HasColumnType("timestamp with time zone"); + + b.Property("ParentId") + .HasColumnType("uuid"); + + b.Property("ScheduleEsppId") + .HasColumnType("text"); + + b.Property("StatusTypeId") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("ParentId"); + + b.ToTable("TemplateHistories"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.TemplateStatusType", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("Description") + .IsRequired() + .HasColumnType("text"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("TemplateStatusTypes", t => + { + t.HasComment("Таблица описания критериев выборки аттрибутов ЭК"); + }); + + b.HasData( + new + { + Id = 0, + Description = "В работе", + Name = "Used" + }, + new + { + Id = 1, + Description = "Не используется", + Name = "Unused" + }, + new + { + Id = 2, + Description = "Обновляется", + Name = "Updating" + }, + new + { + Id = 3, + Description = "Ошибка", + Name = "Error" + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Tnk", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateModified") + .HasColumnType("timestamp with time zone"); + + b.Property("EsppId") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.Property("ShortName") + .HasColumnType("text"); + + b.Property("SubprocessId") + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("SubprocessId"); + + b.ToTable("Tnks"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Unit.Unit", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("LastLogon") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Units", "unit", t => + { + t.HasComment("Таблица с ЭК"); + + t.HasCheckConstraint("CK_Units_Name_Upper", "\"Name\" = UPPER(\"Name\") AND \"Name\" IS NOT NULL AND LENGTH(\"Name\")>0"); + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Unit.UnitField", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("AihitName") + .IsRequired() + .HasColumnType("text"); + + b.Property("Code") + .HasColumnType("text"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DisplayName") + .HasColumnType("text"); + + b.Property("EsppName") + .HasColumnType("text"); + + b.Property("IsMultipleValue") + .HasColumnType("boolean"); + + b.HasKey("Id"); + + b.HasIndex("AihitName"); + + b.HasIndex("EsppName"); + + b.ToTable("Fields", "unit", t => + { + t.HasComment("Справочник полей ЭК"); + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Unit.UnitFieldInUnitFieldValue", b => + { + b.Property("FieldId") + .HasColumnType("uuid"); + + b.Property("FieldValueId") + .HasColumnType("uuid"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.HasKey("FieldId", "FieldValueId"); + + b.HasIndex("FieldValueId"); + + b.ToTable("FieldInFieldValues", "unit", t => + { + t.HasComment("Значения полей ЭК"); + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Unit.UnitFieldValue", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Value") + .IsUnique(); + + b.ToTable("FieldValues", "unit", t => + { + t.HasComment("Значения полей ЭК"); + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Unit.UnitInUnit", b => + { + b.Property("ParentUnitId") + .HasColumnType("uuid"); + + b.Property("ChildUnitId") + .HasColumnType("uuid"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateSynced") + .HasColumnType("timestamp with time zone"); + + b.HasKey("ParentUnitId", "ChildUnitId"); + + b.HasIndex("ChildUnitId"); + + b.ToTable("UnitInUnits", "unit", t => + { + t.HasComment("Таблица связей иерархии между ЭК"); + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Unit.UnitInValue", b => + { + b.Property("UnitId") + .HasColumnType("uuid"); + + b.Property("FieldId") + .HasColumnType("uuid"); + + b.Property("ValueId") + .HasColumnType("uuid"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("DateModified") + .HasColumnType("timestamp with time zone"); + + b.HasKey("UnitId", "FieldId", "ValueId"); + + b.HasIndex("ValueId"); + + b.HasIndex("FieldId", "UnitId"); + + b.HasIndex("FieldId", "ValueId"); + + b.HasIndex("UnitId", "FieldId"); + + b.ToTable("UnitInValues", "unit", t => + { + t.HasComment("Таблица связи ЭК с полями и со значениями"); + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Unit.UnitKiiUnit", b => + { + b.Property("UnitId") + .HasColumnType("uuid"); + + b.HasKey("UnitId"); + + b.ToTable("KiiUnits", "unit", t => + { + t.HasComment("Таблица - Список ЭК КИИ, которые учавствуют в групповых работах. Создавалась как временная"); + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Unit.UnitRegionalEkPtkGroup", b => + { + b.Property("FieldValueId") + .HasColumnType("uuid"); + + b.HasKey("FieldValueId"); + + b.ToTable("RegionalEkPtkGroups", "unit", t => + { + t.HasComment("Таблица - региональные группы ПТК"); + }); + }); + + modelBuilder.Entity("PARR.Domain.Entities.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("DateCreated") + .HasColumnType("timestamp with time zone"); + + b.Property("Description") + .HasColumnType("text"); + + b.Property("Ip") + .IsRequired() + .HasColumnType("text"); + + b.Property("LastLogon") + .HasColumnType("timestamp with time zone"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("Ip") + .IsUnique(); + + b.ToTable("Users"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.UsersInRole", b => + { + b.Property("RoleId") + .HasColumnType("uuid"); + + b.Property("UserId") + .HasColumnType("uuid"); + + b.HasKey("RoleId", "UserId"); + + b.HasIndex("UserId"); + + b.ToTable("UsersInRoles"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.WeekendDay", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("uuid"); + + b.Property("Date") + .HasColumnType("date"); + + b.HasKey("Id"); + + b.HasIndex("Date") + .IsUnique(); + + b.ToTable("WeekendDays", "schedule"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.AgentHistory", b => + { + b.HasOne("PARR.Domain.Entities.AgentHistoryLevel", "AgentHistoryLevel") + .WithMany("AgentHistories") + .HasForeignKey("HistoryLevelId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PARR.Domain.Entities.Order", "Order") + .WithMany("AgentHistories") + .HasForeignKey("OrderId"); + + b.HasOne("PARR.Domain.Entities.Template", "Template") + .WithMany("AgentHistories") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("AgentHistoryLevel"); + + b.Navigation("Order"); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.DistributionPeriod", b => + { + b.HasOne("PARR.Domain.Entities.DistributionPeriodType", "DistributionPeriodType") + .WithMany("Periods") + .HasForeignKey("Type") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("DistributionPeriodType"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Job.Job", b => + { + b.HasOne("PARR.Domain.Entities.JobGroupEntities.JobGroup", "Group") + .WithMany("Jobs") + .HasForeignKey("GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PARR.Domain.Entities.Tnk", "Tnk") + .WithMany("Jobs") + .HasForeignKey("TnkId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Group"); + + b.Navigation("Tnk"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Job.JobAutoControl", b => + { + b.HasOne("PARR.Domain.Entities.Job.Job", "Job") + .WithOne("AutoControl") + .HasForeignKey("PARR.Domain.Entities.Job.JobAutoControl", "JobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Job"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Job.JobFieldFilter", b => + { + b.HasOne("PARR.Domain.Entities.Unit.UnitField", "UnitField") + .WithMany("JobFieldFilters") + .HasForeignKey("FieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PARR.Domain.Entities.Job.JobUnitFilter", "UnitFilter") + .WithMany("FieldFilters") + .HasForeignKey("UnitFilterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("UnitField"); + + b.Navigation("UnitFilter"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Job.JobRelationshipFilter", b => + { + b.HasOne("PARR.Domain.Entities.Unit.UnitField", "UnitField") + .WithMany("RelationshipFilters") + .HasForeignKey("FieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PARR.Domain.Entities.Job.JobUnitFilter", "UnitFilter") + .WithMany("RelationshipFilters") + .HasForeignKey("UnitFilterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("UnitField"); + + b.Navigation("UnitFilter"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Job.JobUnitFilter", b => + { + b.HasOne("PARR.Domain.Entities.Job.Job", "Job") + .WithMany("UnitFilters") + .HasForeignKey("JobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Job"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Job.UnitsInTemplate", b => + { + b.HasOne("PARR.Domain.Entities.Template", "Template") + .WithMany("UnitsInTemplate") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PARR.Domain.Entities.Unit.UnitFieldValue", "UnitFieldValue") + .WithMany("UnitsInTemplates") + .HasForeignKey("UnitFieldValueId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PARR.Domain.Entities.Unit.Unit", "Unit") + .WithMany("TemplatesInUnit") + .HasForeignKey("UnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Template"); + + b.Navigation("Unit"); + + b.Navigation("UnitFieldValue"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.JobGroupEntities.JobGroup", b => + { + b.HasOne("PARR.Domain.Entities.JobGroupEntities.JobGroupType", "GroupType") + .WithMany("JobGroups") + .HasForeignKey("GroupTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PARR.Domain.Entities.Unit.UnitField", "GroupingUnitField") + .WithMany("JobGroupWithGrouping") + .HasForeignKey("GroupingUnitFieldId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("PARR.Domain.Entities.Schedule.ScheduleExcludeTypeCalendar", "ScheduleExcludeTypeCalendar") + .WithMany("JobGroups") + .HasForeignKey("ScheduleExcludeTypeCalendarId"); + + b.HasOne("PARR.Domain.Entities.Schedule.ScheduleExcludeType", "ScheduleExcludeType") + .WithMany("JobGroups") + .HasForeignKey("ScheduleExcludeTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("GroupType"); + + b.Navigation("GroupingUnitField"); + + b.Navigation("ScheduleExcludeType"); + + b.Navigation("ScheduleExcludeTypeCalendar"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.JobGroupEntities.JobGroupAutoControl", b => + { + b.HasOne("PARR.Domain.Entities.JobGroupEntities.JobGroup", "JobGroup") + .WithOne("AutoControl") + .HasForeignKey("PARR.Domain.Entities.JobGroupEntities.JobGroupAutoControl", "JobGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("JobGroup"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.JobGroupEntities.JobGroupDistributionConfig", b => + { + b.HasOne("PARR.Domain.Entities.DistributionPeriod", "DistributionPeriod") + .WithMany("GroupDistributionConfig") + .HasForeignKey("DistributionPeriodId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PARR.Domain.Entities.JobGroupEntities.JobGroup", "Group") + .WithOne("DistributionConfig") + .HasForeignKey("PARR.Domain.Entities.JobGroupEntities.JobGroupDistributionConfig", "GroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("DistributionPeriod"); + + b.Navigation("Group"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.JobGroupEntities.JobGroupFieldFilter", b => + { + b.HasOne("PARR.Domain.Entities.Unit.UnitField", "UnitField") + .WithMany("JobGroupFieldFilters") + .HasForeignKey("FieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PARR.Domain.Entities.JobGroupEntities.JobGroupUnitFilter", "UnitFilter") + .WithMany("FieldFilters") + .HasForeignKey("UnitFilterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("UnitField"); + + b.Navigation("UnitFilter"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.JobGroupEntities.JobGroupRelationshipFilter", b => + { + b.HasOne("PARR.Domain.Entities.Unit.UnitField", "UnitField") + .WithMany("JobGroupRelationshipFilters") + .HasForeignKey("FieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PARR.Domain.Entities.JobGroupEntities.JobGroupUnitFilter", "UnitFilter") + .WithMany("RelationshipFilters") + .HasForeignKey("UnitFilterId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("UnitField"); + + b.Navigation("UnitFilter"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.JobGroupEntities.JobGroupUnitFilter", b => + { + b.HasOne("PARR.Domain.Entities.JobGroupEntities.JobGroup", "JobGroup") + .WithMany() + .HasForeignKey("JobGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("JobGroup"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Order", b => + { + b.HasOne("PARR.Domain.Entities.OrderStatus", "NextStatus") + .WithMany("OrdersNext") + .HasForeignKey("NextStatusCode"); + + b.HasOne("PARR.Domain.Entities.OrderStatus", "OrderStatus") + .WithMany("Orders") + .HasForeignKey("StatusCode") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PARR.Domain.Entities.Template", "Template") + .WithMany("Orders") + .HasForeignKey("TemplateId"); + + b.Navigation("NextStatus"); + + b.Navigation("OrderStatus"); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.RobotConfiguration", b => + { + b.HasOne("PARR.Domain.Entities.Robot", "Robot") + .WithMany("RobotConfigurations") + .HasForeignKey("RobotCode") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PARR.Domain.Entities.RobotStatus", "RobotStatus") + .WithMany("RobotConfigurations") + .HasForeignKey("RobotStatusCode") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PARR.Domain.Entities.TaskStatus", "TaskStatus") + .WithMany("RobotConfigurations") + .HasForeignKey("TaskStatusCode") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PARR.Domain.Entities.Template", "Template") + .WithMany("RobotConfigurations") + .HasForeignKey("TemplateId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Robot"); + + b.Navigation("RobotStatus"); + + b.Navigation("TaskStatus"); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.RobotHistory", b => + { + b.HasOne("PARR.Domain.Entities.RobotHistoryLevel", "RobotHistoryLevel") + .WithMany("RobotHistories") + .HasForeignKey("HistoryLevel") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PARR.Domain.Entities.RobotConfiguration", "RobotConfiguration") + .WithMany("RobotHistories") + .HasForeignKey("RobotConfigurationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PARR.Domain.Entities.TaskStatus", "StatusTask") + .WithMany("RobotHistories") + .HasForeignKey("TaskStatusCode") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("RobotConfiguration"); + + b.Navigation("RobotHistoryLevel"); + + b.Navigation("StatusTask"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Schedule.EsppSchTypeConfig", b => + { + b.HasOne("PARR.Domain.Entities.Schedule.EsppSchType", "EsppSchType") + .WithMany("EsppSchTypeConfigs") + .HasForeignKey("TypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PARR.Domain.Entities.Schedule.EsppSchTypeSchedule", "EsppSchTypeSchedule") + .WithMany("EsppSchTypeConfigs") + .HasForeignKey("TypeScheduleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EsppSchType"); + + b.Navigation("EsppSchTypeSchedule"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Schedule.EsppSchTypeValue", b => + { + b.HasOne("PARR.Domain.Entities.Schedule.EsppSchType", "EsppSchType") + .WithMany("EsppSchTypeValues") + .HasForeignKey("TypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EsppSchType"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Schedule.EsppSchValue", b => + { + b.HasOne("PARR.Domain.Entities.JobGroupEntities.JobGroup", "JobGroup") + .WithMany("EsppSchValues") + .HasForeignKey("JobGroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PARR.Domain.Entities.Schedule.EsppSchTypeConfig", "EsppSchTypeConfig") + .WithMany("EsppSchValues") + .HasForeignKey("TypeConfigId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PARR.Domain.Entities.Schedule.EsppSchTypeValue", "EsppSchTypeValue") + .WithMany("EsppSchValues") + .HasForeignKey("TypeValueId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("EsppSchTypeConfig"); + + b.Navigation("EsppSchTypeValue"); + + b.Navigation("JobGroup"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Subprocess", b => + { + b.HasOne("PARR.Domain.Entities.Process", "Process") + .WithMany("Subprocesses") + .HasForeignKey("ProcessId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Process"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.TaskEntities.TaskError", b => + { + b.HasOne("PARR.Domain.Entities.TaskEntities.TaskItem", "TaskItem") + .WithMany("TaskErrors") + .HasForeignKey("TaskId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("TaskItem"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.TaskEntities.TaskItem", b => + { + b.HasOne("PARR.Domain.Entities.TaskEntities.TaskStatus", "TaskStatus") + .WithMany("Tasks") + .HasForeignKey("StatusCode") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PARR.Domain.Entities.TaskEntities.TaskType", "TaskType") + .WithMany("Tasks") + .HasForeignKey("TypeCode") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("TaskStatus"); + + b.Navigation("TaskType"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Template", b => + { + b.HasOne("PARR.Domain.Entities.Job.Job", "Job") + .WithMany("Templates") + .HasForeignKey("JobId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PARR.Domain.Entities.TemplateStatusType", "StatusType") + .WithMany("Templates") + .HasForeignKey("StatusTypeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PARR.Domain.Entities.Unit.Unit", "Unit") + .WithMany("Templates") + .HasForeignKey("UnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Job"); + + b.Navigation("StatusType"); + + b.Navigation("Unit"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.TemplateHistory", b => + { + b.HasOne("PARR.Domain.Entities.Template", "Template") + .WithMany("TemplateHistories") + .HasForeignKey("ParentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Template"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Tnk", b => + { + b.HasOne("PARR.Domain.Entities.Subprocess", "Subprocess") + .WithMany("Tnks") + .HasForeignKey("SubprocessId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Subprocess"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Unit.UnitFieldInUnitFieldValue", b => + { + b.HasOne("PARR.Domain.Entities.Unit.UnitField", "Field") + .WithMany("UnitFieldValues") + .HasForeignKey("FieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PARR.Domain.Entities.Unit.UnitFieldValue", "FieldValue") + .WithMany("FieldValues") + .HasForeignKey("FieldValueId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Field"); + + b.Navigation("FieldValue"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Unit.UnitInUnit", b => + { + b.HasOne("PARR.Domain.Entities.Unit.Unit", "ChildUnit") + .WithMany("ParentUnits") + .HasForeignKey("ChildUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PARR.Domain.Entities.Unit.Unit", "ParentUnit") + .WithMany("ChildUnits") + .HasForeignKey("ParentUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ChildUnit"); + + b.Navigation("ParentUnit"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Unit.UnitInValue", b => + { + b.HasOne("PARR.Domain.Entities.Unit.UnitField", "Field") + .WithMany("UnitInValues") + .HasForeignKey("FieldId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PARR.Domain.Entities.Unit.Unit", "Unit") + .WithMany("UnitValues") + .HasForeignKey("UnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PARR.Domain.Entities.Unit.UnitFieldValue", "Value") + .WithMany("UnitInValues") + .HasForeignKey("ValueId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Field"); + + b.Navigation("Unit"); + + b.Navigation("Value"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Unit.UnitKiiUnit", b => + { + b.HasOne("PARR.Domain.Entities.Unit.Unit", "Unit") + .WithOne("UnitKii") + .HasForeignKey("PARR.Domain.Entities.Unit.UnitKiiUnit", "UnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Unit"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Unit.UnitRegionalEkPtkGroup", b => + { + b.HasOne("PARR.Domain.Entities.Unit.UnitFieldValue", "FieldValue") + .WithOne("RegionalEkPtkGroup") + .HasForeignKey("PARR.Domain.Entities.Unit.UnitRegionalEkPtkGroup", "FieldValueId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("FieldValue"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.UsersInRole", b => + { + b.HasOne("PARR.Domain.Entities.Role", "Role") + .WithMany("Users") + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("PARR.Domain.Entities.User", "User") + .WithMany("Roles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Role"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.AgentHistoryLevel", b => + { + b.Navigation("AgentHistories"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.DistributionPeriod", b => + { + b.Navigation("GroupDistributionConfig"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.DistributionPeriodType", b => + { + b.Navigation("Periods"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Job.Job", b => + { + b.Navigation("AutoControl"); + + b.Navigation("Templates"); + + b.Navigation("UnitFilters"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Job.JobUnitFilter", b => + { + b.Navigation("FieldFilters"); + + b.Navigation("RelationshipFilters"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.JobGroupEntities.JobGroup", b => + { + b.Navigation("AutoControl"); + + b.Navigation("DistributionConfig"); + + b.Navigation("EsppSchValues"); + + b.Navigation("Jobs"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.JobGroupEntities.JobGroupType", b => + { + b.Navigation("JobGroups"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.JobGroupEntities.JobGroupUnitFilter", b => + { + b.Navigation("FieldFilters"); + + b.Navigation("RelationshipFilters"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Order", b => + { + b.Navigation("AgentHistories"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.OrderStatus", b => + { + b.Navigation("Orders"); + + b.Navigation("OrdersNext"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Process", b => + { + b.Navigation("Subprocesses"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Robot", b => + { + b.Navigation("RobotConfigurations"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.RobotConfiguration", b => + { + b.Navigation("RobotHistories"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.RobotHistoryLevel", b => + { + b.Navigation("RobotHistories"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.RobotStatus", b => + { + b.Navigation("RobotConfigurations"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Role", b => + { + b.Navigation("Users"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Schedule.EsppSchType", b => + { + b.Navigation("EsppSchTypeConfigs"); + + b.Navigation("EsppSchTypeValues"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Schedule.EsppSchTypeConfig", b => + { + b.Navigation("EsppSchValues"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Schedule.EsppSchTypeSchedule", b => + { + b.Navigation("EsppSchTypeConfigs"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Schedule.EsppSchTypeValue", b => + { + b.Navigation("EsppSchValues"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Schedule.ScheduleExcludeType", b => + { + b.Navigation("JobGroups"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Schedule.ScheduleExcludeTypeCalendar", b => + { + b.Navigation("JobGroups"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Subprocess", b => + { + b.Navigation("Tnks"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.TaskEntities.TaskItem", b => + { + b.Navigation("TaskErrors"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.TaskEntities.TaskStatus", b => + { + b.Navigation("Tasks"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.TaskEntities.TaskType", b => + { + b.Navigation("Tasks"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.TaskStatus", b => + { + b.Navigation("RobotConfigurations"); + + b.Navigation("RobotHistories"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Template", b => + { + b.Navigation("AgentHistories"); + + b.Navigation("Orders"); + + b.Navigation("RobotConfigurations"); + + b.Navigation("TemplateHistories"); + + b.Navigation("UnitsInTemplate"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.TemplateStatusType", b => + { + b.Navigation("Templates"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Tnk", b => + { + b.Navigation("Jobs"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Unit.Unit", b => + { + b.Navigation("ChildUnits"); + + b.Navigation("ParentUnits"); + + b.Navigation("Templates"); + + b.Navigation("TemplatesInUnit"); + + b.Navigation("UnitKii"); + + b.Navigation("UnitValues"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Unit.UnitField", b => + { + b.Navigation("JobFieldFilters"); + + b.Navigation("JobGroupFieldFilters"); + + b.Navigation("JobGroupRelationshipFilters"); + + b.Navigation("JobGroupWithGrouping"); + + b.Navigation("RelationshipFilters"); + + b.Navigation("UnitFieldValues"); + + b.Navigation("UnitInValues"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.Unit.UnitFieldValue", b => + { + b.Navigation("FieldValues"); + + b.Navigation("RegionalEkPtkGroup"); + + b.Navigation("UnitInValues"); + + b.Navigation("UnitsInTemplates"); + }); + + modelBuilder.Entity("PARR.Domain.Entities.User", b => + { + b.Navigation("Roles"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/PARR.DAL/Migrations/20260615235401_tblGroupTypesAddRelationshipsSettings.cs b/PARR.DAL/Migrations/20260615235401_tblGroupTypesAddRelationshipsSettings.cs new file mode 100644 index 00000000..0507ec2d --- /dev/null +++ b/PARR.DAL/Migrations/20260615235401_tblGroupTypesAddRelationshipsSettings.cs @@ -0,0 +1,57 @@ +using System; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace PARR.DAL.Migrations +{ + /// + public partial class tblGroupTypesAddRelationshipsSettings : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "IsRelationshipsAllowed", + schema: "jobGroup", + table: "GroupTypes", + type: "boolean", + nullable: false, + defaultValue: false, + comment: "Разрешена настройка кол-ва связей"); + + migrationBuilder.UpdateData( + schema: "jobGroup", + table: "GroupTypes", + keyColumn: "Id", + keyValue: new Guid("318625e5-f833-436a-99df-2a382a1e71c7"), + column: "IsRelationshipsAllowed", + value: true); + + migrationBuilder.UpdateData( + schema: "jobGroup", + table: "GroupTypes", + keyColumn: "Id", + keyValue: new Guid("4fa62e79-86bb-47c2-be1a-72a716a170fa"), + column: "IsRelationshipsAllowed", + value: false); + + migrationBuilder.UpdateData( + schema: "jobGroup", + table: "GroupTypes", + keyColumn: "Id", + keyValue: new Guid("6ec58b1a-5c40-47b9-b036-4fa490e8d503"), + column: "IsRelationshipsAllowed", + value: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "IsRelationshipsAllowed", + schema: "jobGroup", + table: "GroupTypes"); + } + } +} diff --git a/PARR.DAL/Migrations/DataContextModelSnapshot.cs b/PARR.DAL/Migrations/DataContextModelSnapshot.cs index 8a401b27..988b636f 100644 --- a/PARR.DAL/Migrations/DataContextModelSnapshot.cs +++ b/PARR.DAL/Migrations/DataContextModelSnapshot.cs @@ -599,6 +599,10 @@ namespace PARR.DAL.Migrations .HasColumnType("boolean") .HasComment("Автоконтролем управляет JobGroup? true - да JobGroup, false - Job. Влияет на интерфейс и на логику работы автоконтроля."); + b.Property("IsRelationshipsAllowed") + .HasColumnType("boolean") + .HasComment("Разрешена настройка кол-ва связей"); + b.Property("Name") .IsRequired() .HasColumnType("text"); @@ -619,6 +623,7 @@ namespace PARR.DAL.Migrations Description = "Обычный", IsAllowJobUnitFilter = true, IsJobGroupAutoControl = false, + IsRelationshipsAllowed = false, Name = "Simple" }, new @@ -629,6 +634,7 @@ namespace PARR.DAL.Migrations Description = "Зонтик", IsAllowJobUnitFilter = false, IsJobGroupAutoControl = true, + IsRelationshipsAllowed = true, Name = "Umbrella" }, new @@ -639,6 +645,7 @@ namespace PARR.DAL.Migrations Description = "Сгруппированный", IsAllowJobUnitFilter = false, IsJobGroupAutoControl = true, + IsRelationshipsAllowed = true, Name = "Group" }); }); diff --git a/PARR.DAL/Repositories/Job/JobAutoControlRepository.cs b/PARR.DAL/Repositories/Job/JobAutoControlRepository.cs index 3b34d548..13acfcab 100644 --- a/PARR.DAL/Repositories/Job/JobAutoControlRepository.cs +++ b/PARR.DAL/Repositories/Job/JobAutoControlRepository.cs @@ -17,5 +17,10 @@ namespace PARR.DAL.Repositories.Job { return dataContext.JobAutoControls; } + + public void RemoveRange(List autoControlList) + { + dataContext.JobAutoControls.RemoveRange(autoControlList); + } } } diff --git a/PARR.Domain/Entities/JobGroupEntities/JobGroupType.cs b/PARR.Domain/Entities/JobGroupEntities/JobGroupType.cs index 3a0b2a93..29d0bd33 100644 --- a/PARR.Domain/Entities/JobGroupEntities/JobGroupType.cs +++ b/PARR.Domain/Entities/JobGroupEntities/JobGroupType.cs @@ -39,6 +39,12 @@ namespace PARR.Domain.Entities.JobGroupEntities [Comment("Автоконтролем управляет JobGroup? true - да JobGroup, false - Job. Влияет на интерфейс и на логику работы автоконтроля.")] public bool IsJobGroupAutoControl { get; set; } = false; + /// + /// Разрешена настройка кол-ва связей + /// + [Comment("Разрешена настройка кол-ва связей")] + public bool IsRelationshipsAllowed { get; set; } = false; + public ICollection JobGroups { get; set; } = new HashSet(); } } From 4a8a67247d6b5829d2e791586d48082998b274f5 Mon Sep 17 00:00:00 2001 From: Mikhail Trubnikov Date: Fri, 19 Jun 2026 11:19:43 +1000 Subject: [PATCH 2/4] =?UTF-8?q?feat(api):=20=D0=A0=D0=B0=D0=B1=D0=BE=D1=82?= =?UTF-8?q?=D1=8B=20-=20=D1=83=D0=BF=D1=80=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=B0=D0=B2=D1=82=D0=BE=D0=BA=D0=BE=D0=BD=D1=82?= =?UTF-8?q?=D1=80=D0=BE=D0=BB=D0=B5=D0=BC=20=D0=B8=20=D0=BA=D0=BE=D0=BB-?= =?UTF-8?q?=D0=B2=D0=BE=D0=BC=20=D1=81=D0=B2=D1=8F=D0=B7=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- PARR.API/Contracts/V1/Requests/JobRequest.cs | 74 +++-- .../V1/Responses/JobGroupResponse.cs | 4 +- PARR.API/Controllers/V1/JobController.cs | 272 ++++++++++-------- PARR.API/Controllers/V1/JobGroupController.cs | 62 ++-- .../DomainToResponseProfile.cs | 6 +- .../MappingProfiles/RequestToDomainProfile.cs | 3 + PARR.API/Validators/JobGroupValidator.cs | 6 +- PARR.API/Validators/JobRequestValidator.cs | 85 ++++-- .../Entities/JobGroupEntities/JobGroupType.cs | 1 + 9 files changed, 297 insertions(+), 216 deletions(-) diff --git a/PARR.API/Contracts/V1/Requests/JobRequest.cs b/PARR.API/Contracts/V1/Requests/JobRequest.cs index 18dc4c92..77730073 100644 --- a/PARR.API/Contracts/V1/Requests/JobRequest.cs +++ b/PARR.API/Contracts/V1/Requests/JobRequest.cs @@ -1,79 +1,91 @@ namespace PARR.API.Contracts.V1.Requests { - public class JobRequest + public record JobRequest { - public required Guid TnkId { get; set; } + public required Guid TnkId { get; init; } - public required Guid GroupId { get; set; } + public required Guid GroupId { get; init; } - public required string Name { get; set; } + public required string Name { get; init; } - public int? MinValueRelationships { get; set; } + //public int? MinValueRelationships { get; init; } - public int? MaxValueRelationships { get; set; } + //public int? MaxValueRelationships { get; init; } - public bool? IsParentRelationships { get; set; } + //public bool? IsParentRelationships { get; init; } - public required string TemplateNameMask { get; set; } + public JobRelationships? Relationships { get; init; } - public required string WorkGroupMask { get; set; } + public required string TemplateNameMask { get; init; } - public required string WorkName { get; set; } + public required string WorkGroupMask { get; init; } - public required string ResponseAreaMask { get; set; } + public required string WorkName { get; init; } - #region AutoControl + public required string ResponseAreaMask { get; init; } - public bool IsEnableAutoControl { get; set; } + //#region AutoControl - public bool InitUsedTemplateState { get; set; } + //public bool IsEnableAutoControl { get; set; } - public bool InitUsedScheduleState { get; set; } + //public bool InitUsedTemplateState { get; set; } - #endregion + //public bool InitUsedScheduleState { get; set; } - public required List UnitFilters { get; set; } + //#endregion + + public JobAutoControlRequest? AutoControl { get; init; } + + public required List UnitFilters { get; init; } } + public record JobRelationships + { + public int MinValueRelationships { get; init; } - public class UnitFilterRequest + public int MaxValueRelationships { get; init; } + + public bool IsParentRelationships { get; init; } + } + + public record UnitFilterRequest { ///// ///// Id = null в методе Create, в Update обязателен ///// //public Guid? Id { get; set; } - public required string UnitFilterMask { get; set; } + public required string UnitFilterMask { get; init; } - public List? FieldFilters { get; set; } + public List? FieldFilters { get; init; } - public List? RelationshipFilters { get; set; } + public List? RelationshipFilters { get; init; } } - public class FieldFilterRequest + public record FieldFilterRequest { - public Guid FieldId { get; set; } + public Guid FieldId { get; init; } - public string? ValueMask { get; set; } + public string? ValueMask { get; init; } - public bool IsInverse { get; set; } = false; + public bool IsInverse { get; init; } = false; } - public class RelationshipFilterRequest + public record RelationshipFilterRequest { - public Guid FieldId { get; set; } + public Guid FieldId { get; init; } - public bool? IsParent { get; set; } + public bool? IsParent { get; init; } - public string? ValueMask { get; set; } + public string? ValueMask { get; init; } - public bool? IsFullMatch { get; set; } + public bool? IsFullMatch { get; init; } - public bool? IsInverse { get; set; } + public bool? IsInverse { get; init; } } } \ No newline at end of file diff --git a/PARR.API/Contracts/V1/Responses/JobGroupResponse.cs b/PARR.API/Contracts/V1/Responses/JobGroupResponse.cs index 449c40a4..af15d2cf 100644 --- a/PARR.API/Contracts/V1/Responses/JobGroupResponse.cs +++ b/PARR.API/Contracts/V1/Responses/JobGroupResponse.cs @@ -40,6 +40,8 @@ /// public bool IsAutoDistributionEnabled { get; set; } + public JobGroupAutoControlResponse? AutoControl { get; set; } + // public bool IsAgent { get; set; } // public string? AgentName { get; set; } @@ -68,8 +70,6 @@ /// public ScheduleExcludeTypeCalendarResponse? ScheduleExcludeTypeCalendar { get; set; } - public JobGroupAutoControlResponse? AutoControl { get; set; } - ///// ///// Настройки автораспределения ///// diff --git a/PARR.API/Controllers/V1/JobController.cs b/PARR.API/Controllers/V1/JobController.cs index fd2903b6..279e2dbc 100644 --- a/PARR.API/Controllers/V1/JobController.cs +++ b/PARR.API/Controllers/V1/JobController.cs @@ -35,46 +35,43 @@ namespace PARR.API.Controllers.V1 [Authorize(Roles = ParrRoles.Administrator.Role)] public class JobController : BaseApiController { - private readonly ILogger logger; - private readonly IMapper mapper; - private readonly IUriService uriService; - private readonly IJobRepository jobService; - private readonly ITemplateRepository templateService; - //private readonly IValidator jobValidator; - private readonly IRabbitService mqService; - private readonly MqSettings mqSettings; - private readonly IClientService clientService; - private readonly IJobAutoControlRepository jobAutoControlService; - private readonly IMatchingStatusService matchingStatusService; + private readonly ILogger _logger; + private readonly IMapper _mapper; + private readonly IUriService _uriService; + private readonly IJobRepository _jobRepository; + private readonly ITemplateRepository _templateRepository; + private readonly IRabbitService _mqService; + private readonly MqSettings _mqSettings; + private readonly IClientService _clientService; + private readonly IJobAutoControlRepository _jobAutoControlRepository; + private readonly IMatchingStatusService _matchingStatusService; public JobController( ILogger logger, IMapper mapper, IUriService uriService, - IJobRepository jobService, - ITemplateRepository templateService, - IJobGroupRepository jobGroupService, - //IValidator jobValidator, - IUnitFilterService unitFilterService, - IUnitRepository unitService, + IJobRepository jobRepository, + ITemplateRepository templateRepository, + IJobGroupRepository jobGroupRepository, + IUnitFilterService unitFilterRepository, + IUnitRepository unitRepository, IRabbitService mqService, MqSettings mqSettings, IClientService clientService, - IJobAutoControlRepository jobAutoControlService, + IJobAutoControlRepository jobAutoControlRepository, IMatchingStatusService matchingStatusService ) { - this.logger = logger; - this.mapper = mapper; - this.uriService = uriService; - this.jobService = jobService; - this.templateService = templateService; - //this.jobValidator = jobValidator; - this.mqService = mqService; - this.mqSettings = mqSettings; - this.clientService = clientService; - this.jobAutoControlService = jobAutoControlService; - this.matchingStatusService = matchingStatusService; + _logger = logger; + _mapper = mapper; + _uriService = uriService; + _jobRepository = jobRepository; + _templateRepository = templateRepository; + _mqService = mqService; + _mqSettings = mqSettings; + _clientService = clientService; + _jobAutoControlRepository = jobAutoControlRepository; + _matchingStatusService = matchingStatusService; } /// @@ -84,18 +81,20 @@ namespace PARR.API.Controllers.V1 [HttpGet(ApiRoutes.Job.GetAll)] public async Task GetAll([FromQuery] PaginationQuery paginationQuery, [FromQuery] JobQuery filter) { - var paginationFilter = mapper.Map(paginationQuery); + var paginationFilter = _mapper.Map(paginationQuery); + + IQueryable query = _jobRepository.Get() + .Include(t => t.AutoControl); - IQueryable query = jobService.Get().Include(t => t.AutoControl); query = query.OrderBy(t => t.Name); if (!string.IsNullOrEmpty(filter.Name)) { //query = query.Where(t => t.Name.ToLower().Contains(filter.Name.ToLower())); - query = query.Where(t=>EF.Functions.Like(t.Name.ToLower(), SqlHelpers.RegexToLike(filter.Name))); + query = query.Where(t => EF.Functions.Like(t.Name.ToLower(), SqlHelpers.RegexToLike(filter.Name))); } - + if (filter.GroupId.HasValue) query = query.Where(t => t.GroupId == filter.GroupId.Value); @@ -107,9 +106,10 @@ namespace PARR.API.Controllers.V1 if (filter.IsFull) { query = query - .Include(t => t.Tnk) - .Include(t => t.Group).ThenInclude(t => t.GroupType) - .Include(t => t.Group).ThenInclude(t => t.GroupingUnitField); + .Include(t => t.Tnk) + .Include(t => t.Group).ThenInclude(t => t.GroupType) + .Include(t => t.Group).ThenInclude(t => t.GroupingUnitField) + .Include(t => t.Group).ThenInclude(t => t.AutoControl); query = query .Include(t => t.UnitFilters) @@ -120,12 +120,12 @@ namespace PARR.API.Controllers.V1 .ThenInclude(t => t.UnitField); } - var jobs = await jobService.GetPage(query, paginationFilter).ToListAsync(); + var jobs = await _jobRepository.GetPage(query, paginationFilter).ToListAsync(); if (!jobs.Any()) return NoContent(); - var response = mapper.Map>(jobs);//TODO Migration to job + var response = _mapper.Map>(jobs);//TODO Migration to job foreach (var jobResponse in response) { @@ -152,9 +152,10 @@ namespace PARR.API.Controllers.V1 [HttpGet(ApiRoutes.Job.Get)] public async Task GetById([FromRoute] Guid id) { - var job = await jobService.Get() + var job = await _jobRepository.Get() .Include(t => t.Tnk) .Include(t => t.Group).ThenInclude(t => t.GroupType) + .Include(t => t.Group).ThenInclude(t => t.AutoControl) .Include(t => t.Group).ThenInclude(t => t.GroupingUnitField) .Include(t => t.UnitFilters) .ThenInclude(t => t.FieldFilters) @@ -168,7 +169,7 @@ namespace PARR.API.Controllers.V1 if (job == null) return NotFound(); - var response = mapper.Map(job); + var response = _mapper.Map(job); response.TemplatesCount = await GetCountTemplatesAsync(id); //await templateService.Get().CountAsync(t => t.JobId == id); response.MatchingStatus = await GetMatchingStatusAsync(id); @@ -188,51 +189,56 @@ namespace PARR.API.Controllers.V1 [HttpPost(ApiRoutes.Job.Create)] public async Task Create([FromBody] JobRequest request) { - //#region Валидация - //var jobValidateResult = await jobValidator.ValidateAsync(request);//Валидация параметров самого задания + #region Проверка существования работы с такими же настройками связей параметрами - //if (!jobValidateResult.IsValid) - // return BadRequest(new Response(jobValidateResult.Errors)); - //#endregion + if (request.Relationships != null) + { + //todo: не сильно правильный запрос, в нем проверяем полное совпадение, но не проверяем пересечения + var isExistTheSameLinks = await _jobRepository.Get() + //.Include(t => t.Group).ThenInclude(t => t.GroupType) + .AsNoTracking() + .CountAsync(t => + //t.Group!.GroupType!.Code == JobGroupTypesEnum.Umbrella + //(t.Group!.GroupType!.Code == JobGroupTypesEnum.Umbrella || t.Group!.GroupType!.Code == JobGroupTypesEnum.Group) && + t.Group!.GroupType!.IsRelationshipsAllowed && + t.GroupId == request.GroupId && + (t.MinValueRelationships == request.Relationships.MinValueRelationships || + t.MaxValueRelationships == request.Relationships.MaxValueRelationships) + ); - //TODO: !!!!!!! проверить, если тип ЗОНТИК или ГРУППИРОВКА, то обязательно должны быть заполнены поля min max - - #region Проверка существования работы с такими же параметрами - - var isExistTheSameLinks = await jobService.Get() - .Include(t => t.Group).ThenInclude(t => t.GroupType) - .CountAsync(t => - //t.Group!.GroupType!.Code == JobGroupTypesEnum.Umbrella - (t.Group!.GroupType!.Code == JobGroupTypesEnum.Umbrella || t.Group!.GroupType!.Code == JobGroupTypesEnum.Group) && - t.GroupId == request.GroupId && - (t.MinValueRelationships == request.MinValueRelationships || - t.MaxValueRelationships == request.MaxValueRelationships) - ); - - if (isExistTheSameLinks > 0) - return BadRequest(new Response(false, new List { new ErrorModel { FieldName = nameof(request.Name), Message = $"Работа с указанным диапазоном связей пересекается с уже имеющейся в базе данных({request.MinValueRelationships}-{request.MaxValueRelationships})" } })); + if (isExistTheSameLinks > 0) + return BadRequest(new Response(false, new List { new ErrorModel { + FieldName = nameof(request.Name), + Message = $"Работа с указанным диапазоном связей пересекается с уже имеющейся в базе данных({request.Relationships.MinValueRelationships}-{request.Relationships.MaxValueRelationships})" + } })); + } #endregion - var job = mapper.Map(request); + var job = _mapper.Map(request); - job.AutoControl = new JobAutoControl + if (request.AutoControl != null) { - JobId = job.Id, - IsEnable = request.IsEnableAutoControl, - InitUsedScheduleState = request.InitUsedScheduleState, - InitUsedTemplateState = request.InitUsedTemplateState - }; + // разрешен автоконтроль или нет, проверил в валидаторе + job.AutoControl = new JobAutoControl + { + JobId = job.Id, + IsEnable = request.AutoControl.IsEnable, + InitUsedScheduleState = request.AutoControl.InitUsedScheduleState, + InitUsedTemplateState = request.AutoControl.InitUsedTemplateState + }; + } - if (!await jobService.CreateAsync(job) || !await jobService.CommitAsync()) + if (!await _jobRepository.CreateAsync(job) || !await _jobRepository.CommitAsync()) return BadRequest(new Response(false, new List { new ErrorModel { Message = "Ошибка при созании задания на выполнение работ" } })); - logger.LogInformation($"Пользователь {User.Identity?.Name} добавил задание на выполнение работ: {job.Id}, {job.Name}, {job.WorkName}"); + _logger.LogInformation($"Пользователь {User.Identity?.Name} добавил задание на выполнение работ: {job.Id}, {job.Name}, {job.WorkName}"); - var createdJob = await jobService.Get() + var createdJob = await _jobRepository.Get() .Include(t => t.Tnk) .Include(t => t.Group).ThenInclude(t => t.GroupType) + .Include(t => t.Group).ThenInclude(t => t.AutoControl) .Include(t => t.Group).ThenInclude(t => t.GroupingUnitField) .Include(t => t.UnitFilters) .ThenInclude(t => t.FieldFilters) @@ -242,9 +248,9 @@ namespace PARR.API.Controllers.V1 .Include(t => t.AutoControl) .FirstOrDefaultAsync(t => t.Id == job.Id); - var locationUri = uriService.GetUri(ApiRoutes.Job.Get, ApiRoutes.Job.getParam, createdJob!.Id); + var locationUri = _uriService.GetUri(ApiRoutes.Job.Get, ApiRoutes.Job.getParam, createdJob!.Id); - var response = mapper.Map(createdJob); + var response = _mapper.Map(createdJob); // так как мы только что создали Job, то у него нет шаблонов, смело ставим = 0 (ускоряем запрос) response.TemplatesCount = 0; response.MatchingStatus = await GetMatchingStatusAsync(response.Id); @@ -262,11 +268,7 @@ namespace PARR.API.Controllers.V1 [HttpPut(ApiRoutes.Job.Update)] public async Task Update([FromRoute] Guid id, [FromBody] JobRequest request) { - //var resultValidate = await jobValidator.ValidateAsync(request); - //if (!resultValidate.IsValid) - // return BadRequest(new Response(resultValidate.Errors)); - - var orig = await jobService.Get() + var orig = await _jobRepository.Get() .Include(t => t.Tnk) .Include(t => t.Group).ThenInclude(t => t.GroupType) .Include(t => t.Group).ThenInclude(t => t.GroupingUnitField) @@ -287,77 +289,77 @@ namespace PARR.API.Controllers.V1 //TODO: ВОТ ЭТО ВООБЩЕ МЫ БУДЕМ ПРОВЕРЯТЬ, АААА???? - Проверка существования работы с такими же параметрами - //TODO: !!!!!!! проверить, если тип ЗОНТИК или ГРУППИРОВКА, то обязательно должны быть заполнены поля min max - #region обновление полей задания на работу orig.Name = request.Name.Trim(); orig.WorkName = request.WorkName.Trim(); - orig.MinValueRelationships = request.MinValueRelationships; - orig.MaxValueRelationships = request.MaxValueRelationships; - orig.IsParentRelationships = request.IsParentRelationships; + orig.MinValueRelationships = request.Relationships?.MinValueRelationships; + orig.MaxValueRelationships = request.Relationships?.MaxValueRelationships; + orig.IsParentRelationships = request.Relationships?.IsParentRelationships; orig.TemplateNameMask = request.TemplateNameMask.Trim(); orig.WorkGroupMask = request.WorkGroupMask.Trim(); orig.TnkId = request.TnkId; orig.GroupId = request.GroupId; orig.ResponseAreaMask = request.ResponseAreaMask.Trim(); - if (orig.AutoControl != null) + #region Настройки автоконтроля + + // валидатор проверяет корректность + if (request.AutoControl != null) { - orig.AutoControl.IsEnable = request.IsEnableAutoControl; - orig.AutoControl.InitUsedScheduleState = request.InitUsedScheduleState; - orig.AutoControl.InitUsedTemplateState = request.InitUsedTemplateState; - } - else - { - // автоконтрол не загружен, проверяем есть ли он в бд, если нет, то создадим - var existAutoControl = await jobAutoControlService.Get().FirstOrDefaultAsync(t => t.JobId == id); - if (existAutoControl != null) + // Создаем новую запись или обновляем существующую + if (orig.AutoControl != null) { - logger.LogError($"При обновлении job {id}, не загрузась связь с JobAutoControl, но она есть. Не стал обновлять Job, вернул ошибку."); - return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Ошибка при изменении задания на выполнение работ." } })); + orig.AutoControl.IsEnable = request.AutoControl.IsEnable; + orig.AutoControl.InitUsedScheduleState = request.AutoControl.InitUsedScheduleState; + orig.AutoControl.InitUsedTemplateState = request.AutoControl.InitUsedTemplateState; } else { - var autoControl = new JobAutoControl + orig.AutoControl = new JobAutoControl { JobId = id, - InitUsedScheduleState = request.InitUsedScheduleState, - InitUsedTemplateState = request.InitUsedTemplateState, - IsEnable = request.IsEnableAutoControl + InitUsedScheduleState = request.AutoControl.InitUsedScheduleState, + InitUsedTemplateState = request.AutoControl.InitUsedTemplateState, + IsEnable = request.AutoControl.IsEnable }; - orig.AutoControl = autoControl; - logger.LogWarning($"При обновлении job {id}, отсутствовала запись в таблице JobAutoControl, создал ее. {autoControl.ToJson()}"); } } + else + { + // Удаляем настройки, скорей всего автоконтролем управляет группа работ + orig.AutoControl = null; + } + #endregion orig.DateModified = DateTimeOffset.UtcNow; #endregion - var job = mapper.Map(request); + var job = _mapper.Map(request); job.Id = id;//На всякий. Пусть будет для чистоты UpdateUnitFilters(orig, job);//Обновление вложенных дочерних элементов-фильтров - if (!await jobService.CommitAsync()) + if (!await _jobRepository.CommitAsync()) return BadRequest(new Response(false, new List { new ErrorModel { Message = "Ошибка при изменении задания на выполнение работ." } })); // если изменили маску, отправим задание на переименование связанных шаблонов if (isChangedTemplateNameMask) { - var mqResult = await SendRequestToUpdateTemplates(id); + var mqResult = await SendRequestToUpdateTemplates(orig); //todo: если ошибка. пользователя не предупреждаем... возможно ему это и не нужно знать...ну не переименуются шаблоны, может они переименуются позже... } - logger.LogInformation($"Пользователь {User.Identity?.Name} обновил задание на выполнение работ: {orig.Id}," + + _logger.LogInformation($"Пользователь {User.Identity?.Name} обновил задание на выполнение работ: {orig.Id}," + $" {orig.Name}, {orig.WorkName}, {orig.MinValueRelationships}, {orig.MaxValueRelationships}," + $" {orig.TemplateNameMask}, {orig.TnkId}, {nameof(orig.GroupId)}"); - var updatedJob = await jobService.Get() + var updatedJob = await _jobRepository.Get() .Include(t => t.Tnk) .Include(t => t.Group).ThenInclude(t => t.GroupType) + .Include(t => t.Group).ThenInclude(t => t.AutoControl) .Include(t => t.Group).ThenInclude(t => t.GroupingUnitField) .Include(t => t.UnitFilters) .ThenInclude(t => t.FieldFilters) @@ -367,7 +369,7 @@ namespace PARR.API.Controllers.V1 .Include(t => t.AutoControl) .FirstAsync(t => t.Id == orig.Id); - var response = mapper.Map(updatedJob); + var response = _mapper.Map(updatedJob); response.TemplatesCount = await GetCountTemplatesAsync(id); //await templateService.Get().CountAsync(t => t.JobId == id); response.MatchingStatus = await GetMatchingStatusAsync(id); @@ -564,7 +566,7 @@ namespace PARR.API.Controllers.V1 [HttpDelete(ApiRoutes.Job.Delete)] public async Task Delete([FromRoute] Guid id) { - var job = await jobService.Get().Include(t => t.Tnk) + var job = await _jobRepository.Get().Include(t => t.Tnk) .FirstOrDefaultAsync(t => t.Id == id); if (job == null) @@ -572,19 +574,19 @@ namespace PARR.API.Controllers.V1 Message = $"Ошибка при удалении задания на выполнение работ. Не найдено задание на выполнение работ Id: {id}" } })); - var templateCount = await templateService.Get().CountAsync(t => t.JobId == id); + var templateCount = await _templateRepository.Get().CountAsync(t => t.JobId == id); if (templateCount > 0) return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Ошибка при удалении задания на выполнение работ. С данным заданием связаны шаблоны: {templateCount} шт." } })); - if (!jobService.Delete(job) || !await jobService.CommitAsync()) + if (!_jobRepository.Delete(job) || !await _jobRepository.CommitAsync()) return BadRequest(new Response(false, new List { new ErrorModel { Message = $"Ошибка при удалении задания на выполнение работ" } })); - logger.LogInformation($"Пользователь {User.Identity?.Name} удалил задание на выполнение работ: {job.Id},{job.Name}," + + _logger.LogInformation($"Пользователь {User.Identity?.Name} удалил задание на выполнение работ: {job.Id},{job.Name}," + $" {job.WorkName}, {job.MinValueRelationships}, {job.MaxValueRelationships}," + $" {job.TemplateNameMask}, {job.TnkId}, {job.GroupId}"); @@ -599,7 +601,7 @@ namespace PARR.API.Controllers.V1 /// private async Task GetStatisticsAsync(Guid jobId) { - var statResult = await jobService.Get() + var statResult = await _jobRepository.Get() .Include(t => t.Templates) .ThenInclude(t => t.RobotConfigurations) .Where(x => x.Id == jobId) @@ -629,35 +631,53 @@ namespace PARR.API.Controllers.V1 } - private async Task SendRequestToUpdateTemplates(Guid jobId) + private async Task SendRequestToUpdateTemplates(Job job) { + if (job.Group?.GroupType == null) + throw new ArgumentException("Не хватает include для job.Group.GroupType", nameof(job.Group.GroupType)); + + Guid Id = default; + SyncTaskEntityTypeEnum EntityType = default; + + // Смотрим кто управляет автоконтролем, и какой объект можно синхронизировать + if (job.Group.GroupType.IsJobGroupAutoControl) + { + // Управляет JobGroup + Id = job.GroupId; + EntityType = SyncTaskEntityTypeEnum.JobGroup; + + } + else + { + // Управляет Job + Id = job.Id; + EntityType = SyncTaskEntityTypeEnum.Job; + } + var request = new TemplateMatcherMq { - Id = jobId, - EntityType = SyncTaskEntityTypeEnum.Job, + Id = Id, + EntityType = EntityType, Action = TemplateMatcherActionEnum.Update, Initiator = new HistoryInitiator { - InitiatorIp = clientService.GetClientIp()?.ToString(), + InitiatorIp = _clientService.GetClientIp()?.ToString(), InitiatorParrComponentId = ParrComponentsEnum.Api, InitiatorComment = $"В GUI изменено имя шаблона, при сохранении Job отправлен запрос на обновление связанных шаблонов" } }; - //var msg = JsonSerializer.Serialize(request); + var result = await _mqService.SendAsync(_mqSettings.TemplatesMatcher, new List { request }); - //var result = await mqService.SendAsync(mqSettings.TemplatesMatcher, new[] { msg }); - var result = await mqService.SendAsync(mqSettings.TemplatesMatcher, new List { request }); - - logger.LogDebug("Получен код отпрвки: {IsSuccess}", result.IsSuccess); + _logger.LogDebug("Получен код отпрвки: {IsSuccess}", result.IsSuccess); if (!result.IsSuccess) { - logger.LogError($"Ошибка при отправке запроса в очередь на обновление связанных шаблонов, после обновления маски шаблона. {request.ToJson()}"); + _logger.LogError($"Ошибка при отправке запроса в очередь на обновление связанных шаблонов, после обновления маски шаблона. {request.ToJson()}"); return false; } - logger.LogInformation($"После изменения маски шаблона в jobId: {jobId}, отправлен запрос в очередь на переименование связанных шаблонов: {request.ToJson()}"); + _logger.LogInformation($"После изменения маски шаблона в jobId: {job.Id}, отправлен запрос в очередь на переименование связанных шаблонов: {request.ToJson()}"); return true; } @@ -671,7 +691,7 @@ namespace PARR.API.Controllers.V1 private async Task GetCountTemplatesAsync(Guid jobId) { // Получаем только шаблоны в статусе used - return await templateService.Get().CountAsync(t => t.JobId == jobId && t.StatusTypeId == TemplateStatusTypeEnum.Used); + return await _templateRepository.Get().CountAsync(t => t.JobId == jobId && t.StatusTypeId == TemplateStatusTypeEnum.Used); } /// @@ -681,9 +701,9 @@ namespace PARR.API.Controllers.V1 /// private async Task GetMatchingStatusAsync(Guid jobId) { - var statusMatching = await matchingStatusService.GetStatusAsync(jobId, SyncTaskEntityTypeEnum.Job); + var statusMatching = await _matchingStatusService.GetStatusAsync(jobId, SyncTaskEntityTypeEnum.Job); - return mapper.Map(statusMatching); + return _mapper.Map(statusMatching); } } diff --git a/PARR.API/Controllers/V1/JobGroupController.cs b/PARR.API/Controllers/V1/JobGroupController.cs index c4aac721..30c5db67 100644 --- a/PARR.API/Controllers/V1/JobGroupController.cs +++ b/PARR.API/Controllers/V1/JobGroupController.cs @@ -33,9 +33,9 @@ namespace PARR.API.Controllers.V1 [Authorize(Roles = ParrRoles.Administrator.Role)] public class JobGroupController : BaseApiController { - private readonly ILogger logger; - private readonly IMapper mapper; - private readonly IUriService uriService; + private readonly ILogger _logger; + private readonly IMapper _mapper; + private readonly IUriService _uriService; private readonly IJobGroupRepository _groupRepository; private readonly IJobRepository _jobRepository; private readonly IEsppSchTypeConfigRepository _esppConfigRepository; @@ -43,8 +43,8 @@ namespace PARR.API.Controllers.V1 private readonly IMatchingStatusService _matchingStatusRepository; private readonly IScheduleResponseAreaTimeOffsetRepository _scheduleResponseAreaTimeOffsetRepository; private readonly IJobAutoControlRepository _jobAutoControlRepository; - private readonly IRabbitService mqService; - private readonly MqSettings mqSettings; + private readonly IRabbitService _mqService; + private readonly MqSettings _mqSettings; public JobGroupController( ILogger logger, @@ -61,9 +61,9 @@ namespace PARR.API.Controllers.V1 MqSettings mqSettings ) { - this.logger = logger; - this.mapper = mapper; - this.uriService = uriService; + this._logger = logger; + this._mapper = mapper; + this._uriService = uriService; _groupRepository = groupRepository; _jobRepository = jobRepository; _esppConfigRepository = esppConfigRepository; @@ -71,8 +71,8 @@ namespace PARR.API.Controllers.V1 _matchingStatusRepository = matchingStatusRepository; _scheduleResponseAreaTimeOffsetRepository = scheduleResponseAreaTimeOffsetRepository; _jobAutoControlRepository = jobAutoControlRepository; - this.mqService = mqService; - this.mqSettings = mqSettings; + this._mqService = mqService; + this._mqSettings = mqSettings; } @@ -83,7 +83,7 @@ namespace PARR.API.Controllers.V1 [HttpGet(ApiRoutes.JobGroup.GetAll)] public async Task GetAll([FromQuery] PaginationQuery paginationQuery, [FromQuery] JobGroupQuery filter) { - var paginationFilter = mapper.Map(paginationQuery); + var paginationFilter = _mapper.Map(paginationQuery); IQueryable query = _groupRepository.Get() .Include(t => t.GroupType) @@ -110,7 +110,7 @@ namespace PARR.API.Controllers.V1 if (!jobGroups.Any()) return NoContent(); - var response = mapper.Map>(jobGroups); + var response = _mapper.Map>(jobGroups); if (filter.IsFull) foreach (var jobGroupResponse in response) @@ -143,7 +143,7 @@ namespace PARR.API.Controllers.V1 if (jobGroup == null) return NotFound(); - var response = mapper.Map(jobGroup); + var response = _mapper.Map(jobGroup); await AppendMissingDataAsync(response); return Ok(new Response(response, true)); @@ -188,7 +188,7 @@ namespace PARR.API.Controllers.V1 // на всякий проверим, но вообще это проверяется в валидаторе if (request.DistributionConfig == null) { - logger.LogError("Ошибка при создании группы работ '{name}', отсутствуют настройки автораспределения", request.Name); + _logger.LogError("Ошибка при создании группы работ '{name}', отсутствуют настройки автораспределения", request.Name); return BadRequest(new Response(false, new List { new ErrorModel { Message = "Ошибка при создании группы заданий на выполнение работ" } })); } @@ -226,7 +226,7 @@ namespace PARR.API.Controllers.V1 if (!await _groupRepository.CreateAsync(jobGroup) || !await _groupRepository.CommitAsync()) return BadRequest(new Response(false, new List { new ErrorModel { Message = "Ошибка при создании группы заданий на выполнение работ" } })); - logger.LogInformation($"Пользователь {User.Identity?.Name} добавил группу заданий на выполнение работ: {jobGroup.Id}, {jobGroup.GroupName}, {jobGroup.ShortDescription}"); + _logger.LogInformation($"Пользователь {User.Identity?.Name} добавил группу заданий на выполнение работ: {jobGroup.Id}, {jobGroup.GroupName}, {jobGroup.ShortDescription}"); var createdJobGroup = await _groupRepository.Get().Include(t => t.Jobs).ThenInclude(t => t.Tnk) @@ -238,9 +238,9 @@ namespace PARR.API.Controllers.V1 .Include(t => t.AutoControl) .FirstAsync(t => t.Id == jobGroup.Id); - var locationUri = uriService.GetUri(ApiRoutes.JobGroup.Get, ApiRoutes.JobGroup.getParam, createdJobGroup.Id); + var locationUri = _uriService.GetUri(ApiRoutes.JobGroup.Get, ApiRoutes.JobGroup.getParam, createdJobGroup.Id); - var response = mapper.Map(createdJobGroup); + var response = _mapper.Map(createdJobGroup); await AppendMissingDataAsync(response); return Created(locationUri, new Response(response, true)); @@ -297,7 +297,7 @@ namespace PARR.API.Controllers.V1 { if (request.DistributionConfig == null) { - logger.LogError("Ошибка при изменении группы работ '{name}', отсутствуют настройки автораспределения", request.Name); + _logger.LogError("Ошибка при изменении группы работ '{name}', отсутствуют настройки автораспределения", request.Name); return BadRequest(new Response(false, new List { new ErrorModel { Message = "Ошибка при изменении группы заданий на выполнение работ" } })); } @@ -378,7 +378,7 @@ namespace PARR.API.Controllers.V1 if (!await _groupRepository.CommitAsync()) return BadRequest(new Response(false, new List { new ErrorModel { Message = "Ошибка при изменении группы заданий на выполнение работ." } })); - logger.LogInformation($"Пользователь {User.Identity?.Name} обновил группу заданий на выполнение работ: {orig.Id}," + + _logger.LogInformation($"Пользователь {User.Identity?.Name} обновил группу заданий на выполнение работ: {orig.Id}," + $" {orig.GroupName}, {orig.ShortDescription}, {orig.FullDescription}," + $" {orig.Solution}, {orig.TemplateDuration}, {orig.ReferenceDate}, {orig.IsAutoDistributionEnabled}" + $", {orig.IsAgent}, {orig.AgentName}, {orig.AgentTimeOutSec}, {orig.AgentScript}"); @@ -393,12 +393,12 @@ namespace PARR.API.Controllers.V1 JobGroupId = id, Initiator = new HistoryInitiator { InitiatorComment = "Изменилось расписание группы работ в ГУИ, отправлен запрос на перерасчет nextRun", InitiatorParrComponentId = ParrComponentsEnum.Api } }; - var sendResult = await mqService.SendAsync(mqSettings.NextRun, new List { requestToMq }); + var sendResult = await _mqService.SendAsync(_mqSettings.NextRun, new List { requestToMq }); if (sendResult.IsSuccess) - logger.LogInformation("Задание на перерасчет NextRun успешно отправлено в очередь MQ {queueName}", mqSettings.NextRun.QueueName); + _logger.LogInformation("Задание на перерасчет NextRun успешно отправлено в очередь MQ {queueName}", _mqSettings.NextRun.QueueName); else - logger.LogError("Ошибка при отправке задания на перерасчет NextRun в очередь MQ {queueName}", mqSettings.NextRun.QueueName); + _logger.LogError("Ошибка при отправке задания на перерасчет NextRun в очередь MQ {queueName}", _mqSettings.NextRun.QueueName); } #endregion @@ -414,7 +414,7 @@ namespace PARR.API.Controllers.V1 .Include(t => t.AutoControl) .FirstAsync(t => t.Id == orig.Id); - var response = mapper.Map(updatedJobGroup); + var response = _mapper.Map(updatedJobGroup); await AppendMissingDataAsync(response); return Ok(new Response(response, true)); @@ -448,7 +448,7 @@ namespace PARR.API.Controllers.V1 Message = $"Ошибка при удалении группы заданий на выполнение работ" } })); - logger.LogInformation($"Пользователь {User.Identity?.Name} удалил группу заданий на выполнение работ: {jobGroup.Id},{jobGroup.GroupName}," + + _logger.LogInformation($"Пользователь {User.Identity?.Name} удалил группу заданий на выполнение работ: {jobGroup.Id},{jobGroup.GroupName}," + $" {jobGroup.ShortDescription}, {jobGroup.FullDescription}," + $" {jobGroup.Solution}, {jobGroup.TemplateDuration}, {jobGroup.ReferenceDate}," + $" {jobGroup.IsAutoDistributionEnabled}, {jobGroup.IsAgent}, {jobGroup.AgentName}," + @@ -471,6 +471,8 @@ namespace PARR.API.Controllers.V1 if (!jobAutoControlsToRemove.Any()) return; + _logger.LogInformation("У группы работ {JobGroupId}, у связанных работ {JobsCount} шт. удалены настройки автоконтроля, так как автоконтролем управляем группа работ.", jobGroupId, jobAutoControlsToRemove.Count); + _jobAutoControlRepository.RemoveRange(jobAutoControlsToRemove); } @@ -540,7 +542,7 @@ namespace PARR.API.Controllers.V1 if (schedule == null) { - logger.LogError($"Не смог замапить расписание, так как оно null. JobGroupId: {jobGroupResponse.Id}"); + _logger.LogError($"Не смог замапить расписание, так как оно null. JobGroupId: {jobGroupResponse.Id}"); return; } @@ -548,8 +550,8 @@ namespace PARR.API.Controllers.V1 { //Timezone = settingsFromDb.ScheduleTimezone, Timezone = _scheduleResponseAreaTimeOffsetRepository.GetDefault.EsppValue, - TypeSchedule = mapper.Map(schedule.TypeSchedule), - Values = mapper.Map>(schedule.Values).OrderBy(t => t.Order).ToList() + TypeSchedule = _mapper.Map(schedule.TypeSchedule), + Values = _mapper.Map>(schedule.Values).OrderBy(t => t.Order).ToList() }; jobGroupResponse.Schedule = scheduleResponse; @@ -580,7 +582,7 @@ namespace PARR.API.Controllers.V1 else { // Это не сгруппированный тип, обнуляем IsGroupByResponsible - logger.LogInformation("При сохраненни JobGroup, был передан IsGroupByResponsible: {IsGroupByResponsible}, но при этом, тип группы не сгруппированный, а GroupTypeId: {GroupTypeId}, обнулил IsGroupByResponsible", + _logger.LogInformation("При сохраненни JobGroup, был передан IsGroupByResponsible: {IsGroupByResponsible}, но при этом, тип группы не сгруппированный, а GroupTypeId: {GroupTypeId}, обнулил IsGroupByResponsible", request.IsGroupByResponsible, request.GroupTypeId); return null; } @@ -609,7 +611,7 @@ namespace PARR.API.Controllers.V1 else { // Это не сгруппированный тип, обнуляем GroupingUnitFieldId - logger.LogInformation("При сохраненни JobGroup, был передан GroupingUnitFieldId: {GroupingUnitFieldId}, но при этом, тип группы не сгруппированный, а GroupTypeId: {GroupTypeId}, обнулил GroupingUnitFieldId", + _logger.LogInformation("При сохраненни JobGroup, был передан GroupingUnitFieldId: {GroupingUnitFieldId}, но при этом, тип группы не сгруппированный, а GroupTypeId: {GroupTypeId}, обнулил GroupingUnitFieldId", request.GroupingUnitFieldId, request.GroupTypeId); return null; } @@ -625,7 +627,7 @@ namespace PARR.API.Controllers.V1 { var statusMatching = await _matchingStatusRepository.GetStatusAsync(jobGroupId, SyncTaskEntityTypeEnum.JobGroup); - return mapper.Map(statusMatching); + return _mapper.Map(statusMatching); } diff --git a/PARR.API/MappingProfiles/DomainToResponseProfile.cs b/PARR.API/MappingProfiles/DomainToResponseProfile.cs index 802340d3..b1e2b251 100644 --- a/PARR.API/MappingProfiles/DomainToResponseProfile.cs +++ b/PARR.API/MappingProfiles/DomainToResponseProfile.cs @@ -368,7 +368,8 @@ namespace PARR.API.MappingProfiles .Include() .ForMember(d => d.GroupType, o => o.MapFrom(s => s.GroupType)) .ForMember(d => d.GroupingUnitField, o => o.MapFrom(s => s.GroupingUnitField)) - .ForMember(d => d.IsWorkGroupTimezone, o => o.MapFrom(s => s.IsResponseAreaTimezone)); + .ForMember(d => d.IsWorkGroupTimezone, o => o.MapFrom(s => s.IsResponseAreaTimezone)) + .ForMember(d => d.AutoControl, o => o.MapFrom(s => s.AutoControl)); CreateMap() .ForMember(d => d.Name, o => o.MapFrom(s => s.GroupName)) @@ -379,8 +380,7 @@ namespace PARR.API.MappingProfiles CreateMap() .ForMember(d => d.ScheduleExcludeType, o => o.MapFrom(s => s.ScheduleExcludeType)) - .ForMember(d => d.ScheduleExcludeTypeCalendar, o => o.MapFrom(s => s.ScheduleExcludeTypeCalendar)) - .ForMember(d => d.AutoControl, o => o.MapFrom(s => s.AutoControl)); + .ForMember(d => d.ScheduleExcludeTypeCalendar, o => o.MapFrom(s => s.ScheduleExcludeTypeCalendar)); //.ForMember(d => d.DistributionConfig, o => o.MapFrom(s => s.DistributionConfig)); CreateMap(); diff --git a/PARR.API/MappingProfiles/RequestToDomainProfile.cs b/PARR.API/MappingProfiles/RequestToDomainProfile.cs index 1278a3ed..4264fc5c 100644 --- a/PARR.API/MappingProfiles/RequestToDomainProfile.cs +++ b/PARR.API/MappingProfiles/RequestToDomainProfile.cs @@ -17,6 +17,9 @@ namespace PARR.API.MappingProfiles CreateMap() .ForMember(d => d.Id, o => o.MapFrom(s => Guid.NewGuid())) + .ForMember(d => d.IsParentRelationships, o => o.MapFrom(s => s.Relationships != null ? s.Relationships.IsParentRelationships : (bool?)null)) + .ForMember(d => d.MaxValueRelationships, o => o.MapFrom(s => s.Relationships != null ? s.Relationships.MaxValueRelationships : (int?)null)) + .ForMember(d => d.MinValueRelationships, o => o.MapFrom(s => s.Relationships != null ? s.Relationships.MinValueRelationships : (int?)null)) .ForMember(d => d.DateCreated, o => o.MapFrom(s => DateTimeOffset.UtcNow)) .AfterMap((s, d) => { diff --git a/PARR.API/Validators/JobGroupValidator.cs b/PARR.API/Validators/JobGroupValidator.cs index 2c68cda9..d885d2e1 100644 --- a/PARR.API/Validators/JobGroupValidator.cs +++ b/PARR.API/Validators/JobGroupValidator.cs @@ -135,7 +135,9 @@ namespace PARR.API.Validators .MustAsync(async (entity, value, c) => { // Автоконтроль разрешен только типам работ у которых включен IsJobGroupAutoControl - var isAllowedAutocontrol = await jobGroupTypeRepository.Get().AsNoTracking().AnyAsync(t => t.Id == entity.GroupTypeId && t.IsJobGroupAutoControl == true); + var isAllowedAutocontrol = await jobGroupTypeRepository.Get() + .AnyAsync(t => t.Id == entity.GroupTypeId && t.IsJobGroupAutoControl == true); + // Разрешен автоконтроль и есть значение if (isAllowedAutocontrol && value != null) return true; @@ -146,7 +148,7 @@ namespace PARR.API.Validators return false; }) - .WithMessage("Не верные параметры автоконтроля"); + .WithMessage("Некорректные параметры автоконтроля"); } } diff --git a/PARR.API/Validators/JobRequestValidator.cs b/PARR.API/Validators/JobRequestValidator.cs index 1ced6f2b..33ea9456 100644 --- a/PARR.API/Validators/JobRequestValidator.cs +++ b/PARR.API/Validators/JobRequestValidator.cs @@ -1,31 +1,32 @@ using FluentValidation; +using Microsoft.EntityFrameworkCore; +using Newtonsoft.Json.Linq; using PARR.API.Contracts.V1.Requests; using PARR.Core.Repositories.Interfaces; using PARR.Core.Repositories.Interfaces.Job; using PARR.Core.Repositories.Interfaces.Unit; -using PARR.Domain.Entities.JobGroupEntities; namespace PARR.API.Validators { public class JobRequestValidator : AbstractValidator { - private readonly ITnkRepository tnkService; - private readonly IJobGroupRepository jobGroupService; - private readonly IJobRepository jobRepository; - private readonly IUnitFieldRepository unitFieldService; - private JobGroup? jobGroup; + private readonly ITnkRepository _tnkRepository; + private readonly IJobGroupRepository _jobGroupRepository; + private readonly IJobRepository _jobRepository; + private readonly IUnitFieldRepository _unitFieldRepository; + //private JobGroup? jobGroup; public JobRequestValidator( - ITnkRepository tnkService, - IJobGroupRepository jobGroupService, - IJobRepository jobService, - IUnitFieldRepository unitFieldService + ITnkRepository tnkRepository, + IJobGroupRepository jobGroupRepository, + IJobRepository jobRepository, + IUnitFieldRepository unitFieldRepository ) { - this.tnkService = tnkService; - this.jobGroupService = jobGroupService; - this.jobRepository = jobService; - this.unitFieldService = unitFieldService; + _tnkRepository = tnkRepository; + _jobGroupRepository = jobGroupRepository; + _jobRepository = jobRepository; + _unitFieldRepository = unitFieldRepository; RuleFor(t => t.Name) .NotNull().NotEmpty(); @@ -48,14 +49,54 @@ namespace PARR.API.Validators .MustAsync(async (entity, value, c) => await IsUnitFiltersCorrect(entity)) .WithMessage("Неверно заданы параметры фильтров. Внимательнее, пожалуйста!"); - RuleFor(t => t.MinValueRelationships) - .GreaterThanOrEqualTo(0); + RuleFor(t => t.Relationships) + .MustAsync(async (entity, value, c) => + { + // Relationships должны быть обязательно заполнены если в типе работ IsRelationshipsAllowed==true + var relationshipsIsRequired = await jobGroupRepository.Get() + .AnyAsync(t => t.Id == entity.GroupId && t.GroupType!.IsRelationshipsAllowed, c); + + if (relationshipsIsRequired && value != null) + return true; + + if (!relationshipsIsRequired && value == null) + return true; + + return false; + }) + .WithMessage("Некорректные настройки кол-ва связей"); + + When(t => t.Relationships != null, () => + { + RuleFor(t => t.Relationships!.MinValueRelationships) + .GreaterThanOrEqualTo(0); + + RuleFor(t => t.Relationships!.MaxValueRelationships) + .GreaterThanOrEqualTo(t => t.Relationships!.MinValueRelationships); + }); - RuleFor(t => t.MaxValueRelationships) - .GreaterThanOrEqualTo(t => t.MinValueRelationships); RuleFor(t => t.ResponseAreaMask) .NotNull().NotEmpty(); + + RuleFor(t => t.AutoControl) + .MustAsync(async (entity, value, c) => + { + // Автоконтроль разрешен только типам работ, у которых выключен IsJobGroupAutoControl + var isAllowedJobAutocontrol = await jobGroupRepository.Get() + .AnyAsync(t => t.Id == entity.GroupId && t.GroupType!.IsJobGroupAutoControl == false, c); + + // Разрешен автоконтроль и есть значение + if (isAllowedJobAutocontrol && value != null) + return true; + + // Запрещен автоконтроль и нет значения + if (!isAllowedJobAutocontrol && value == null) + return true; + + return false; + }) + .WithMessage("Некорректные параметры автоконтроля"); } private async Task IsUnitFiltersCorrect(JobRequest entity) @@ -72,7 +113,7 @@ namespace PARR.API.Validators foreach (var fieldFilter in unitFilter.FieldFilters) { var fieldId = fieldFilter.FieldId; - if (await unitFieldService.GetAsync(fieldId) == null) + if (await _unitFieldRepository.GetAsync(fieldId) == null) return false; } @@ -80,7 +121,7 @@ namespace PARR.API.Validators foreach (var relationshipFilter in unitFilter.RelationshipFilters!) { var fieldId = relationshipFilter.FieldId; - if (await unitFieldService.GetAsync(fieldId) == null) + if (await _unitFieldRepository.GetAsync(fieldId) == null) return false; } } @@ -90,7 +131,7 @@ namespace PARR.API.Validators private async Task IsGroupExist(JobRequest entity) { - jobGroup = await jobGroupService.GetAsync(entity.GroupId); + var jobGroup = await _jobGroupRepository.GetAsync(entity.GroupId); return jobGroup != null; } @@ -98,7 +139,7 @@ namespace PARR.API.Validators private async Task IsTnkExist(JobRequest entity) { - return await tnkService.GetAsync(entity.TnkId) != null; + return await _tnkRepository.GetAsync(entity.TnkId) != null; } } } \ No newline at end of file diff --git a/PARR.Domain/Entities/JobGroupEntities/JobGroupType.cs b/PARR.Domain/Entities/JobGroupEntities/JobGroupType.cs index 29d0bd33..93f3a827 100644 --- a/PARR.Domain/Entities/JobGroupEntities/JobGroupType.cs +++ b/PARR.Domain/Entities/JobGroupEntities/JobGroupType.cs @@ -35,6 +35,7 @@ namespace PARR.Domain.Entities.JobGroupEntities /// /// Автоконтролем управляет JobGroup? true - да JobGroup, false - Job. /// Влияет на интерфейс и на логику работы автоконтроля. + /// Если true - то в GUI, кнопку синхронизировать можно нажать только в группах. /// [Comment("Автоконтролем управляет JobGroup? true - да JobGroup, false - Job. Влияет на интерфейс и на логику работы автоконтроля.")] public bool IsJobGroupAutoControl { get; set; } = false; From 16f97904eb5a41ce9506ddb78517854c85541ca5 Mon Sep 17 00:00:00 2001 From: Mikhail Trubnikov Date: Tue, 30 Jun 2026 16:12:52 +1000 Subject: [PATCH 3/4] =?UTF-8?q?feat(api,core,jobAutoControl):=20=D0=92?= =?UTF-8?q?=D0=B0=D0=BB=D0=B8=D0=B4=D0=B0=D1=86=D0=B8=D1=8F=20=D0=BF=D1=80?= =?UTF-8?q?=D0=B8=20=D0=BF=D0=BE=D0=BB=D1=83=D1=87=D0=B5=D0=BD=D0=B8=D0=B8?= =?UTF-8?q?=20=D0=B7=D0=B0=D0=BF=D1=80=D0=BE=D1=81=D0=B0=20=D0=BD=D0=B0=20?= =?UTF-8?q?=D1=81=D0=B8=D0=BD=D1=85=D1=80=D0=BE=D0=BD=D0=B8=D0=B7=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D1=8E=20=D0=B3=D1=80=D1=83=D0=BF=D0=BF,=20=D1=80?= =?UTF-8?q?=D0=B0=D0=B1=D0=BE=D1=82.=20JobAutoControlWorker=20-=20=D0=B8?= =?UTF-8?q?=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD=D0=B0=20=D0=BB=D0=BE=D0=B3?= =?UTF-8?q?=D0=B8=D0=BA=D0=B0,=20=D0=BC=D0=BE=D0=B6=D0=B5=D1=82=20=D0=BE?= =?UTF-8?q?=D0=B1=D1=80=D0=B0=D0=B1=D0=B0=D1=82=D1=8B=D0=B2=D0=B0=D1=82?= =?UTF-8?q?=D1=8C=20=D0=B3=D1=80=D1=83=D0=BF=D0=BF=D1=8B=20=D0=B8=20=D1=80?= =?UTF-8?q?=D0=B0=D0=B1=D0=BE=D1=82=D1=8B.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitlab/issue_templates/Bug.md | 21 ++++ PARR.API/Controllers/V1/SyncTaskController.cs | 3 - .../MappingProfiles/RequestToDomainProfile.cs | 1 + .../MatchTemplatesRequestValidator.cs | 50 +++++++++ .../RabbitServices/IRabbitService.cs | 2 +- PARR.Infrastructure/Rabbit/RabbitService.cs | 2 +- PARR.JobAutoControl/JobAutoControlManager.cs | 102 +++++++++++------- 7 files changed, 135 insertions(+), 46 deletions(-) create mode 100644 .gitlab/issue_templates/Bug.md create mode 100644 PARR.API/Validators/MatchTemplatesRequestValidator.cs diff --git a/.gitlab/issue_templates/Bug.md b/.gitlab/issue_templates/Bug.md new file mode 100644 index 00000000..0136e78a --- /dev/null +++ b/.gitlab/issue_templates/Bug.md @@ -0,0 +1,21 @@ +### 📋 Описание бага +Кратко и понятно опишите, что идет не так. + +### 🔄 Шаги для воспроизведения +1. Перейти на страницу... +2. Нажать кнопку... +3. Ввести в поле поиска... + +### ❌ Фактический результат +Что произошло на самом деле? (Например: Приложение завершилось с ошибкой 500). + +### ✅ Ожидаемый результат +Что должно было произойти? (Например: Появился список найденных товаров). + +### 🖥️ Окружение +* **ОС:** Windows 11 / macOS Sequoia +* **Браузер / Версия:** Chrome 124 / iOS App v2.1 +* **Стенд:** Staging / Production + +### 📎 Вложения +Скриншоты, гифки или логи, которые помогают понять проблему. diff --git a/PARR.API/Controllers/V1/SyncTaskController.cs b/PARR.API/Controllers/V1/SyncTaskController.cs index 2ff7528a..4b7a13b0 100644 --- a/PARR.API/Controllers/V1/SyncTaskController.cs +++ b/PARR.API/Controllers/V1/SyncTaskController.cs @@ -48,9 +48,6 @@ namespace PARR.API.Controllers.V1 [HttpPost(ApiRoutes.SyncTask.MatchTemplates)] public async Task MatchTemplatesForJob([FromBody] MatchTemplatesRequest request) { - //todo: Валидатор! Валидатор то забыли!!! - - // проверяем, если уже идет синхронизация по этому объекту, то ахтунг, ошибка var matchingStatus = await matchingStatusService.GetStatusAsync(request.ObjectId, request.EntityType); if (matchingStatus.IsMatchingObject) diff --git a/PARR.API/MappingProfiles/RequestToDomainProfile.cs b/PARR.API/MappingProfiles/RequestToDomainProfile.cs index 4264fc5c..ba67bb7e 100644 --- a/PARR.API/MappingProfiles/RequestToDomainProfile.cs +++ b/PARR.API/MappingProfiles/RequestToDomainProfile.cs @@ -21,6 +21,7 @@ namespace PARR.API.MappingProfiles .ForMember(d => d.MaxValueRelationships, o => o.MapFrom(s => s.Relationships != null ? s.Relationships.MaxValueRelationships : (int?)null)) .ForMember(d => d.MinValueRelationships, o => o.MapFrom(s => s.Relationships != null ? s.Relationships.MinValueRelationships : (int?)null)) .ForMember(d => d.DateCreated, o => o.MapFrom(s => DateTimeOffset.UtcNow)) + .ForMember(d => d.AutoControl, o => o.Ignore()) .AfterMap((s, d) => { if (d.UnitFilters != null) diff --git a/PARR.API/Validators/MatchTemplatesRequestValidator.cs b/PARR.API/Validators/MatchTemplatesRequestValidator.cs new file mode 100644 index 00000000..959a17f8 --- /dev/null +++ b/PARR.API/Validators/MatchTemplatesRequestValidator.cs @@ -0,0 +1,50 @@ +using FluentValidation; +using Microsoft.EntityFrameworkCore; +using PARR.API.Contracts.V1.Requests; +using PARR.Core.Repositories.Interfaces; +using PARR.Core.Repositories.Interfaces.Job; +using PARR.Domain.Enums; + +namespace PARR.API.Validators +{ + public class MatchTemplatesRequestValidator : AbstractValidator + { + public MatchTemplatesRequestValidator( + IJobGroupRepository jobGroupRepository, + IJobRepository jobRepository, + ITemplateRepository templateRepository + ) + { + RuleFor(t => t.ObjectId) + .NotNull() + .NotEmpty() + .WithMessage("Идентификатор объекта не может быть пустым."); + + RuleFor(t => t) + .MustAsync(async (request, cancellation) => + { + return request.EntityType switch + { + SyncTaskEntityTypeEnum.JobGroup => + await jobGroupRepository.Get().AsNoTracking().AnyAsync(t => t.Id == request.ObjectId, cancellation), + + SyncTaskEntityTypeEnum.Job => + await jobRepository.Get().AsNoTracking().AnyAsync(t => t.Id == request.ObjectId && t.Group!.GroupType!.IsJobGroupAutoControl == false, cancellation), + + SyncTaskEntityTypeEnum.Template => + false, // TODO: Синхронизировать шаблоны нельзя + + _ => false + }; + }) + .WithMessage(request => request.EntityType switch + { + SyncTaskEntityTypeEnum.Template => "Синхронизация шаблонов пока не поддерживается.", + SyncTaskEntityTypeEnum.Job => "Объект не найден или данные работы нельзя отправить на синхронизацию.", + _ => "Не найден объект с переданным ИД." + }); + + + } + } +} diff --git a/PARR.Core/Common/Interfaces/RabbitServices/IRabbitService.cs b/PARR.Core/Common/Interfaces/RabbitServices/IRabbitService.cs index 05ef85d1..954ca3cf 100644 --- a/PARR.Core/Common/Interfaces/RabbitServices/IRabbitService.cs +++ b/PARR.Core/Common/Interfaces/RabbitServices/IRabbitService.cs @@ -24,6 +24,6 @@ namespace PARR.Core.Common.Interfaces.RabbitServices /// /// /// - Task SendAsync(IMqSettings mqSettings, List msgObjectList); + Task SendAsync(IMqSettings mqSettings, IEnumerable msgObjectList); } } diff --git a/PARR.Infrastructure/Rabbit/RabbitService.cs b/PARR.Infrastructure/Rabbit/RabbitService.cs index 7c3ed030..21c2e969 100644 --- a/PARR.Infrastructure/Rabbit/RabbitService.cs +++ b/PARR.Infrastructure/Rabbit/RabbitService.cs @@ -115,7 +115,7 @@ namespace PARR.Infrastructure.Rabbit } } - public async Task SendAsync(IMqSettings mqSettings, List msgObjectList) + public async Task SendAsync(IMqSettings mqSettings, IEnumerable msgObjectList) { var msgStringList = msgObjectList.Select(t => JsonSerializer.Serialize(t, jsonOptions)).ToArray(); diff --git a/PARR.JobAutoControl/JobAutoControlManager.cs b/PARR.JobAutoControl/JobAutoControlManager.cs index 2325337d..ac0c60e4 100644 --- a/PARR.JobAutoControl/JobAutoControlManager.cs +++ b/PARR.JobAutoControl/JobAutoControlManager.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.Logging; using PARR.Core.Common.Interfaces; using PARR.Core.Common.Interfaces.RabbitServices; using PARR.Core.Repositories.Interfaces.Job; +using PARR.Core.Repositories.Interfaces.JobGroupRepositories; using PARR.Domain.Common.Rabbit.Messages; using PARR.Domain.Entities.Base.History; using PARR.Domain.Enums; @@ -13,11 +14,11 @@ namespace PARR.JobAutoControl { internal class JobAutoControlManager : IJobAutoControlManager { - private readonly WorkerSettings workerSettings; - private readonly ILogger logger; - private readonly IIntervalService intervalService; - private readonly IServiceProvider serviceProvider; - private readonly MqSettings mqSettings; + private readonly WorkerSettings _workerSettings; + private readonly ILogger _logger; + private readonly IIntervalService _intervalService; + private readonly IServiceProvider _serviceProvider; + private readonly MqSettings _mqSettings; public JobAutoControlManager( WorkerSettings workerSettings, @@ -27,68 +28,87 @@ namespace PARR.JobAutoControl MqSettings mqSettings ) { - this.workerSettings = workerSettings; - this.logger = logger; - this.intervalService = intervalService; - this.serviceProvider = serviceProvider; - this.mqSettings = mqSettings; + _workerSettings = workerSettings; + _logger = logger; + _intervalService = intervalService; + _serviceProvider = serviceProvider; + _mqSettings = mqSettings; } public async Task StartAsync() { - logger.LogInformation("Запуск сервиса управления авто-контролем РР (JobAutoControl)"); + _logger.LogInformation("Запуск сервиса управления авто-контролем РР (JobAutoControl)"); - await intervalService.IntervalInitAsync(async () => + await _intervalService.IntervalInitAsync(async () => { - await using (var scope = serviceProvider.CreateAsyncScope()) - //using (var scope = serviceProvider.CreateScope()) + await using (var scope = _serviceProvider.CreateAsyncScope()) { - var jobAutoControlService = scope.ServiceProvider.GetService(); - var mqService = scope.ServiceProvider.GetService(); + var jobAutoControlRepository = scope.ServiceProvider.GetRequiredService(); + var jobGroupAutoControlRepository = scope.ServiceProvider.GetRequiredService(); + var mqService = scope.ServiceProvider.GetRequiredService(); - if (jobAutoControlService == null || mqService == null) - throw new Exception($"Не смог получить серивс {nameof(IJobAutoControlRepository)} или {nameof(IRabbitService)}"); - - await HandlerAsync(jobAutoControlService, mqService); + await HandlerAsync(jobAutoControlRepository, jobGroupAutoControlRepository, mqService); } - }, workerSettings.RepeatEvery); + }, _workerSettings.RepeatEvery); } - private async Task HandlerAsync(IJobAutoControlRepository jobAutoControlService, IRabbitService mqService) + private async Task HandlerAsync(IJobAutoControlRepository jobAutoControlRepository, IJobGroupAutoControlRepository jobGroupAutoControlRepository, IRabbitService mqService) { - var jobsWithAutoControl = await jobAutoControlService.Get().Where(t => t.IsEnable).ToListAsync(); + // Список JobGroup с включенным автоконтролем + var jobGroupsIds = await jobGroupAutoControlRepository.Get() + .AsNoTracking() + .Where(t => t.IsEnable) + .Select(t => t.JobGroupId) + .ToListAsync(); - logger.LogInformation($"Работ с включенным авто-контролем: {jobsWithAutoControl.Count} шт."); + // Список Job с включенным автоконтролем, но у которых в JobGroupType.IsJobGroupAutocOntrol==false + var jobIds = await jobAutoControlRepository.Get() + .AsNoTracking() + .Where(t => t.IsEnable && t.Job!.Group!.GroupType!.IsJobGroupAutoControl == false) + .Select(t => t.JobId) + .ToListAsync(); - if (jobsWithAutoControl.Count == 0) + _logger.LogInformation("Найдено объектов с включенным автоконтролем, групп: {JobGroupCount} шт., работ: {JobCount} шт.", jobGroupsIds.Count, jobIds.Count); + + if (jobGroupsIds.Count == 0 && jobIds.Count == 0) return; - // формируем сообщения - var msgList = jobsWithAutoControl.Select(t => new TemplateMatcherMq + var msgList = new List(jobGroupsIds.Count + jobIds.Count); + + var initiator = new HistoryInitiator + { + InitiatorComment = $"Инициатор авто-контроль, периодичность: {_workerSettings.RepeatEvery}", + InitiatorIp = null, + InitiatorParrComponentId = ParrComponentsEnum.JobAutoControl + }; + + // группы + msgList.AddRange(jobGroupsIds.Select(id => new TemplateMatcherMq + { + Action = TemplateMatcherActionEnum.Sync, + EntityType = SyncTaskEntityTypeEnum.JobGroup, + Id = id, + Initiator = initiator + })); + + // работы + msgList.AddRange(jobIds.Select(id => new TemplateMatcherMq { Action = TemplateMatcherActionEnum.Sync, EntityType = SyncTaskEntityTypeEnum.Job, - Id = t.JobId, - Initiator = new HistoryInitiator - { - InitiatorComment = $"Инициатор авто-контроль, периодичность: {workerSettings.RepeatEvery}", - InitiatorIp = null, - InitiatorParrComponentId = ParrComponentsEnum.JobAutoControl - } - }).ToList(); - - //var msgStrList = msgList.Select(t => JsonSerializer.Serialize(t)); + Id = id, + Initiator = initiator + })); // отправляем задания в очередь template matcher`a - //var sendResult = await mqService.SendAsync(mqSettings.TemplateMatcher, msgStrList.ToArray()); - var sendResult = await mqService.SendAsync(mqSettings.TemplateMatcher, msgList.ToList()); + var sendResult = await mqService.SendAsync(_mqSettings.TemplateMatcher, msgList); if (!sendResult.IsSuccess) - logger.LogError($"Ошибка при отправке сообщений ({msgList.Count()} шт.) в очередь."); + _logger.LogError("Ошибка при отправке сообщений ({Count} шт.) в очередь.", msgList.Count); else - logger.LogInformation($"Выполнена отправка сообщений в очередь, {msgList.Count()} шт."); + _logger.LogInformation("Выполнена отправка сообщений в очередь, {Count} шт.", msgList.Count); } } From cb3c98ed8c5a9ce2efe6e480fe4148907737b38d Mon Sep 17 00:00:00 2001 From: Mikhail Trubnikov Date: Wed, 1 Jul 2026 10:18:43 +1000 Subject: [PATCH 4/4] =?UTF-8?q?feat:=20=D0=9E=D0=B1=D0=B2=D0=BD=D0=BE?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B0=20=D0=B2=D0=B5=D1=80=D1=81=D0=B8=D1=8F?= =?UTF-8?q?=20Redis,=20c=207.2=20=D0=B4=D0=BE=208.8.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index bb4dc106..07319179 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -48,15 +48,16 @@ services: # REDIS STACK parr-redis: - image: redis/redis-stack:7.2.0-v6 + #image: redis/redis-stack:7.2.0-v6 + image: redis:8.8.0 restart: always ports: - 6379:6379 volumes: - parr_redis_data:/data - #- parr_redis_config/redis.conf:/usr/local/etc/redis/redis.conf - environment: - - REDIS_ARGS=--requirepass ParrP@ssPtk202MMdevDvs + #environment: + #- REDIS_ARGS=--requirepass ParrP@ssPtk202MMdevDvs + command: redis-server --requirepass ParrP@ssPtk202MMdevDvs deploy: replicas: 1 networks: