Skip to content

Commit

Permalink
calculate age between task date and birthdate for age validation
Browse files Browse the repository at this point in the history
  • Loading branch information
haoleanh committed Apr 25, 2024
1 parent e5f4130 commit 1f124c2
Show file tree
Hide file tree
Showing 10 changed files with 82 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down
10 changes: 10 additions & 0 deletions Valghalla.Application/TaskValidation/EvaluatedTask.cs
Original file line number Diff line number Diff line change
@@ -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; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
public interface ITaskValidationRepository
{
Task<IEnumerable<TaskValidationRule>> GetValidationRules(Guid electionId, CancellationToken cancellationToken);
Task<EvaluatedTaskType> GetEvaluatedTaskType(Guid taskTypeId, CancellationToken cancellationToken);
Task<EvaluatedTaskType> GetEvaluatedTaskTypeByTaskId(Guid taskId, CancellationToken cancellationToken);
Task<EvaluatedTask> GetEvaluatedTask(Guid taskAssignmentId, CancellationToken cancellationToken);
Task<EvaluatedParticipant> GetEvaluatedParticipant(Guid participantId, CancellationToken cancellationToken);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
{
public interface ITaskValidationService
{
TaskValidationResult Execute(EvaluatedTaskType taskType, EvaluatedParticipant participant, IEnumerable<TaskValidationRule> rules);
Task<TaskValidationResult> ExecuteAsync(Guid taskTypeId, Guid electionId, Guid participantId, CancellationToken cancellationToken);
Task<TaskValidationResult> ExecuteAsync(Guid taskTypeId, Guid electionId, string cpr, CancellationToken cancellationToken);
TaskValidationResult Execute(EvaluatedTask taskAssignment, EvaluatedParticipant participant, IEnumerable<TaskValidationRule> rules);
Task<TaskValidationResult> ExecuteAsync(Guid taskAssignmentId, Guid electionId, Guid participantId, CancellationToken cancellationToken);
Task<TaskValidationResult> ExecuteAsync(Guid taskAssignmentId, Guid electionId, string cpr, CancellationToken cancellationToken);
}
}
46 changes: 37 additions & 9 deletions Valghalla.Application/TaskValidation/TaskValidationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public TaskValidationService(ITaskValidationRepository taskValidationRepository,
this.cprService = cprService;
}

public TaskValidationResult Execute(EvaluatedTaskType taskType, EvaluatedParticipant participant, IEnumerable<TaskValidationRule> rules)
public TaskValidationResult Execute(EvaluatedTask taskAssignment, EvaluatedParticipant participant, IEnumerable<TaskValidationRule> rules)
{
var failedRules = new List<TaskValidationRule>();

Expand All @@ -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)
Expand All @@ -53,25 +58,25 @@ public TaskValidationResult Execute(EvaluatedTaskType taskType, EvaluatedPartici
return new(failedRules);
}

public async Task<TaskValidationResult> ExecuteAsync(Guid taskTypeId, Guid electionId, Guid participantId, CancellationToken cancellationToken)
public async Task<TaskValidationResult> 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<TaskValidationResult> ExecuteAsync(Guid taskId, Guid electionId, string cpr, CancellationToken cancellationToken)
public async Task<TaskValidationResult> 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,
Expand All @@ -82,5 +87,28 @@ public async Task<TaskValidationResult> 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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public async Task<Response> 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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,26 +44,23 @@ public async Task<IEnumerable<TaskValidationRule>> GetValidationRules(Guid elect
return entities.Select(i => new TaskValidationRule(i.ValidationRuleId)).ToArray();
}

public async Task<EvaluatedTaskType> GetEvaluatedTaskType(Guid taskTypeId, CancellationToken cancellationToken)
{
var entity = await taskTypes
.Where(i => i.Id == taskTypeId)
.SingleAsync(cancellationToken);

return mapper.Map<EvaluatedTaskType>(entity);
}

public async Task<EvaluatedTaskType> GetEvaluatedTaskTypeByTaskId(Guid taskId, CancellationToken cancellationToken)
public async Task<EvaluatedTask> 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<EvaluatedTaskType>(entity);
return new EvaluatedTask()
{
TaskAssignmentId = taskAssignmentId,
TaskTypeId = entity.Id,
TaskDate = task.TaskDate,
ValidationNotRequired = entity.ValidationNotRequired
};
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<TaskValidationRule> { })));

var result = validator.TestValidate(command);
Expand All @@ -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<TaskValidationRule> { })));

var result = validator.TestValidate(command);
Expand All @@ -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<TaskValidationRule> { })));

var result = validator.TestValidate(command);
Expand All @@ -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<TaskValidationRule> { })));

var result = validator.TestValidate(command);
Expand Down Expand Up @@ -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<TaskValidationRule> { new TaskValidationRule(TaskValidationRule.Alive.Id) })));

var result = validator.TestValidate(command);
Expand Down Expand Up @@ -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<TaskValidationRule> { new TaskValidationRule(TaskValidationRule.Age18.Id) })));

var result = validator.TestValidate(command);
Expand Down Expand Up @@ -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<TaskValidationRule> { new TaskValidationRule(TaskValidationRule.ResidencyMunicipality.Id) })));

var result = validator.TestValidate(command);
Expand Down Expand Up @@ -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<TaskValidationRule> { new TaskValidationRule(TaskValidationRule.Disenfranchised.Id) })));

var result = validator.TestValidate(command);
Expand Down Expand Up @@ -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<TaskValidationRule> { new TaskValidationRule(TaskValidationRule.Citizenship.Id) })));

var result = validator.TestValidate(command);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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())
{
Expand Down
12 changes: 10 additions & 2 deletions Valghalla.Worker/Services/ParticipantSyncService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public ParticipantSyncService(
ITaskAssignmentCommandRepository taskAssignmentCommandRepository,
ITaskValidationService taskValidationService,
ICommunicationService communicationService,
ICPRService cprService)
ICPRService cprService)
{
this.logger = logger;
this.electionQueryRepository = electionQueryRepository;
Expand Down Expand Up @@ -136,7 +136,15 @@ private Dictionary<Guid, IEnumerable<Guid>> 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)
{
Expand Down

0 comments on commit 1f124c2

Please sign in to comment.