From 92f5b66565d8abfa05f4eb87627388c1f991a810 Mon Sep 17 00:00:00 2001 From: Magnus Gule Date: Fri, 20 Oct 2023 13:36:03 +0200 Subject: [PATCH] * Moved HolidayService to be Consultant dependant. (#165) --- backend/Api/Api.csproj | 30 ++++----- .../Api/Consultants/ConsultantController.cs | 6 +- ...tantService.cs => ConsultantExtensions.cs} | 29 +++----- backend/Api/Consultants/HolidayService.cs | 51 -------------- backend/Api/Options/OrganizationOptions.cs | 9 --- .../OrganisationHolidayExtensions.cs | 48 +++++++++++++ backend/Api/Program.cs | 6 -- backend/Tests/AbsenceTest.cs | 67 +++++++++++++------ 8 files changed, 121 insertions(+), 125 deletions(-) rename backend/Api/Consultants/{ConsultantService.cs => ConsultantExtensions.cs} (64%) delete mode 100644 backend/Api/Consultants/HolidayService.cs delete mode 100644 backend/Api/Options/OrganizationOptions.cs create mode 100644 backend/Api/Organisation/OrganisationHolidayExtensions.cs diff --git a/backend/Api/Api.csproj b/backend/Api/Api.csproj index f4186b36..a3ded17e 100644 --- a/backend/Api/Api.csproj +++ b/backend/Api/Api.csproj @@ -10,35 +10,35 @@ - - - + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - + + + + + + + - + - + - <_ContentIncludedByDefault Remove="Routes\obj\Api.csproj.nuget.dgspec.json"/> - <_ContentIncludedByDefault Remove="Routes\obj\project.assets.json"/> - <_ContentIncludedByDefault Remove="Routes\obj\project.packagespec.json"/> + <_ContentIncludedByDefault Remove="Routes\obj\Api.csproj.nuget.dgspec.json" /> + <_ContentIncludedByDefault Remove="Routes\obj\project.assets.json" /> + <_ContentIncludedByDefault Remove="Routes\obj\project.packagespec.json" /> diff --git a/backend/Api/Consultants/ConsultantController.cs b/backend/Api/Consultants/ConsultantController.cs index 22cc5b71..ed29837a 100644 --- a/backend/Api/Consultants/ConsultantController.cs +++ b/backend/Api/Consultants/ConsultantController.cs @@ -16,14 +16,12 @@ namespace Api.Consultants; public class ConsultantController : ControllerBase { private readonly IMemoryCache _cache; - private readonly ConsultantService _consultantService; private readonly ApplicationContext _context; - public ConsultantController(ApplicationContext context, IMemoryCache cache, ConsultantService consultantService) + public ConsultantController(ApplicationContext context, IMemoryCache cache) { _context = context; _cache = cache; - _consultantService = consultantService; } [HttpGet] @@ -81,7 +79,7 @@ private List GetConsultantsWithAvailability(string orgUrlKe } var consultants = LoadConsultantAvailability(orgUrlKey, numberOfWeeks) - .Select(c => _consultantService.MapConsultantToReadModel(c, numberOfWeeks)).ToList(); + .Select(c => c.MapConsultantToReadModel(numberOfWeeks)).ToList(); _cache.Set($"{orgUrlKey}/{CacheKeys.ConsultantAvailability8Weeks}", consultants); return consultants; diff --git a/backend/Api/Consultants/ConsultantService.cs b/backend/Api/Consultants/ConsultantExtensions.cs similarity index 64% rename from backend/Api/Consultants/ConsultantService.cs rename to backend/Api/Consultants/ConsultantExtensions.cs index 03c9696a..398e8ef6 100644 --- a/backend/Api/Consultants/ConsultantService.cs +++ b/backend/Api/Consultants/ConsultantExtensions.cs @@ -1,22 +1,12 @@ -using Api.Options; +using Api.Organisation; using Core.DomainModels; using Core.Services; -using Microsoft.Extensions.Options; namespace Api.Consultants; -public class ConsultantService +public static class ConsultantExtensions { - private readonly HolidayService _holidayService; - private readonly OrganizationOptions _organizationOptions; - - public ConsultantService(IOptions orgOptions, HolidayService holidayService) - { - _organizationOptions = orgOptions.Value; - _holidayService = holidayService; - } - - public ConsultantReadModel MapConsultantToReadModel(Consultant consultant, int weeks) + public static ConsultantReadModel MapConsultantToReadModel(this Consultant consultant, int weeks) { const double tolerance = 0.1; var bookedHours = GetBookedHoursForWeeks(consultant, weeks); @@ -34,12 +24,13 @@ public ConsultantReadModel MapConsultantToReadModel(Consultant consultant, int w ); } - public double GetBookedHours(Consultant consultant, int year, int week) + public static double GetBookedHours(this Consultant consultant, int year, int week) { - var hoursPrWorkDay = consultant.Department.Organization.HoursPerWorkday; - // var hoursPrWorkDay = _organizationOptions.HoursPerWorkday; + var org = consultant.Department.Organization; + + var hoursPrWorkDay = org.HoursPerWorkday; - var holidayHours = _holidayService.GetTotalHolidaysOfWeek(year, week) * hoursPrWorkDay; + var holidayHours = org.GetTotalHolidaysOfWeek(year, week) * hoursPrWorkDay; var vacationHours = consultant.Vacations.Count(v => DateService.DateIsInWeek(v.Date, year, week)) * hoursPrWorkDay; @@ -57,7 +48,7 @@ public double GetBookedHours(Consultant consultant, int year, int week) return Math.Min(bookedHours, 5 * hoursPrWorkDay); } - public List GetBookedHoursForWeeks(Consultant consultant, int weeksAhead) + private static List GetBookedHoursForWeeks(this Consultant consultant, int weeksAhead) { return Enumerable.Range(0, weeksAhead) .Select(offset => @@ -74,7 +65,7 @@ public List GetBookedHoursForWeeks(Consultant consultant, in .ToList(); } - public double GetHoursPrWeek(Consultant consultant) + private static double GetHoursPrWeek(this Consultant consultant) { return consultant.Department.Organization.HoursPerWorkday * 5; } diff --git a/backend/Api/Consultants/HolidayService.cs b/backend/Api/Consultants/HolidayService.cs deleted file mode 100644 index dd81385d..00000000 --- a/backend/Api/Consultants/HolidayService.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Api.Options; -using Core.Services; -using Microsoft.Extensions.Options; -using PublicHoliday; - -namespace Api.Consultants; - -public class HolidayService -{ - private readonly OrganizationOptions _organizationOptions; - - public HolidayService(IOptions options) - { - _organizationOptions = options.Value; - } - - public int GetTotalHolidaysOfWeek(int year, int week) - { - var datesOfThisWeek = DateService.GetDatesInWorkWeek(year, week); - return datesOfThisWeek.Count(IsHoliday); - } - - private bool IsHoliday(DateOnly day) - { - var holidayCountry = GetHolidayCountry(); - var isPublicHoliday = holidayCountry.IsPublicHoliday(day.ToDateTime(TimeOnly.MinValue)); - return isPublicHoliday || IsVariantChristmasHoliday(day); - } - - private PublicHolidayBase GetHolidayCountry() - { - var country = _organizationOptions.Country; - - return country switch - { - "norway" => new NorwayPublicHoliday(), - "sweden" => new SwedenPublicHoliday(), - _ => new NorwayPublicHoliday() - }; - } - - private bool IsVariantChristmasHoliday(DateOnly date) - { - if (!_organizationOptions.HasVacationInChristmas) return false; - - var startDate = new DateOnly(date.Year, 12, 24); - var endDate = new DateOnly(date.Year, 12, 31); - - return date >= startDate && date <= endDate; - } -} \ No newline at end of file diff --git a/backend/Api/Options/OrganizationOptions.cs b/backend/Api/Options/OrganizationOptions.cs deleted file mode 100644 index f30d889b..00000000 --- a/backend/Api/Options/OrganizationOptions.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Api.Options; - -public class OrganizationOptions -{ - public double HoursPerWorkday { get; set; } - public bool HasVacationInChristmas { get; set; } - public int NumberOfVacationDaysInYear { get; set; } - public string Country { get; set; } -} \ No newline at end of file diff --git a/backend/Api/Organisation/OrganisationHolidayExtensions.cs b/backend/Api/Organisation/OrganisationHolidayExtensions.cs new file mode 100644 index 00000000..b033880a --- /dev/null +++ b/backend/Api/Organisation/OrganisationHolidayExtensions.cs @@ -0,0 +1,48 @@ +using Core.DomainModels; +using Core.Services; +using PublicHoliday; + +namespace Api.Organisation; + +public static class OrganisationHolidayExtensions +{ + public static int GetTotalHolidaysOfWeek(this Organization organization, int year, int week) + { + var datesOfThisWeek = DateService.GetDatesInWorkWeek(year, week); + return datesOfThisWeek.Count(organization.IsHoliday); + } + + private static bool IsHoliday(this Organization organization, DateOnly day) + { + return organization.IsPublicHoliday(day) || organization.IsChristmasHoliday(day); + } + + private static bool IsPublicHoliday(this Organization organization, DateOnly day) + { + var publicHoliday = organization.GetPublicHoliday(); + var isPublicHoliday = publicHoliday.IsPublicHoliday(day.ToDateTime(TimeOnly.MinValue)); + return isPublicHoliday || organization.IsChristmasHoliday(day); + } + + private static PublicHolidayBase GetPublicHoliday(this Organization organization) + { + var country = organization.Country; + + return country switch + { + "norway" => new NorwayPublicHoliday(), + "sweden" => new SwedenPublicHoliday(), + _ => new NorwayPublicHoliday() + }; + } + + private static bool IsChristmasHoliday(this Organization organization, DateOnly date) + { + if (organization.HasVacationInChristmas) return false; + + var startDate = new DateOnly(date.Year, 12, 24); + var endDate = new DateOnly(date.Year, 12, 31); + + return date >= startDate && date <= endDate; + } +} \ No newline at end of file diff --git a/backend/Api/Program.cs b/backend/Api/Program.cs index ee59d56c..6a331bed 100644 --- a/backend/Api/Program.cs +++ b/backend/Api/Program.cs @@ -1,9 +1,7 @@ using Api.BuildHelpers; -using Api.Consultants; using Api.Options; using Database.DatabaseContext; using Microsoft.AspNetCore.Authentication.JwtBearer; -using Microsoft.AspNetCore.Authorization; using Microsoft.EntityFrameworkCore; using Microsoft.Identity.Web; using Microsoft.OpenApi.Models; @@ -22,10 +20,6 @@ builder.Services.AddMemoryCache(); - -builder.Services.Configure(builder.Configuration.GetSection("OrganizationSettings")); -builder.Services.AddSingleton(); -builder.Services.AddSingleton(); builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); diff --git a/backend/Tests/AbsenceTest.cs b/backend/Tests/AbsenceTest.cs index 4e9bad62..4c2530bd 100644 --- a/backend/Tests/AbsenceTest.cs +++ b/backend/Tests/AbsenceTest.cs @@ -1,8 +1,6 @@ using Api.Consultants; -using Api.Options; using Core.DomainModels; using Core.Services; -using Microsoft.Extensions.Options; using NSubstitute; namespace Tests; @@ -22,13 +20,33 @@ public class Tests [TestCase(0, 0, 0, 37.5, 37.5)] [TestCase(0, 0, 0, 30, 30)] [TestCase(0, 7.5, 0, 22.5, 30)] - [Ignore("Ignored until organizations has been rewritten into Holiday-logic and Consultant")] - public void AvailabilityCalculation(int vacationDays, double plannedAbsenceHours, int numberOfHolidays, double staffedHours, double expectedBookedHours) { - var department = Substitute.For(); + var org = new Organization + { + Id = "konsulent-as", + Name = "Konsulent as", + UrlKey = "konsulent-as", + Country = "norway", + NumberOfVacationDaysInYear = 25, + HoursPerWorkday = 7.5, + Departments = new List(), + HasVacationInChristmas = false, + Customers = new List() + }; + + var department = new Department + { + Id = "barteby", + Name = "Barteby", + Hotkey = 1, + Organization = org, + Consultants = Substitute.For>() + }; + + var consultant = new Consultant { Id = 1, @@ -79,22 +97,34 @@ public void AvailabilityCalculation(int vacationDays, double plannedAbsenceHours Hours = staffedHours }); - var organization = new OrganizationOptions(); - organization.HoursPerWorkday = 7.5; - organization.HasVacationInChristmas = true; - var orgOptions = Options.Create(organization); - var holidayService = new HolidayService(orgOptions); - - var bookedHours = - new ConsultantService(orgOptions, holidayService).GetBookedHours(consultant, year, week); + var bookedHours = consultant.GetBookedHours(year, week); Assert.That(bookedHours, Is.EqualTo(expectedBookedHours)); } [Test] - [Ignore("Ignored until organizations has been rewritten into Holiday-logic and Consultant")] public void MultiplePlannedAbsences() { - var department = Substitute.For(); + var org = new Organization + { + Id = "konsulent-as", + Name = "Konsulent as", + UrlKey = "konsulent-as", + Country = "norway", + NumberOfVacationDaysInYear = 25, + HoursPerWorkday = 7.5, + HasVacationInChristmas = false, + Customers = new List() + }; + + var department = new Department + { + Id = "barteby", + Name = "Barteby", + Hotkey = 1, + Organization = org, + Consultants = Substitute.For>() + }; + var consultant = new Consultant { Id = 1, @@ -123,13 +153,8 @@ public void MultiplePlannedAbsences() Hours = 15 }); - var organization = new OrganizationOptions(); - organization.HoursPerWorkday = 7.5; - var orgOptions = Options.Create(organization); - var holidayService = new HolidayService(orgOptions); - var bookedHours = - new ConsultantService(orgOptions, holidayService).GetBookedHours(consultant, year, week); + consultant.GetBookedHours(year, week); Assert.That(bookedHours, Is.EqualTo(30)); }