diff --git a/PARR.API/Contracts/V1/ApiRoutes.cs b/PARR.API/Contracts/V1/ApiRoutes.cs index 3d97c61d..0763c6ce 100644 --- a/PARR.API/Contracts/V1/ApiRoutes.cs +++ b/PARR.API/Contracts/V1/ApiRoutes.cs @@ -489,6 +489,11 @@ public const string Distribute = Base + "/distributor/"; } + public static class DistributionPeriod + { + public const string GetAll = Base + "/distribution-periods/"; + } + #endregion #region SyncTask diff --git a/PARR.API/Contracts/V1/Requests/JobGroupRequest.cs b/PARR.API/Contracts/V1/Requests/JobGroupRequest.cs index 561fac21..6d1142ef 100644 --- a/PARR.API/Contracts/V1/Requests/JobGroupRequest.cs +++ b/PARR.API/Contracts/V1/Requests/JobGroupRequest.cs @@ -27,7 +27,12 @@ public Guid? ScheduleExcludeTypeCalendarId { get; set; } - //public bool IsAutoDistributionEnabled { get; set; } + public bool IsAutoDistributionEnabled { get; set; } + + /// + /// Настройки автораспределения + /// + public DistributionConfigRequest? DistributionConfig { get; set; } //public bool IsAgent { get; set; } @@ -46,4 +51,19 @@ public Guid TypeConfigId { get; set; } } + + public class DistributionConfigRequest + { + public Guid DistributionPeriodId { get; set; } + + /// + /// Исключать выходные и праздники + /// + public bool IsExcludeWeekends { get; set; } + + /// + /// Группировать по рабочей группе + /// + public bool IsGroupingByWorkGroup { get; set; } + } } diff --git a/PARR.API/Controllers/V1/DistributionPeriodController.cs b/PARR.API/Controllers/V1/DistributionPeriodController.cs new file mode 100644 index 00000000..10a8642b --- /dev/null +++ b/PARR.API/Controllers/V1/DistributionPeriodController.cs @@ -0,0 +1,52 @@ +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; + +namespace PARR.API.Controllers.V1 +{ + /// + /// Периоды распределения РР + /// + [Authorize(Roles = ParrRoles.Administrator.Role)] + public class DistributionPeriodController : BaseApiController + { + private readonly IDistributionPeriodService distributionPeriodService; + private readonly IMapper mapper; + + public DistributionPeriodController( + IDistributionPeriodService distributionPeriodService, + IMapper mapper + ) + { + this.distributionPeriodService = distributionPeriodService; + this.mapper = mapper; + } + + + /// + /// Список периодов распределения + /// + /// + [HttpGet(ApiRoutes.DistributionPeriod.GetAll)] + public async Task GetAll() + { + var periods = await distributionPeriodService.Get() + .OrderBy(t => t.Name) + .ToListAsync(); + + if (!periods.Any()) + return NoContent(); + + var response = mapper.Map>(periods); + + return Ok(new Response>(response, true)); + } + } +} diff --git a/PARR.API/Controllers/V1/JobGroupController.cs b/PARR.API/Controllers/V1/JobGroupController.cs index 68e8b4b5..281b913f 100644 --- a/PARR.API/Controllers/V1/JobGroupController.cs +++ b/PARR.API/Controllers/V1/JobGroupController.cs @@ -160,14 +160,28 @@ namespace PARR.API.Controllers.V1 TemplateDuration = request.TemplateDuration.Trim(), ReferenceDate = request.ReferenceDate, ScheduleExcludeTypeId = request.ScheduleExcludeTypeId, - ScheduleExcludeTypeCalendarId = request.ScheduleExcludeTypeCalendarId - //IsAutoDistributionEnabled = request.IsAutoDistributionEnabled, + ScheduleExcludeTypeCalendarId = request.ScheduleExcludeTypeCalendarId, + IsAutoDistributionEnabled = request.IsAutoDistributionEnabled, //IsAgent = request.IsAgent, //AgentName = request.AgentName, //AgentTimeOutSec = request.AgentTimeOutSec, //AgentScript = request.AgentScript }; + #region Если включено автораспределение, добавляем настройки + if (request.IsAutoDistributionEnabled) + { + // на всякий проверим, но вообще это проверяется в валидаторе + if (request.DistributionConfig == null) + { + logger.LogError("Ошибка при создании группы работ '{name}', отсутствуют настройки автораспределения", request.Name); + return BadRequest(new Response(false, new List { new ErrorModel { Message = "Ошибка при создании группы заданий на выполнение работ" } })); + } + + jobGroup.DistributionConfig = CreateDistributionConfig(request.DistributionConfig, jobGroup.Id); + } + #endregion + //Добавляем настройки планировщика request.Schedule.ForEach(item => { @@ -220,6 +234,7 @@ namespace PARR.API.Controllers.V1 .Include(t => t.Jobs) .ThenInclude(t => t.Tnk) .Include(t => t.EsppSchValues) + .Include(t => t.DistributionConfig).ThenInclude(t => t.DistributionPeriod) .FirstOrDefaultAsync(t => t.Id == id); if (orig == null) @@ -239,12 +254,45 @@ namespace PARR.API.Controllers.V1 orig.ReferenceDate = request.ReferenceDate; orig.ScheduleExcludeTypeId = request.ScheduleExcludeTypeId; orig.ScheduleExcludeTypeCalendarId = request.ScheduleExcludeTypeCalendarId; - //orig.IsAutoDistributionEnabled = request.IsAutoDistributionEnabled; + orig.IsAutoDistributionEnabled = request.IsAutoDistributionEnabled; //orig.IsAgent = request.IsAgent; //orig.AgentName = request.AgentName; //orig.AgentTimeOutSec = request.AgentTimeOutSec; //orig.AgentScript = request.AgentScript; - orig.DateModified = DateTimeOffset.UtcNow; + + #region Обновляем настройки автораспределения + + if (request.IsAutoDistributionEnabled) + { + if (request.DistributionConfig == null) + { + logger.LogError("Ошибка при изменении группы работ '{name}', отсутствуют настройки автораспределения", request.Name); + return BadRequest(new Response(false, new List { new ErrorModel { Message = "Ошибка при изменении группы заданий на выполнение работ" } })); + } + + // если настройки были, меняем, если не было, создаем + if (orig.DistributionConfig != null) + { + orig.DistributionConfig.DistributionPeriodId = request.DistributionConfig.DistributionPeriodId; + orig.DistributionConfig.IsExcludeWeekends = request.DistributionConfig.IsExcludeWeekends; + orig.DistributionConfig.IsGroupingByWorkGroup = request.DistributionConfig.IsGroupingByWorkGroup; + } + else + { + //создаем + orig.DistributionConfig = CreateDistributionConfig(request.DistributionConfig, orig.Id); + } + } + else + { + // удаляем настройки распределения если они были + if (orig.DistributionConfig != null) + { + groupService.DeleteDistributionConfig(orig.DistributionConfig); + } + } + + #endregion //обновляем планировщик orig.EsppSchValues.Clear(); @@ -443,5 +491,23 @@ namespace PARR.API.Controllers.V1 return mapper.Map(statusMatching); } + + + /// + /// Создать конфиг распределения + /// + /// + /// + /// + private JobGroupDistributionConfig CreateDistributionConfig(DistributionConfigRequest distributionConfigRequest, Guid jobGroupId) + { + return new JobGroupDistributionConfig + { + GroupId = jobGroupId, + DistributionPeriodId = distributionConfigRequest.DistributionPeriodId, + IsExcludeWeekends = distributionConfigRequest.IsExcludeWeekends, + IsGroupingByWorkGroup = distributionConfigRequest.IsGroupingByWorkGroup + }; + } } } diff --git a/PARR.API/Validators/JobGroupValidator.cs b/PARR.API/Validators/JobGroupValidator.cs index 9d0496ba..1823937c 100644 --- a/PARR.API/Validators/JobGroupValidator.cs +++ b/PARR.API/Validators/JobGroupValidator.cs @@ -2,6 +2,7 @@ using Microsoft.EntityFrameworkCore; using PARR.API.Contracts.V1.Requests; using PARR.DAL.Contracts; +using PARR.DAL.Services.Interfaces; using PARR.DAL.Services.Interfaces.Job; using PARR.DAL.Services.Interfaces.Schedule; using PARR.DAL.Services.Interfaces.Unit; @@ -14,7 +15,8 @@ namespace PARR.API.Validators IJobGroupTypeService jobGroupTypeService, IUnitFieldService unitFieldService, IScheduleExcludeTypeService scheduleExcludeTypeService, - IScheduleExcludeTypeCalendarService scheduleExcludeTypeCalendarService + IScheduleExcludeTypeCalendarService scheduleExcludeTypeCalendarService, + IDistributionPeriodService distributionPeriodService ) { RuleFor(t => t.Name) @@ -91,6 +93,35 @@ namespace PARR.API.Validators }) .WithMessage("Некорректное значение"); + RuleFor(t => t.DistributionConfig) + .Must((entity, value, c) => + { + // если включено автораспределение, должны быть настройки + if (entity.IsAutoDistributionEnabled && value != null) + return true; + + // если выкл автораспределение, то валидно + if (!entity.IsAutoDistributionEnabled) + return true; + + return false; + }).WithMessage("Отсутствуют настройки автораспределения"); + + RuleFor(t => t.DistributionConfig) + .MustAsync(async (entity, value, c) => + { + // если есть настройка периода, проверить что она валидна + var periodId = value?.DistributionPeriodId; + + if (periodId.HasValue) + { + var exist = await distributionPeriodService.GetAsync(periodId.Value); + + return exist != null; + } + + return true; + }).WithMessage("Некорректное значение периода распределения"); } } diff --git a/PARR.DAL.Tests/TransformServices/EsppScheduleTransformServiceTests.cs b/PARR.DAL.Tests/TransformServices/EsppScheduleTransformServiceTests.cs index b270167e..d490cfca 100644 --- a/PARR.DAL.Tests/TransformServices/EsppScheduleTransformServiceTests.cs +++ b/PARR.DAL.Tests/TransformServices/EsppScheduleTransformServiceTests.cs @@ -3,15 +3,15 @@ using Moq; using PARR.DAL.Contracts; using PARR.DAL.DomainModels; using PARR.DAL.Models; +using PARR.DAL.NextRunServices.Subservices; using PARR.DAL.Services.Interfaces; -using PARR.DAL.TransformServices; namespace PARR.DAL.Tests.TransformServices { public class EsppScheduleTransformServiceTests { private Mock esppSchTypeConfigServiceMock; - private Mock nextRunModifierServiceMock; + //private Mock nextRunModifierServiceMock; private ILogger logger; private EsppScheduleTransformService service; @@ -19,7 +19,7 @@ namespace PARR.DAL.Tests.TransformServices public EsppScheduleTransformServiceTests() { esppSchTypeConfigServiceMock = new Mock(); - nextRunModifierServiceMock = new Mock(); + //nextRunModifierServiceMock = new Mock(); var loggerFactory = new LoggerFactory(); logger = loggerFactory.CreateLogger(); @@ -27,8 +27,8 @@ namespace PARR.DAL.Tests.TransformServices service = new EsppScheduleTransformService( logger, - esppSchTypeConfigServiceMock.Object, - nextRunModifierServiceMock.Object + esppSchTypeConfigServiceMock.Object + //nextRunModifierServiceMock.Object ); } diff --git a/PARR.DAL/NextRunServices/NextRunService.cs b/PARR.DAL/NextRunServices/NextRunService.cs index 0d03f249..8a416218 100644 --- a/PARR.DAL/NextRunServices/NextRunService.cs +++ b/PARR.DAL/NextRunServices/NextRunService.cs @@ -8,7 +8,6 @@ using PARR.DAL.NextRunServices.Models; using PARR.DAL.NextRunServices.Subservices; using PARR.DAL.Services.Interfaces; using PARR.DAL.Services.Interfaces.Job; -using PARR.DAL.TransformServices; namespace PARR.DAL.NextRunServices { diff --git a/PARR.DAL/TransformServices/EsppScheduleTransformService.cs b/PARR.DAL/NextRunServices/Subservices/EsppScheduleTransformService.cs similarity index 96% rename from PARR.DAL/TransformServices/EsppScheduleTransformService.cs rename to PARR.DAL/NextRunServices/Subservices/EsppScheduleTransformService.cs index 57c0ffe3..6c204f35 100644 --- a/PARR.DAL/TransformServices/EsppScheduleTransformService.cs +++ b/PARR.DAL/NextRunServices/Subservices/EsppScheduleTransformService.cs @@ -1,16 +1,15 @@ using Microsoft.Extensions.Logging; -using PARR.Constants; using PARR.DAL.Contracts; using PARR.DAL.DomainModels; -using PARR.DAL.Extensions; using PARR.DAL.Services.Interfaces; +using PARR.DAL.TransformServices; -namespace PARR.DAL.TransformServices +namespace PARR.DAL.NextRunServices.Subservices { internal class EsppScheduleTransformService : IEsppScheduleTransformService { private readonly IEsppSchTypeConfigService esppSchTypeConfigService; - private readonly INextRunModifierService nextRunModifierService; + //private readonly INextRunModifierService nextRunModifierService; private readonly ILogger logger; private static readonly Dictionary monthDict = new Dictionary() @@ -52,12 +51,12 @@ namespace PARR.DAL.TransformServices public EsppScheduleTransformService( ILogger logger, - IEsppSchTypeConfigService esppSchTypeConfigService, - INextRunModifierService nextRunModifierService + IEsppSchTypeConfigService esppSchTypeConfigService + //INextRunModifierService nextRunModifierService ) { this.esppSchTypeConfigService = esppSchTypeConfigService; - this.nextRunModifierService = nextRunModifierService; + //this.nextRunModifierService = nextRunModifierService; this.logger = logger; } @@ -493,18 +492,18 @@ namespace PARR.DAL.TransformServices //} - private int ParseInt(string value) - { - try - { - return int.Parse(value); - } - catch (Exception ex) - { - logger.LogError(ex, $"{nameof(this.GetType)}, получение конца периода. Не смог распарсить string в int для значения {value}."); - return 0; - } - } + //private int ParseInt(string value) + //{ + // try + // { + // return int.Parse(value); + // } + // catch (Exception ex) + // { + // logger.LogError(ex, $"{nameof(this.GetType)}, получение конца периода. Не смог распарсить string в int для значения {value}."); + // return 0; + // } + //} //private DistributionPeriodTypeEnum ParseDistributionPeriodType(string value) diff --git a/PARR.DAL/TransformServices/IEsppScheduleTransformService.cs b/PARR.DAL/NextRunServices/Subservices/IEsppScheduleTransformService.cs similarity index 98% rename from PARR.DAL/TransformServices/IEsppScheduleTransformService.cs rename to PARR.DAL/NextRunServices/Subservices/IEsppScheduleTransformService.cs index b0ffecc6..354e11b1 100644 --- a/PARR.DAL/TransformServices/IEsppScheduleTransformService.cs +++ b/PARR.DAL/NextRunServices/Subservices/IEsppScheduleTransformService.cs @@ -1,4 +1,4 @@ -namespace PARR.DAL.TransformServices +namespace PARR.DAL.NextRunServices.Subservices { /// /// Сервис трансформации расписания ЕСПП в дату/расписание diff --git a/PARR.DAL/NextRunServices/Subservices/ITemplateDistributor.cs b/PARR.DAL/NextRunServices/Subservices/ITemplateDistributor.cs index 8ef6474a..c7d43853 100644 --- a/PARR.DAL/NextRunServices/Subservices/ITemplateDistributor.cs +++ b/PARR.DAL/NextRunServices/Subservices/ITemplateDistributor.cs @@ -2,8 +2,7 @@ namespace PARR.DAL.NextRunServices.Subservices { - //todo: public -> internal!!! - public interface ITemplateDistributor + internal interface ITemplateDistributor { /// /// Распределяет все шаблоны на указанный период, учитывая план нагрузки. diff --git a/PARR.DAL/Services/Implementations/Job/JobGroupService.cs b/PARR.DAL/Services/Implementations/Job/JobGroupService.cs index a57f611c..c6b4ef97 100644 --- a/PARR.DAL/Services/Implementations/Job/JobGroupService.cs +++ b/PARR.DAL/Services/Implementations/Job/JobGroupService.cs @@ -18,5 +18,11 @@ namespace PARR.DAL.Services.Implementations.Job protected override DbSet EntitySet => dataContext.JobGroups; protected override DataContext EntitiContext => dataContext; + + + public void DeleteDistributionConfig(JobGroupDistributionConfig distributionConfig) + { + EntitiContext.JobGroupDistributionConfigs.Remove(distributionConfig); + } } } diff --git a/PARR.DAL/Services/Interfaces/Job/IJobGroupService.cs b/PARR.DAL/Services/Interfaces/Job/IJobGroupService.cs index 219febf4..57c50105 100644 --- a/PARR.DAL/Services/Interfaces/Job/IJobGroupService.cs +++ b/PARR.DAL/Services/Interfaces/Job/IJobGroupService.cs @@ -1,8 +1,14 @@ -using PARR.DAL.Services.Interfaces.Base; +using PARR.DAL.Models.Job; +using PARR.DAL.Services.Interfaces.Base; namespace PARR.DAL.Services.Interfaces.Job { public interface IJobGroupService : IBaseService { + /// + /// Удалить настройки автораспределения + /// + /// + void DeleteDistributionConfig(JobGroupDistributionConfig distributionConfig); } } diff --git a/PARR.Test/NextRun/NextRunTest.cs b/PARR.Test/NextRun/NextRunTest.cs index 48dbe1a9..5ad3ec64 100644 --- a/PARR.Test/NextRun/NextRunTest.cs +++ b/PARR.Test/NextRun/NextRunTest.cs @@ -6,12 +6,12 @@ namespace PARR.Test.NextRun { internal class NextRunTest { - private readonly ITemplateDistributor templateDistributor; + //private readonly ITemplateDistributor templateDistributor; private readonly INextRunService nextRunService; - public NextRunTest(ITemplateDistributor templateDistributor, INextRunService nextRunService) + public NextRunTest(/*ITemplateDistributor templateDistributor,*/ INextRunService nextRunService) { - this.templateDistributor = templateDistributor; + //this.templateDistributor = templateDistributor; this.nextRunService = nextRunService; } @@ -51,7 +51,7 @@ namespace PARR.Test.NextRun NextRun: null ); - var template = await templateDistributor.GetValidNextRunForTemplateAsync(GetDateStart(), periodDays, referenceDate, targetTemplate, new List(), excludeWeekends, isNew); + //var template = await templateDistributor.GetValidNextRunForTemplateAsync(GetDateStart(), periodDays, referenceDate, targetTemplate, new List(), excludeWeekends, isNew); } @@ -63,7 +63,7 @@ namespace PARR.Test.NextRun // исключать выходные и праздники var excludeWeekends = true; - var templates = await templateDistributor.DistributeTemplatesAsync(GetDateStart(), periodDays, referenceDate, GetTemplates(), excludeWeekends); + // var templates = await templateDistributor.DistributeTemplatesAsync(GetDateStart(), periodDays, referenceDate, GetTemplates(), excludeWeekends); //await GetValidNextRunForTemplateAsync(templates); }