Skip to content

Commit

Permalink
Merge pull request #549 from DFE-Digital/feature/173374-add-transfer-…
Browse files Browse the repository at this point in the history
…in-projectgroup

Added transfers by outgoing trust ukprn endpoint
  • Loading branch information
mshakirdfe authored Aug 16, 2024
2 parents e95d87e + d39a5fd commit cbdd0a8
Show file tree
Hide file tree
Showing 32 changed files with 3,036 additions and 309 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace Dfe.Academies.Academisation.Data.Migrations
{
/// <inheritdoc />
public partial class AddProjectGroupIdInTransferProject : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "ProjectGroupId",
schema: "academisation",
table: "TransferProject",
type: "int",
nullable: true);
}

/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "ProjectGroupId",
schema: "academisation",
table: "TransferProject");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -916,6 +916,9 @@ protected override void BuildModel(ModelBuilder modelBuilder)
b.Property<DateTime?>("PreviousAdvisoryBoardDate")
.HasColumnType("datetime2");

b.Property<int?>("ProjectGroupId")
.HasColumnType("int");

b.Property<string>("ProjectRationale")
.HasColumnType("nvarchar(max)");

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using Dfe.Academies.Academisation.Domain.SeedWork;
using Dfe.Academies.Academisation.Domain.TransferProjectAggregate;
using Dfe.Academies.Academisation.Domain.TransferProjectAggregate;
using Dfe.Academies.Academisation.IDomain.TransferProjectAggregate;
using Microsoft.EntityFrameworkCore;

Expand All @@ -19,6 +19,14 @@ public TransferProjectRepository(AcademisationContext context) : base(context)
{
return await DefaultIncludes().SingleOrDefaultAsync(x => x.Urn == urn);
}

public async Task<IEnumerable<ITransferProject>> GetTransfersProjectsForGroup(string ukprn, CancellationToken cancellationToken)
=> await DefaultIncludes().Where(x => x.TransferringAcademies.Any(a => a.IncomingTrustUkprn == ukprn)
&& x.Status == null && x.ProjectGroupId == null).ToListAsync(cancellationToken);
public async Task<IEnumerable<ITransferProject>> GetTransferProjectsByIdsAsync(List<int> ids, CancellationToken cancellationToken)
=> await DefaultIncludes()
.Where(x => ids.Contains(x.Id) && x.ProjectGroupId == null).ToListAsync(cancellationToken);

public async Task<(IEnumerable<ITransferProject>, int totalcount)> SearchProjects(IEnumerable<string>? states, string? title, IEnumerable<string>? deliveryOfficers, int page, int count)
{
IQueryable<TransferProject> queryable = DefaultIncludes();
Expand Down Expand Up @@ -103,6 +111,9 @@ private static IQueryable<TransferProject> FilterByStatus(IEnumerable<string>? s
return await DefaultIncludes().ToListAsync();
}

public async Task<IEnumerable<ITransferProject>> GetProjectsByProjectGroupIdAsync(int? projectGroupId, CancellationToken cancellationToken)
=> await dbSet.Where(x => x.ProjectGroupId == projectGroupId).ToListAsync(cancellationToken);

private IQueryable<TransferProject> DefaultIncludes()
{
var x = this.dbSet
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ public void CreateTransferProject_WithNullOutgoingTrustUkprn_ThrowsArgumentNullE

// Act
Assert.Throws<ArgumentNullException>(() => TransferProject.Create(
null,
null!,
outgoingTrustName,
academies,
isFormAMat,
Expand Down Expand Up @@ -456,15 +456,15 @@ public class CreationArgumentExceptionTestData : IEnumerable<object[]>

public IEnumerator<object[]> GetEnumerator()
{
yield return new object[] { null, "out trust", _transferringAcademies, false, DateTime.Now, typeof(ArgumentNullException) };
yield return new object[] { null!, "out trust", _transferringAcademies, false, DateTime.Now, typeof(ArgumentNullException) };
yield return new object[] { string.Empty, "out trust", _transferringAcademies, false, DateTime.Now, typeof(ArgumentException) };

yield return new object[] { "11112222", "out trust", null, false, DateTime.Now, typeof(ArgumentNullException) };
yield return new object[] { "11112222", "out trust", null!, false, DateTime.Now, typeof(ArgumentNullException) };
yield return new object[] { "11112222", "out trust", new List<TransferringAcademy>(), false, DateTime.Now, typeof(ArgumentException) };

yield return new object[] { "11112222", "out trust", _transferringAcademies, false, DateTime.MinValue, typeof(ArgumentOutOfRangeException) };
yield return new object[] { "11112222", "out trust", _transferringAcademies, false, DateTime.MaxValue, typeof(ArgumentOutOfRangeException) };
yield return new object[] { "11112222", "out trust", _transferringAcademies, false, null, typeof(ArgumentOutOfRangeException) };
yield return new object[] { "11112222", "out trust", _transferringAcademies, false, null!, typeof(ArgumentOutOfRangeException) };
}

IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ public interface ITransferProjectRepository : IRepository<TransferProject>, IGen
public Task<ITransferProject?> GetByUrn(int urn);
public Task<IEnumerable<ITransferProject?>> GetAllTransferProjects();
public Task<IEnumerable<ITransferProject?>> GetIncompleteProjects();
Task<IEnumerable<ITransferProject>> GetTransfersProjectsForGroup(string ukprn, CancellationToken cancellationToken);
Task<IEnumerable<ITransferProject>> GetTransferProjectsByIdsAsync(List<int> ids, CancellationToken cancellationToken);
Task<(IEnumerable<ITransferProject>, int totalcount)> SearchProjects(IEnumerable<string>? states, string? title, IEnumerable<string>? deliveryOfficers, int page, int count);
Task<IEnumerable<ITransferProject>> GetProjectsByProjectGroupIdAsync(int? projectGroupId, CancellationToken cancellationToken);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ protected TransferProject() { }
public string? AssignedUserFullName { get; private set; }
public string? AssignedUserEmailAddress { get; private set; }
public Guid? AssignedUserId { get; private set; }
public bool? IsFormAMat { get; private set; }
public bool? IsFormAMat { get; set; }
public int? ProjectGroupId { get; private set; }

public DateTime? DeletedAt { get; set; }

Expand Down Expand Up @@ -119,6 +120,16 @@ public void SetRationale(string projectRationale, string trustSponsorRationale,
RationaleSectionIsCompleted = isCompleted;
}

public void SetProjectGroupId(int? projectGroupId)
{
ProjectGroupId = projectGroupId;
}

public void SetId(int id)
{
Id = id;
}

public void SetGeneralInformation(string recommendation, string author)
{
Recommendation = recommendation;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,7 @@ public interface ITransferProject
void SetTransferringAcademyGeneralInformation(string transferringAcademyUkprn, string pfiScheme, string pfiSchemeDetails, string distanceFromAcademyToTrustHq, string distanceFromAcademyToTrustHqDetails, string viabilityIssues, string financialDeficit, string mpNameAndParty, string publishedAdmissionNumber);
void SetAcademyReferenceData(string outgoingAcademyUkprn, string name, string localAuthorityName);
void SetDeletedAt();
void SetProjectGroupId(int? projectGroupId);
void SetId(int id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public interface ITransferringAcademy
string? DistanceFromAcademyToTrustHq { get; }
string? DistanceFromAcademyToTrustHqDetails { get; }
string? PublishedAdmissionNumber { get; }
string? Region { get; }
string? LocalAuthority { get; }

void SetSchoolAdditionalData(string latestOfstedReportAdditionalInformation, string pupilNumbersAdditionalInformation, string keyStage2PerformanceAdditionalInformation, string keyStage4PerformanceAdditionalInformation, string keyStage5PerformanceAdditionalInformation);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public interface ITransferProjectQueryService
{
Task<AcademyTransferProjectResponse?> GetByUrn(int Urn);
Task<AcademyTransferProjectResponse?> GetById(int id);
Task<IEnumerable<AcademyTransferProjectSummaryResponse>?> GetTransfersProjectsForGroup(string ukprn, CancellationToken cancellationToken);
Task<PagedResultResponse<AcademyTransferProjectSummaryResponse>> GetTransferProjects(int page, int count, int? urn,
string title);
Task<PagedDataResponse<AcademyTransferProjectSummaryResponse>?> GetProjects(IEnumerable<string>? states, string? title, IEnumerable<string>? deliveryOfficers, int page, int count);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Dfe.Academies.Academisation.IService.ServiceModels.Legacy.ProjectAggregate;
using Dfe.Academies.Academisation.IService.ServiceModels.TransferProject;

namespace Dfe.Academies.Academisation.IService.ServiceModels.ProjectGroup
{
Expand All @@ -14,5 +15,7 @@ public class ProjectGroupResponseModel(int id, string referenceNumber, string tr
public User AssignedUser { get; init; } = assignedUser;

public List<ConversionProjectServiceModel> Projects { get; init; } = projects;

public List<AcademyTransferProjectResponse>? Transfers { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
using Dfe.Academies.Academisation.Domain.ProjectAggregate;
using Dfe.Academies.Academisation.Domain.ProjectGroupsAggregate;
using Dfe.Academies.Academisation.Domain.SeedWork;
using Dfe.Academies.Academisation.Domain.TransferProjectAggregate;
using Dfe.Academies.Academisation.IDomain.TransferProjectAggregate;
using Dfe.Academies.Academisation.IService.ServiceModels.ProjectGroup;
using Dfe.Academies.Academisation.Service.Commands.ProjectGroup;
using Microsoft.Extensions.Logging;
Expand All @@ -19,7 +21,7 @@ public class CreateProjectGroupCommandHandlerTests

private Mock<IProjectGroupRepository> _mockProjectGroupRepository;
private Mock<IConversionProjectRepository> _mockConversionProjectRepository;

private Mock<ITransferProjectRepository> _mockTransferProjectRepository;
private Mock<IDateTimeProvider> _mockDateTimeProvider;
private Mock<ILogger<CreateProjectGroupCommandHandler>> _mocklogger;
private readonly Fixture _fixture = new();
Expand All @@ -28,7 +30,7 @@ public class CreateProjectGroupCommandHandlerTests
public CreateProjectGroupCommandHandlerTests()
{
_mockRepository = new MockRepository(MockBehavior.Strict);

_mockTransferProjectRepository = _mockRepository.Create<ITransferProjectRepository>();
_mockProjectGroupRepository = _mockRepository.Create<IProjectGroupRepository>();
_mockDateTimeProvider = _mockRepository.Create<IDateTimeProvider>();
_mockConversionProjectRepository = _mockRepository.Create<IConversionProjectRepository>();
Expand All @@ -37,6 +39,7 @@ public CreateProjectGroupCommandHandlerTests()
var mockContext = new Mock<IUnitOfWork>();
_mockProjectGroupRepository.Setup(x => x.UnitOfWork).Returns(mockContext.Object);
_mockConversionProjectRepository.Setup(x => x.UnitOfWork).Returns(mockContext.Object);
_mockTransferProjectRepository.Setup(x => x.UnitOfWork).Returns(mockContext.Object);
}

private CreateProjectGroupCommandHandler CreateProjectGroupCommandHandler()
Expand All @@ -45,19 +48,20 @@ private CreateProjectGroupCommandHandler CreateProjectGroupCommandHandler()
_mockProjectGroupRepository.Object,
_mockDateTimeProvider.Object,
_mockConversionProjectRepository.Object,
_mocklogger.Object);
_mocklogger.Object,
_mockTransferProjectRepository.Object);
}

[Fact]
public async Task Handle_ValidCommandWithoutConversions_PersistsExpectedProjectGroup()
public async Task Handle_ValidCommandWithoutConversionsAndTransfers_PersistsExpectedProjectGroup()
{
// Arrange
var now = DateTime.Now;
var expectedProjects = _fixture.Create<List<Project>>()[..0];
_mockDateTimeProvider.Setup(x => x.Now).Returns(now);
_mockProjectGroupRepository.Setup(x => x.Insert(It.IsAny<Domain.ProjectGroupsAggregate.ProjectGroup>()));
var createTransferProjectCommandHandler = CreateProjectGroupCommandHandler();
var request = CreateValidCreateProjectProjectCommand(false);
var request = CreateValidCreateProjectProjectCommand(false, false);
var expectedProjectGroupReference = "GRP_00000000";

// Act
Expand All @@ -83,23 +87,26 @@ public async Task Handle_ValidCommandWithoutConversions_PersistsExpectedProjectG
}

[Fact]
public async Task Handle_ValidCommandWithConversions_PersistsExpectedProjectGroup()
public async Task Handle_ValidCommandWithConversionsAndTransfer_PersistsExpectedProjectGroup()
{
// Arrange
var now = DateTime.Now;
_mockDateTimeProvider.Setup(x => x.Now).Returns(now);
var createTransferProjectCommandHandler = CreateProjectGroupCommandHandler();
var request = CreateValidCreateProjectProjectCommand();
var cancellationToken = CancellationToken.None;
var expectedTransferProject = GetTransferProject(request.TrustUkprn);
_mockProjectGroupRepository.Setup(x => x.Insert(It.IsAny<Domain.ProjectGroupsAggregate.ProjectGroup>()));
var expectedProjects = _fixture.Create<List<Project>>();
_mockConversionProjectRepository.Setup(x => x.GetConversionProjectsByProjectIds(request.ConversionProjectIds, It.Is<CancellationToken>(x => x == cancellationToken))).ReturnsAsync(expectedProjects);
_mockConversionProjectRepository.Setup(x => x.GetConversionProjectsByProjectIds(request.ConversionProjectIds, It.Is<CancellationToken>(x => x == _cancellationToken))).ReturnsAsync(expectedProjects);
_mockConversionProjectRepository.Setup(x => x.Update(It.IsAny<Project>()));
_mockTransferProjectRepository.Setup(x => x.GetTransferProjectsByIdsAsync(request.TransferProjectIds!, _cancellationToken))
.ReturnsAsync([expectedTransferProject]);
_mockTransferProjectRepository.Setup(x => x.Update(It.IsAny<Domain.TransferProjectAggregate.TransferProject>()));

// Act
var result = await createTransferProjectCommandHandler.Handle(
request,
cancellationToken);
_cancellationToken);

// Assert
var responseModel = Assert.IsType<CreateSuccessResult<ProjectGroupResponseModel>>(result).Payload;
Expand All @@ -115,17 +122,28 @@ public async Task Handle_ValidCommandWithConversions_PersistsExpectedProjectGrou
_mockProjectGroupRepository.Verify(x => x.Insert(It.Is<Domain.ProjectGroupsAggregate.ProjectGroup>(x => x.TrustReference == request.TrustReferenceNumber
&& x.ReferenceNumber != null
&& x.CreatedOn == now)), Times.Once());

_mockProjectGroupRepository.Verify(x => x.UnitOfWork.SaveChangesAsync(It.Is<CancellationToken>(x => x == cancellationToken)), Times.Exactly(3));
_mockTransferProjectRepository.Verify(x => x.GetTransferProjectsByIdsAsync(request.TransferProjectIds!, _cancellationToken), Times.Once);
_mockTransferProjectRepository.Verify(x => x.Update(It.IsAny<Domain.TransferProjectAggregate.TransferProject>()), Times.Once);
_mockProjectGroupRepository.Verify(x => x.UnitOfWork.SaveChangesAsync(It.Is<CancellationToken>(x => x == _cancellationToken)), Times.Exactly(4));
}

private static CreateProjectGroupCommand CreateValidCreateProjectProjectCommand(bool includeConversions = true)
private static CreateProjectGroupCommand CreateValidCreateProjectProjectCommand(bool includeConversions = true, bool includeTransfers = true)
{
string trustReference = "TR00001";
string trustUkprn = "1111333";
string trustName = "Test trust";

return new CreateProjectGroupCommand(trustName, trustReference, trustUkprn, includeConversions ? [03823] : []);
return new CreateProjectGroupCommand(trustName, trustReference, trustUkprn,
includeConversions ? [03823] : [],
includeTransfers ? [1234] : []);
}

private Domain.TransferProjectAggregate.TransferProject GetTransferProject(string incomingTrustUkprn)
{
var transferAcademy = new TransferringAcademy(incomingTrustUkprn, "in trust", _fixture.Create<string>()[..8], "region", "local authority");
var transferringAcademies = new List<TransferringAcademy>() { transferAcademy };

return Domain.TransferProjectAggregate.TransferProject.Create("12345678", "out trust", transferringAcademies, false, DateTime.Now);
}
}
}
Loading

0 comments on commit cbdd0a8

Please sign in to comment.