Skip to content
Open
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
Expand Up @@ -4,4 +4,5 @@ public class ValidateUlnOverlapOnStartDateResponse
{
public long? HasOverlapWithApprenticeshipId { get; set; }
public bool HasStartDateOverlap { get; set; }
public bool HasOverlapWithIlrWithdrawnApprenticeship { get; set; }
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using SFA.DAS.CommitmentsV2.Api.Controllers;
using SFA.DAS.CommitmentsV2.Api.Types.Requests;
using SFA.DAS.CommitmentsV2.Application.Commands.ValidateDraftApprenticeshipDetails;
using Microsoft.AspNetCore.Mvc;
using SFA.DAS.CommitmentsV2.Api.Controllers;
using SFA.DAS.CommitmentsV2.Api.Types.Responses;
using SFA.DAS.CommitmentsV2.Application.Queries.GetOverlappingApprenticeshipDetails;
using SFA.DAS.CommitmentsV2.Shared.Interfaces;

Expand All @@ -19,10 +19,22 @@ public void Arrange()
[Test]
public async Task ValidateUlnOverlapOnStartDate_VerifyQuerySent()
{
await _fixture.ValidateUlnOverlapOnStartDate();
var response = await _fixture.ValidateUlnOverlapOnStartDate();
_fixture.VerifyQuerySent();
}

[Test]
[TestCase(true)]
[TestCase(false)]
public async Task ValidateUlnOverlapOnStartDate_HasOverlapWithIlrWithdrawnApprenticeship(bool HasOverlapWithIlrWithdrawnApprenticeship)
{
var response = await _fixture.withHasOverlapWithIlrWithdrawnApprenticeship(HasOverlapWithIlrWithdrawnApprenticeship).ValidateUlnOverlapOnStartDate();
var result = response.Value as ValidateUlnOverlapOnStartDateResponse;

result.Should().NotBeNull();
result.HasOverlapWithIlrWithdrawnApprenticeship.Should().Be(HasOverlapWithIlrWithdrawnApprenticeship);
}

private class ValidateUlnOverlapOnStartDateFixture
{
private readonly Mock<IMediator> _mediator;
Expand All @@ -33,6 +45,7 @@ private class ValidateUlnOverlapOnStartDateFixture
public string Uln;
public string StartDate;
public string EndDate;
private ValidateUlnOverlapOnStartDateQueryResult queryResult;

public ValidateUlnOverlapOnStartDateFixture()
{
Expand All @@ -44,17 +57,24 @@ public ValidateUlnOverlapOnStartDateFixture()
StartDate = "Jan 2022";
EndDate = "Dec 2022";

var queryResult = _autoFixture.Create<ValidateUlnOverlapOnStartDateQueryResult>();
queryResult = _autoFixture.Create<ValidateUlnOverlapOnStartDateQueryResult>();
_mediator
.Setup(x => x.Send(It.IsAny<ValidateUlnOverlapOnStartDateQuery>(), It.IsAny<CancellationToken>()))
.ReturnsAsync(queryResult);

_controller = new OverlappingTrainingDateRequestController(_mediator.Object, _mapper.Object);
}

public async Task ValidateUlnOverlapOnStartDate()
public async Task<OkObjectResult> ValidateUlnOverlapOnStartDate()
{
var response = await _controller.ValidateUlnOverlapOnStartDate(ProviderId, Uln, StartDate, EndDate) as OkObjectResult;
return response;
}

public ValidateUlnOverlapOnStartDateFixture withHasOverlapWithIlrWithdrawnApprenticeship(bool value)
{
await _controller.ValidateUlnOverlapOnStartDate(ProviderId, Uln, StartDate, EndDate);
queryResult.HasOverlapWithIlrWithdrawnApprenticeship = value;
return this;
}

public void VerifyQuerySent()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ public async Task<IActionResult> ValidateUlnOverlapOnStartDate(long providerId,
return Ok(new ValidateUlnOverlapOnStartDateResponse
{
HasOverlapWithApprenticeshipId = result.HasOverlapWithApprenticeshipId,
HasStartDateOverlap = result.HasStartDateOverlap
HasStartDateOverlap = result.HasStartDateOverlap,
HasOverlapWithIlrWithdrawnApprenticeship = result.HasOverlapWithIlrWithdrawnApprenticeship
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,43 @@ public async Task ThenIfStartDateFallsWithinRangeOfExistingApprenticeshipThenIsO
Assert.That(result.HasOverlappingStartDate, Is.True);
}

[Test]
public async Task WhenOverlappingApprenticeshipHasIlrWithdrawal_HasOverlapWithIlrWithdrawnApprenticeshipIsTrue()
{
var result = await _fixture
.WithDateRange(new DateTime(2018, 03, 15), new DateTime(2018, 05, 15))
.WithApprenticeshipWithdrawnReasonCode(1, 40)
.CheckForOverlapsOnStartDate();

result.HasOverlappingStartDate.Should().BeTrue();
result.ApprenticeshipId.Should().Be(1);
result.HasOverlapWithIlrWithdrawnApprenticeship.Should().BeTrue();
}

[Test]
public async Task WhenOverlappingApprenticeshipHasNoIlrWithdrawal_HasOverlapWithIlrWithdrawnApprenticeshipIsFalse()
{
var result = await _fixture
.WithDateRange(new DateTime(2018, 03, 15), new DateTime(2018, 05, 15))
.WithApprenticeshipWithdrawnReasonCode(1, null)
.CheckForOverlapsOnStartDate();

result.HasOverlapWithIlrWithdrawnApprenticeship.Should().BeFalse();
}

[Test]
public async Task WhenDifferentApprenticeshipOnUlnHasIlrWithdrawal_OverlappingRecordIsNotFlagged()
{
var result = await _fixture
.WithDateRange(new DateTime(2018, 03, 15), new DateTime(2018, 05, 15))
.WithApprenticeshipWithdrawnReasonCode(1, null)
.WithApprenticeshipWithdrawnReasonCode(2, 40)
.CheckForOverlapsOnStartDate();

result.ApprenticeshipId.Should().Be(1);
result.HasOverlapWithIlrWithdrawnApprenticeship.Should().BeFalse();
}

[Test]
public async Task ThenIfEndDateFallsWithinRangeOfExistingApprenticeshipThenIsOverlapping()
{
Expand Down Expand Up @@ -356,6 +393,22 @@ public OverlapCheckServiceTestFixture WithExistingApprenticeship()
return this;
}

public OverlapCheckServiceTestFixture WithApprenticeshipWithdrawnReasonCode(long id, int? withdrawnReasonCode)
{
var existing = _db.Apprenticeships.Local.FirstOrDefault(a => a.Id == id);
if (existing != null)
{
existing.WithdrawnReasonCode = withdrawnReasonCode;
}
else
{
_db.Apprenticeships.Add(new Apprenticeship { Id = id, WithdrawnReasonCode = withdrawnReasonCode });
}

_db.SaveChanges();
return this;
}

public OverlapCheckServiceTestFixture WithNoMatchingUlnUtilisations()
{
_ulnUtilisationService.Setup(x => x.GetUlnUtilisations(It.IsAny<string>(), It.IsAny<CancellationToken>()))
Expand Down Expand Up @@ -434,6 +487,11 @@ public async Task<OverlapCheckResult> CheckForOverlaps()
return await _overlapCheckService.CheckForOverlaps("", _startDate.To(_endDate, _isWithdrawn), _apprenticeshipId, new CancellationToken());
}

public async Task<OverlapCheckResultOnStartDate> CheckForOverlapsOnStartDate()
{
return await _overlapCheckService.CheckForOverlapsOnStartDate("", new SFA.DAS.CommitmentsV2.Domain.Entities.CourseDateRange(_startDate, _endDate), _apprenticeshipId, CancellationToken.None);
}

public async Task<EmailOverlapCheckResult> CheckForEmailOverlaps()
{
return await _overlapCheckService.CheckForEmailOverlaps(_email, _startDate.To(_endDate, _isWithdrawn), _apprenticeshipId, _cohortId, new CancellationToken());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public void WhenPartyIsProvider_AndApprenticeshipIdInvalid_ThrowException(
long apprenticeshipId
)
{
// arrange
// arrange
var draftApprenticeships = Fixture
.Build<DraftApprenticeship>()
.With(app => app.Id, Fixture.Create<Generator<long>>().Where(l => l != apprenticeshipId).First())
Expand Down Expand Up @@ -143,7 +143,7 @@ string uln
_overlapCheckServiceMock
.Setup(m => m.CheckForOverlapsOnStartDate(uln, It.IsAny<CourseDateRange>(),
apprenticeshipId, It.IsAny<CancellationToken>()))
.ReturnsAsync(new OverlapCheckResultOnStartDate(false, null));
.ReturnsAsync(new OverlapCheckResultOnStartDate(false, null, false));

// assert
Assert.ThrowsAsync<InvalidOperationException>(async () =>
Expand All @@ -166,13 +166,14 @@ string uln
var draftApprenticeships = GetDraftApprenticeshipTestData(apprenticeshipId, false);
draftApprenticeships[0].Id = apprenticeshipId;
draftApprenticeships[0].Uln = uln;
draftApprenticeships[0].PreviousApprenticeship.WithdrawnReasonCode = null;

_dbContext.Setup(db => db.DraftApprenticeships).ReturnsDbSet(draftApprenticeships);

_overlapCheckServiceMock
.Setup(m => m.CheckForOverlapsOnStartDate(uln, It.IsAny<CourseDateRange>(),
apprenticeshipId, It.IsAny<CancellationToken>()))
.ReturnsAsync(new OverlapCheckResultOnStartDate(true, previousApprenticeshipId));
.ReturnsAsync(new OverlapCheckResultOnStartDate(true, previousApprenticeshipId, false));

// act
var result = await _sut.CreateOverlappingTrainingDateRequest(apprenticeshipId, Party.Provider, null,
Expand All @@ -197,13 +198,14 @@ string uln
var draftApprenticeships = GetDraftApprenticeshipTestData(apprenticeshipId, false);
draftApprenticeships[0].Id = apprenticeshipId;
draftApprenticeships[0].Uln = uln;
draftApprenticeships[0].PreviousApprenticeship.WithdrawnReasonCode = null;

_dbContext.Setup(db => db.DraftApprenticeships).ReturnsDbSet(draftApprenticeships);

_overlapCheckServiceMock
.Setup(m => m.CheckForOverlapsOnStartDate(uln, It.IsAny<CourseDateRange>(),
apprenticeshipId, It.IsAny<CancellationToken>()))
.ReturnsAsync(new OverlapCheckResultOnStartDate(true, previousApprenticeshipId));
.ReturnsAsync(new OverlapCheckResultOnStartDate(true, previousApprenticeshipId, false));

// act
var result = await _sut.CreateOverlappingTrainingDateRequest(apprenticeshipId, Party.Provider, null,
Expand All @@ -213,6 +215,34 @@ string uln
_dbContext.Verify(db => db.SaveChangesAsync(It.IsAny<CancellationToken>()), Times.Once);
}

[Test, MoqAutoData]
public async Task WhenOverlapExists_OverlapRequestNotCreated_IfWithdrawnFromIlr(
Comment thread
cofaulco marked this conversation as resolved.
UserInfo userInfo,
long apprenticeshipId,
string uln
)
{
// arrange
var now = DateTime.UtcNow;
_currentDateTimeMock.Setup(m => m.UtcNow).Returns(now);

var draftApprenticeships = GetDraftApprenticeshipTestData(apprenticeshipId, false);
draftApprenticeships[0].Id = apprenticeshipId;
draftApprenticeships[0].Uln = uln;

_dbContext.Setup(db => db.DraftApprenticeships).ReturnsDbSet(draftApprenticeships);

_overlapCheckServiceMock
.Setup(m => m.CheckForOverlapsOnStartDate(uln, It.IsAny<CommitmentsV2.Domain.Entities.CourseDateRange>(),
apprenticeshipId, It.IsAny<CancellationToken>()))
.ReturnsAsync(new OverlapCheckResultOnStartDate(true, null, true));

// assert
Assert.ThrowsAsync<InvalidOperationException>(async () =>
await _sut.CreateOverlappingTrainingDateRequest(apprenticeshipId, Party.Provider, null, userInfo,
new CancellationToken()));
}

private List<DraftApprenticeship> GetDraftApprenticeshipTestData(long testApprenticeshipId,
bool isCohortApproved)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ public ResolveOverlappingTrainingDateRequestServiceTestsFixture()
_fixture = new Fixture();
UnitOfWorkContext = new UnitOfWorkContext();
_overlapCheckService = new Mock<IOverlapCheckService>();
_overlapCheckResultOnStartDate = new OverlapCheckResultOnStartDate(false, null);
_overlapCheckResultOnStartDate = new OverlapCheckResultOnStartDate(false, null,false);

_overlapCheckService.Setup(x => x.CheckForOverlapsOnStartDate(It.IsAny<string>(), It.IsAny<CourseDateRange>(), null, It.IsAny<CancellationToken>())).ReturnsAsync(() => _overlapCheckResultOnStartDate);

Expand All @@ -271,7 +271,7 @@ public ResolveOverlappingTrainingDateRequestServiceTestsFixture()

public ResolveOverlappingTrainingDateRequestServiceTestsFixture SetupOverlapCheckService(bool hasStartDateOverlap, long? apprneticeshipId)
{
_overlapCheckResultOnStartDate = new OverlapCheckResultOnStartDate(hasStartDateOverlap, apprneticeshipId);
_overlapCheckResultOnStartDate = new OverlapCheckResultOnStartDate(hasStartDateOverlap, apprneticeshipId,false);
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ public async Task<ValidateUlnOverlapOnStartDateQueryResult> Handle(ValidateUlnOv

var apprenticeshipWithOverlap = await overlapCheckService.CheckForOverlapsOnStartDate(request.Uln, new Domain.Entities.CourseDateRange(startDate, endDate), null, cancellationToken);

var result = new ValidateUlnOverlapOnStartDateQueryResult { HasStartDateOverlap = apprenticeshipWithOverlap.HasOverlappingStartDate, HasOverlapWithApprenticeshipId = apprenticeshipWithOverlap.ApprenticeshipId };
var result = new ValidateUlnOverlapOnStartDateQueryResult
{
HasStartDateOverlap = apprenticeshipWithOverlap.HasOverlappingStartDate,
HasOverlapWithApprenticeshipId = apprenticeshipWithOverlap.ApprenticeshipId,
HasOverlapWithIlrWithdrawnApprenticeship = apprenticeshipWithOverlap.HasOverlapWithIlrWithdrawnApprenticeship
};

return await Task.FromResult(result);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ public class ValidateUlnOverlapOnStartDateQueryResult
{
public long? HasOverlapWithApprenticeshipId { get; set; }
public bool HasStartDateOverlap { get; set; }
public bool HasOverlapWithIlrWithdrawnApprenticeship { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

public class OverlapCheckResultOnStartDate
{
public OverlapCheckResultOnStartDate(bool hasOverlappingStartDate, long? apprenticeshipId)
public OverlapCheckResultOnStartDate(bool hasOverlappingStartDate, long? apprenticeshipId, bool hasOverlapWithIlrWithdrawnApprenticeship)
{
HasOverlappingStartDate = hasOverlappingStartDate;
ApprenticeshipId = apprenticeshipId;
HasOverlapWithIlrWithdrawnApprenticeship = hasOverlapWithIlrWithdrawnApprenticeship;
}

public bool HasOverlappingStartDate { get; }
public long? ApprenticeshipId { get; }
public bool HasOverlapWithIlrWithdrawnApprenticeship { get; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ public async Task<OverlapCheckResult> CheckForOverlaps(string uln, CourseDateRan
case OverlapStatus.OverlappingStartDate:
overlapStartDate = true;
break;

case OverlapStatus.OverlappingEndDate:
overlapEndDate = true;
break;

case OverlapStatus.DateWithin:
case OverlapStatus.DateEmbrace:
overlapStartDate = true;
Expand All @@ -45,7 +47,9 @@ public async Task<OverlapCheckResultOnStartDate> CheckForOverlapsOnStartDate(str
var overlapStartDate = false;
long? apprenticeshipId = null;

foreach (var utilisation in await GetCandidateUlnUtilisations(uln, existingApprenticeshipId, cancellationToken))
var utilisations = await GetCandidateUlnUtilisations(uln, existingApprenticeshipId, cancellationToken);

foreach (var utilisation in utilisations)
{
var overlapStatus = utilisation.DateRange.DetermineOverlap(range);

Expand All @@ -66,7 +70,7 @@ public async Task<OverlapCheckResultOnStartDate> CheckForOverlapsOnStartDate(str
}
}

return new OverlapCheckResultOnStartDate(overlapStartDate, apprenticeshipId);
return new OverlapCheckResultOnStartDate(overlapStartDate, apprenticeshipId, await IsOverlapWithIlrWithdrawnApprenticeship(apprenticeshipId));
}

private async Task<IEnumerable<UlnUtilisation>> GetCandidateUlnUtilisations(string uln, long? existingApprenticeshipId, CancellationToken cancellationToken)
Expand Down Expand Up @@ -94,9 +98,9 @@ public async Task<List<EmailOverlapCheckResult>> CheckForEmailOverlaps(long coho
var overlappingEmails = await emailOverlapService.GetOverlappingEmails(cohortId, cancellationToken);

var singleEmails = from overlap in overlappingEmails
group overlap by overlap.RowId
group overlap by overlap.RowId
into groups
select groups.OrderBy(e => e.RowId).First();
select groups.OrderBy(e => e.RowId).First();

var summary = singleEmails.Select(x => new EmailOverlapCheckResult(x.RowId, x.OverlapStatus, x.IsApproved));

Expand Down Expand Up @@ -125,4 +129,15 @@ public async Task<List<OverlapCheckResult>> CheckForOverlaps(long cohortId, Canc

return overlapCheckResult.ToList();
}

private async Task<bool> IsOverlapWithIlrWithdrawnApprenticeship(long? apprenticeshipId)
{
if (!apprenticeshipId.HasValue)
{
return false;
}

return await dbContext.Value.Apprenticeships.AsNoTracking()
.AnyAsync(x => x.Id == apprenticeshipId.Value && x.WithdrawnReasonCode.HasValue);
}
}
Loading
Loading