Skip to content

Commit

Permalink
Merge pull request #540 from DFE-Digital/feature/173335-grouping-proj…
Browse files Browse the repository at this point in the history
…ects

Update Conversion projects with project group Id on adding them into a project
  • Loading branch information
mshakirdfe authored Aug 9, 2024
2 parents a7c7805 + 6359867 commit b77a567
Show file tree
Hide file tree
Showing 15 changed files with 107 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -333,5 +333,12 @@ public async Task<IEnumerable<IProject>> GetProjectsByProjectGroupIdsAsync(IEnum
.Where(p => projectGroupIds.Contains(p.ProjectGroupId.GetValueOrDefault()))
.ToListAsync(cancellationToken);
}

public async Task<IEnumerable<IProject>> GetProjectsByIdsAsync(IEnumerable<int> projectIds, CancellationToken cancellationToken)
{
return await dbSet
.Where(p => projectIds.Contains(p.Id))
.ToListAsync(cancellationToken);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@ public interface IConversionProjectRepository : IRepository<Project>, IGenericRe
Task<IEnumerable<IProject>> GetConversionProjectsForNewGroup(string trustReferenceNumber, CancellationToken cancellationToken);
Task<IEnumerable<IProject>> GetProjectsByProjectGroupIdsAsync(IEnumerable<int> projectGroupIds, CancellationToken cancellationToken);
Task<IEnumerable<IProject>> GetConversionProjectsByProjectGroupIdAsync(int? projectGroupId, CancellationToken cancellationToken = default);
Task<IEnumerable<IProject>> GetProjectsByIdsAsync(IEnumerable<int> projectIds, CancellationToken cancellationToken);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace Dfe.Academies.Academisation.IService.Query
{
public interface IProjectGroupQueryService
{
Task<ProjectGroupResponseModel> GetProjectGroupById(int id, CancellationToken cancellationToken);
Task<ProjectGroupResponseModel> GetProjectGroupByIdAsync(int id, CancellationToken cancellationToken);
Task<PagedDataResponse<ProjectGroupResponseModel>?> GetProjectGroupsAsync(IEnumerable<string>? states, string? title,
IEnumerable<string>? deliveryOfficers, IEnumerable<string>? regions,
IEnumerable<string>? localAuthorities, IEnumerable<string>? advisoryBoardDates, int page, int count, CancellationToken cancellationToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Dfe.Academies.Academisation.IService.ServiceModels.ProjectGroup
{
public class ProjectGroupResponseModel(int id, string referenceNumber, string trustReferenceNumber, string trustName, string trustUkprn, User assignedUser)
public class ProjectGroupResponseModel(int id, string referenceNumber, string trustReferenceNumber, string trustName, string trustUkprn, User assignedUser, List<ConversionProjectServiceModel> projects)
{
public int Id { get; init; } = id;
public string TrustReferenceNumber { get; init; } = trustReferenceNumber;
Expand All @@ -13,6 +13,6 @@ public class ProjectGroupResponseModel(int id, string referenceNumber, string tr
public string? ReferenceNumber { get; init; } = referenceNumber;
public User AssignedUser { get; init; } = assignedUser;

public List<ConversionProjectServiceModel> projects { get; init; }
public List<ConversionProjectServiceModel> Projects { get; init; } = projects;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ public async Task Handle_ValidCommandWithoutConversions_PersistsExpectedProjectG
var responseModel = Assert.IsType<CreateSuccessResult<ProjectGroupResponseModel>>(result).Payload;
Assert.Equal(responseModel.TrustReferenceNumber, request.TrustReferenceNumber);
Assert.Equal(responseModel.ReferenceNumber, expectedProjectGroupReference);
Assert.Equal(responseModel.projects.Count(), expectedProjects.Count);
foreach (var conversion in responseModel.projects.Select((Value, Index) => (Value, Index)))
Assert.Equal(responseModel.Projects.Count(), expectedProjects.Count);
foreach (var conversion in responseModel.Projects.Select((Value, Index) => (Value, Index)))
{
Assert.Equal(conversion.Value.Urn, expectedProjects[conversion.Index].Details.Urn);
Assert.Equal(conversion.Value.SchoolName, expectedProjects[conversion.Index].Details.SchoolName);
Expand Down Expand Up @@ -104,10 +104,10 @@ public async Task Handle_ValidCommandWithConversions_PersistsExpectedProjectGrou
// Assert
var responseModel = Assert.IsType<CreateSuccessResult<ProjectGroupResponseModel>>(result).Payload;
Assert.Equal(responseModel.TrustReferenceNumber, request.TrustReferenceNumber);
Assert.Equal(responseModel.projects.Count(), expectedProjects.Count);
Assert.NotEmpty(responseModel.ReferenceNumber);
Assert.Equal(responseModel.Projects.Count(), expectedProjects.Count);
Assert.NotEmpty(responseModel.ReferenceNumber!);
Assert.StartsWith(responseModel.ReferenceNumber, "GRP_00000000");
foreach (var conversion in responseModel.projects.Select((Value, Index) => (Value, Index)))
foreach (var conversion in responseModel.Projects.Select((Value, Index) => (Value, Index)))
{
Assert.Equal(conversion.Value.Urn, expectedProjects[conversion.Index].Details.Urn);
Assert.Equal(conversion.Value.SchoolName, expectedProjects[conversion.Index].Details.SchoolName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ public async Task Handle_ValidRequestWithoutConversions_ReturnsSuccess()
};
_mockProjectGroupRepository.Setup(x => x.Update(It.IsAny<Domain.ProjectGroupsAggregate.ProjectGroup>()));
_mockProjectGroupRepository.Setup(x => x.GetByReferenceNumberAsync(request.GroupReferenceNumber, _cancellationToken)).ReturnsAsync(expectedProjectGroup);
_mockConversionProjectRepository.Setup(x => x.GetProjectsByIdsAsync(request.ConversionProjectIds, _cancellationToken)).ReturnsAsync([]);
_mockConversionProjectRepository.Setup(x => x.GetConversionProjectsByProjectGroupIdAsync(expectedProjectGroup.Id, _cancellationToken)).ReturnsAsync([]);

// Act
Expand All @@ -84,6 +85,7 @@ public async Task Handle_ValidRequestWithoutConversions_ReturnsSuccess()

// Assert
var commandSuccessResult = Assert.IsType<CommandSuccessResult>(result);
_mockConversionProjectRepository.Verify(x => x.GetProjectsByIdsAsync(request.ConversionProjectIds, _cancellationToken), Times.Once);
_mockConversionProjectRepository.Verify(x => x.GetConversionProjectsByProjectGroupIdAsync(expectedProjectGroup.Id, _cancellationToken), Times.Once);
_mockProjectGroupRepository.Verify(x => x.Update(It.IsAny<Domain.ProjectGroupsAggregate.ProjectGroup>()), Times.Never);
_mockProjectGroupRepository.Verify(x => x.GetByReferenceNumberAsync(request.GroupReferenceNumber, _cancellationToken), Times.Once);
Expand All @@ -105,7 +107,9 @@ public async Task Handle_ValidRequestWithNoRemovedConversions_ReturnsSuccess()
};
_mockProjectGroupRepository.Setup(x => x.Update(It.IsAny<Domain.ProjectGroupsAggregate.ProjectGroup>()));
_mockProjectGroupRepository.Setup(x => x.GetByReferenceNumberAsync(request.GroupReferenceNumber, _cancellationToken)).ReturnsAsync(expectedProjectGroup);
_mockConversionProjectRepository.Setup(x => x.GetConversionProjectsByProjectGroupIdAsync(expectedProjectGroup.Id, _cancellationToken)).ReturnsAsync(expectedProjects);
_mockConversionProjectRepository.Setup(x => x.GetProjectsByIdsAsync(request.ConversionProjectIds, _cancellationToken)).ReturnsAsync(expectedProjects);
_mockConversionProjectRepository.Setup(x => x.GetConversionProjectsByProjectGroupIdAsync(expectedProjectGroup.Id, _cancellationToken)).ReturnsAsync([]);

_mockConversionProjectRepository.Setup(x => x.Update(It.IsAny<Domain.ProjectAggregate.Project>()));

// Act
Expand All @@ -115,6 +119,7 @@ public async Task Handle_ValidRequestWithNoRemovedConversions_ReturnsSuccess()

// Assert
var commandSuccessResult = Assert.IsType<CommandSuccessResult>(result);
_mockConversionProjectRepository.Verify(x => x.GetProjectsByIdsAsync(request.ConversionProjectIds, _cancellationToken), Times.Once);
_mockConversionProjectRepository.Verify(x => x.GetConversionProjectsByProjectGroupIdAsync(expectedProjectGroup.Id, _cancellationToken), Times.Once);
_mockConversionProjectRepository.Verify(x => x.UnitOfWork.SaveChangesAsync(_cancellationToken), Times.Once);
}
Expand All @@ -134,6 +139,7 @@ public async Task Handle_ValidRequestWithOneRemovedConversions_ReturnsSuccess()
};
_mockProjectGroupRepository.Setup(x => x.Update(It.IsAny<Domain.ProjectGroupsAggregate.ProjectGroup>()));
_mockProjectGroupRepository.Setup(x => x.GetByReferenceNumberAsync(request.GroupReferenceNumber, _cancellationToken)).ReturnsAsync(expectedProjectGroup);
_mockConversionProjectRepository.Setup(x => x.GetProjectsByIdsAsync(request.ConversionProjectIds, _cancellationToken)).ReturnsAsync([]);
_mockConversionProjectRepository.Setup(x => x.GetConversionProjectsByProjectGroupIdAsync(expectedProjectGroup.Id, _cancellationToken)).ReturnsAsync(expectedProjects);
_mockConversionProjectRepository.Setup(x => x.Update(It.IsAny<Domain.ProjectAggregate.Project>()));

Expand All @@ -144,7 +150,8 @@ public async Task Handle_ValidRequestWithOneRemovedConversions_ReturnsSuccess()

// Assert
var commandSuccessResult = Assert.IsType<CommandSuccessResult>(result);
_mockConversionProjectRepository.Verify(x => x.GetConversionProjectsByProjectGroupIdAsync(expectedProjectGroup.Id, _cancellationToken), Times.Once);
_mockConversionProjectRepository.Verify(x => x.GetProjectsByIdsAsync(request.ConversionProjectIds, _cancellationToken), Times.Once);
_mockConversionProjectRepository.Verify(x => x.GetConversionProjectsByProjectGroupIdAsync(expectedProjectGroup.Id, _cancellationToken), Times.Once);
_mockConversionProjectRepository.Verify(x => x.Update(It.IsAny<Domain.ProjectAggregate.Project>()), Times.Exactly(expectedProjects.Count));
_mockConversionProjectRepository.Verify(x => x.UnitOfWork.SaveChangesAsync(_cancellationToken), Times.Once);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using Dfe.Academies.Academisation.Domain.ProjectGroupsAggregate;
using Dfe.Academies.Academisation.IService.ServiceModels.ProjectGroup;
using Dfe.Academies.Academisation.Service.Commands.ProjectGroup.QueryService;
using Microsoft.Extensions.Logging;
using Moq;
using Xunit;
using Dfe.Academies.Academisation.IService.ServiceModels.Legacy.ProjectAggregate;
Expand All @@ -14,7 +13,6 @@ public class ProjectGroupQueryServiceTests
{
private Mock<IProjectGroupRepository> _mockProjectGroupRepository;
private Mock<IConversionProjectRepository> _mockConversionProjectRepository;
private Mock<ILogger<ProjectGroupQueryService>> _mockLogger;
private ProjectGroupQueryService _projectGroupQueryService;
private CancellationToken _cancellationToken;
private readonly Fixture _fixture;
Expand All @@ -23,12 +21,10 @@ public ProjectGroupQueryServiceTests()
{
_mockProjectGroupRepository = new Mock<IProjectGroupRepository>();
_mockConversionProjectRepository = new Mock<IConversionProjectRepository>();
_mockLogger = new Mock<ILogger<ProjectGroupQueryService>>();
_fixture = new();
_projectGroupQueryService = new ProjectGroupQueryService(
_mockProjectGroupRepository.Object,
_mockConversionProjectRepository.Object,
_mockLogger.Object
_mockConversionProjectRepository.Object
);
_cancellationToken = CancellationToken.None;
}
Expand All @@ -42,7 +38,7 @@ public async Task GetProjectGroupsAsync_WithReferenceNumber_ShouldReturnResultAs
var expectedProject = _fixture.Create<Domain.ProjectAggregate.Project>();
expectedProject.SetProjectGroupId(expectedProjectGroup.Id);
var emptyList = new List<string>();
_mockProjectGroupRepository.Setup(x => x.SearchProjectGroups(searchModel.ReferenceNumber, _cancellationToken))
_mockProjectGroupRepository.Setup(x => x.SearchProjectGroups(searchModel.ReferenceNumber!, _cancellationToken))
.ReturnsAsync([expectedProjectGroup]);
_mockConversionProjectRepository.Setup(x => x.GetProjectsByProjectGroupIdsAsync(new List<int> { expectedProjectGroup.Id }, _cancellationToken)).ReturnsAsync([expectedProject]);

Expand All @@ -58,7 +54,7 @@ public async Task GetProjectGroupsAsync_WithReferenceNumber_ShouldReturnResultAs
Assert.Equal(data.ReferenceNumber, expectedProjectGroup.ReferenceNumber);
Assert.Equal(data.TrustReferenceNumber, expectedProjectGroup.TrustReference);
}
_mockProjectGroupRepository.Verify(x => x.SearchProjectGroups(searchModel.ReferenceNumber, _cancellationToken), Times.Once());
_mockProjectGroupRepository.Verify(x => x.SearchProjectGroups(searchModel.ReferenceNumber!, _cancellationToken), Times.Once());
_mockConversionProjectRepository.Verify(x => x.GetProjectsByProjectGroupIdsAsync(new List<int> { expectedProjectGroup.Id }, _cancellationToken), Times.Once());

}
Expand All @@ -71,7 +67,7 @@ public async Task GetProjectGroupsAsync_WithTrustReference_ShouldReturnResult()
var expectedProjectGroup = _fixture.Create<ProjectGroup>();
var expectedProject = _fixture.Create<Domain.ProjectAggregate.Project>();
expectedProject.SetProjectGroupId(expectedProjectGroup.Id);
_mockProjectGroupRepository.Setup(x => x.SearchProjectGroups(searchModel.TrustReference, _cancellationToken))
_mockProjectGroupRepository.Setup(x => x.SearchProjectGroups(searchModel.TrustReference!, _cancellationToken))
.ReturnsAsync([expectedProjectGroup]);
_mockConversionProjectRepository.Setup(x => x.GetProjectsByProjectGroupIdsAsync(new List<int> { expectedProjectGroup.Id }, _cancellationToken)).ReturnsAsync([expectedProject]);
var emptyList = new List<string>();
Expand All @@ -87,7 +83,7 @@ public async Task GetProjectGroupsAsync_WithTrustReference_ShouldReturnResult()
Assert.Equal(data.ReferenceNumber, expectedProjectGroup.ReferenceNumber);
Assert.Equal(data.TrustReferenceNumber, expectedProjectGroup.TrustReference);
}
_mockProjectGroupRepository.Verify(x => x.SearchProjectGroups(searchModel.TrustReference, _cancellationToken), Times.Once());
_mockProjectGroupRepository.Verify(x => x.SearchProjectGroups(searchModel.TrustReference!, _cancellationToken), Times.Once());
_mockConversionProjectRepository.Verify(x => x.GetProjectsByProjectGroupIdsAsync(new List<int> { expectedProjectGroup.Id }, _cancellationToken), Times.Once());

}
Expand All @@ -100,7 +96,7 @@ public async Task GetProjectGroupsAsync_WithTitle_ShouldReturnResult()
var expectedProjectGroup = _fixture.Create<ProjectGroup>();
var expectedProject = _fixture.Create<Domain.ProjectAggregate.Project>();
expectedProject.SetProjectGroupId(expectedProjectGroup.Id);
_mockProjectGroupRepository.Setup(x => x.SearchProjectGroups(searchModel.Title, _cancellationToken))
_mockProjectGroupRepository.Setup(x => x.SearchProjectGroups(searchModel.Title!, _cancellationToken))
.ReturnsAsync([expectedProjectGroup]);
_mockConversionProjectRepository.Setup(x => x.GetProjectsByProjectGroupIdsAsync(new List<int> { expectedProjectGroup.Id }, _cancellationToken)).ReturnsAsync([expectedProject]);
var emptyList = new List<string>();
Expand All @@ -116,9 +112,36 @@ public async Task GetProjectGroupsAsync_WithTitle_ShouldReturnResult()
Assert.Equal(data.ReferenceNumber, expectedProjectGroup.ReferenceNumber);
Assert.Equal(data.TrustReferenceNumber, expectedProjectGroup.TrustReference);
}
_mockProjectGroupRepository.Verify(x => x.SearchProjectGroups(searchModel.Title, _cancellationToken), Times.Once());
_mockProjectGroupRepository.Verify(x => x.SearchProjectGroups(searchModel.Title!, _cancellationToken), Times.Once());
_mockConversionProjectRepository.Verify(x => x.GetProjectsByProjectGroupIdsAsync(new List<int> { expectedProjectGroup.Id }, _cancellationToken), Times.Once());
}

[Fact]
public async Task GetProjectGroupByIdAsync_WithId_ShouldReturnResult()
{
// Arrange
var expectedProjectGroup = _fixture.Create<ProjectGroup>();
var expectedProject = _fixture.Create<Domain.ProjectAggregate.Project>();
expectedProject.SetProjectGroupId(expectedProjectGroup.Id);
_mockProjectGroupRepository.Setup(x => x.GetById(expectedProjectGroup.Id))
.ReturnsAsync(expectedProjectGroup);
_mockConversionProjectRepository.Setup(x => x.GetConversionProjectsByProjectGroupIdAsync(expectedProjectGroup.Id, _cancellationToken)).ReturnsAsync([expectedProject]);

// Action
var result = await _projectGroupQueryService.GetProjectGroupByIdAsync(expectedProjectGroup.Id, _cancellationToken);

//Assert
var responseModel = Assert.IsType<ProjectGroupResponseModel>(result);
Assert.Equal(responseModel.TrustName, expectedProjectGroup.TrustName);
Assert.Equal(responseModel.ReferenceNumber, expectedProjectGroup.ReferenceNumber);
Assert.Equal(responseModel.Id, expectedProjectGroup.Id);
foreach (var project in responseModel.Projects)
{
Assert.Equal(project.Id, expectedProject.Id);
Assert.Equal(project.NameOfTrust, expectedProject.Details.NameOfTrust);
}
_mockProjectGroupRepository.Verify(x => x.GetById(expectedProjectGroup.Id), Times.Once());
_mockConversionProjectRepository.Verify(x => x.GetConversionProjectsByProjectGroupIdAsync(expectedProjectGroup.Id, _cancellationToken), Times.Once());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,25 @@ public class SetProjectGroupAssignUserCommandValidator : AbstractValidator<SetPr
{
public SetProjectGroupAssignUserCommandValidator()
{

RuleFor(x => x.GroupReferenceNumber)
.NotEmpty().WithMessage("Must specify a group reference number")
.NotNull().WithMessage("Trust Reference must not be null");

.NotNull().WithMessage("Group Reference number must not be null");
/*
RuleFor(x => x.FullName)
.NotEmpty().WithMessage("Full name must not be empty");
.NotEmpty()
.When(x => x.UserId != null && !string.IsNullOrEmpty(x.EmailAddress))
.WithMessage("Full name must not be empty");
RuleFor(x => x.UserId)
.NotEmpty().WithMessage("Full name must not be empty");

RuleFor(x => x.FullName)
.NotEmpty().WithMessage("Full name must not be empty");
.NotEmpty()
.When(x => !string.IsNullOrEmpty(x.FullName) && !string.IsNullOrEmpty(x.EmailAddress))
.WithMessage("Full name must not be empty");
RuleFor(x => x.EmailAddress)
.NotEmpty().WithMessage("Email address must not be empty")
.EmailAddress().WithMessage("Must be a valid email address.");
.NotEmpty()
.When(x => x.UserId != null && !string.IsNullOrEmpty(x.FullName))
.EmailAddress().WithMessage("Must be a valid email address.");*/
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,7 @@ public async Task<CreateResult> Handle(CreateProjectGroupCommand message, Cancel
conversionsProjectModels = conversionProjects.Select(p => p.MapToServiceModel()).ToList();
}

var responseModel = new ProjectGroupResponseModel(projectGroup.Id, projectGroup.ReferenceNumber!, projectGroup.TrustReference, null, null, null) {
projects = conversionsProjectModels
};
var responseModel = new ProjectGroupResponseModel(projectGroup.Id, projectGroup.ReferenceNumber!, projectGroup.TrustReference, null, null, null, conversionsProjectModels);

return new CreateSuccessResult<ProjectGroupResponseModel>(responseModel);

Expand Down
Loading

0 comments on commit b77a567

Please sign in to comment.