Skip to content

Commit

Permalink
Merge pull request #446 from DFE-Digital/feature/filter-transfers
Browse files Browse the repository at this point in the history
Feature/filter transfers
  • Loading branch information
dneed-nimble authored Apr 17, 2024
2 parents fe37300 + f4cbe5a commit 24a1095
Show file tree
Hide file tree
Showing 12 changed files with 252 additions and 91 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
namespace Dfe.Academies.Academisation.Data.ProjectAggregate
{
public class GetAcademyConversionSearchModel
public class GetProjectSearchModel
{
public GetAcademyConversionSearchModel(int page, int count, string? titleFilter,
public GetProjectSearchModel(int page, int count, string? titleFilter,
IEnumerable<string>? deliveryOfficerQueryString, IEnumerable<string>? regionQueryString,
IEnumerable<string>? statusQueryString, IEnumerable<string>? applicationReferences)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,94 @@ public TransferProjectRepository(AcademisationContext context) : base(context)
{
return await DefaultIncludes().SingleOrDefaultAsync(x => x.Urn == urn);
}
public async Task<(IEnumerable<ITransferProject>, int totalcount)> SearchProjects(IEnumerable<string>? states, string? title, IEnumerable<string>? deliveryOfficers, int page, int count)
{
IQueryable<TransferProject> queryable = this.dbSet;

// Region & Local Authority isn't on Transfers right now
//queryable = FilterByRegion(regions, queryable);
//queryable = FilterByLocalAuthority(localAuthorities, queryable);
queryable = FilterByStatus(states, queryable);
queryable = FilterByKeyword(title, queryable);
queryable = FilterByDeliveryOfficer(deliveryOfficers, queryable);

var totalProjects = queryable.Count();
var projects = await queryable
.OrderByDescending(acp => acp.CreatedOn)
.Skip((page - 1) * count)
.Take(count).ToListAsync();

return (projects, totalProjects);
}
private static IQueryable<TransferProject> FilterByDeliveryOfficer(IEnumerable<string>? deliveryOfficers, IQueryable<TransferProject> queryable)
{
if (deliveryOfficers != null && deliveryOfficers.Any())
{
var lowerCaseDeliveryOfficers = deliveryOfficers.Select(officer => officer.ToLower());

if (lowerCaseDeliveryOfficers.Contains("not assigned"))
{
// Query by unassigned or assigned delivery officer
queryable = queryable.Where(p =>
(!string.IsNullOrEmpty(p.AssignedUserFullName) && lowerCaseDeliveryOfficers.Contains(p.AssignedUserFullName.ToLower()))
|| string.IsNullOrEmpty(p.AssignedUserFullName));
}
else
{
// Query by assigned delivery officer only
queryable = queryable.Where(p =>
!string.IsNullOrEmpty(p.AssignedUserFullName) && lowerCaseDeliveryOfficers.Contains(p.AssignedUserFullName.ToLower()));
}
}

return queryable;
}
private static IQueryable<TransferProject> FilterByKeyword(string? title, IQueryable<TransferProject> queryable)
{
if (!string.IsNullOrWhiteSpace(title))
{

queryable = FilterIncomingTrust(title, queryable);
queryable = FilterOutgoingTrust(title, queryable);
queryable = FilterURN(title, queryable);

}

return queryable;
}

private static IQueryable<TransferProject> FilterIncomingTrust(string title, IQueryable<TransferProject> queryable)
{
return queryable.Where(p =>
p.TransferringAcademies.Any(x =>
x.IncomingTrustName != null &&
x.IncomingTrustName.Contains(title, StringComparison.CurrentCultureIgnoreCase)
)
);
}
private static IQueryable<TransferProject> FilterOutgoingTrust(string title, IQueryable<TransferProject> queryable)
{
return queryable.Where(p => p.OutgoingTrustName != null && p.OutgoingTrustName.Contains(title, StringComparison.CurrentCultureIgnoreCase));
}
private static IQueryable<TransferProject> FilterURN(string title, IQueryable<TransferProject> queryable)
{
return queryable.Where(p => p.Urn.ToString().Contains(title, StringComparison.CurrentCultureIgnoreCase));
}
private static IQueryable<TransferProject> FilterByUrn(int? urn, IQueryable<TransferProject> queryable)
{
if (urn.HasValue) queryable = queryable.Where(p => p.Urn == urn);

return queryable;
}
private static IQueryable<TransferProject> FilterByStatus(IEnumerable<string>? states, IQueryable<TransferProject> queryable)
{
if (states != null && states!.Any())
{
queryable = queryable.Where(p => states.Contains(p.Status!.ToLower()));
}

return queryable;
}
public async Task<IEnumerable<ITransferProject?>> GetAllTransferProjects()
{
try
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ public interface ITransferProjectRepository : IRepository<TransferProject>, IGen
{
public Task<ITransferProject?> GetByUrn(int urn);
public Task<IEnumerable<ITransferProject?>> GetAllTransferProjects();
Task<(IEnumerable<ITransferProject>, int totalcount)> SearchProjects(IEnumerable<string>? states, string? title, IEnumerable<string>? deliveryOfficers, int page, int count);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ protected TransferProject() { }

public string? ProjectReference { get; private set; }
public string OutgoingTrustUkprn { get; private set; }
public string? OutgoingTrustName{ get; private set; }
public string? OutgoingTrustName { get; private set; }
public string? WhoInitiatedTheTransfer { get; private set; }


Expand Down Expand Up @@ -94,7 +94,7 @@ protected TransferProject() { }
public IReadOnlyCollection<TransferringAcademy> TransferringAcademies => _transferringAcademies;

IReadOnlyCollection<IIntendedTransferBenefit> ITransferProject.IntendedTransferBenefits => _intendedTransferBenefits;
IReadOnlyCollection<ITransferringAcademy> ITransferProject.TransferringAcademies =>
IReadOnlyCollection<ITransferringAcademy> ITransferProject.TransferringAcademies =>
_transferringAcademies;

public DateTime? CreatedOn { get; private set; }
Expand Down Expand Up @@ -133,7 +133,7 @@ public void AssignUser(Guid userId, string userEmail, string userFullName)
}

public void SetFeatures(string whoInitiatedTheTransfer, List<string> specificReasonsForTransfer, string transferType, bool? isCompleted)
{
{
WhoInitiatedTheTransfer = whoInitiatedTheTransfer;
_specificReasonsForTransfer = specificReasonsForTransfer;
TypeOfTransfer = transferType;
Expand Down Expand Up @@ -166,12 +166,12 @@ public void SetTransferringAcademiesSchoolData(string transferringAcademyUkprn,
);
}

public void SetBenefitsAndRisks(bool? anyRisks, bool? equalitiesImpactAssessmentConsidered,
List<string> selectedBenefits, string? otherBenefitValue,
bool? highProfileShouldBeConsidered, string? highProfileFurtherSpecification,
bool? complexLandAndBuildingShouldBeConsidered, string? complexLandAndBuildingFurtherSpecification,
bool? financeAndDebtShouldBeConsidered, string? financeAndDebtFurtherSpecification,
bool? otherRisksShouldBeConsidered, string? otherRisksFurtherSpecification,
public void SetBenefitsAndRisks(bool? anyRisks, bool? equalitiesImpactAssessmentConsidered,
List<string> selectedBenefits, string? otherBenefitValue,
bool? highProfileShouldBeConsidered, string? highProfileFurtherSpecification,
bool? complexLandAndBuildingShouldBeConsidered, string? complexLandAndBuildingFurtherSpecification,
bool? financeAndDebtShouldBeConsidered, string? financeAndDebtFurtherSpecification,
bool? otherRisksShouldBeConsidered, string? otherRisksFurtherSpecification,
bool? isCompleted)
{
AnyRisks = anyRisks;
Expand All @@ -182,7 +182,7 @@ public void SetBenefitsAndRisks(bool? anyRisks, bool? equalitiesImpactAssessment
OtherBenefitValue = otherBenefitValue;

HighProfileShouldBeConsidered = highProfileShouldBeConsidered;
HighProfileFurtherSpecification = highProfileFurtherSpecification;
HighProfileFurtherSpecification = highProfileFurtherSpecification;
ComplexLandAndBuildingShouldBeConsidered = complexLandAndBuildingShouldBeConsidered;
ComplexLandAndBuildingFurtherSpecification = complexLandAndBuildingFurtherSpecification;
FinanceAndDebtShouldBeConsidered = financeAndDebtShouldBeConsidered;
Expand Down Expand Up @@ -219,7 +219,8 @@ public void SetAcademyIncomingTrustName(int academyId, string incomingTrustName)
var transferringAcademy =
TransferringAcademies.SingleOrDefault(x => x.Id == academyId);

if (transferringAcademy != null) {
if (transferringAcademy != null)
{

transferringAcademy.SetIncomingTrustName(incomingTrustName);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Dfe.Academies.Academisation.IDomain.TransferProjectAggregate;
using Dfe.Academies.Academisation.IService.ServiceModels.Legacy.ProjectAggregate;
using Dfe.Academies.Academisation.IService.ServiceModels.Legacy.ProjectAggregate;
using Dfe.Academies.Academisation.IService.ServiceModels.TransferProject;

namespace Dfe.Academies.Academisation.IService.Query
Expand All @@ -10,6 +9,7 @@ public interface ITransferProjectQueryService
Task<AcademyTransferProjectResponse?> GetById(int id);
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);
Task<PagedResultResponse<ExportedTransferProjectModel>> GetExportedTransferProjects(string? title);

}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
using Xunit;
using Moq;
using FluentAssertions;
using Dfe.Academies.Academisation.Domain.TransferProjectAggregate;
using Dfe.Academies.Academisation.Service.Mappers.TransferProject;
using Dfe.Academies.Academisation.Service.Queries;
using Dfe.Academies.Academisation.Domain.TransferProjectAggregate;
using Dfe.Academies.Academisation.IData.ConversionAdvisoryBoardDecisionAggregate;
using Dfe.Academies.Academisation.IDomain.ConversionAdvisoryBoardDecisionAggregate;
using Dfe.Academies.Academisation.IDomain.TransferProjectAggregate;
using Dfe.Academies.Academisation.IService.Query;
using Dfe.Academies.Academisation.IService.ServiceModels.TransferProject;
using Dfe.Academies.Academisation.IData.ConversionAdvisoryBoardDecisionAggregate;
using Dfe.Academies.Academisation.IDomain.ConversionAdvisoryBoardDecisionAggregate;
using Dfe.Academies.Academisation.IService.ServiceModels.Academies;
using Dfe.Academies.Academisation.Service.Mappers.TransferProject;
using Dfe.Academies.Academisation.Service.Queries;
using Dfe.Academies.Academisation.Service.UnitTest.Mocks;
using Microsoft.Extensions.DependencyInjection;
using Dfe.Academies.Contracts.V4.Establishments;
using FluentAssertions;
using Microsoft.Extensions.DependencyInjection;
using Moq;
using Xunit;

namespace Dfe.Academies.Academisation.Service.UnitTest.Queries
{
Expand All @@ -35,16 +34,18 @@ public async Task GetByUrn_ShouldReturnExpectedResponse()

var dummyUrn = 1;

// Create a TransferProject
ITransferProject dummyTransferProject = TransferProject.Create(
"dummyOutgoingTrustUkprn",
"out trust",
"dummyIncomingTrustUkprn",
"in trust",
new List<string> { "dummyUkprn1", "dummyUkprn2" },
false,
DateTime.Now
);

// Create a TransferProject
ITransferProject dummyTransferProject = TransferProject.Create(
"dummyOutgoingTrustUkprn",
"out trust",
"dummyIncomingTrustUkprn",
"in trust",
new List<string> { "dummyUkprn1", "dummyUkprn2" },
false,
DateTime.Now
);


// Mock the setup to return the dummy project
mockRepository.Setup(repo => repo.GetByUrn(It.IsAny<int>())).Returns(Task.FromResult((ITransferProject?)dummyTransferProject));
Expand All @@ -69,16 +70,17 @@ public async Task GetById_ShouldReturnExpectedResponse()

var dummyId = 1;

// Create a TransferProject
var dummyTransferProject = TransferProject.Create(
"dummyOutgoingTrustUkprn",
"out trust",
"dummyIncomingTrustUkprn",
"in trust",
new List<string> { "dummyUkprn1", "dummyUkprn2" },
false,
DateTime.Now
);

// Create a TransferProject
var dummyTransferProject = TransferProject.Create(
"dummyOutgoingTrustUkprn",
"out trust",
"dummyIncomingTrustUkprn",
"in trust",
new List<string> { "dummyUkprn1", "dummyUkprn2" },
false,
DateTime.Now
);

// Mock the setup to return the dummy project
mockRepository.Setup(repo => repo.GetById(It.IsAny<int>())).Returns(Task.FromResult(dummyTransferProject));
Expand Down Expand Up @@ -248,5 +250,58 @@ private static ExportedTransferProjectModel GetDummyTransferProjectModel(
Urn = "0"
};
}


[Fact]
public async Task GetProjects_ReturnsFilteredProjects()
{
// Arrange
var mockRepository = new Mock<ITransferProjectRepository>();
var service = new TransferProjectQueryService(mockRepository.Object, _establishmentRepo, _advisoryBoardDecisionGetDataByProjectIdQuery);

var states = new List<string> { "Active", "Completed" };
var title = "Project X";
var deliveryOfficers = new List<string> { "Officer A" };
var page = 1;
var count = 10;

// Sample data setup
var dummyProjects = new List<TransferProject>
{
TransferProject.Create("outUkprn1", "Out Trust 1", "inUkprn1", "In Trust 1", new List<string> { "ukprn1" },false, DateTime.UtcNow),
TransferProject.Create("outUkprn2", "Out Trust 2", "inUkprn2", "In Trust 2", new List<string> { "ukprn2" },false, DateTime.UtcNow)
};

// Expected data setup
var expectedData = dummyProjects.Select(p => new AcademyTransferProjectSummaryResponse
{
ProjectUrn = p.Urn.ToString(),
ProjectReference = p.ProjectReference,
OutgoingTrustUkprn = p.OutgoingTrustUkprn,
OutgoingTrustName = p.OutgoingTrustName,
Status = p.Status,
TransferringAcademies = p.TransferringAcademies.Select(a => new TransferringAcademiesResponse
{
IncomingTrustName = a.IncomingTrustName,
IncomingTrustUkprn = a.IncomingTrustUkprn,
OutgoingAcademyUkprn = a.OutgoingAcademyUkprn,
}).ToList(),
AssignedUser = null,
IsFormAMat = false
});

mockRepository.Setup(repo => repo.SearchProjects(states, title, deliveryOfficers, page, count))
.ReturnsAsync((dummyProjects, 2)); // 2 represents the total count of items

// Act
var result = await service.GetProjects(states, title, deliveryOfficers, page, count);

// Assert
result.Should().NotBeNull();
result!.Data.Should().BeEquivalentTo(expectedData);
result.Paging.Page.Should().Be(page);
result.Paging.RecordCount.Should().Be(2);
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
using Dfe.Academies.Academisation.IData.ConversionAdvisoryBoardDecisionAggregate;
using Dfe.Academies.Academisation.IDomain.TransferProjectAggregate;
using Dfe.Academies.Academisation.IService.Query;
using Dfe.Academies.Academisation.IService.ServiceModels.Legacy.ProjectAggregate;
using Dfe.Academies.Academisation.IService.ServiceModels.TransferProject;
using Dfe.Academies.Academisation.Service.Extensions;
using Dfe.Academies.Academisation.Service.Factories;
using Dfe.Academies.Academisation.Service.Mappers.TransferProject;

namespace Dfe.Academies.Academisation.Service.Queries
Expand Down Expand Up @@ -61,7 +63,18 @@ public async Task<PagedResultResponse<AcademyTransferProjectSummaryResponse>> Ge

return await Task.FromResult(new PagedResultResponse<AcademyTransferProjectSummaryResponse>(projects, recordTotal));
}

public async Task<PagedDataResponse<AcademyTransferProjectSummaryResponse>?> GetProjects(IEnumerable<string>? states, string? title, IEnumerable<string>? deliveryOfficers, int page, int count)
{
var (projects, totalCount) = await _transferProjectRepository.SearchProjects(states, title, deliveryOfficers, page, count);
IEnumerable<AcademyTransferProjectSummaryResponse> data = AcademyTransferProjectSummaryResponse(projects);
var pageResponse = PagingResponseFactory.Create("transfer-projects/projects", page, count, totalCount,
new Dictionary<string, object?> {
{"states", states},
});

return new PagedDataResponse<AcademyTransferProjectSummaryResponse>(data,
pageResponse);
}
public async Task<PagedResultResponse<ExportedTransferProjectModel>> GetExportedTransferProjects(string? title)
{
IEnumerable<ITransferProject?> transferProjects = (await _transferProjectRepository.GetAllTransferProjects()).ToList();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ public async Task FormAMatApplicationExists___ApplicationIsSubmitted_And_Project

var projectController = new ProjectController(
Mock.Of<ICreateNewProjectCommand>(), new ConversionProjectQueryService(new ConversionProjectRepository(_context, null), new FormAMatProjectRepository(_context)), Mock.Of<IMediator>());
var projectResults = await projectController.GetProjects(new GetAcademyConversionSearchModel(1, 3, null, null, null, null, new[] { $"A2B_{createdPayload.ApplicationReference!}" }));
var projectResults = await projectController.GetProjects(new GetProjectSearchModel(1, 3, null, null, null, null, new[] { $"A2B_{createdPayload.ApplicationReference!}" }));

(_, PagedDataResponse<ConversionProjectServiceModel> projects) = DfeAssert.OkObjectResult(projectResults);

Expand Down
Loading

0 comments on commit 24a1095

Please sign in to comment.