Skip to content

Commit

Permalink
Use backend-types properly, and fix minor lint errors (#366)
Browse files Browse the repository at this point in the history
  • Loading branch information
jonasbjoralt authored Dec 11, 2023
1 parent 3101f0c commit a0db6b8
Show file tree
Hide file tree
Showing 40 changed files with 477 additions and 387 deletions.
25 changes: 8 additions & 17 deletions backend/Api/Common/StorageService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,16 +129,10 @@ private List<Consultant> LoadConsultantsFromDb(string orgUrlKey)
return hydratedConsultants;
}

private async Task<List<Consultant>> LoadConsultantsFromDbAsync(string orgUrlKey)
{
return await Task.Run(() => LoadConsultantsFromDb(orgUrlKey));
}

private Staffing CreateStaffing(StaffingKey staffingKey, double hours)
{
var consultant = _dbContext.Consultant.Find(staffingKey.ConsultantId);
var project = _dbContext.Project
.Find(staffingKey.EngagementId);
var consultant = _dbContext.Consultant.Single(c => c.Id == staffingKey.ConsultantId);
var project = _dbContext.Project.Single(p => p.Id == staffingKey.EngagementId);

var staffing = new Staffing
{
Expand All @@ -154,9 +148,8 @@ private Staffing CreateStaffing(StaffingKey staffingKey, double hours)

private PlannedAbsence CreateAbsence(PlannedAbsenceKey plannedAbsenceKey, double hours)
{
var consultant = _dbContext.Consultant.Find(plannedAbsenceKey.ConsultantId);
var absence = _dbContext.Absence
.Find(plannedAbsenceKey.AbsenceId);
var consultant = _dbContext.Consultant.Single(c => c.Id == plannedAbsenceKey.ConsultantId);
var absence = _dbContext.Absence.Single(a => a.Id == plannedAbsenceKey.AbsenceId);

var plannedAbsence = new PlannedAbsence
{
Expand Down Expand Up @@ -207,9 +200,8 @@ public void UpdateOrCreatePlannedAbsence(PlannedAbsenceKey plannedAbsenceKey, do
public void UpdateOrCreateStaffings(int consultantId, int projectId, List<Week> weeks, double hours,
string orgUrlKey)
{
var consultant = _dbContext.Consultant.Find(consultantId);
var project = _dbContext.Project
.Find(projectId);
var consultant = _dbContext.Consultant.Single(c => c.Id == consultantId);
var project = _dbContext.Project.Single(p => p.Id == projectId);

var org = _dbContext.Organization.FirstOrDefault(o => o.UrlKey == orgUrlKey);

Expand Down Expand Up @@ -258,9 +250,8 @@ public void UpdateOrCreateStaffings(int consultantId, int projectId, List<Week>
public void UpdateOrCreatePlannedAbsences(int consultantId, int absenceId, List<Week> weeks, double hours,
string orgUrlKey)
{
var consultant = _dbContext.Consultant.Find(consultantId);
var absence = _dbContext.Absence
.Find(absenceId);
var consultant = _dbContext.Consultant.Single(c => c.Id == consultantId);
var absence = _dbContext.Absence.Single(a => a.Id == absenceId);

var org = _dbContext.Organization.FirstOrDefault(o => o.UrlKey == orgUrlKey);
foreach (var week in weeks)
Expand Down
5 changes: 3 additions & 2 deletions backend/Api/Organisation/DeparmentController.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.ComponentModel.DataAnnotations;
using Database.DatabaseContext;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
Expand Down Expand Up @@ -46,6 +47,6 @@ public ActionResult<double> GetWeeklyWorkHours([FromRoute] string orgUrlKey)
}
}

public record DepartmentReadModel(string Id, string Name, int? Hotkey);
public record DepartmentReadModel([property: Required] string Id, [property: Required] string Name, int? Hotkey);

public record OrganisationReadModel(string Name, string UrlKey);
public record OrganisationReadModel([property: Required] string Name, [property: Required] string UrlKey);
1 change: 1 addition & 0 deletions backend/Api/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
{
genOptions.SwaggerDoc("v0", new OpenApiInfo { Title = "Vibes API", Version = "v0" });
genOptions.ConfigureSwaggerAuthentication(adOptions);
genOptions.SupportNonNullableReferenceTypes();
});

var app = builder.Build();
Expand Down
7 changes: 2 additions & 5 deletions backend/Api/Projects/ProjectController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ public ActionResult<List<ConsultantReadModel>> Put([FromRoute] string orgUrlKey,
}
else
{
// TODO: Gjerne flytt dette ut i en egen metode også. Kanskje storageservice?
engagement = _context.Project
.Include(p => p.Consultants)
.Include(p => p.Staffings)
Expand Down Expand Up @@ -107,7 +106,6 @@ public ActionResult<List<ConsultantReadModel>> Put([FromRoute] string orgUrlKey,

private bool EngagementHasSoftMatch(int id)
{
// TODO: Noe usikker på hvor denne metoden skal være. Om du har en bedre idé, gjerne flytt den :)
var engagementToChange = _context.Project
.Include(p => p.Customer)
.Single(p => p.Id == id);
Expand All @@ -120,7 +118,6 @@ private bool EngagementHasSoftMatch(int id)

private Engagement MergeProjects(int id)
{
// TODO: Noe usikker på hvor denne metoden skal være. Om du har en bedre idé, gjerne flytt den :)
var engagementToChange = _context.Project
.Include(p => p.Staffings)
.Include(p => p.Customer)
Expand Down Expand Up @@ -163,15 +160,15 @@ public ActionResult<ProjectWithCustomerModel> Put([FromRoute] string orgUrlKey,
.SingleOrDefault(p => p.Customer.Name == body.CustomerName
&& p.IsBillable == body.IsBillable
&& p.Name == body.ProjectName
&& p.State == body.ProjectState
&& p.State == body.BookingType
);

if (project is null)
{
project = new Engagement
{
Customer = customer,
State = body.ProjectState,
State = body.BookingType,
Staffings = new List<Staffing>(),
Consultants = new List<Consultant>(),
Name = body.ProjectName,
Expand Down
23 changes: 16 additions & 7 deletions backend/Api/Projects/ProjectModels.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
using System.ComponentModel.DataAnnotations;
using Core.DomainModels;

namespace Api.Projects;

public record EngagementPerCustomerReadModel(int CustomerId, string CustomerName,
List<EngagementReadModel> Engagements);
public record EngagementPerCustomerReadModel(
[property: Required] int CustomerId,
[property: Required] string CustomerName,
[property: Required] List<EngagementReadModel> Engagements);

public record EngagementReadModel(int EngagementId, string EngagementName, EngagementState ProjectState,
bool IsBillable);
public record EngagementReadModel(
[property: Required] int EngagementId,
[property: Required] string EngagementName,
[property: Required] EngagementState BookingType,
[property: Required] bool IsBillable);

public record EngagementWriteModel(EngagementState ProjectState,
public record EngagementWriteModel(List<int> ConsultantIds, EngagementState BookingType,
bool IsBillable, string ProjectName, string CustomerName);

public record ProjectWithCustomerModel(string ProjectName, string CustomerName, EngagementState ProjectState,
bool IsBillable);
public record ProjectWithCustomerModel(
[property: Required] string ProjectName,
[property: Required] string CustomerName,
[property: Required] EngagementState BookingType,
[property: Required] bool IsBillable);

public record UpdateProjectWriteModel(int EngagementId, EngagementState ProjectState, int StartYear, int StartWeek,
int WeekSpan);
62 changes: 36 additions & 26 deletions backend/Api/StaffingController/ConsultantController.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System.Configuration;
using Api.Common;
using Core.DomainModels;
using Database.DatabaseContext;
Expand Down Expand Up @@ -96,32 +95,33 @@ [FromBody] SeveralStaffingWriteModel severalStaffingWriteModel
var service = new StorageService(_cache, _context);

if (!StaffingControllerValidator.ValidateStaffingWriteModel(severalStaffingWriteModel, service, orgUrlKey))
{
return BadRequest();
}

var startWeek = new Week(severalStaffingWriteModel.StartYear, severalStaffingWriteModel.StartWeek);
var endWeek = new Week(severalStaffingWriteModel.EndYear, severalStaffingWriteModel.EndWeek);

var weekSet = startWeek.CompareTo(endWeek) < 0 ? startWeek.GetNextWeeks(endWeek) : endWeek.GetNextWeeks(startWeek);
var weekSet = startWeek.CompareTo(endWeek) < 0
? startWeek.GetNextWeeks(endWeek)
: endWeek.GetNextWeeks(startWeek);
try
{

switch (severalStaffingWriteModel.Type)
{
case BookingType.Booking:
case BookingType.Offer:
service.UpdateOrCreateStaffings(severalStaffingWriteModel.ConsultantId, severalStaffingWriteModel.EngagementId, weekSet, severalStaffingWriteModel.Hours, orgUrlKey);
break;
case BookingType.PlannedAbsence:
service.UpdateOrCreatePlannedAbsences(severalStaffingWriteModel.ConsultantId, severalStaffingWriteModel.EngagementId, weekSet, severalStaffingWriteModel.Hours, orgUrlKey);
break;
case BookingType.Vacation:
break;
default:
throw new ArgumentOutOfRangeException(nameof(severalStaffingWriteModel.Type), severalStaffingWriteModel.Type, "Invalid bookingType");
}

switch (severalStaffingWriteModel.Type)
{
case BookingType.Booking:
case BookingType.Offer:
service.UpdateOrCreateStaffings(severalStaffingWriteModel.ConsultantId,
severalStaffingWriteModel.EngagementId, weekSet, severalStaffingWriteModel.Hours, orgUrlKey);
break;
case BookingType.PlannedAbsence:
service.UpdateOrCreatePlannedAbsences(severalStaffingWriteModel.ConsultantId,
severalStaffingWriteModel.EngagementId, weekSet, severalStaffingWriteModel.Hours, orgUrlKey);
break;
case BookingType.Vacation:
break;
default:
throw new ArgumentOutOfRangeException(nameof(severalStaffingWriteModel.Type),
severalStaffingWriteModel.Type, "Invalid bookingType");
}
}
catch (Exception e)
{
Expand All @@ -130,14 +130,24 @@ [FromBody] SeveralStaffingWriteModel severalStaffingWriteModel
}

return new ReadModelFactory(service).GetConsultantReadModelForWeeks(
severalStaffingWriteModel.ConsultantId, weekSet );
severalStaffingWriteModel.ConsultantId, weekSet);
}
}

public record StaffingWriteModel(BookingType Type, int ConsultantId, int EngagementId, int StartYear, int StartWeek,
[property: LongValidator(MinValue = 0, MaxValue = 100)]
public record StaffingWriteModel(
BookingType Type,
int ConsultantId,
int EngagementId,
int StartYear,
int StartWeek,
double Hours);

public record SeveralStaffingWriteModel(BookingType Type, int ConsultantId, int EngagementId, int StartYear, int StartWeek, int EndYear, int EndWeek,
[property: LongValidator(MinValue = 0, MaxValue = 100)]
double Hours);
public record SeveralStaffingWriteModel(
BookingType Type,
int ConsultantId,
int EngagementId,
int StartYear,
int StartWeek,
int EndYear,
int EndWeek,
double Hours);
81 changes: 39 additions & 42 deletions backend/Api/StaffingController/ConsultantReadModel.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
using System.ComponentModel.DataAnnotations;
using Core.DomainModels;

// ReSharper disable NotAccessedPositionalProperty.Global

namespace Api.StaffingController;

public record ConsultantReadModel(int Id, string Name, string Email, List<string> Competences, string Department,
int YearsOfExperience, Degree Degree,
List<BookedHoursPerWeek> Bookings, List<DetailedBooking> DetailedBooking, bool IsOccupied)
public record ConsultantReadModel(
[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,
[property: Required] List<BookedHoursPerWeek> Bookings,
[property: Required] List<DetailedBooking> DetailedBooking,
[property: Required] bool IsOccupied)
{
public ConsultantReadModel(Consultant consultant, List<BookedHoursPerWeek> bookings,
List<DetailedBooking> detailedBookings, bool IsOccupied)
Expand All @@ -24,40 +35,17 @@ public ConsultantReadModel(Consultant consultant, List<BookedHoursPerWeek> booki
}
}

public record ConsultantReadModelSingleWeek(int Id, string Name, string Email, List<string> Competences,
string Department,
int YearsOfExperience, Degree Degree,
BookedHoursPerWeek Bookings, DetailedBooking DetailedBooking, bool IsOccupied)
{
public ConsultantReadModelSingleWeek(Consultant consultant, BookedHoursPerWeek bookings,
DetailedBooking detailedBookings, bool IsOccupied)
: this(
consultant.Id,
consultant.Name,
consultant.Email,
consultant.Competences.Select(c => c.Name).ToList(),
consultant.Department.Name,
consultant.YearsOfExperience,
consultant.Degree ?? Degree.Master,
bookings,
detailedBookings,
IsOccupied
)
{
}
}

public record BookedHoursPerWeek(int Year, int WeekNumber, int SortableWeek, string DateString,
WeeklyBookingReadModel BookingModel);
public record BookedHoursPerWeek(
[property: Required] int Year,
[property: Required] int WeekNumber,
[property: Required] int SortableWeek,
[property: Required] string DateString,
[property: Required] WeeklyBookingReadModel BookingModel);

public record DetailedBooking(BookingDetails BookingDetails, List<WeeklyHours> Hours)
public record DetailedBooking(
[property: Required] BookingDetails BookingDetails,
[property: Required] List<WeeklyHours> Hours)
{
public DetailedBooking(string projectName, BookingType type, string customerName, int projectId,
List<WeeklyHours> bookings) : this(
new BookingDetails(projectName, type, customerName, projectId), bookings)
{
}

private double TotalHoursForWeek(Week week)
{
return Hours.Where(weeklySum => weeklySum.Week == week.ToSortableInt()).Sum(weeklyHours => weeklyHours.Hours);
Expand All @@ -73,19 +61,28 @@ internal static double GetTotalHoursPrBookingTypeAndWeek(IEnumerable<DetailedBoo
}
}

public record WeeklyBookingReadModel(double TotalBillable, double TotalOffered, double TotalPlannedAbstences,
double TotalSellableTime, double TotalHolidayHours, double TotalVacationHours, double TotalOverbooking);

public record BookingReadModel(string Name, double Hours, BookingType Type);
public record WeeklyBookingReadModel(
[property: Required] double TotalBillable,
[property: Required] double TotalOffered,
[property: Required] double TotalPlannedAbsences,
[property: Required] double TotalSellableTime,
[property: Required] double TotalHolidayHours,
[property: Required] double TotalVacationHours,
[property: Required] double TotalOverbooking);

public record BookingDetails(string ProjectName, BookingType Type, string CustomerName, int ProjectId);
public record BookingDetails(
[property: Required] string ProjectName,
[property: Required] BookingType Type,
[property: Required] string CustomerName,
[property: Required] int ProjectId);

public record WeeklyHours(int Week, double Hours);
public record WeeklyHours([property: Required] int Week, [property: Required] double Hours);

public enum BookingType
{
Offer,
Booking,
PlannedAbsence,
Vacation
Vacation,
Available
}
2 changes: 1 addition & 1 deletion backend/Api/StaffingController/ReadModelFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public static ConsultantReadModel MapToReadModelList(

//isOccupied should not include offered or sellable time, as it's sometimes necessary to "double-book"
var isOccupied = bookingSummary.All(b =>
b.BookingModel.TotalBillable + b.BookingModel.TotalPlannedAbstences + b.BookingModel.TotalVacationHours +
b.BookingModel.TotalBillable + b.BookingModel.TotalPlannedAbsences + b.BookingModel.TotalVacationHours +
b.BookingModel.TotalHolidayHours >= hoursPrWeek);

return new ConsultantReadModel(
Expand Down
2 changes: 1 addition & 1 deletion backend/Core/DomainModels/Vacation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ public class Vacation
[Required] public int Id { get; set; }

public required int ConsultantId { get; set; }
[Required] public Consultant Consultant { get; set; }
public required Consultant Consultant { get; set; }
[Required] public DateOnly Date { get; set; }
}
4 changes: 2 additions & 2 deletions backend/Tests/AbsenceTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public void AvailabilityCalculation(int vacationDays, double plannedAbsenceHours
Assert.Multiple(() =>
{
Assert.That(bookingModel.TotalBillable, Is.EqualTo(staffedHours));
Assert.That(bookingModel.TotalPlannedAbstences, Is.EqualTo(plannedAbsenceHours));
Assert.That(bookingModel.TotalPlannedAbsences, Is.EqualTo(plannedAbsenceHours));
Assert.That(bookingModel.TotalHolidayHours, Is.EqualTo(numberOfHolidays * 7.5));
Assert.That(bookingModel.TotalSellableTime, Is.EqualTo(expectedSellableHours));
});
Expand Down Expand Up @@ -176,6 +176,6 @@ public void MultiplePlannedAbsences()
var bookedHours = ReadModelFactory.MapToReadModelList(consultant, new List<Week> { week }).Bookings.First()
.BookingModel;

Assert.That(bookedHours.TotalPlannedAbstences, Is.EqualTo(30));
Assert.That(bookedHours.TotalPlannedAbsences, Is.EqualTo(30));
}
}
Loading

0 comments on commit a0db6b8

Please sign in to comment.