Skip to content

Commit

Permalink
Have vacations work! (#389)
Browse files Browse the repository at this point in the history
Co-authored-by: Jonas Bjøralt <[email protected]>
  • Loading branch information
sigridge and jonasbjoralt authored Dec 12, 2023
1 parent 46578db commit d25df06
Show file tree
Hide file tree
Showing 26 changed files with 1,211 additions and 28 deletions.
46 changes: 46 additions & 0 deletions backend/Api/Common/StorageService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,18 @@ public StorageService(IMemoryCache cache, ApplicationContext context)
_dbContext = context;
}

public Consultant? GetConsultantByEmail(string orgUrlKey, string email)
{
var consultant = _dbContext.Consultant.Include(c=>c.Department).ThenInclude(d=> d.Organization).SingleOrDefault(c => c.Email == email);
if (consultant is null || consultant.Department.Organization.UrlKey != orgUrlKey)
{
return null;
}

return consultant;

}

public void ClearConsultantCache(string orgUrlKey)
{
_cache.Remove($"{ConsultantCacheKey}/{orgUrlKey}");
Expand Down Expand Up @@ -358,4 +370,38 @@ public Engagement GetProjectWithOrganisationById(int id)
.ThenInclude(c => c.Organization)
.Single(p => p.Id == id);
}

public List<Vacation> LoadConsultantVacation(int consultantId)
{
return _dbContext.Vacation.Where(v => v.ConsultantId == consultantId).ToList();
}

public List<DateOnly>? LoadPublicHolidays(string orgUrlKey)
{
var org = _dbContext.Organization.SingleOrDefault(org => org.UrlKey == orgUrlKey);
if (org is null) return null;
return org.GetPublicHolidays(DateOnly.FromDateTime(DateTime.Now).Year);
}

public void RemoveVacationDay(int consultantId, DateOnly date)
{
var vacation = _dbContext.Vacation.Single(v => v.ConsultantId == consultantId && v.Date.Equals(date));

_dbContext.Vacation.Remove(vacation);
_dbContext.SaveChanges();
}

public void AddVacationDay(int consultantId, DateOnly date)
{
var consultant = _dbContext.Consultant.Single(c => c.Id == consultantId);
var vacation = new Vacation
{
ConsultantId = consultantId,
Consultant = consultant,
Date = date
};
_dbContext.Add(vacation);
_dbContext.SaveChanges();
}

}
43 changes: 43 additions & 0 deletions backend/Api/Consultants/ConsultantController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using Api.Common;
using Database.DatabaseContext;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Memory;

namespace Api.Consultants;

[Authorize]
[Route("/v0/{orgUrlKey}/consultants")]
[ApiController]
public class ConsultantController : ControllerBase
{

private readonly IMemoryCache _cache;
private readonly ApplicationContext _context;

public ConsultantController(ApplicationContext context, IMemoryCache cache)
{
_context = context;
_cache = cache;
}


[HttpGet]
public ActionResult<SingleConsultantReadModel> Get([FromRoute] string orgUrlKey,
[FromQuery(Name = "Email")] string? email = "")
{
var service = new StorageService(_cache, _context);

var consultant = service.GetConsultantByEmail(orgUrlKey, email ?? "");


if (consultant is null)
{
return NotFound();
}

return Ok( new SingleConsultantReadModel(consultant));
}


}
27 changes: 27 additions & 0 deletions backend/Api/Consultants/ConsultantReadModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using System.ComponentModel.DataAnnotations;
using Core.DomainModels;

namespace Api.Consultants;

public record SingleConsultantReadModel([property: Required] int Id,
[property: Required] string Name,
[property: Required] string Email,
[property: Required] List<string> Competences,
[property: Required] string Department,
[property: Required] int YearsOfExperience,
[property: Required] Degree Degree)

{
public SingleConsultantReadModel(Consultant consultant)
: this(
consultant.Id,
consultant.Name,
consultant.Email,
consultant.Competences.Select(c => c.Name).ToList(),
consultant.Department.Name,
consultant.YearsOfExperience,
consultant.Degree ?? Degree.Master
)
{
}
}
16 changes: 16 additions & 0 deletions backend/Api/Organisation/OrganisationHolidayExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,20 @@ private static bool IsChristmasHoliday(this Organization organization, DateOnly

return date >= startDate && date <= endDate;
}

public static List<DateOnly> GetPublicHolidays(this Organization organization, int year)
{
var publicHoliday = organization.GetPublicHoliday();
var publicHolidays = publicHoliday.PublicHolidays(year).Select(DateOnly.FromDateTime).ToList();
if (organization.HasVacationInChristmas)
{
var startDate = new DateTime(year, 12, 24);
var endDate = new DateTime(year, 12, 31);
var list = Enumerable.Range(0, 1 + endDate.Subtract(startDate).Days)
.Select(offset => DateOnly.FromDateTime(startDate.AddDays(offset)))
.ToList();
publicHolidays = publicHolidays.Concat(list).Distinct().ToList();
}
return publicHolidays;
}
}
2 changes: 1 addition & 1 deletion backend/Api/Projects/ProjectController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public ActionResult Delete(int id)

[HttpPut]
[Route("updateState")]
public ActionResult<List<ConsultantReadModel>> Put([FromRoute] string orgUrlKey,
public ActionResult<List<StaffingReadModel>> Put([FromRoute] string orgUrlKey,
[FromBody] UpdateProjectWriteModel projectWriteModel)
{
// Merk: Service kommer snart via Dependency Injection, da slipper å lage ny hele tiden
Expand Down
20 changes: 10 additions & 10 deletions backend/Api/StaffingController/ReadModelFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public ReadModelFactory(StorageService storageService)
_storageService = storageService;
}

public List<ConsultantReadModel> GetConsultantReadModelsForWeeks(string orgUrlKey, List<Week> weeks)
public List<StaffingReadModel> GetConsultantReadModelsForWeeks(string orgUrlKey, List<Week> weeks)
{
var firstDayInScope = weeks.First().FirstDayOfWorkWeek();
var firstWorkDayOutOfScope = weeks.Last().LastWorkDayOfWeek();
Expand All @@ -26,40 +26,40 @@ public List<ConsultantReadModel> GetConsultantReadModelsForWeeks(string orgUrlKe
}


public ConsultantReadModel GetConsultantReadModelForWeek(int consultantId, Week week)
public StaffingReadModel GetConsultantReadModelForWeek(int consultantId, Week week)
{
var consultant = _storageService.LoadConsultantForSingleWeek(consultantId, week);
var readModel = MapToReadModelList(consultant, new List<Week> { week });

return new ConsultantReadModel(consultant, new List<BookedHoursPerWeek> { readModel.Bookings.First() },
return new StaffingReadModel(consultant, new List<BookedHoursPerWeek> { readModel.Bookings.First() },
readModel.DetailedBooking.ToList(), readModel.IsOccupied);
}

public ConsultantReadModel GetConsultantReadModelForWeeks(int consultantId, List<Week> weeks)
public StaffingReadModel GetConsultantReadModelForWeeks(int consultantId, List<Week> weeks)
{
var consultant = _storageService.LoadConsultantForWeekSet(consultantId, weeks);
var readModel = MapToReadModelList(consultant, weeks);

return new ConsultantReadModel(consultant, readModel.Bookings,
return new StaffingReadModel(consultant, readModel.Bookings,
readModel.DetailedBooking, readModel.IsOccupied);
}

public List<ConsultantReadModel> GetConsultantReadModelForWeeks(List<int> consultantIds, List<Week> weeks)
public List<StaffingReadModel> GetConsultantReadModelForWeeks(List<int> consultantIds, List<Week> weeks)
{
var consultants = new List<ConsultantReadModel>();
var consultants = new List<StaffingReadModel>();
foreach (var i in consultantIds)
{
var consultant = _storageService.LoadConsultantForWeekSet(i, weeks);
var readModel = MapToReadModelList(consultant, weeks);

consultants.Add(new ConsultantReadModel(consultant, readModel.Bookings,
consultants.Add(new StaffingReadModel(consultant, readModel.Bookings,
readModel.DetailedBooking, readModel.IsOccupied));
}

return consultants;
}

public static ConsultantReadModel MapToReadModelList(
public static StaffingReadModel MapToReadModelList(
Consultant consultant,
List<Week> weekSet)
{
Expand All @@ -80,7 +80,7 @@ public static ConsultantReadModel MapToReadModelList(
b.BookingModel.TotalBillable + b.BookingModel.TotalPlannedAbsences + b.BookingModel.TotalVacationHours +
b.BookingModel.TotalHolidayHours >= hoursPrWeek);

return new ConsultantReadModel(
return new StaffingReadModel(
consultant,
bookingSummary,
detailedBookings.ToList(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,22 @@
using Microsoft.Extensions.Caching.Memory;

namespace Api.StaffingController;

[Authorize]
[Route("/v0/{orgUrlKey}/consultants")]
[Route("/v0/{orgUrlKey}/staffings")]
[ApiController]
public class ConsultantController : ControllerBase
public class StaffingController : ControllerBase
{
private readonly IMemoryCache _cache;
private readonly ApplicationContext _context;

public ConsultantController(ApplicationContext context, IMemoryCache cache)
public StaffingController(ApplicationContext context, IMemoryCache cache)
{
_context = context;
_cache = cache;
}

[HttpGet]
public ActionResult<List<ConsultantReadModel>> Get(
public ActionResult<List<StaffingReadModel>> Get(
[FromRoute] string orgUrlKey,
[FromQuery(Name = "Year")] int? selectedYearParam = null,
[FromQuery(Name = "Week")] int? selectedWeekParam = null,
Expand All @@ -39,10 +38,11 @@ public ActionResult<List<ConsultantReadModel>> Get(
var readModels = new ReadModelFactory(service).GetConsultantReadModelsForWeeks(orgUrlKey, weekSet);
return Ok(readModels);
}


[HttpPut]
[Route("staffing/update")]
public ActionResult<ConsultantReadModel> Put(
[Route("update")]
public ActionResult<StaffingReadModel> Put(
[FromRoute] string orgUrlKey,
[FromBody] StaffingWriteModel staffingWriteModel
)
Expand Down Expand Up @@ -86,8 +86,8 @@ [FromBody] StaffingWriteModel staffingWriteModel
}

[HttpPut]
[Route("staffing/update/several")]
public ActionResult<ConsultantReadModel> Put(
[Route("update/several")]
public ActionResult<StaffingReadModel> Put(
[FromRoute] string orgUrlKey,
[FromBody] SeveralStaffingWriteModel severalStaffingWriteModel
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

namespace Api.StaffingController;

public record ConsultantReadModel(
public record StaffingReadModel(
[property: Required] int Id,
[property: Required] string Name,
[property: Required] string Email,
Expand All @@ -17,7 +17,7 @@ public record ConsultantReadModel(
[property: Required] List<DetailedBooking> DetailedBooking,
[property: Required] bool IsOccupied)
{
public ConsultantReadModel(Consultant consultant, List<BookedHoursPerWeek> bookings,
public StaffingReadModel(Consultant consultant, List<BookedHoursPerWeek> bookings,
List<DetailedBooking> detailedBookings, bool IsOccupied)
: this(
consultant.Id,
Expand All @@ -35,6 +35,7 @@ public ConsultantReadModel(Consultant consultant, List<BookedHoursPerWeek> booki
}
}


public record BookedHoursPerWeek(
[property: Required] int Year,
[property: Required] int WeekNumber,
Expand Down
Loading

0 comments on commit d25df06

Please sign in to comment.