diff --git a/PARR.API/Contracts/V1/ApiRoutes.cs b/PARR.API/Contracts/V1/ApiRoutes.cs index 54d05f8f..dc64907f 100644 --- a/PARR.API/Contracts/V1/ApiRoutes.cs +++ b/PARR.API/Contracts/V1/ApiRoutes.cs @@ -517,6 +517,16 @@ public const string GetAll = Base + "/shortcodes/"; } + public static class RegionalEkPtkGroup + { + public const string GetAll = Base + "/regional-ek-ptk-groups/"; + } + + public static class KiiUnit + { + public const string GetAll = Base + "/kii-units/"; + } + } } diff --git a/PARR.API/Contracts/V1/Requests/JobGroupRequest.cs b/PARR.API/Contracts/V1/Requests/JobGroupRequest.cs index ee410762..be390ba2 100644 --- a/PARR.API/Contracts/V1/Requests/JobGroupRequest.cs +++ b/PARR.API/Contracts/V1/Requests/JobGroupRequest.cs @@ -8,6 +8,11 @@ public Guid GroupTypeId { get; set; } + /// + /// Поле по которому групиируем, если тип - ГРУППА + /// + public Guid? GroupingUnitFieldId { get; set; } + public required string ShortDescription { get; set; } public required string FullDescription { get; set; } diff --git a/PARR.API/Contracts/V1/Responses/JobGroupResponse.cs b/PARR.API/Contracts/V1/Responses/JobGroupResponse.cs index 8141617e..004a489a 100644 --- a/PARR.API/Contracts/V1/Responses/JobGroupResponse.cs +++ b/PARR.API/Contracts/V1/Responses/JobGroupResponse.cs @@ -20,6 +20,11 @@ public required JobGroupTypeResponse GroupType { get; set; } + /// + /// По какому полю грппируется, если используется тип ГРУППИРОВКА + /// + public FieldResponse? GroupingUnitField { get; set; } + // public bool IsAutoDistributionEnabled { get; set; } // public bool IsAgent { get; set; } diff --git a/PARR.API/Controllers/V1/JobController.cs b/PARR.API/Controllers/V1/JobController.cs index c7cbb17b..d3631ea2 100644 --- a/PARR.API/Controllers/V1/JobController.cs +++ b/PARR.API/Controllers/V1/JobController.cs @@ -100,7 +100,8 @@ namespace PARR.API.Controllers.V1 { query = query .Include(t => t.Tnk) - .Include(t => t.Group).ThenInclude(t => t.GroupType); + .Include(t => t.Group).ThenInclude(t => t.GroupType) + .Include(t => t.Group).ThenInclude(t => t.GroupingUnitField); query = query .Include(t => t.UnitFilters) @@ -140,6 +141,7 @@ namespace PARR.API.Controllers.V1 var job = await jobService.Get() .Include(t => t.Tnk) .Include(t => t.Group).ThenInclude(t => t.GroupType) + .Include(t => t.Group).ThenInclude(t => t.GroupingUnitField) .Include(t => t.UnitFilters) .ThenInclude(t => t.FieldFilters) .ThenInclude(t => t.UnitField) @@ -178,14 +180,15 @@ namespace PARR.API.Controllers.V1 return BadRequest(new Response(jobValidateResult.Errors)); #endregion + //TODO: !!!!!!! проверить, если тип ЗОНТИК или ГРУППИРОВКА, то обязательно должны быть заполнены поля min max #region Проверка существования работы с такими же параметрами var isExistTheSameLinks = await jobService.Get() .Include(t => t.Group).ThenInclude(t => t.GroupType) .CountAsync(t => - //t.Group!.IsUmbrella == true && - t.Group!.GroupType!.Code == JobGroupTypesEnum.Umbrella && + //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) @@ -215,6 +218,7 @@ namespace PARR.API.Controllers.V1 var createdJob = await jobService.Get() .Include(t => t.Tnk) .Include(t => t.Group).ThenInclude(t => t.GroupType) + .Include(t => t.Group).ThenInclude(t => t.GroupingUnitField) .Include(t => t.UnitFilters) .ThenInclude(t => t.FieldFilters) .ThenInclude(t => t.UnitField) @@ -249,6 +253,7 @@ namespace PARR.API.Controllers.V1 var orig = await jobService.Get() .Include(t => t.Tnk) .Include(t => t.Group).ThenInclude(t => t.GroupType) + .Include(t => t.Group).ThenInclude(t => t.GroupingUnitField) .Include(t => t.UnitFilters) .ThenInclude(t => t.FieldFilters) .Include(t => t.UnitFilters) @@ -263,6 +268,11 @@ namespace PARR.API.Controllers.V1 // если изменили маску шаблона, ниже отправим в очередь, на изменение связанных имен шаблонов var isChangedTemplateNameMask = orig.TemplateNameMask != request.TemplateNameMask.Trim(); + + //TODO: ВОТ ЭТО ВООБЩЕ МЫ БУДЕМ ПРОВЕРЯТЬ, АААА???? - Проверка существования работы с такими же параметрами + + //TODO: !!!!!!! проверить, если тип ЗОНТИК или ГРУППИРОВКА, то обязательно должны быть заполнены поля min max + #region обновление полей задания на работу orig.Name = request.Name.Trim(); @@ -331,6 +341,7 @@ namespace PARR.API.Controllers.V1 var updatedJob = await jobService.Get() .Include(t => t.Tnk) .Include(t => t.Group).ThenInclude(t => t.GroupType) + .Include(t => t.Group).ThenInclude(t => t.GroupingUnitField) .Include(t => t.UnitFilters) .ThenInclude(t => t.FieldFilters) .ThenInclude(t => t.UnitField) diff --git a/PARR.API/Controllers/V1/JobGroupController.cs b/PARR.API/Controllers/V1/JobGroupController.cs index 55616180..ef8eaaad 100644 --- a/PARR.API/Controllers/V1/JobGroupController.cs +++ b/PARR.API/Controllers/V1/JobGroupController.cs @@ -34,6 +34,7 @@ namespace PARR.API.Controllers.V1 private readonly IJobService jobService; private readonly IEsppSchTypeConfigService esppConfigService; private readonly IValidator validator; + private readonly IJobGroupTypeService jobGroupTypeService; private readonly SettingsFromDb settingsFromDb; public JobGroupController( @@ -44,6 +45,7 @@ namespace PARR.API.Controllers.V1 IJobService jobService, IEsppSchTypeConfigService esppConfigService, IValidator validator, + IJobGroupTypeService jobGroupTypeService, SettingsFromDb settingsFromDb ) { @@ -54,6 +56,7 @@ namespace PARR.API.Controllers.V1 this.jobService = jobService; this.esppConfigService = esppConfigService; this.validator = validator; + this.jobGroupTypeService = jobGroupTypeService; this.settingsFromDb = settingsFromDb; } @@ -67,7 +70,9 @@ namespace PARR.API.Controllers.V1 { var paginationFilter = mapper.Map(paginationQuery); - IQueryable query = groupService.Get().Include(t => t.GroupType); + IQueryable query = groupService.Get() + .Include(t => t.GroupType) + .Include(t => t.GroupingUnitField); query = query.OrderBy(t => t.GroupName); @@ -105,6 +110,7 @@ namespace PARR.API.Controllers.V1 var jobGroup = await groupService.Get() .Include(t => t.Jobs).ThenInclude(t => t.Tnk) .Include(t => t.GroupType) + .Include(t => t.GroupingUnitField) .FirstOrDefaultAsync(t => t.Id == id); if (jobGroup == null) @@ -136,6 +142,7 @@ namespace PARR.API.Controllers.V1 GroupName = request.Name.Trim(), //IsUmbrella = request.IsUmbrella, GroupTypeId = request.GroupTypeId, + GroupingUnitFieldId = await GetGroupingUnitFieldIdAsync(request), ShortDescription = request.ShortDescription.Trim(), FullDescription = request.FullDescription.Trim(), Solution = request.Solution.Trim(), @@ -167,6 +174,7 @@ namespace PARR.API.Controllers.V1 var createdJobGroup = await groupService.Get().Include(t => t.Jobs).ThenInclude(t => t.Tnk) .Include(t => t.GroupType) + .Include(t => t.GroupingUnitField) .FirstAsync(t => t.Id == jobGroup.Id); var locationUri = uriService.GetUri(ApiRoutes.JobGroup.Get, ApiRoutes.JobGroup.getParam, createdJobGroup.Id); @@ -206,6 +214,7 @@ namespace PARR.API.Controllers.V1 orig.GroupName = request.Name.Trim(); //orig.IsUmbrella = request.IsUmbrella; orig.GroupTypeId = request.GroupTypeId; + orig.GroupingUnitFieldId = await GetGroupingUnitFieldIdAsync(request); orig.ShortDescription = request.ShortDescription.Trim(); orig.FullDescription = request.FullDescription.Trim(); orig.Solution = request.Solution.Trim(); @@ -263,6 +272,7 @@ namespace PARR.API.Controllers.V1 .Include(t => t.Jobs) .ThenInclude(t => t.Tnk) .Include(t => t.GroupType) + .Include(t => t.GroupingUnitField) .FirstAsync(t => t.Id == orig.Id); var response = mapper.Map(updatedJobGroup); @@ -361,7 +371,34 @@ namespace PARR.API.Controllers.V1 jobGroupResponse.Schedule = scheduleResponse; jobGroupResponse.JobsCount = await jobService.Get().CountAsync(t => t.GroupId == jobGroupResponse.Id); + } + + /// + /// Смотрим на тип Группы, и возвращаем GroupingUnitFieldId или обнуляем его + /// + /// + /// + private async Task GetGroupingUnitFieldIdAsync(JobGroupRequest request) + { + // Если request.GroupingUnitFieldId == null, то ничего проверять не будем + if (request.GroupingUnitFieldId == null) + return request.GroupingUnitFieldId; + + + var groupingType = await jobGroupTypeService.Get().FirstAsync(t => t.Code == JobGroupTypesEnum.Group); + + if (request.GroupTypeId == groupingType.Id) + { + // Это сгруппированный тип, все ок + return request.GroupingUnitFieldId; + } + else + { + // Это не сгруппированный тип, обнуляем GroupingUnitFieldId + logger.LogWarning($"При сохраненни JobGroup, был передан {nameof(request.GroupingUnitFieldId)}: {request.GroupingUnitFieldId}, но при этом тип группы был не ГРУППА, а {request.GroupTypeId}. Обнулил request.GroupingUnitFieldId"); + return null; + } } } } diff --git a/PARR.API/Controllers/V1/KiiUnitController.cs b/PARR.API/Controllers/V1/KiiUnitController.cs new file mode 100644 index 00000000..dfb5ab99 --- /dev/null +++ b/PARR.API/Controllers/V1/KiiUnitController.cs @@ -0,0 +1,57 @@ +using AutoMapper; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using PARR.API.Contracts.V1; +using PARR.API.Contracts.V1.Responses; +using PARR.API.Contracts.V1.Responses.Base; +using PARR.API.Controllers.V1.Base; +using PARR.Constants; +using PARR.DAL.Services.Interfaces.Unit; + +namespace PARR.API.Controllers.V1 +{ + /// + /// Список КИИ ЭК + /// + [Authorize(Roles = ParrRoles.Administrator.Role)] + public class KiiUnitController : BaseApiController + { + private readonly IMapper mapper; + private readonly IUnitKiiUnitService unitKiiUnitService; + + public KiiUnitController( + IMapper mapper, + IUnitKiiUnitService unitKiiUnitService + ) + { + this.mapper = mapper; + this.unitKiiUnitService = unitKiiUnitService; + } + + + /// + /// Список КИИ ЭК + /// + /// + [HttpGet(ApiRoutes.KiiUnit.GetAll)] + public async Task GetAll() + { + var query = unitKiiUnitService.Get() + .Include(t => t.Unit) + .Select(t => t.Unit) + .OrderBy(t => t.Name); + + var units = await query.ToListAsync(); + + if (!units.Any()) + return NoContent(); + + var response = mapper.Map>(units); + + return Ok(new Response>(response, true)); + } + + + } +} diff --git a/PARR.API/Controllers/V1/RegionalEkPtkGroupController.cs b/PARR.API/Controllers/V1/RegionalEkPtkGroupController.cs new file mode 100644 index 00000000..9aa89d46 --- /dev/null +++ b/PARR.API/Controllers/V1/RegionalEkPtkGroupController.cs @@ -0,0 +1,56 @@ +using AutoMapper; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; +using PARR.API.Contracts.V1; +using PARR.API.Contracts.V1.Responses; +using PARR.API.Contracts.V1.Responses.Base; +using PARR.API.Controllers.V1.Base; +using PARR.Constants; +using PARR.DAL.Services.Interfaces.Unit; + +namespace PARR.API.Controllers.V1 +{ + /// + /// Региональные ЭК ПТК для групповых работ + /// + [Authorize(Roles = ParrRoles.Administrator.Role)] + public class RegionalEkPtkGroupController : BaseApiController + { + private readonly IMapper mapper; + private readonly IUnitRegionalEkPtkGroupService unitRegionalEkPtkGroupService; + + public RegionalEkPtkGroupController( + IMapper mapper, + IUnitRegionalEkPtkGroupService unitRegionalEkPtkGroupService + ) + { + this.mapper = mapper; + this.unitRegionalEkPtkGroupService = unitRegionalEkPtkGroupService; + } + + + /// + /// Региональные ЭК ПТК для групповых работ + /// + /// + [HttpGet(ApiRoutes.RegionalEkPtkGroup.GetAll)] + public async Task GetAll() + { + var query = unitRegionalEkPtkGroupService.Get() + .Include(t => t.FieldValue) + .Select(t => t.FieldValue) + .OrderBy(t => t.Value); + + var objs = await query.ToListAsync(); + + if (!objs.Any()) + return NoContent(); + + var response = mapper.Map>(objs); + + return Ok(new Response>(response, true)); + + } + } +} diff --git a/PARR.API/MappingProfiles/DomainToResponseProfile.cs b/PARR.API/MappingProfiles/DomainToResponseProfile.cs index 143cc196..04bfdfb8 100644 --- a/PARR.API/MappingProfiles/DomainToResponseProfile.cs +++ b/PARR.API/MappingProfiles/DomainToResponseProfile.cs @@ -353,7 +353,8 @@ namespace PARR.API.MappingProfiles #region JobGroup CreateMap() .Include() - .ForMember(d => d.GroupType, o => o.MapFrom(s => s.GroupType)); + .ForMember(d => d.GroupType, o => o.MapFrom(s => s.GroupType)) + .ForMember(d => d.GroupingUnitField, o => o.MapFrom(s => s.GroupingUnitField)); CreateMap() .ForMember(d => d.Name, o => o.MapFrom(s => s.GroupName)); diff --git a/PARR.API/Validators/JobGroupValidator.cs b/PARR.API/Validators/JobGroupValidator.cs index e05ebc90..97cbec6b 100644 --- a/PARR.API/Validators/JobGroupValidator.cs +++ b/PARR.API/Validators/JobGroupValidator.cs @@ -1,12 +1,19 @@ using FluentValidation; +using Microsoft.EntityFrameworkCore; +using Newtonsoft.Json.Linq; using PARR.API.Contracts.V1.Requests; +using PARR.DAL.Contracts; using PARR.DAL.Services.Interfaces.Job; +using PARR.DAL.Services.Interfaces.Unit; namespace PARR.API.Validators { public class JobGroupValidator : AbstractValidator { - public JobGroupValidator(IJobGroupTypeService jobGroupTypeService) + public JobGroupValidator( + IJobGroupTypeService jobGroupTypeService, + IUnitFieldService unitFieldService + ) { RuleFor(t => t.Name) .NotNull().NotEmpty(); @@ -26,6 +33,33 @@ namespace PARR.API.Validators RuleFor(t => t.GroupTypeId) .MustAsync(async (entity, value, c) => await jobGroupTypeService.GetAsync(value) != null) .WithMessage("Указан несуществующий Id типа"); + + //Проверяем существует ли такой GroupingUnitFieldId в unitField + RuleFor(t => t.GroupingUnitFieldId) + .MustAsync(async (entity, value, c) => + { + if (!value.HasValue) + { + return true; + } + + return await unitFieldService.GetAsync(value.Value) != null; + }) + .WithMessage("Указано несуществующий Id поля"); + + + RuleFor(t => t.GroupingUnitFieldId) + .MustAsync(async (entity, value, c) => + { + var groupingJobType = await jobGroupTypeService.Get().FirstAsync(t => t.Code == JobGroupTypesEnum.Group); + + // Если это сгруппированный тип, то у него обязательно должно быть заполнено поле GroupingUnitFieldId + if (entity.GroupTypeId == groupingJobType.Id) + return value.HasValue; + + return true; + }) + .WithMessage("Не указано поле для группировки"); } } }