Skip to content

Commit

Permalink
Added test and updated logic
Browse files Browse the repository at this point in the history
  • Loading branch information
Jonathanio123 committed Nov 5, 2024
1 parent 58b8c52 commit d531e17
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class SummaryReportsController : BaseController
{
[HttpGet("resource-owners-summary-reports/{sapDepartmentId}/weekly")]
[MapToApiVersion("1.0")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status202Accepted)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ODataFilter(nameof(ApiWeeklySummaryReport.Period))]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,44 +58,46 @@ public async Task RunAsync(

private async Task CreateAndStoreReportAsync(WeeklyTaskOwnerReportMessage message, CancellationToken cancellationToken)
{
var allProjectPositions = await orgApiClient.GetProjectPositions(message.OrgProjectExternalId.ToString(), cancellationToken);
var now = DateTime.UtcNow;
WeeklyTaskOwnerReportDataCreator.NowDate = now;
// Exclude Products
var allProjectPositions = (await orgApiClient.GetProjectPositions(message.OrgProjectExternalId.ToString(), cancellationToken))
.Where(p => p.BasePosition.ProjectType != "Product").ToArray();
var activeRequestsForProject = await resourcesApiClient.GetActiveRequestsForProjectAsync(message.OrgProjectExternalId, cancellationToken);
var admins = await ResolveAdminsAsync(message, cancellationToken);


// KPIs
var expiringAdmins = WeeklyTaskOwnerReportDataCreator.GetExpiringAdmins(admins);
var actionsAwaitingTaskOwner = WeeklyTaskOwnerReportDataCreator.GetActionsAwaitingTaskOwnerAsync(activeRequestsForProject);
var expiringPositions = WeeklyTaskOwnerReportDataCreator.GetPositionsEndingNextThreeMonths(allProjectPositions);
var tbnPositions = WeeklyTaskOwnerReportDataCreator.GetTBNPositionsStartingWithinThreeMonts(allProjectPositions);
var tbnPositions = WeeklyTaskOwnerReportDataCreator.GetTBNPositionsStartingWithinThreeMonts(allProjectPositions, activeRequestsForProject);

var now = DateTime.UtcNow;
var lastMonday = now.GetPreviousWeeksMondayDate();
var report = new ApiWeeklyTaskOwnerReport()
{
Id = Guid.Empty,
PeriodStart = now.GetPreviousWeeksMondayDate(),
PeriodEnd = now,
PeriodStart = lastMonday,
PeriodEnd = lastMonday.AddDays(7),
ProjectId = message.ProjectId,
ActionsAwaitingTaskOwnerAction = actionsAwaitingTaskOwner,
AdminAccessExpiringInLessThanThreeMonths = expiringAdmins.Select(ea => new ApiAdminAccessExpiring()
{
AzureUniqueId = ea.AzureUniqueId,
FullName = ea.FullName,
Expires = ea.ValidTo.DateTime
Expires = ea.ValidTo
}).ToArray(),
PositionAllocationsEndingInNextThreeMonths = expiringPositions.Select(ep => new ApiPositionAllocationEnding()
{
PositionName = ep.Position.BasePosition.Name ?? string.Empty,
PositionNameDetailed = ep.Position.Name,
PositionExternalId = ep.Position.ExternalId ?? string.Empty,
PositionAppliesTo = ep.ExpiresAt.DateTime
PositionAppliesTo = ep.ExpiresAt
}).ToArray(),
TBNPositionsStartingInLessThanThreeMonths = tbnPositions.Select(tp => new ApiTBNPositionStartingSoon()
{
PositionName = tp.Position.BasePosition.Name ?? string.Empty,
PositionNameDetailed = tp.Position.Name,
PositionExternalId = tp.Position.ExternalId ?? string.Empty,
PositionAppliesFrom = tp.StartsAt.DateTime
PositionAppliesFrom = tp.StartsAt
}).ToArray()
};

Expand Down Expand Up @@ -137,7 +139,7 @@ private async Task<List<PersonAdmin>> ResolveAdminsAsync(WeeklyTaskOwnerReportMe
if (projectAdmin.ValidTo == null)
continue;

admins.Add(new PersonAdmin(profile.AzureUniqueId.Value, profile.Name, projectAdmin.ValidTo.Value));
admins.Add(new PersonAdmin(profile.AzureUniqueId.Value, profile.Name, projectAdmin.ValidTo.Value.DateTime));
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.1.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,62 +8,103 @@ namespace Fusion.Summary.Functions.ReportCreator;

public abstract class WeeklyTaskOwnerReportDataCreator
{
public static List<TBNPosition> GetTBNPositionsStartingWithinThreeMonts(IEnumerable<ApiPositionV2> allProjectPositions)
public static DateTime NowDate { get; set; }

// Logic taken/inspired from the frontend
// https://github.com/equinor/fusion-resource-allocation-apps/blob/a9330b2aa8d104e51536692a72334252d5e474e1/apps/org-admin/src/pages/ProjectPage/components/ChartComponent/components/utils.ts#L28
public static List<TBNPosition> GetTBNPositionsStartingWithinThreeMonts(IEnumerable<ApiPositionV2> allProjectPositions,
ICollection<IResourcesApiClient.ResourceAllocationRequest> requests)
{
var nowDate = DateTimeOffset.UtcNow;
// Exclude Products
allProjectPositions = allProjectPositions.Where(p => p.BasePosition.ProjectType != "Product");
var nowDate = NowDate;

var tbnPositions = new List<TBNPosition>();

foreach (var position in allProjectPositions)
{
var startingInstance = position.Instances.MinBy(i => i.AppliesFrom);
if (startingInstance.AppliesFrom.Date >= nowDate.AddMonths(3).Date)
if (IsSupportPosition(position))
continue;

var isPositionActive = position.Instances.Any(i => i.AppliesFrom.Date <= nowDate.Date && i.AppliesTo.Date >= nowDate.Date);

if (isPositionActive)
continue;

var futureInstances = position.Instances.Where(i => i.AppliesFrom.Date >= nowDate.Date).ToList();

if (futureInstances.Count == 0)
continue;

var startingInstance = futureInstances.MinBy(i => i.AppliesFrom); // Get the instance starting soonest

if (startingInstance is null)
continue;

// TODO: In the fronted they dont show the warning if the instance has a resource allocation request
// I'm wondering if we should do the same here...
// If we don't do it here then it will be inconsistent with the frontend
var instanceHasPersonalRequest = requests.Any(r => r.OrgPositionInstance?.Id == startingInstance.Id);

if (instanceHasPersonalRequest)
continue;

if (startingInstance.AppliesFrom.Date < nowDate.AddMonths(3).Date && startingInstance.AssignedPerson is null)
tbnPositions.Add(new TBNPosition(position, startingInstance.AppliesFrom));
}

return tbnPositions;
}

public static List<ExpiringPosition> GetPositionsEndingNextThreeMonths(IEnumerable<ApiPositionV2> allProjectPositions)
// https://github.com/equinor/fusion-resource-allocation-apps/blob/0c8477f48021c594af20c0b1ba7b549b187e2e71/apps/org-admin/src/pages/ProjectPage/utils.ts#L86
private static bool IsSupportPosition(ApiPositionV2 position)
{
var nowDate = DateTimeOffset.UtcNow;
var supportNames = new[] { "support", "advisor", "assistance" };
return supportNames.Any(s => position.Name.Contains(s, StringComparison.OrdinalIgnoreCase));
}

// Exclude Products
allProjectPositions = allProjectPositions.Where(p => p.BasePosition.ProjectType != "Product");
public static List<ExpiringPosition> GetPositionsEndingNextThreeMonths(IEnumerable<ApiPositionV2> allProjectPositions)
{
var nowDate = NowDate;

var expiringPositions = new List<ExpiringPosition>();

foreach (var position in allProjectPositions)
{
var isPositionActiveNow = position.Instances.Any(i => i.AppliesFrom.Date <= nowDate.Date && i.AppliesTo.Date >= nowDate.Date);

if (!isPositionActiveNow)
continue;

var endingInstance = position.Instances.MaxBy(i => i.AppliesTo);
if (endingInstance.AppliesTo.Date <= nowDate.AddMonths(3).Date)

if (endingInstance is null)
continue;

if (endingInstance.AppliesTo.Date < nowDate.AddMonths(3).Date)
expiringPositions.Add(new ExpiringPosition(position, endingInstance.AppliesTo));
}


return expiringPositions;
}


// https://github.com/equinor/fusion-resource-allocation-apps/blob/0c8477f48021c594af20c0b1ba7b549b187e2e71/apps/org-admin/src/pages/ProjectPage/utils.ts#L53
public static int GetActionsAwaitingTaskOwnerAsync(IEnumerable<IResourcesApiClient.ResourceAllocationRequest> requests)
{
return requests
.Where(r => r.State is not null && !r.State.Equals("Completed", StringComparison.OrdinalIgnoreCase))
.Count(r => (r.HasProposedPerson && !r.State!.Equals("Created", StringComparison.OrdinalIgnoreCase) && !r.IsDraft) || r.Type == "ResourceOwnerChange");
}

public static List<PersonAdmin> GetExpiringAdmins(IEnumerable<PersonAdmin> admins)
public static List<PersonAdmin> GetExpiringAdmins(IEnumerable<PersonAdmin> activeAdmins)
{
var now = DateTimeOffset.UtcNow;
var now = NowDate;

return admins.Where(a => a.ValidTo <= now.AddMonths(3)).ToList();
return activeAdmins.Where(a => a.ValidTo <= now.AddMonths(3)).ToList();
}
}

public record PersonAdmin(Guid AzureUniqueId, string FullName, DateTimeOffset ValidTo);
public record PersonAdmin(Guid AzureUniqueId, string FullName, DateTime ValidTo);

public record ExpiringPosition(ApiPositionV2 Position, DateTimeOffset ExpiresAt);
public record ExpiringPosition(ApiPositionV2 Position, DateTime ExpiresAt);

public record TBNPosition(ApiPositionV2 Position, DateTimeOffset StartsAt);
public record TBNPosition(ApiPositionV2 Position, DateTime StartsAt);
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using FluentAssertions;
using Fusion.Summary.Functions.ReportCreator;

namespace Fusion.Summary.Functions.Tests.Notifications;

public class WeeklyTaskOwnerReportDataCreatorTests
{
[Fact]
public void ActiveAdmins_AreConsideredExpiring_IfValidToIsLessThanThreeMonths()
{
var now = DateTime.UtcNow;
WeeklyTaskOwnerReportDataCreator.NowDate = now;

var admins = new List<PersonAdmin>()
{
new PersonAdmin(Guid.NewGuid(), "", now.Add(TimeSpan.FromDays(1))), // Is expiring
new PersonAdmin(Guid.NewGuid(), "", now.Add(TimeSpan.FromDays(90))), // Is expiring
new PersonAdmin(Guid.NewGuid(), "", now.Add(TimeSpan.FromDays(120))), // Is not expiring
new PersonAdmin(Guid.NewGuid(), "", now.Add(TimeSpan.FromDays(365))) // Is not expiring
};

var data = WeeklyTaskOwnerReportDataCreator.GetExpiringAdmins(admins);

data.Should().HaveCount(2);
}


[Fact]
public void GetPositionsEndingNextThreeMonthsTest()
{
// throw new NotImplementedException();
}

[Fact]
public void GetTBNPositionsStartingWithinThreeMontsTests()
{
// throw new NotImplementedException();
}
}

0 comments on commit d531e17

Please sign in to comment.