diff --git a/api/models/dto/TrainingReportDto.cs b/api/models/dto/TrainingReportDto.cs index a29a7501..cf4073e9 100644 --- a/api/models/dto/TrainingReportDto.cs +++ b/api/models/dto/TrainingReportDto.cs @@ -11,6 +11,7 @@ public class TrainingReportDto public bool excluded { get; set; } public Guid sheriffId { get; set; } public string status { get; set; } + public string location { get; set; } public string _rowVariant { get; set; } } } \ No newline at end of file diff --git a/api/models/dto/TrainingReportSearchDto.cs b/api/models/dto/TrainingReportSearchDto.cs index 7b52535f..57d002d7 100644 --- a/api/models/dto/TrainingReportSearchDto.cs +++ b/api/models/dto/TrainingReportSearchDto.cs @@ -7,7 +7,7 @@ public class TrainingReportSearchDto { public int? regionId { get; set; } public int? locationId { get; set; } - public int? reportSubtypeId { get; set; } + public int[]? reportSubtypeIds { get; set; } public DateTimeOffset? startDate { get; set; } public DateTimeOffset? endDate { get; set; } } diff --git a/api/services/ManageTypesService.cs b/api/services/ManageTypesService.cs index b85e76b1..dcfd244e 100644 --- a/api/services/ManageTypesService.cs +++ b/api/services/ManageTypesService.cs @@ -139,12 +139,12 @@ public async Task> GetAll(LookupTypes? codeType, int? locationI return lookupCodes; } - public async Task> GetAllForReports(int? id, LookupTypes? codeType, int? locationId, bool? mandatory, bool showExpired = false) + public async Task> GetAllForReports(int[]? ids, LookupTypes? codeType, int? locationId, bool? mandatory, bool showExpired = false) { var lookupCodes = await Db.LookupCode.AsNoTracking() .Include(lc => lc.SortOrder.Where(so => so.LocationId == locationId)) .Where(lc => - (id == null || lc.Id == id) && + (ids == null || ids.Length==0 || ids.Contains(lc.Id)) && (codeType == null || lc.Type == codeType) && (locationId == null || lc.LocationId == null || lc.LocationId == locationId) && (mandatory == null || lc.Mandatory == mandatory) && diff --git a/api/services/usermanagement/TrainingService.cs b/api/services/usermanagement/TrainingService.cs index 5d2feb24..5fedcf1b 100644 --- a/api/services/usermanagement/TrainingService.cs +++ b/api/services/usermanagement/TrainingService.cs @@ -80,8 +80,8 @@ public async Task> GetSheriffsTrainingReports(TrainingRe var sheriffs = await sheriffQuery.ToListAsync(); - List mandatoryTrainings = await ManageTypesService.GetAllForReports(trainingReportSearch.reportSubtypeId, LookupTypes.TrainingType, null, true, false); - List optionalTrainings = await ManageTypesService.GetAllForReports(trainingReportSearch.reportSubtypeId, LookupTypes.TrainingType, null, false, false); + List mandatoryTrainings = await ManageTypesService.GetAllForReports(trainingReportSearch.reportSubtypeIds, LookupTypes.TrainingType, null, true, false); + List optionalTrainings = await ManageTypesService.GetAllForReports(trainingReportSearch.reportSubtypeIds, LookupTypes.TrainingType, null, false, false); var sheriffTrainings = new List(); @@ -100,6 +100,7 @@ public async Task> GetSheriffsTrainingReports(TrainingRe sheriffTrainings.Add(new TrainingReportDto() { name = sheriff.FirstName + ' ' + sheriff.LastName, + location = sheriff.HomeLocation.Name, trainingType = training.Description, end = null, expiryDate = null, @@ -111,13 +112,29 @@ public async Task> GetSheriffsTrainingReports(TrainingRe } else { - 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, training, takenTraining.FirstNotice); + var takenTrainings = sheriff.Training.FindAll(t => t.TrainingTypeId == training.Id).OrderByDescending(t => t.EndDate).ToList(); + var takenTraining = new SheriffTraining(); + var timezone = ""; + + TrainingStatus trainingStatus = new TrainingStatus(); + if(trainingReportSearch.startDate != null && trainingReportSearch.endDate != null) + { + var takenTrainingInRange = takenTrainings.Find(t => t.EndDate < trainingReportSearch.endDate); + takenTraining = takenTrainingInRange !=null ? takenTrainingInRange : takenTrainings.LastOrDefault(); + timezone = takenTraining.Timezone == null? "America/Vancouver" : takenTraining.Timezone; + trainingStatus = GetTrainingStatusOnDateRange(trainingReportSearch, takenTraining.TrainingCertificationExpiry, timezone, training, takenTraining.EndDate); + } + else + { + takenTraining = takenTrainings[0]; + timezone = takenTraining.Timezone == null? "America/Vancouver" : takenTraining.Timezone; + trainingStatus = GetTrainingStatus(takenTraining.TrainingCertificationExpiry, timezone, training.AdvanceNotice, training, takenTraining.FirstNotice); + } sheriffTrainings.Add(new TrainingReportDto() { name = sheriff.FirstName + ' ' + sheriff.LastName, + location = sheriff.HomeLocation.Name, trainingType = training.Description, end = takenTraining.EndDate.ConvertToTimezone(timezone), expiryDate = takenTraining.TrainingCertificationExpiry != null ? ((DateTimeOffset)takenTraining.TrainingCertificationExpiry).ConvertToTimezone(timezone): null, @@ -132,13 +149,13 @@ public async Task> GetSheriffsTrainingReports(TrainingRe Logger.LogInformation("__________End_Creating_Reports____________"); - if(trainingReportSearch.startDate != null && trainingReportSearch.endDate != null) - return sheriffTrainings.FindAll(t => - t.end>=trainingReportSearch.startDate && - t.end<=trainingReportSearch.endDate - ); - else - return sheriffTrainings; + // if(trainingReportSearch.startDate != null && trainingReportSearch.endDate != null) + // return sheriffTrainings.FindAll(t => + // t.end>=trainingReportSearch.startDate && + // t.end<=trainingReportSearch.endDate + // ); + // else + return sheriffTrainings; } #endregion Training Reports @@ -221,6 +238,37 @@ private TrainingStatus GetTrainingStatus(DateTimeOffset? requalificationDate, s return trainingStatus; } + private TrainingStatus GetTrainingStatusOnDateRange(TrainingReportSearchDto trainingReportSearch, DateTimeOffset? requalificationDate, string timezone, LookupCode trainingType, DateTimeOffset trainingCompletionDate) + { + TrainingStatus trainingStatus = new TrainingStatus(); + + var reportEndDate = ((DateTimeOffset)trainingReportSearch.endDate).ConvertToTimezone(timezone); + var expiryDate = IsRotatingTraining(trainingType)? requalificationDate : requalificationDate?.AddYears(1); + + if(reportEndDate > expiryDate) + { + trainingStatus.rowType = "alert"; + trainingStatus.status = TrainingStatusTypes.alert; + } + else if(reportEndDate > requalificationDate) + { + trainingStatus.rowType = "warning"; + trainingStatus.status = TrainingStatusTypes.warning; + } + else if(reportEndDate >= trainingCompletionDate && (reportEndDate <= requalificationDate || requalificationDate == null) ) + { + trainingStatus.rowType = "white"; + trainingStatus.status = ""; + } + else + { + trainingStatus.rowType = "danger"; + trainingStatus.status = TrainingStatusTypes.danger; + } + + return trainingStatus; + } + public bool IsRotatingTraining(LookupCode trainingType){ return trainingType.Rotating || !YearsInDays.Contains(trainingType.ValidityPeriod); } diff --git a/web/package.json b/web/package.json index 36af3055..82da3ee9 100644 --- a/web/package.json +++ b/web/package.json @@ -14,6 +14,7 @@ "@fortawesome/free-solid-svg-icons": "^5.15.1", "@fortawesome/vue-fontawesome": "^2.0.0", "@types/underscore": "^1.10.0", + "@mdi/font": "^6.5.95", "ansi-regex": "^6.0.1", "axios": "^0.21.4", "axios-auth-refresh": "^3.2.1", @@ -44,6 +45,7 @@ "vue-property-decorator": "^8.4.2", "vue-resource": "^1.5.3", "vue-router": "^3.1.6", + "vuetify": "^2.6.3", "vuex": "^3.3.0", "vuex-class": "^0.3.2", "vuex-module-decorators": "^0.17.0" @@ -68,6 +70,7 @@ "ts-loader": "^7.0.1", "tslib": "^1.11.1", "typescript": "3.8.3", + "vue-cli-plugin-vuetify": "~2.0.5", "vue-template-compiler": "2.6.11", "webpack-bundle-analyzer": "^4.5.0" }, diff --git a/web/public/index.html b/web/public/index.html index efc3210c..013632cf 100644 --- a/web/public/index.html +++ b/web/public/index.html @@ -4,7 +4,24 @@ - + + + + Sheriff Scheduling diff --git a/web/src/components/Home.vue b/web/src/components/Home.vue index 86ae128f..7a151372 100644 --- a/web/src/components/Home.vue +++ b/web/src/components/Home.vue @@ -100,7 +100,7 @@ export default class Home extends Vue { location = {} as locationInfoType; trainingTypeOptions: leaveTrainingTypeInfoType[] = []; - statusOptions: trainingStatusInfoType = { danger:'Not Taken', alert:'Expired', warning:'Requalification
Requierd', notify:'Requalify Soon' }; + statusOptions: trainingStatusInfoType = { danger:'Not Taken', alert:'Expired', warning:'Requalification
Required', notify:'Requalify Soon' }; training: trainingStatusCardInfoType = { danger: [], alert: [], warning: [], notify: [] }; trainingAlert=false; diff --git a/web/src/components/MyTeam/Components/DateRange.vue b/web/src/components/MyTeam/Components/DateRange.vue index d8c48fef..7aa1fcdb 100644 --- a/web/src/components/MyTeam/Components/DateRange.vue +++ b/web/src/components/MyTeam/Components/DateRange.vue @@ -53,9 +53,9 @@ -