diff --git a/LangLang/BusinessLogic/UseCases/CourseService.cs b/LangLang/BusinessLogic/UseCases/CourseService.cs index 6dbe1dc..b0ee04e 100644 --- a/LangLang/BusinessLogic/UseCases/CourseService.cs +++ b/LangLang/BusinessLogic/UseCases/CourseService.cs @@ -47,7 +47,7 @@ public void Delete(int id) } public void DeleteByTutor(Tutor tutor) { - foreach (Course course in GetByTutor(tutor)) + foreach (Course course in GetByTutor(tutor.Id)) { if (course.StartDateTime > DateTime.Now) { @@ -180,30 +180,19 @@ public List GetAll() { return _courses.GetAll(); } - public DateTime GetEnd(Course course) - { - return course.TimeSlots[course.TimeSlots.Count - 1].GetEnd(); - } - - public bool IsActive(Course course) - { - if (course.StartDateTime <= DateTime.Now && GetEnd(course) >= DateTime.Now) return true; - return false; - } - public List GetByTutor(Tutor tutor) + public int NumActiveCourses(Tutor tutor) { - List coursesByTutor = new List(); - - foreach (Course course in GetAll()) + int active = 0; + List coursesByTutor = GetByTutor(tutor.Id); + foreach (Course course in coursesByTutor) { - if (course.TutorId == tutor.Id) + if (course.IsActive()) { - coursesByTutor.Add(course); + active++; } } - - return coursesByTutor; + return active; } public List GetByTutor(int tutorId) diff --git a/LangLang/BusinessLogic/UseCases/PdfService.cs b/LangLang/BusinessLogic/UseCases/PdfService.cs index 2e01fe3..8a735d7 100644 --- a/LangLang/BusinessLogic/UseCases/PdfService.cs +++ b/LangLang/BusinessLogic/UseCases/PdfService.cs @@ -50,6 +50,47 @@ public PdfGrid DataToGrid(Dictionary data) } return grid; } + public PdfGrid DataToGrid(Dictionary> data) + { + PdfGrid grid = new PdfGrid(); + grid.Columns.Add(4); + foreach (var item in data) + { + PdfGridRow row = grid.Rows.Add(); + row.Cells[0].Value = item.Key; + row.Cells[1].Value = item.Value[0].ToString(); + row.Cells[2].Value = item.Value[1].ToString(); + row.Cells[3].Value = item.Value[2].ToString(); + } + return grid; + } + + public PdfGrid DataToGrid(float[] data) + { + PdfGrid grid = new PdfGrid(); + grid.Columns.Add(4); + PdfGridRow row = grid.Rows.Add(); + row.Cells[0].Value = data[0].ToString(); + row.Cells[1].Value = data[1].ToString(); + row.Cells[2].Value = data[2].ToString(); + row.Cells[3].Value = data[3].ToString(); + return grid; + } + + public PdfGrid DataToGrid(Dictionary data) + { + PdfGrid grid = new PdfGrid(); + grid.Columns.Add(4); + foreach (var item in data) + { + PdfGridRow row = grid.Rows.Add(); + row.Cells[0].Value = item.Key; + row.Cells[1].Value = item.Value[0].ToString(); + row.Cells[2].Value = item.Value[1].ToString(); + row.Cells[3].Value = item.Value[2].ToString(); + } + return grid; + } public PdfGrid DataToGrid(Dictionary<(Course, int), double> data) { @@ -77,8 +118,8 @@ public PdfGrid DataToGrid(Dictionary data) row.Cells[0].Value = item.Key.Language + " " + item.Key.Level.ToString(); row.Cells[1].Value = item.Value.ToString(); } - return grid; } + } } diff --git a/LangLang/BusinessLogic/UseCases/ReportService.cs b/LangLang/BusinessLogic/UseCases/ReportService.cs index 4f8fe3d..750d9cf 100644 --- a/LangLang/BusinessLogic/UseCases/ReportService.cs +++ b/LangLang/BusinessLogic/UseCases/ReportService.cs @@ -66,10 +66,14 @@ public float[] GetAverageResults() averages[2] += result.WritingPoints; averages[3] += result.ListeningPoints; } + + if (results.Count == 0) return averages; + for (int i = 0; i < averages.Length; i++) { averages[i] /= results.Count; } + return averages; } public int NumStudentsAttended(Course course) @@ -82,16 +86,31 @@ public int NumStudentsPassed(Course course) CourseService coursesService = new(); return coursesService.NumStudentsPassed(course); } - public double CalculatePassingPercentage(Course course) + public float CalculatePassingPercentage(Course course) { int attended = NumStudentsAttended(course); + if (attended == 0) return 0; int passed = NumStudentsPassed(course); return (passed / attended)*100; } - - public Dictionary> GetAverageGradesOfCourses() + public Dictionary GetCoursesAccomplishment() + { + Dictionary accomplishments = new(); + CourseService courseService = new(); + List courses = courseService.GetCoursesHeldInLastYear(); + foreach (Course course in courses) + { + float[] res = new float[3]; + res[0] = NumStudentsAttended(course); + res[1] = NumStudentsPassed(course); + res[2] = CalculatePassingPercentage(course); + accomplishments.Add(course.ToPdfString(), res); + } + return accomplishments; + } + public Dictionary> GetAverageGradesOfCourses() { - Dictionary> averages = new(); + Dictionary> averages = new(); CourseService courseService = new(); List courses = courseService.GetCoursesHeldInLastYear(); GradeService gradeService = new(); @@ -102,7 +121,7 @@ public Dictionary> GetAverageGradesOfCourses() avg.Add(gradeService.GetAverageKnowledgeGrade(course)); avg.Add(gradeService.GetAverageActivityGrade(course)); avg.Add(tutorRatingService.GetAverageTutorRating(course)); - averages.Add(course, avg); + averages.Add(course.ToPdfString(), avg); } return averages; } diff --git a/LangLang/BusinessLogic/UseCases/SenderService.cs b/LangLang/BusinessLogic/UseCases/SenderService.cs index 8166676..13a490e 100644 --- a/LangLang/BusinessLogic/UseCases/SenderService.cs +++ b/LangLang/BusinessLogic/UseCases/SenderService.cs @@ -38,6 +38,42 @@ public void SendResults(ExamSlot exam) EmailService.SendEmail(student.Profile.Email, subject, body); } } + public void SendAverageCourseGrades(Director director) + { + var reportService = new ReportService(); + var pdfService = new PdfService(); + + var reportName = "Average grades and tutor rating per course"; + var headers = new string[] { "Course", "Average knowledge grade", "Average activity grade", "Average tutor rating" }; + + var document = PdfService.GeneratePdf>>(reportService.GetAverageGradesOfCourses(), headers, reportName, data => pdfService.DataToGrid(data)); + EmailService.SendEmail(director.Profile.Email, reportName, "", document); + + } + public void SendAverageResultsPerSkill(Director director) + { + var reportService = new ReportService(); + var pdfService = new PdfService(); + + var reportName = "Average exams results per skill in last year"; + var headers = new string[] { "Reading average score", "Writing average score", "Listening average score", "Speaking average score" }; + + var document = PdfService.GeneratePdf(reportService.GetAverageResults(), headers, reportName, data => pdfService.DataToGrid(data)); + EmailService.SendEmail(director.Profile.Email, reportName, "", document); + + } + public void SendCoursesAccomplishments(Director director) + { + var reportService = new ReportService(); + var pdfService = new PdfService(); + + var reportName = "Courses enrollments and pass rates analysis"; + var headers = new string[] { "Course", "Total Attendees", "Students Passed", "Pass Rate (%)" }; + + var document = PdfService.GeneratePdf>(reportService.GetCoursesAccomplishment(), headers, reportName, data => pdfService.DataToGrid(data)); + EmailService.SendEmail(director.Profile.Email, reportName, "", document); + + } public void SendGratitudeMail(Course course, List students) { diff --git a/LangLang/BusinessLogic/UseCases/SmartSystem.cs b/LangLang/BusinessLogic/UseCases/SmartSystem.cs index ccc09dd..5306db8 100644 --- a/LangLang/BusinessLogic/UseCases/SmartSystem.cs +++ b/LangLang/BusinessLogic/UseCases/SmartSystem.cs @@ -2,6 +2,7 @@ using LangLang.Configuration; using LangLang.Domain.Models; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; namespace LangLang.BusinessLogic.UseCases @@ -65,21 +66,66 @@ public static int MostSuitableTutor(Course course) { TutorService tutorService = new(); List tutors = tutorService.GetBySkill(course.Language, course.Level); + //there is no free tutors for given course if (tutors.Count == 0) return -1; - TutorRatingService tutorRatingService = new(); - Dictionary tutorsAndRatings = new(); + + //consider only tutors that are free in time of course + List availableTutors = new(); + CourseService coursesService = new(); foreach (Tutor tutor in tutors) { - tutorsAndRatings[tutor] = tutorRatingService.GetAverageRating(tutor); + course.TutorId = tutor.Id; + if (coursesService.CanCreateOrUpdate(course)) availableTutors.Add(tutor); } - Dictionary sorted = tutorsAndRatings.OrderBy(pair => pair.Value).ToDictionary(pair => pair.Key, pair => pair.Value); + //find least busy tutors + List leastBusyTutors = WithLeastActiveCourses(availableTutors); + //check who is rated the best + return GetBestRankedTutor(leastBusyTutors); + } + private static int MinimumActiveCourses(List tutors) + { CourseService coursesService = new(); - foreach (Tutor tutor in sorted.Keys) + int minActive = int.MaxValue; + int active = 0; + foreach (var tutor in tutors) { - course.TutorId = tutor.Id; - if (coursesService.CanCreateOrUpdate(course)) return tutor.Id; + active = coursesService.NumActiveCourses(tutor); + if (active < minActive) + { + minActive = active; + } } - return -1; + + return minActive; + } + private static List WithLeastActiveCourses(List tutors) + { + int minActive = MinimumActiveCourses(tutors); + List leastBusyTutors = new List(); + CourseService coursesService = new(); + + foreach (var tutor in tutors) + { + int active = coursesService.NumActiveCourses(tutor); + if (active == minActive) + { + leastBusyTutors.Add(tutor); + } + } + + return leastBusyTutors; + } + private static int GetBestRankedTutor(List tutors) + { + TutorRatingService tutorRatingService = new(); + Dictionary ratings = new(); + foreach (Tutor tutor in tutors) + { + ratings[tutor] = tutorRatingService.GetAverageRating(tutor); + } + Tutor bestRanked = ratings.Aggregate((x, y) => x.Value < y.Value ? x : y).Key; + return bestRanked.Id; } + } } diff --git a/LangLang/BusinessLogic/UseCases/TutorRatingService.cs b/LangLang/BusinessLogic/UseCases/TutorRatingService.cs index bd8d21c..bc6b488 100644 --- a/LangLang/BusinessLogic/UseCases/TutorRatingService.cs +++ b/LangLang/BusinessLogic/UseCases/TutorRatingService.cs @@ -72,7 +72,7 @@ public double GetAverageRating(Tutor tutor) { CourseService courseService = new(); List ratings = new(); - foreach (Course course in courseService.GetByTutor(tutor)) + foreach (Course course in courseService.GetByTutor(tutor.Id)) { ratings.Add(GetAverageTutorRating(course)); } diff --git a/LangLang/Domain/Models/Course.cs b/LangLang/Domain/Models/Course.cs index 905ba4c..9d5cd06 100644 --- a/LangLang/Domain/Models/Course.cs +++ b/LangLang/Domain/Models/Course.cs @@ -105,9 +105,8 @@ public int DaysUntilStart() public bool IsHeldInLastYear() { - var endDate = TimeSlots[^1].GetEnd(); DateTime oneYearAgo = DateTime.Now.AddYears(-1); - return endDate > oneYearAgo; + return GetEnd() > oneYearAgo && GetEnd() <= DateTime.Now; } public override string ToString() @@ -125,5 +124,24 @@ public override string ToString() } return string.Join("|", new object[] { Id, TutorId, Language, Level.ToString(), NumberOfWeeks, sbDays.ToString(), Online, NumberOfStudents, MaxStudents, StartDateTime.ToString(), CreatedByDirector, Modifiable, GratitudeEmailSent }); } + + public string ToPdfString() + { + return Id + " " + " " + Language + " " + Level; + } + + public DateTime GetEnd() + { + return TimeSlots[TimeSlots.Count - 1].GetEnd(); + } + public bool IsActive() + { + if (StartDateTime <= DateTime.Now && GetEnd() >= DateTime.Now) return true; + return false; + } + public bool CanChange() + { + return StartDateTime >= DateTime.Now.AddDays(Constants.COURSE_MODIFY_PERIOD); ; + } } } diff --git a/LangLang/WPF/ViewModels/CourseViewModels/CoursesTutorViewModel.cs b/LangLang/WPF/ViewModels/CourseViewModels/CoursesTutorViewModel.cs index 247eac8..bf0c2d6 100644 --- a/LangLang/WPF/ViewModels/CourseViewModels/CoursesTutorViewModel.cs +++ b/LangLang/WPF/ViewModels/CourseViewModels/CoursesTutorViewModel.cs @@ -28,7 +28,7 @@ public void Update() { Courses.Clear(); CourseService courseService = new(); - foreach (Course course in courseService.GetByTutor(LoggedIn)) + foreach (Course course in courseService.GetByTutor(LoggedIn.Id)) { Courses.Add(new CourseViewModel(course)); } diff --git a/LangLang/WPF/ViewModels/DirectorViewModels/ReportsViewModel.cs b/LangLang/WPF/ViewModels/DirectorViewModels/ReportsViewModel.cs index 262a094..ac7c3a6 100644 --- a/LangLang/WPF/ViewModels/DirectorViewModels/ReportsViewModel.cs +++ b/LangLang/WPF/ViewModels/DirectorViewModels/ReportsViewModel.cs @@ -38,6 +38,24 @@ public void SendPenaltiesCountLastYear() ShowSuccess(); } + public void SentAverageCourseGrades() + { + var senderService = new SenderService(); + senderService.SendAverageCourseGrades(_director); + ShowSuccess(); + } + public void SentAverageResultsPerSkill() + { + var senderService = new SenderService(); + senderService.SendAverageResultsPerSkill(_director); + ShowSuccess(); + } + public void SentCoursesAccomplishments() + { + var senderService = new SenderService(); + senderService.SendCoursesAccomplishments(_director); + ShowSuccess(); + } private void ShowSuccess() { MessageBox.Show("Successfully completed!", "Notification", MessageBoxButton.OK, MessageBoxImage.Information); diff --git a/LangLang/WPF/Views/DirectorView/Tabs/Reports.xaml b/LangLang/WPF/Views/DirectorView/Tabs/Reports.xaml index b7b87db..3f1eb7c 100644 --- a/LangLang/WPF/Views/DirectorView/Tabs/Reports.xaml +++ b/LangLang/WPF/Views/DirectorView/Tabs/Reports.xaml @@ -26,8 +26,9 @@