Skip to content

Commit

Permalink
SS-768: Adding functionality to handle rotating training types, SS-76…
Browse files Browse the repository at this point in the history
…9: Updating the email notification behaviour and content
  • Loading branch information
marzmehr committed Dec 18, 2023
1 parent 4531ab4 commit 0d62bba
Show file tree
Hide file tree
Showing 17 changed files with 2,678 additions and 36 deletions.
24 changes: 20 additions & 4 deletions api/cronjobs/TrainingNotification.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,14 @@ public async void ProcessTrainings()
Logger.LogInformation(training.Sheriff.Email);

if(training.TrainingCertificationExpiry < noticeDate){
var emailBody = GetEmailBody(training);

bool rotatingTraining = TrainingService.IsRotatingTraining(training.TrainingType);
var emailBody = rotatingTraining? GetEmailRotatingBody(training) : GetEmailEndOfYearBody(training);
var emailTitle = rotatingTraining? "Training Expiry Notice" : "Training Requalification Notice";

var emailSent = await ChesEmailService.SendEmail(
emailBody,
"Training Expiry Notice",
emailTitle,
training.Sheriff.Email
);
if(emailSent)
Expand All @@ -52,17 +56,29 @@ public async void ProcessTrainings()
Logger.LogInformation("CronJob Done");
}

public string GetEmailBody(SheriffTraining training)
public string GetEmailRotatingBody(SheriffTraining training)
{
var expiryDate = training.TrainingCertificationExpiry.Value.ToString("MMMM dd, yyyy");
var emailBody =
$"Dear {training.Sheriff.FirstName} {training.Sheriff.LastName}, \n"+
$"Dear {training.Sheriff.FirstName} {training.Sheriff.LastName}, \n\n"+
$"Your \'{training.TrainingType.Code}\' certification will expire on \'{expiryDate}\'. \n"+
"Please ensure your certification is renewed before this date.";

return emailBody;
}

public string GetEmailEndOfYearBody(SheriffTraining training)
{
var expiryYear = training.TrainingCertificationExpiry.Value.AddDays(-1).AddYears(1).ToString("yyyy");
var emailBody =
$"Dear {training.Sheriff.FirstName} {training.Sheriff.LastName}, \n\n"+
$"Your \'{training.TrainingType.Code}\' certification will require renewal for the calendar year \'{expiryYear}\'. \n"+
$"Please ensure you renew your certification between January 1st and December 31, {expiryYear}. \n\n" +
"It is recommended to schedule training early in the year to ensure end of year compliance.";

return emailBody;
}

public Task Execute(IJobExecutionContext context)
{
Logger.LogInformation("___Running CronJob___");
Expand Down
1 change: 1 addition & 0 deletions api/models/dto/AddLookupCodeDto.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public class AddLookupCodeDto
public DateTimeOffset? ExpiryDate { get; set; }
public int? LocationId { get; set; }
public bool? Mandatory { get; set; }
public bool? Rotating { get; set; }
public int? ValidityPeriod { get; set; }
public string? Category { get; set; }
public int? AdvanceNotice { get; set; }
Expand Down
1 change: 1 addition & 0 deletions api/models/dto/generated/LookupCodeDto.g.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public partial class LookupCodeDto
public int ValidityPeriod { get; set; }
public string Category { get; set; }
public int AdvanceNotice { get; set; }
public bool Rotating { get; set; }
public uint ConcurrencyToken { get; set; }
public LookupSortOrderDto SortOrderForLocation { get; set; }
}
Expand Down
37 changes: 25 additions & 12 deletions api/services/usermanagement/TrainingService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class TrainingService
private SheriffDbContext Db { get; }
private ManageTypesService ManageTypesService { get; }
private ILogger<TrainingService> Logger { get; }
public static readonly IList<int> YearsInDays = new List<int>{365, 730, 1095, 1461, 1826, 2191, 2556, 2922, 3287, 3652};

public TrainingService(ManageTypesService manageTypesService, SheriffDbContext db, ILogger<TrainingService> logger)
{
Expand Down Expand Up @@ -112,7 +113,7 @@ public async Task<List<TrainingReportDto>> GetSheriffsTrainingReports(TrainingRe
{
var takenTraining = sheriff.Training.Find(t => t.TrainingTypeId == training.Id);
var timezone = takenTraining.Timezone == null? "America/Vancouver" : takenTraining.Timezone;
var trainingStatus = GetTrainingStatus(takenTraining.TrainingCertificationExpiry, timezone, training.AdvanceNotice);
var trainingStatus = GetTrainingStatus(takenTraining.TrainingCertificationExpiry, timezone, training.AdvanceNotice, training, takenTraining.FirstNotice);

sheriffTrainings.Add(new TrainingReportDto()
{
Expand Down Expand Up @@ -151,26 +152,34 @@ public async Task TrainingExpiryAdjustment()
.Where(t => t.ExpiryDate == null)
.Include(t => t.TrainingType);
var allTrainings = await trainingsQuery.ToListAsync();

int processCounter = 0;
int allTrainingsCounts = allTrainings.Count();

foreach (var training in allTrainings)
{
if(training.TrainingType.ValidityPeriod > 0){
var timezone = training.Timezone == null? "America/Vancouver" : training.Timezone;
if(training.TrainingType.ValidityPeriod == 365){
training.TrainingCertificationExpiry = training.EndDate.EndOfYearWithTimezone(0,timezone);//moment(this.selectedEndDate).endOf('year').format("YYYY-MM-DD");
}else if(training.TrainingType.ValidityPeriod == 730){
training.TrainingCertificationExpiry = training.EndDate.EndOfYearWithTimezone(1,timezone);//moment(this.selectedEndDate).endOf('year').add(1,'year').format("YYYY-MM-DD");
}else if(training.TrainingType.ValidityPeriod == 1095){
training.TrainingCertificationExpiry = training.EndDate.EndOfYearWithTimezone(2,timezone);//moment(this.selectedEndDate).endOf('year').add(2,'year').format("YYYY-MM-DD");
var timezone = training.Timezone == null? "America/Vancouver" : training.Timezone;
if(!IsRotatingTraining(training.TrainingType)){
int years = (training.TrainingType.ValidityPeriod / 365) - 1;
training.TrainingCertificationExpiry = training.EndDate.EndOfYearWithTimezone(years, timezone);
}else{
training.TrainingCertificationExpiry = training.EndDate.AddDays(training.TrainingType.ValidityPeriod).ConvertToTimezone(timezone);//moment(this.selectedEndDate).add(this.selectedTrainingType.validityPeriod, 'days').format("YYYY-MM-DD");
}
var noticeDate = DateTimeOffset.UtcNow.AddDays(training.TrainingType.AdvanceNotice);
if(training.TrainingCertificationExpiry > noticeDate){
training.FirstNotice = false;
}
}
else{
training.TrainingCertificationExpiry = null;
training.FirstNotice = false;
}
Db.Entry(training).Property(x => x.TrainingCertificationExpiry).IsModified = true;
Db.Entry(training).Property(x => x.FirstNotice).IsModified = true;
Db.SaveChanges();

processCounter++;
Logger.LogInformation($"_______Training Expiry Adjustment__{processCounter}_of_{allTrainingsCounts}_______");
}

}
Expand All @@ -180,13 +189,13 @@ public async Task TrainingExpiryAdjustment()

#region Help Methods

private TrainingStatus GetTrainingStatus(DateTimeOffset? requalificationDate, string timezone, int advanceNotice)
private TrainingStatus GetTrainingStatus(DateTimeOffset? requalificationDate, string timezone, int advanceNotice, LookupCode trainingType, bool firstNotice)
{
TrainingStatus trainingStatus = new TrainingStatus();

var todayDate = DateTimeOffset.UtcNow.ConvertToTimezone(timezone);
var advanceNoticeDate = DateTimeOffset.UtcNow.AddDays(advanceNotice).ConvertToTimezone(timezone);
var expiryDate = requalificationDate?.AddYears(1);
var expiryDate = IsRotatingTraining(trainingType)? requalificationDate : requalificationDate?.AddYears(1);

if(todayDate > expiryDate)
{
Expand All @@ -198,7 +207,7 @@ private TrainingStatus GetTrainingStatus(DateTimeOffset? requalificationDate, s
trainingStatus.rowType = "warning";
trainingStatus.status = TrainingStatusTypes.warning;
}
else if(advanceNoticeDate > requalificationDate)
else if((advanceNoticeDate > requalificationDate) && firstNotice)
{
trainingStatus.rowType = "notify";
trainingStatus.status = TrainingStatusTypes.notify;
Expand All @@ -212,6 +221,10 @@ private TrainingStatus GetTrainingStatus(DateTimeOffset? requalificationDate, s
return trainingStatus;
}

public bool IsRotatingTraining(LookupCode trainingType){
return trainingType.Rotating || !YearsInDays.Contains(trainingType.ValidityPeriod);
}

#endregion Help Methods
}
}
Loading

0 comments on commit 0d62bba

Please sign in to comment.