Skip to content

APPMAN-1314 display max funding on edit apprenticeship page #1868

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Threading;
using System;
using System.Threading;
using System.Threading.Tasks;
using AutoFixture;
using KellermanSoftware.CompareNetObjects;
Expand All @@ -22,6 +23,7 @@ public class WhenGettingAddDraftApprenticeshipDetails

private long _cohortId;
private string _courseCode;
private DateTime? _startDate;

[SetUp]
public void Setup()
Expand All @@ -30,11 +32,13 @@ public void Setup()
_queryResult = fixture.Create<GetAddDraftApprenticeshipDetailsQueryResult>();

_cohortId = fixture.Create<long>();
_startDate = fixture.Create<DateTime?>();

_mediator = new Mock<IMediator>();
_mediator.Setup(x => x.Send(It.Is<GetAddDraftApprenticeshipDetailsQuery>(q =>
q.CohortId == _cohortId
&& q.CourseCode == _courseCode),
&& q.CourseCode == _courseCode
&& q.StartDate == _startDate),
It.IsAny<CancellationToken>()))
.ReturnsAsync(_queryResult);

Expand All @@ -44,7 +48,7 @@ public void Setup()
[Test]
public async Task AddDraftApprenticeshipDetailsResponseIsReturned()
{
var result = await _controller.GetAddDraftApprenticeshipDetails(_cohortId, _courseCode);
var result = await _controller.GetAddDraftApprenticeshipDetails(_cohortId, _courseCode, _startDate);

Assert.That(result, Is.InstanceOf<OkObjectResult>());
var okObjectResult = (OkObjectResult) result;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using AutoFixture.NUnit3;
using FluentAssertions;
using MediatR;
using Microsoft.AspNetCore.Mvc;
using Moq;
using NUnit.Framework;
using SFA.DAS.Approvals.Api.Controllers;
using SFA.DAS.Approvals.Application.Courses.Queries;
using SFA.DAS.Testing.AutoFixture;

namespace SFA.DAS.Approvals.Api.UnitTests.Controllers.TrainingCourses
{
public class WhenGettingCourseFundingBandDetails
{
[Test, MoqAutoData]
public async Task Then_Gets_FundingBand_From_Mediator(
string courseCode,
DateTime startDate,
GetFundingBandResult mediatorResult,
[Frozen] Mock<IMediator> mockMediator,
[Greedy] TrainingCoursesController controller)
{
mockMediator
.Setup(mediator => mediator.Send(
It.Is<GetFundingBandQuery>(x => x.CourseCode == courseCode && x.StartDate == startDate),
It.IsAny<CancellationToken>()))
.ReturnsAsync(mediatorResult);

var controllerResult = await controller.GetFundingBand(courseCode, startDate) as ObjectResult;

Assert.That(controllerResult, Is.Not.Null);
controllerResult.StatusCode.Should().Be((int)HttpStatusCode.OK);
var model = controllerResult.Value as GetFundingBandResult;
model.Should().NotBeNull();
model.Should().BeEquivalentTo(mediatorResult);
}

[Test, MoqAutoData]
public async Task And_Then_No_FundingBand_Is_Returned_From_Mediator(
string courseCode,
DateTime startDate,
[Frozen] Mock<IMediator> mockMediator,
[Greedy] TrainingCoursesController controller)
{
mockMediator
.Setup(mediator => mediator.Send(
It.Is<GetFundingBandQuery>(x => x.CourseCode == courseCode && x.StartDate == startDate),
It.IsAny<CancellationToken>()))
.ReturnsAsync((GetFundingBandResult)null);

var controllerResult = await controller.GetFundingBand(courseCode, startDate) as NotFoundResult;

controllerResult.StatusCode.Should().Be((int)HttpStatusCode.NotFound);
}

[Test, MoqAutoData]
public async Task And_Exception_Then_Returns_InternalServerError(
string courseCode,
DateTime startDate,
[Frozen] Mock<IMediator> mockMediator,
[Greedy] TrainingCoursesController controller)
{
mockMediator
.Setup(mediator => mediator.Send(
It.IsAny<GetFundingBandQuery>(),
It.IsAny<CancellationToken>()))
.Throws<InvalidOperationException>();

var controllerResult = await controller.GetFundingBand(courseCode, startDate) as StatusCodeResult;

controllerResult.StatusCode.Should().Be((int)HttpStatusCode.InternalServerError);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,12 @@ public async Task<IActionResult> Details(long cohortId, [FromBody] DetailsPostRe
[HttpGet]
[Route("employer/{accountId}/unapproved/add/apprenticeship")]
[Route("provider/{providerId}/unapproved/add/apprenticeship")]
public async Task<IActionResult> GetAddDraftApprenticeshipDetails([FromQuery] long accountLegalEntityId, [FromQuery] long? providerId, [FromQuery] string courseCode)
public async Task<IActionResult> GetAddDraftApprenticeshipDetails([FromQuery] long accountLegalEntityId, [FromQuery] long? providerId, [FromQuery] string courseCode, [FromQuery] DateTime? startDate)
{
try
{
var result = await mediator.Send(new GetAddDraftApprenticeshipDetailsQuery
{ ProviderId = providerId, AccountLegalEntityId = accountLegalEntityId, CourseCode = courseCode });
{ ProviderId = providerId, AccountLegalEntityId = accountLegalEntityId, CourseCode = courseCode, StartDate = startDate });

if (result == null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,11 @@ public async Task<IActionResult> GetEditDraftApprenticeshipCourse(long cohortId,
[HttpGet]
[Route("employer/{accountId}/unapproved/{cohortId}/apprentices/add/details")]
[Route("provider/{providerId}/unapproved/{cohortId}/apprentices/add/details")]
public async Task<IActionResult> GetAddDraftApprenticeshipDetails(long cohortId, [FromQuery] string courseCode)
public async Task<IActionResult> GetAddDraftApprenticeshipDetails(long cohortId, [FromQuery] string courseCode, [FromQuery] DateTime? startDate)
{
try
{
var result = await _mediator.Send(new GetAddDraftApprenticeshipDetailsQuery { CohortId = cohortId, CourseCode = courseCode });
var result = await _mediator.Send(new GetAddDraftApprenticeshipDetailsQuery { CohortId = cohortId, CourseCode = courseCode, StartDate = startDate });

if (result == null)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
using System;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using MediatR;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using SFA.DAS.Approvals.Api.Models;
using SFA.DAS.Approvals.Application.Courses.Queries;
using SFA.DAS.Approvals.Application.TrainingCourses.Queries;

namespace SFA.DAS.Approvals.Api.Controllers
Expand Down Expand Up @@ -90,5 +92,27 @@ public async Task<IActionResult> GetStandard(string courseCode)
return BadRequest();
}
}

[HttpGet]
[Route("{courseCode}/funding-band")]
public async Task<IActionResult> GetFundingBand(string courseCode, [FromQuery] DateTime? startDate)
{
try
{
_logger.LogInformation("Getting Funding Band details for course {courseId} with start date of {startDate}", courseCode, startDate);
var result = await _mediator.Send(new GetFundingBandQuery { CourseCode = courseCode, StartDate = startDate });
if (result == null)
{
return NotFound();
}

return Ok(result);
}
catch (Exception e)
{
_logger.LogError(e, "Error gettingFunding Band details {courseId}", courseCode);
return new StatusCodeResult((int)HttpStatusCode.InternalServerError);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,18 @@ public class GetAddDraftApprenticeshipDetailsResponse
public string LegalEntityName { get; set; }
public string ProviderName { get; set; }
public bool HasMultipleDeliveryModelOptions { get; set; }
public string StandardPageUrl { get; set; }
public int? ProposedMaxFunding { get; set; }

public static implicit operator GetAddDraftApprenticeshipDetailsResponse(GetAddDraftApprenticeshipDetailsQueryResult source)
{
return new GetAddDraftApprenticeshipDetailsResponse
{
LegalEntityName = source.LegalEntityName,
ProviderName = source.ProviderName,
HasMultipleDeliveryModelOptions = source.HasMultipleDeliveryModelOptions
HasMultipleDeliveryModelOptions = source.HasMultipleDeliveryModelOptions,
StandardPageUrl = source.StandardPageUrl,
ProposedMaxFunding = source.ProposedMaxFunding
};
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ public class GetAddDraftApprenticeshipDetailsResponse
public string LegalEntityName { get; set; }
public string ProviderName { get; set; }
public bool HasMultipleDeliveryModelOptions { get; set; }
public bool IsFundedByTransfer { get; set; }
public long? TransferSenderId { get; set; }
public string StandardPageUrl { get; set; }
public int? ProposedMaxFunding { get; set; }

public static implicit operator GetAddDraftApprenticeshipDetailsResponse(GetAddDraftApprenticeshipDetailsQueryResult source)
{
Expand All @@ -16,7 +20,11 @@ public static implicit operator GetAddDraftApprenticeshipDetailsResponse(GetAddD
AccountLegalEntityId = source.AccountLegalEntityId,
LegalEntityName = source.LegalEntityName,
ProviderName = source.ProviderName,
HasMultipleDeliveryModelOptions = source.HasMultipleDeliveryModelOptions
HasMultipleDeliveryModelOptions = source.HasMultipleDeliveryModelOptions,
IsFundedByTransfer = source.IsFundedByTransfer,
TransferSenderId = source.TransferSenderId,
StandardPageUrl = source.StandardPageUrl,
ProposedMaxFunding = source.ProposedMaxFunding
};
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ public class GetEditDraftApprenticeshipResponse
public int? TrainingTotalHours { get; set; }
public int? DurationReducedByHours { get; set; }
public bool? IsDurationReducedByRpl { get; set; }

public string StandardPageUrl { get; set; }
public int? ProposedMaxFunding { get; set; }

public static implicit operator GetEditDraftApprenticeshipResponse(GetEditDraftApprenticeshipQueryResult source)
{
Expand Down Expand Up @@ -101,7 +102,9 @@ public static implicit operator GetEditDraftApprenticeshipResponse(GetEditDraftA
EmailAddressConfirmed = source.EmailAddressConfirmed,
TrainingTotalHours = source.TrainingTotalHours,
DurationReducedByHours = source.DurationReducedByHours,
IsDurationReducedByRpl = source.IsDurationReducedByRpl
IsDurationReducedByRpl = source.IsDurationReducedByRpl,
StandardPageUrl = source.StandardPageUrl,
ProposedMaxFunding = source.ProposedMaxFunding
};
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
using System.Collections.Generic;
using System;
using System.Threading;
using System.Threading.Tasks;
using AutoFixture;
using FluentAssertions;
using Moq;
using NUnit.Framework;
using SFA.DAS.Approvals.Application.Courses.Queries;
using SFA.DAS.Approvals.InnerApi.CommitmentsV2Api.Requests.Courses;
using SFA.DAS.Approvals.InnerApi.CommitmentsV2Api.Responses;
using SFA.DAS.SharedOuterApi.Configuration;
using SFA.DAS.SharedOuterApi.Interfaces;

namespace SFA.DAS.Approvals.UnitTests.Application.Apprentices.Queries;

[TestFixture]
public class GetFundingBandQueryHandlerTests
{
private GetFundingBandQueryHandler _handler;
private Mock<ICommitmentsV2ApiClient<CommitmentsV2ApiConfiguration>> _apiClient;

private GetTrainingProgrammeResponse _trainingProgrammeResponse;
private GetFundingBandQuery _query;

[SetUp]
public void Setup()
{
var fixture = new Fixture();

_query = fixture.Create<GetFundingBandQuery>();
_trainingProgrammeResponse = new GetTrainingProgrammeResponse();
_trainingProgrammeResponse.TrainingProgramme = new TrainingProgramme
{
CourseCode = _query.CourseCode,
StandardUId = "XXXX",
StandardPageUrl = "https://test123",
FundingPeriods = new List<TrainingProgrammeFundingPeriod>()
{
new TrainingProgrammeFundingPeriod
{EffectiveFrom = DateTime.MinValue, EffectiveTo = DateTime.MaxValue, FundingCap = 1234}
}
};

_apiClient = new Mock<ICommitmentsV2ApiClient<CommitmentsV2ApiConfiguration>>();

_apiClient.Setup(x =>
x.Get<GetTrainingProgrammeResponse>(It.Is<GetCalculatedVersionOfTrainingProgrammeRequest>(r =>
r.CourseCode == _query.CourseCode && r.StartDate == _query.StartDate.Value)))
.ReturnsAsync(_trainingProgrammeResponse);

_handler = new GetFundingBandQueryHandler(_apiClient.Object);
}

[Test]
public async Task Handle_Returns_FundingInfo_From_Commitments_Api()
{
var result = await _handler.Handle(_query, CancellationToken.None);
result.StandardPageUrl.Should().Be(_trainingProgrammeResponse.TrainingProgramme.StandardPageUrl);
result.Version.Should().Be(_trainingProgrammeResponse.TrainingProgramme.Version);
}

[Test]
public async Task Handle_Returns_null_if_FundingInfo_not_found()
{
_apiClient.Setup(x =>
x.Get<GetTrainingProgrammeResponse>(It.Is<GetCalculatedVersionOfTrainingProgrammeRequest>(r =>
r.CourseCode == _query.CourseCode && r.StartDate == _query.StartDate.Value)))
.ReturnsAsync((GetTrainingProgrammeResponse) null);

var result = await _handler.Handle(_query, CancellationToken.None);
Assert.That(result, Is.Null);
}
}

Loading