diff --git a/Valghalla.Application/TaskValidation/EvaluatedParticipant.cs b/Valghalla.Application/TaskValidation/EvaluatedParticipant.cs index 22ed56f..303f05f 100644 --- a/Valghalla.Application/TaskValidation/EvaluatedParticipant.cs +++ b/Valghalla.Application/TaskValidation/EvaluatedParticipant.cs @@ -3,7 +3,7 @@ public sealed record EvaluatedParticipant { public Guid Id { get; init; } - public int Age { get; init; } + public DateTime Birthdate { get; init; } public string? MunicipalityCode { get; set; } public string? CountryCode { get; set; } public bool Deceased { get; init; } diff --git a/Valghalla.Application/TaskValidation/EvaluatedTask.cs b/Valghalla.Application/TaskValidation/EvaluatedTask.cs new file mode 100644 index 0000000..9c7073a --- /dev/null +++ b/Valghalla.Application/TaskValidation/EvaluatedTask.cs @@ -0,0 +1,10 @@ +namespace Valghalla.Application.TaskValidation +{ + public sealed record EvaluatedTask + { + public Guid TaskAssignmentId { get; init; } + public Guid TaskTypeId { get; init; } + public DateTime TaskDate { get; init; } + public bool ValidationNotRequired { get; init; } + } +} diff --git a/Valghalla.Application/TaskValidation/ITaskValidationRepository.cs b/Valghalla.Application/TaskValidation/ITaskValidationRepository.cs index df89ba0..36b65a4 100644 --- a/Valghalla.Application/TaskValidation/ITaskValidationRepository.cs +++ b/Valghalla.Application/TaskValidation/ITaskValidationRepository.cs @@ -3,8 +3,7 @@ public interface ITaskValidationRepository { Task> GetValidationRules(Guid electionId, CancellationToken cancellationToken); - Task GetEvaluatedTaskType(Guid taskTypeId, CancellationToken cancellationToken); - Task GetEvaluatedTaskTypeByTaskId(Guid taskId, CancellationToken cancellationToken); + Task GetEvaluatedTask(Guid taskAssignmentId, CancellationToken cancellationToken); Task GetEvaluatedParticipant(Guid participantId, CancellationToken cancellationToken); } } diff --git a/Valghalla.Application/TaskValidation/ITaskValidationService.cs b/Valghalla.Application/TaskValidation/ITaskValidationService.cs index 527cdc0..2e5cd5d 100644 --- a/Valghalla.Application/TaskValidation/ITaskValidationService.cs +++ b/Valghalla.Application/TaskValidation/ITaskValidationService.cs @@ -2,8 +2,8 @@ { public interface ITaskValidationService { - TaskValidationResult Execute(EvaluatedTaskType taskType, EvaluatedParticipant participant, IEnumerable rules); - Task ExecuteAsync(Guid taskTypeId, Guid electionId, Guid participantId, CancellationToken cancellationToken); - Task ExecuteAsync(Guid taskTypeId, Guid electionId, string cpr, CancellationToken cancellationToken); + TaskValidationResult Execute(EvaluatedTask taskAssignment, EvaluatedParticipant participant, IEnumerable rules); + Task ExecuteAsync(Guid taskAssignmentId, Guid electionId, Guid participantId, CancellationToken cancellationToken); + Task ExecuteAsync(Guid taskAssignmentId, Guid electionId, string cpr, CancellationToken cancellationToken); } } diff --git a/Valghalla.Application/TaskValidation/TaskValidationService.cs b/Valghalla.Application/TaskValidation/TaskValidationService.cs index 17f14e5..1769700 100644 --- a/Valghalla.Application/TaskValidation/TaskValidationService.cs +++ b/Valghalla.Application/TaskValidation/TaskValidationService.cs @@ -16,7 +16,7 @@ public TaskValidationService(ITaskValidationRepository taskValidationRepository, this.cprService = cprService; } - public TaskValidationResult Execute(EvaluatedTaskType taskType, EvaluatedParticipant participant, IEnumerable rules) + public TaskValidationResult Execute(EvaluatedTask taskAssignment, EvaluatedParticipant participant, IEnumerable rules) { var failedRules = new List(); @@ -25,14 +25,19 @@ public TaskValidationResult Execute(EvaluatedTaskType taskType, EvaluatedPartici failedRules.Add(TaskValidationRule.Alive); } - if (taskType.ValidationNotRequired) + if (taskAssignment.ValidationNotRequired) { return new(failedRules); } - if (rules.Any(i => i.Id == TaskValidationRule.Age18.Id) && participant.Age < 18) + if (rules.Any(i => i.Id == TaskValidationRule.Age18.Id)) { - failedRules.Add(TaskValidationRule.Age18); + var age = CalculateAge(participant, taskAssignment); + + if (age < 18) + { + failedRules.Add(TaskValidationRule.Age18); + } } if (rules.Any(i => i.Id == TaskValidationRule.Disenfranchised.Id) && participant.Disenfranchised) @@ -53,25 +58,25 @@ public TaskValidationResult Execute(EvaluatedTaskType taskType, EvaluatedPartici return new(failedRules); } - public async Task ExecuteAsync(Guid taskTypeId, Guid electionId, Guid participantId, CancellationToken cancellationToken) + public async Task ExecuteAsync(Guid taskAssignmentId, Guid electionId, Guid participantId, CancellationToken cancellationToken) { - var taskType = await taskValidationRepository.GetEvaluatedTaskType(taskTypeId, cancellationToken); + var taskType = await taskValidationRepository.GetEvaluatedTask(taskAssignmentId, cancellationToken); var participant = await taskValidationRepository.GetEvaluatedParticipant(participantId, cancellationToken); var rules = await taskValidationRepository.GetValidationRules(electionId, cancellationToken); return Execute(taskType, participant, rules); } - public async Task ExecuteAsync(Guid taskId, Guid electionId, string cpr, CancellationToken cancellationToken) + public async Task ExecuteAsync(Guid taskAssignmentId, Guid electionId, string cpr, CancellationToken cancellationToken) { - var taskType = await taskValidationRepository.GetEvaluatedTaskTypeByTaskId(taskId, cancellationToken); + var taskType = await taskValidationRepository.GetEvaluatedTask(taskAssignmentId, cancellationToken); var cprPersonInfo = await cprService.ExecuteAsync(cpr); var record = cprPersonInfo.ToRecord(); var evaluatedParticipant = new EvaluatedParticipant() { Id = Guid.Empty, - Age = record.Age, + Birthdate = record.Birthdate, CountryCode = record.CountryCode, Deceased = record.Deceased, Disenfranchised = record.Disenfranchised, @@ -82,5 +87,28 @@ public async Task ExecuteAsync(Guid taskId, Guid electionI return Execute(taskType, evaluatedParticipant, rules); } + + private static int CalculateAge(EvaluatedParticipant participant, EvaluatedTask taskAssignment) + { + var taskDateLocalTime = taskAssignment.TaskDate.ToLocalTime(); + var birthDateLocalTime = participant.Birthdate.ToLocalTime(); + var taskDate = new DateTime(taskDateLocalTime.Year, taskDateLocalTime.Month, taskDateLocalTime.Day); + var birthdate = new DateTime(birthDateLocalTime.Year, birthDateLocalTime.Month, birthDateLocalTime.Day); + + var months = taskDate.Month - birthdate.Month; + var years = taskDate.Year - birthdate.Year; + + if (taskDate.Day < birthdate.Day) + { + months--; + } + + if (months < 0) + { + years--; + } + + return years; + } } } diff --git a/Valghalla.External.Application/Modules/Tasks/Commands/AcceptTaskCommand.cs b/Valghalla.External.Application/Modules/Tasks/Commands/AcceptTaskCommand.cs index 9c93fea..29af0aa 100644 --- a/Valghalla.External.Application/Modules/Tasks/Commands/AcceptTaskCommand.cs +++ b/Valghalla.External.Application/Modules/Tasks/Commands/AcceptTaskCommand.cs @@ -58,7 +58,7 @@ public async Task Handle(AcceptTaskCommand command, CancellationToken return Response.Ok(TaskConfirmationResult.ConflictResult()); } - var validationResult = await taskValidationService.ExecuteAsync(taskAssignment.TaskTypeId, taskAssignment.ElectionId, participantId, cancellationToken); + var validationResult = await taskValidationService.ExecuteAsync(taskAssignment.Id, taskAssignment.ElectionId, participantId, cancellationToken); if (!validationResult.Succeed) { diff --git a/Valghalla.Infrastructure/TaskValidation/TaskValidationRepository.cs b/Valghalla.Infrastructure/TaskValidation/TaskValidationRepository.cs index 183122e..09308d6 100644 --- a/Valghalla.Infrastructure/TaskValidation/TaskValidationRepository.cs +++ b/Valghalla.Infrastructure/TaskValidation/TaskValidationRepository.cs @@ -44,26 +44,23 @@ public async Task> GetValidationRules(Guid elect return entities.Select(i => new TaskValidationRule(i.ValidationRuleId)).ToArray(); } - public async Task GetEvaluatedTaskType(Guid taskTypeId, CancellationToken cancellationToken) - { - var entity = await taskTypes - .Where(i => i.Id == taskTypeId) - .SingleAsync(cancellationToken); - - return mapper.Map(entity); - } - - public async Task GetEvaluatedTaskTypeByTaskId(Guid taskId, CancellationToken cancellationToken) + public async Task GetEvaluatedTask(Guid taskAssignmentId, CancellationToken cancellationToken) { var task = await tasks - .Where(i => i.Id == taskId) + .Where(i => i.Id == taskAssignmentId) .SingleAsync(cancellationToken); var entity = await taskTypes .Where(i => i.Id == task.TaskTypeId) .SingleAsync(cancellationToken); - return mapper.Map(entity); + return new EvaluatedTask() + { + TaskAssignmentId = taskAssignmentId, + TaskTypeId = entity.Id, + TaskDate = task.TaskDate, + ValidationNotRequired = entity.ValidationNotRequired + }; } } } diff --git a/Valghalla.Internal.Application.Tests/Tasks/Commands/AssignParticipantToTaskCommandHandlerTests.cs b/Valghalla.Internal.Application.Tests/Tasks/Commands/AssignParticipantToTaskCommandHandlerTests.cs index e8d6dd8..ed6f225 100644 --- a/Valghalla.Internal.Application.Tests/Tasks/Commands/AssignParticipantToTaskCommandHandlerTests.cs +++ b/Valghalla.Internal.Application.Tests/Tasks/Commands/AssignParticipantToTaskCommandHandlerTests.cs @@ -66,7 +66,7 @@ public void AssignParticipantToTaskCommandHandlerTests_Should_ReturnValidationEr var validator = new AssignParticipantToTaskCommandValidator(_mockTaskValidationService, _mockElectionWorkLocationTasksQueryRepository); _mockTaskValidationService - .ExecuteAsync(request.TaskTypeId, request.ElectionId, request.ParticipantId, default) + .ExecuteAsync(request.TaskAssignmentId, request.ElectionId, request.ParticipantId, default) .Returns(Task.FromResult(new TaskValidationResult(new List { }))); var result = validator.TestValidate(command); @@ -92,7 +92,7 @@ public void AssignParticipantToTaskCommandHandlerTests_Should_ReturnValidationEr var validator = new AssignParticipantToTaskCommandValidator(_mockTaskValidationService, _mockElectionWorkLocationTasksQueryRepository); _mockTaskValidationService - .ExecuteAsync(request.TaskTypeId, request.ElectionId, request.ParticipantId, default) + .ExecuteAsync(request.TaskAssignmentId, request.ElectionId, request.ParticipantId, default) .Returns(Task.FromResult(new TaskValidationResult(new List { }))); var result = validator.TestValidate(command); @@ -118,7 +118,7 @@ public void AssignParticipantToTaskCommandHandlerTests_Should_ReturnValidationEr var validator = new AssignParticipantToTaskCommandValidator(_mockTaskValidationService, _mockElectionWorkLocationTasksQueryRepository); _mockTaskValidationService - .ExecuteAsync(request.TaskTypeId, request.ElectionId, request.ParticipantId, default) + .ExecuteAsync(request.TaskAssignmentId, request.ElectionId, request.ParticipantId, default) .Returns(Task.FromResult(new TaskValidationResult(new List { }))); var result = validator.TestValidate(command); @@ -144,7 +144,7 @@ public void AssignParticipantToTaskCommandHandlerTests_Should_ReturnValidationEr var validator = new AssignParticipantToTaskCommandValidator(_mockTaskValidationService, _mockElectionWorkLocationTasksQueryRepository); _mockTaskValidationService - .ExecuteAsync(request.TaskTypeId, request.ElectionId, request.ParticipantId, default) + .ExecuteAsync(request.TaskAssignmentId, request.ElectionId, request.ParticipantId, default) .Returns(Task.FromResult(new TaskValidationResult(new List { }))); var result = validator.TestValidate(command); @@ -172,7 +172,7 @@ public void AssignParticipantToTaskCommandHandlerTests_Should_ReturnValidationEr var validator = new AssignParticipantToTaskCommandValidator(_mockTaskValidationService, _mockElectionWorkLocationTasksQueryRepository); _mockTaskValidationService - .ExecuteAsync(request.TaskTypeId, request.ElectionId, request.ParticipantId, default) + .ExecuteAsync(request.TaskAssignmentId, request.ElectionId, request.ParticipantId, default) .Returns(Task.FromResult(new TaskValidationResult(new List { new TaskValidationRule(TaskValidationRule.Alive.Id) }))); var result = validator.TestValidate(command); @@ -202,7 +202,7 @@ public void AssignParticipantToTaskCommandHandlerTests_Should_ReturnValidationEr var validator = new AssignParticipantToTaskCommandValidator(_mockTaskValidationService, _mockElectionWorkLocationTasksQueryRepository); _mockTaskValidationService - .ExecuteAsync(request.TaskTypeId, request.ElectionId, request.ParticipantId, default) + .ExecuteAsync(request.TaskAssignmentId, request.ElectionId, request.ParticipantId, default) .Returns(Task.FromResult(new TaskValidationResult(new List { new TaskValidationRule(TaskValidationRule.Age18.Id) }))); var result = validator.TestValidate(command); @@ -232,7 +232,7 @@ public void AssignParticipantToTaskCommandHandlerTests_Should_ReturnValidationEr var validator = new AssignParticipantToTaskCommandValidator(_mockTaskValidationService, _mockElectionWorkLocationTasksQueryRepository); _mockTaskValidationService - .ExecuteAsync(request.TaskTypeId, request.ElectionId, request.ParticipantId, default) + .ExecuteAsync(request.TaskAssignmentId, request.ElectionId, request.ParticipantId, default) .Returns(Task.FromResult(new TaskValidationResult(new List { new TaskValidationRule(TaskValidationRule.ResidencyMunicipality.Id) }))); var result = validator.TestValidate(command); @@ -262,7 +262,7 @@ public void AssignParticipantToTaskCommandHandlerTests_Should_ReturnValidationEr var validator = new AssignParticipantToTaskCommandValidator(_mockTaskValidationService, _mockElectionWorkLocationTasksQueryRepository); _mockTaskValidationService - .ExecuteAsync(request.TaskTypeId, request.ElectionId, request.ParticipantId, default) + .ExecuteAsync(request.TaskAssignmentId, request.ElectionId, request.ParticipantId, default) .Returns(Task.FromResult(new TaskValidationResult(new List { new TaskValidationRule(TaskValidationRule.Disenfranchised.Id) }))); var result = validator.TestValidate(command); @@ -292,7 +292,7 @@ public void AssignParticipantToTaskCommandHandlerTests_Should_ReturnValidationEr var validator = new AssignParticipantToTaskCommandValidator(_mockTaskValidationService, _mockElectionWorkLocationTasksQueryRepository); _mockTaskValidationService - .ExecuteAsync(request.TaskTypeId, request.ElectionId, request.ParticipantId, default) + .ExecuteAsync(request.TaskAssignmentId, request.ElectionId, request.ParticipantId, default) .Returns(Task.FromResult(new TaskValidationResult(new List { new TaskValidationRule(TaskValidationRule.Citizenship.Id) }))); var result = validator.TestValidate(command); diff --git a/Valghalla.Internal.Application/Modules/Tasks/Commands/AssignParticipantToTaskCommand.cs b/Valghalla.Internal.Application/Modules/Tasks/Commands/AssignParticipantToTaskCommand.cs index df2da65..3046b65 100644 --- a/Valghalla.Internal.Application/Modules/Tasks/Commands/AssignParticipantToTaskCommand.cs +++ b/Valghalla.Internal.Application/Modules/Tasks/Commands/AssignParticipantToTaskCommand.cs @@ -34,7 +34,7 @@ public AssignParticipantToTaskCommandValidator(ITaskValidationService taskValida .Must((command) => !electionWorkLocationTasksQueryRepository.CheckIfTaskHasConflictsAsync(command.ElectionId, command.TaskAssignmentId, command.ParticipantId, default).Result) .WithMessage("tasks.error.task_conflict"); - RuleFor(x => taskValidationService.ExecuteAsync(x.TaskTypeId, x.ElectionId, x.ParticipantId, default).Result).Custom((result, context) => + RuleFor(x => taskValidationService.ExecuteAsync(x.TaskAssignmentId, x.ElectionId, x.ParticipantId, default).Result).Custom((result, context) => { if (!result.IsAlive()) { diff --git a/Valghalla.Worker/Services/ParticipantSyncService.cs b/Valghalla.Worker/Services/ParticipantSyncService.cs index 929b63a..68fece9 100644 --- a/Valghalla.Worker/Services/ParticipantSyncService.cs +++ b/Valghalla.Worker/Services/ParticipantSyncService.cs @@ -38,7 +38,7 @@ public ParticipantSyncService( ITaskAssignmentCommandRepository taskAssignmentCommandRepository, ITaskValidationService taskValidationService, ICommunicationService communicationService, - ICPRService cprService) + ICPRService cprService) { this.logger = logger; this.electionQueryRepository = electionQueryRepository; @@ -136,7 +136,15 @@ private Dictionary> Evaluate( var taskType = taskTypes.Single(i => i.Id == taskAssignment.TaskTypeId); ruleDict.TryGetValue(taskAssignment.ElectionId, out var rules); - var taskValidationResult = taskValidationService.Execute(taskType, participant, rules!); + var evaluatedTask = new EvaluatedTask() + { + TaskAssignmentId = taskAssignment.Id, + TaskTypeId = taskType.Id, + TaskDate = taskAssignment.TaskDate, + ValidationNotRequired = taskType.ValidationNotRequired + }; + + var taskValidationResult = taskValidationService.Execute(evaluatedTask, participant, rules!); if (!taskValidationResult.Succeed) {