diff --git a/backend/Api/Projects/AgreementController.cs b/backend/Api/Agreements/AgreementController.cs similarity index 98% rename from backend/Api/Projects/AgreementController.cs rename to backend/Api/Agreements/AgreementController.cs index 7390c3d3..0e23e9b4 100644 --- a/backend/Api/Projects/AgreementController.cs +++ b/backend/Api/Agreements/AgreementController.cs @@ -198,6 +198,7 @@ public async Task> Post([FromRoute] string orgU UploadedOn: f.UploadedOn )).ToList() ); + cache.Remove($"consultantCacheKey/{orgUrlKey}"); return Ok(responseModel); } @@ -294,6 +295,8 @@ public async Task> Put([FromRoute] string orgUr )).ToList() ); + cache.Remove($"consultantCacheKey/{orgUrlKey}"); + return Ok(responseModel); } @@ -308,6 +311,7 @@ public async Task Delete([FromRoute] string orgUrlKey, [FromRoute] if (agreement is null) return NotFound(); await agreementsRepository.DeleteAgreementAsync(agreementId, ct); + cache.Remove($"consultantCacheKey/{orgUrlKey}"); return Ok("Deleted"); } diff --git a/backend/Api/Projects/AgreementModels.cs b/backend/Api/Agreements/AgreementModels.cs similarity index 100% rename from backend/Api/Projects/AgreementModels.cs rename to backend/Api/Agreements/AgreementModels.cs diff --git a/backend/Api/Common/StorageService.cs b/backend/Api/Common/StorageService.cs index d5d9f3e3..5d9aa87f 100644 --- a/backend/Api/Common/StorageService.cs +++ b/backend/Api/Common/StorageService.cs @@ -49,8 +49,11 @@ public Consultant LoadConsultantForSingleWeek(int consultantId, Week week) .Single(c => c.Id == consultantId); consultant.Staffings = _dbContext.Staffing.Where(staffing => - staffing.Week.Equals(week) && staffing.ConsultantId == consultantId).Include(s => s.Engagement) - .ThenInclude(p => p.Customer).ToList(); + staffing.Week.Equals(week) && staffing.ConsultantId == consultantId) + .Include(s => s.Engagement) + .ThenInclude(p => p.Customer) + .Include(s => s.Engagement) + .ThenInclude(e => e.Agreements).ToList(); consultant.PlannedAbsences = _dbContext.PlannedAbsence .Where(absence => absence.Week.Equals(week) && absence.ConsultantId == consultantId).Include(a => a.Absence) @@ -70,8 +73,12 @@ public Consultant LoadConsultantForWeekSet(int consultantId, List weeks) consultant.Staffings = _dbContext.Staffing.Where(staffing => - weeks.Contains(staffing.Week) && staffing.ConsultantId == consultantId).Include(s => s.Engagement) - .ThenInclude(p => p.Customer).ToList(); + weeks.Contains(staffing.Week) && staffing.ConsultantId == consultantId) + .Include(s => s.Engagement) + .ThenInclude(p => p.Customer) + .Include(s => s.Engagement) + .ThenInclude(e => e.Agreements) + .ToList(); consultant.PlannedAbsences = _dbContext.PlannedAbsence .Where(absence => weeks.Contains(absence.Week) && absence.ConsultantId == consultantId) diff --git a/backend/Api/StaffingController/ReadModelFactory.cs b/backend/Api/StaffingController/ReadModelFactory.cs index 252f63c7..a88e7b38 100644 --- a/backend/Api/StaffingController/ReadModelFactory.cs +++ b/backend/Api/StaffingController/ReadModelFactory.cs @@ -101,7 +101,8 @@ private static List DetailedBookings(Consultant consultant, .Select(grouping => new DetailedBooking( new BookingDetails(grouping.First().Engagement.Name, BookingType.Booking, grouping.First().Engagement.Customer.Name, - grouping.Key, false, grouping.First().Engagement.IsBillable), + grouping.Key, false, grouping.First().Engagement.IsBillable, + grouping.First().Engagement.Agreements.Select(a => (DateTime?)a.EndDate).DefaultIfEmpty(null).Max()), weekSet.Select(week => new WeeklyHours( week.ToSortableInt(), grouping @@ -117,7 +118,8 @@ private static List DetailedBookings(Consultant consultant, .Select(grouping => new DetailedBooking( new BookingDetails(grouping.First().Engagement.Name, BookingType.Offer, grouping.First().Engagement.Customer.Name, - grouping.Key, false, grouping.First().Engagement.IsBillable), + grouping.Key, false, grouping.First().Engagement.IsBillable, + grouping.First().Engagement.Agreements.Select(a => (DateTime?)a.EndDate).DefaultIfEmpty(null).Max()), weekSet.Select(week => new WeeklyHours( week.ToSortableInt(), diff --git a/backend/Api/StaffingController/StaffingReadModel.cs b/backend/Api/StaffingController/StaffingReadModel.cs index 94f5d282..b0e60006 100644 --- a/backend/Api/StaffingController/StaffingReadModel.cs +++ b/backend/Api/StaffingController/StaffingReadModel.cs @@ -98,7 +98,8 @@ public record BookingDetails( [property: Required] string CustomerName, [property: Required] int ProjectId, [property: Required] bool ExcludeFromBilling = false, - [property: Required] bool IsBillable = false); + [property: Required] bool IsBillable = false, + DateTime? EndDateAgreement = null); public record WeeklyHours([property: Required] int Week, [property: Required] double Hours); diff --git a/backend/Infrastructure/Repositories/RepositoryExtensions.cs b/backend/Infrastructure/Repositories/RepositoryExtensions.cs index 72589cdd..c28558ee 100644 --- a/backend/Infrastructure/Repositories/RepositoryExtensions.cs +++ b/backend/Infrastructure/Repositories/RepositoryExtensions.cs @@ -27,7 +27,7 @@ public static void AddRepositories(this WebApplicationBuilder builder) builder.Services.Decorate(); builder.Services.AddScoped(); - builder.Services.Decorate(); + //builder.Services.Decorate(); builder.Services.AddScoped(); builder.Services.AddScoped(); diff --git a/backend/Infrastructure/Repositories/Staffings/StaffingDbRepository.cs b/backend/Infrastructure/Repositories/Staffings/StaffingDbRepository.cs index 6ac66d24..9f7654b2 100644 --- a/backend/Infrastructure/Repositories/Staffings/StaffingDbRepository.cs +++ b/backend/Infrastructure/Repositories/Staffings/StaffingDbRepository.cs @@ -16,6 +16,8 @@ public async Task>> GetStaffingForConsultants(Lis .Include(s => s.Consultant) .Include(staffing => staffing.Engagement) .ThenInclude(project => project.Customer) + .Include(staffing => staffing.Engagement) + .ThenInclude(project => project.Agreements) .GroupBy(staffing => staffing.Consultant.Id) .ToDictionaryAsync(group => group.Key, grouping => grouping.ToList(), ct); } diff --git a/frontend/src/api-types.ts b/frontend/src/api-types.ts index 77086d9f..0f02d598 100644 --- a/frontend/src/api-types.ts +++ b/frontend/src/api-types.ts @@ -30,6 +30,7 @@ export interface BookingDetails { /** @format int32 */ projectId: number; isBillable: boolean; + endDateAgreement?: string | null; } export enum BookingType { diff --git a/frontend/src/components/Staffing/ConsultantRow.tsx b/frontend/src/components/Staffing/ConsultantRow.tsx index 54001e6e..69736fa9 100644 --- a/frontend/src/components/Staffing/ConsultantRow.tsx +++ b/frontend/src/components/Staffing/ConsultantRow.tsx @@ -1,7 +1,7 @@ "use client"; import { ConsultantReadModel, ProjectWithCustomerModel } from "@/api-types"; import React, { useContext, useEffect, useState } from "react"; -import { ChevronDown, Plus } from "react-feather"; +import { AlertCircle, ChevronDown, Plus } from "react-feather"; import { DetailedBookingRows } from "@/components/Staffing/DetailedBookingRows"; import { WeekCell } from "@/components/Staffing/WeekCell"; import { useModal } from "@/hooks/useModal"; @@ -155,6 +155,28 @@ export default function ConsultantRows({ } } + function getAlert() { + const dates = consultant.detailedBooking + .filter((e) => e.bookingDetails.projectId > 0) + .map((e) => e.bookingDetails.endDateAgreement); + + if (dates.some((e) => e === null)) { + return ; + } else if (dates.length > 0) { + const newestDate = dates.reduce((a, b) => { + return new Date(a as string) < new Date(b as string) ? a : b; + }); + + const now = DateTime.now(); + const endDate = DateTime.fromISO(newestDate as string); + if (endDate < now) { + return ; + } else { + return null; + } + } + } + return ( <> -
+
+ {getAlert()}
{consultant.imageThumbUrl ? ( new Date(p.endDate).getTime()), - ); + const endDateString = detailedBooking.bookingDetails.endDateAgreement; + if (endDateString && endDateString !== null) { + const endDate = new Date(endDateString).getTime(); + const today = new Date().getTime(); if (today > endDate) { return setAlertColor(colors.find((c) => c.color == "orange")); @@ -127,7 +123,9 @@ export function DetailedBookingRows(props: { return setAlertColor(colors.find((c) => c.color == "green")); } } else { - return setAlertColor(colors.find((c) => c.color == "red")); + if (endDateString === null) { + return setAlertColor(colors.find((c) => c.color == "red")); + } } } @@ -138,7 +136,7 @@ export function DetailedBookingRows(props: { >
- {alert ? : } + {alert && }
{alert?.text}