diff --git a/src/Core/Dfe.Complete.Application/Projects/Commands/CreateProject/CreateProject.cs b/src/Core/Dfe.Complete.Application/Projects/Commands/CreateProject/CreateConversionProject.cs similarity index 100% rename from src/Core/Dfe.Complete.Application/Projects/Commands/CreateProject/CreateProject.cs rename to src/Core/Dfe.Complete.Application/Projects/Commands/CreateProject/CreateConversionProject.cs diff --git a/src/Core/Dfe.Complete.Application/Projects/Commands/CreateProject/CreateMatConversionProject.cs b/src/Core/Dfe.Complete.Application/Projects/Commands/CreateProject/CreateMatConversionProject.cs new file mode 100644 index 00000000..9594e57e --- /dev/null +++ b/src/Core/Dfe.Complete.Application/Projects/Commands/CreateProject/CreateMatConversionProject.cs @@ -0,0 +1,96 @@ +using Dfe.Complete.Domain.Entities; +using Dfe.Complete.Domain.Enums; +using Dfe.Complete.Domain.Interfaces.Repositories; +using Dfe.Complete.Domain.ValueObjects; +using Dfe.Complete.Utils; +using MediatR; + +namespace Dfe.Complete.Application.Projects.Commands.CreateProject; + +public record CreateMatConversionProjectCommand( + Urn Urn, + string NewTrustName, + string NewTrustReferenceNumber, + DateOnly SignificantDate, + bool IsSignificantDateProvisional, + bool IsDueTo2Ri, + bool HasAcademyOrderBeenIssued, + DateOnly AdvisoryBoardDate, + string AdvisoryBoardConditions, + string EstablishmentSharepointLink, + string IncomingTrustSharepointLink, + bool HandingOverToRegionalCaseworkService, + string? HandoverComments, + string? UserAdId) : IRequest; + + public class CreateMatConversionProjectCommandHandler( + ICompleteRepository projectRepository, + ICompleteRepository conversionTaskRepository, + ICompleteRepository userRepository) + : IRequestHandler + { + public async Task Handle(CreateMatConversionProjectCommand request, CancellationToken cancellationToken) + { + // The user Team should be moved as a Claim or Group to the Entra (MS AD) + var projectUser = await GetUserByAdId(request.UserAdId); + + var projectUserTeam = projectUser.Team; + var projectUserId = projectUser?.Id; + + var projectTeam = EnumExtensions.FromDescription(projectUserTeam); + var region = EnumMapper.MapTeamToRegion(projectTeam); + + var createdAt = DateTime.UtcNow; + var conversionTaskId = Guid.NewGuid(); + var projectId = new ProjectId(Guid.NewGuid()); + + var conversionTask = new ConversionTasksData(new TaskDataId(conversionTaskId), createdAt, createdAt); + + ProjectTeam team; + DateTime? assignedAt = null; + UserId? projectUserAssignedToId = null; + + if (request.HandingOverToRegionalCaseworkService) + { + team = ProjectTeam.RegionalCaseWorkerServices; + } + else + { + team = projectTeam; + assignedAt = DateTime.UtcNow; + projectUserAssignedToId = projectUserId; + } + + var project = Project.CreateMatConversionProject( + projectId, + request.Urn, + createdAt, + updatedAt: createdAt, + TaskType.Conversion, + ProjectType.Conversion, + conversionTaskId, + region, + team, + projectUser?.Id, + projectUserAssignedToId, + assignedAt, + request.EstablishmentSharepointLink, + request.IncomingTrustSharepointLink, + request.AdvisoryBoardDate, + request.AdvisoryBoardConditions, + request.SignificantDate, + request.IsSignificantDateProvisional, + request.IsDueTo2Ri, + request.NewTrustName, + request.NewTrustReferenceNumber, + request.HasAcademyOrderBeenIssued, + request.HandoverComments); + + await conversionTaskRepository.AddAsync(conversionTask, cancellationToken); + await projectRepository.AddAsync(project, cancellationToken); + + return project.Id; + } + + private async Task GetUserByAdId(string? userAdId) => await userRepository.FindAsync(x => x.ActiveDirectoryUserId == userAdId); + } \ No newline at end of file diff --git a/src/Core/Dfe.Complete.Application/Projects/Models/GetProjectByTrnDto.cs b/src/Core/Dfe.Complete.Application/Projects/Models/GetProjectByTrnDto.cs new file mode 100644 index 00000000..727d4e25 --- /dev/null +++ b/src/Core/Dfe.Complete.Application/Projects/Models/GetProjectByTrnDto.cs @@ -0,0 +1,3 @@ +namespace Dfe.Complete.Application.Projects.Models; + +public record GetProjectByTrnResponseDto(Guid ProjectId, string? NewTrustName); \ No newline at end of file diff --git a/src/Core/Dfe.Complete.Application/Projects/Queries/GetProject/GetProjectByTrn.cs b/src/Core/Dfe.Complete.Application/Projects/Queries/GetProject/GetProjectByTrn.cs new file mode 100644 index 00000000..1664497c --- /dev/null +++ b/src/Core/Dfe.Complete.Application/Projects/Queries/GetProject/GetProjectByTrn.cs @@ -0,0 +1,26 @@ +using Dfe.Complete.Application.Common.Models; +using Dfe.Complete.Application.Projects.Models; +using Dfe.Complete.Domain.Entities; +using Dfe.Complete.Domain.Interfaces.Repositories; +using MediatR; + +namespace Dfe.Complete.Application.Projects.Queries.GetProject; + + +public record GetProjectByTrnQuery(string NewTrustReferenceNumber) : IRequest>; + +public class GetProjectByTrn(ICompleteRepository projectRepo) : IRequestHandler> +{ + public async Task> Handle(GetProjectByTrnQuery request, CancellationToken cancellationToken) + { + try + { + var result = await projectRepo.FindAsync(x => x.NewTrustReferenceNumber == request.NewTrustReferenceNumber, cancellationToken); + return Result.Success(new GetProjectByTrnResponseDto(result.Id.Value, result.NewTrustName)); + } + catch (Exception e) + { + return Result.Failure(e.Message); + } + } +} \ No newline at end of file diff --git a/src/Core/Dfe.Complete.Application/Projects/Queries/GetProject/GetProjectByUrn.cs b/src/Core/Dfe.Complete.Application/Projects/Queries/GetProject/GetProjectByUrn.cs index aeb0f3eb..de5ea9b3 100644 --- a/src/Core/Dfe.Complete.Application/Projects/Queries/GetProject/GetProjectByUrn.cs +++ b/src/Core/Dfe.Complete.Application/Projects/Queries/GetProject/GetProjectByUrn.cs @@ -6,36 +6,35 @@ using DfE.CoreLibs.Caching.Interfaces; using Dfe.Complete.Application.Common.Models; -namespace Dfe.Complete.Application.Projects.Queries.GetProject -{ - public record GetProjectByUrnQuery(Urn Urn) : IRequest>; +namespace Dfe.Complete.Application.Projects.Queries.GetProject; + +public record GetProjectByUrnQuery(Urn Urn) : IRequest>; - public class GetProjectByUrnQueryHandler(ICompleteRepository projectRepository, - ICacheService cacheService) - : IRequestHandler> +public class GetProjectByUrnQueryHandler(ICompleteRepository projectRepository, + ICacheService cacheService) + : IRequestHandler> +{ + public async Task> Handle(GetProjectByUrnQuery request, CancellationToken cancellationToken) { - public async Task> Handle(GetProjectByUrnQuery request, CancellationToken cancellationToken) - { - var cacheKey = $"Project_{CacheKeyHelper.GenerateHashedCacheKey(request.Urn.Value.ToString())}"; + var cacheKey = $"Project_{CacheKeyHelper.GenerateHashedCacheKey(request.Urn.Value.ToString())}"; - var methodName = nameof(GetProjectByUrnQueryHandler); + var methodName = nameof(GetProjectByUrnQueryHandler); - // Please use AutoMapper to make sure return a DTO instead of the actual aggregate/ entity + // Please use AutoMapper to make sure return a DTO instead of the actual aggregate/ entity - return await cacheService.GetOrAddAsync(cacheKey, async () => + return await cacheService.GetOrAddAsync(cacheKey, async () => + { + try { - try - { - var result = await projectRepository.GetAsync(p => p.Urn == request.Urn); + var result = await projectRepository.GetAsync(p => p.Urn == request.Urn); - return Result.Success(result); - } - catch (Exception ex) - { - return Result.Failure(ex.Message); - } + return Result.Success(result); + } + catch (Exception ex) + { + return Result.Failure(ex.Message); + } - }, methodName); - } + }, methodName); } } \ No newline at end of file diff --git a/src/Core/Dfe.Complete.Domain/Entities/Project.cs b/src/Core/Dfe.Complete.Domain/Entities/Project.cs index d68f2a78..bbd902e6 100644 --- a/src/Core/Dfe.Complete.Domain/Entities/Project.cs +++ b/src/Core/Dfe.Complete.Domain/Entities/Project.cs @@ -2,8 +2,6 @@ using Dfe.Complete.Domain.Enums; using Dfe.Complete.Domain.Events; using Dfe.Complete.Domain.ValueObjects; -using Dfe.Complete.Infrastructure.Models; -using Dfe.Complete.Utils; namespace Dfe.Complete.Domain.Entities; @@ -108,8 +106,8 @@ public Project(ProjectId id, Guid tasksDataId, DateOnly significantDate, bool isSignificantDateProvisional, - Ukprn incomingTrustUkprn, - Ukprn outgoingTrustUkprn, + Ukprn? incomingTrustUkprn, + Ukprn? outgoingTrustUkprn, Region? region, bool isDueTo2RI, bool? hasAcademyOrderBeenIssued, @@ -122,7 +120,9 @@ public Project(ProjectId id, ProjectTeam? team, UserId? regionalDeliveryOfficerId, UserId? assignedTo, - DateTime? assignedAt) + DateTime? assignedAt, + string? newTrustName, + string? newTrustReferenceNumber) { Id = id ?? throw new ArgumentNullException(nameof(id)); Urn = urn ?? throw new ArgumentNullException(nameof(urn)); @@ -149,8 +149,10 @@ public Project(ProjectId id, AssignedAt = assignedAt; AssignedToId = assignedTo; - } + NewTrustName = newTrustName; + NewTrustReferenceNumber = newTrustReferenceNumber; + } public static Project CreateConversionProject( ProjectId Id, @@ -201,7 +203,9 @@ public static Project CreateConversionProject( team, regionalDeliveryOfficerId, assignedToId, - assignedAt); + assignedAt, + null, + null); if (!string.IsNullOrEmpty(handoverComments)) { @@ -217,7 +221,6 @@ public static Project CreateConversionProject( return project; } - public static Project CreateTransferProject ( ProjectId Id, @@ -242,7 +245,7 @@ public static Project CreateTransferProject string advisoryBoardConditions, DateOnly significantDate, bool isSignificantDateProvisional, - bool isDueTo2RI, + bool isDueTo2RI, string? handoverComments ) { @@ -270,8 +273,54 @@ public static Project CreateTransferProject team, regionalDeliveryOfficerId, assignedToId, - assignedAt); + assignedAt, + null, + null); + + if (!string.IsNullOrEmpty(handoverComments)) + { + project.AddNote(new Note + { + CreatedAt = project.CreatedAt, ProjectId = project.Id, Body = handoverComments, + TaskIdentifier = "handover", UserId = assignedToId + }); + } + + project.AddDomainEvent(new ProjectCreatedEvent(project)); + + return project; + } + public static Project CreateMatConversionProject( + ProjectId Id, + Urn urn, + DateTime createdAt, + DateTime updatedAt, + TaskType taskType, + ProjectType projectType, + Guid tasksDataId, + Region? region, + ProjectTeam team, + UserId? regionalDeliveryOfficerId, + UserId? assignedToId, + DateTime? assignedAt, + string establishmentSharepointLink, + string incomingTrustSharepointLink, + DateOnly advisoryBoardDate, + string advisoryBoardConditions, + DateOnly significantDate, + bool isSignificantDateProvisional, + bool isDueTo2Ri, + string newTrustName, + string newTrustReferenceNumber, + bool hasDirectiveAcademyOrderBeenIssue, + string? handoverComments) + { + var project = new Project(Id, urn, createdAt, updatedAt, taskType, projectType, tasksDataId, significantDate, + isSignificantDateProvisional, null, null, region, isDueTo2Ri, hasDirectiveAcademyOrderBeenIssue, + advisoryBoardDate, advisoryBoardConditions, establishmentSharepointLink, incomingTrustSharepointLink, null, + null, team, regionalDeliveryOfficerId, assignedToId, assignedAt, newTrustName, newTrustReferenceNumber); + if (!string.IsNullOrEmpty(handoverComments)) { project.AddNote(new Note diff --git a/src/Frontend/Dfe.Complete/Pages/Projects/MatConversion/CreateNewProject.cshtml b/src/Frontend/Dfe.Complete/Pages/Projects/MatConversion/CreateNewProject.cshtml index 37495a42..b170e4c0 100644 --- a/src/Frontend/Dfe.Complete/Pages/Projects/MatConversion/CreateNewProject.cshtml +++ b/src/Frontend/Dfe.Complete/Pages/Projects/MatConversion/CreateNewProject.cshtml @@ -52,16 +52,16 @@ - + Trust name

Enter the proposed name for the new trust. This can be changed later on if necessary.

- @if (ErrorService.HasErrorForKey(trustRefNumber)) + @if (ErrorService.HasErrorForKey(trustName)) { - @(ErrorService.GetErrorMessage(trustRefNumber)) + @(ErrorService.GetErrorMessage(trustName)) }
diff --git a/src/Frontend/Dfe.Complete/Pages/Projects/MatConversion/CreateNewProject.cshtml.cs b/src/Frontend/Dfe.Complete/Pages/Projects/MatConversion/CreateNewProject.cshtml.cs index 6674f7b5..83c23508 100644 --- a/src/Frontend/Dfe.Complete/Pages/Projects/MatConversion/CreateNewProject.cshtml.cs +++ b/src/Frontend/Dfe.Complete/Pages/Projects/MatConversion/CreateNewProject.cshtml.cs @@ -1,39 +1,44 @@ using System.ComponentModel.DataAnnotations; +using Dfe.Complete.Application.Projects.Commands.CreateProject; +using Dfe.Complete.Application.Projects.Queries.GetProject; +using Dfe.Complete.Domain.ValueObjects; +using Dfe.Complete.Extensions; using Dfe.Complete.Services; using Dfe.Complete.Validators; +using MediatR; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; namespace Dfe.Complete.Pages.Projects.MatConversion; -public class CreateNewProject(IErrorService errorService) : PageModel +[Authorize(policy: "CanCreateProjects")] +public class CreateNewProject(ISender sender, IErrorService errorService) : PageModel { [BindProperty] [Urn] [Required(ErrorMessage = "Enter a school URN")] [Display(Name = "Urn")] public string URN { get; set; } - + [BindProperty] - [Ukprn] + [Trn] [Required(ErrorMessage = "Enter a Trust reference number (TRN)")] [Display(Name = "Trust reference number (TRN)")] public string TrustReferenceNumber { get; set; } - + [BindProperty] [Display(Name = "Trust name")] [Required(ErrorMessage = "Enter a Trust name")] public string TrustName { get; set; } - + [BindProperty] [Required(ErrorMessage = "Enter a date for the Advisory Board Date, like 1 4 2023")] [Display(Name = "Advisory Board Date")] public DateTime? AdvisoryBoardDate { get; set; } - - - [BindProperty] - public string AdvisoryBoardConditions { get; set; } - + + [BindProperty] public string? AdvisoryBoardConditions { get; set; } + [BindProperty] [Required(ErrorMessage = "Enter a date for the Provisional Conversion Date, like 1 4 2023")] [Display(Name = "Provisional Conversion Date")] @@ -51,39 +56,77 @@ public class CreateNewProject(IErrorService errorService) : PageModel [Required(ErrorMessage = "Enter an incoming trust Sharepoint link")] [Display(Name = "Incoming trust SharePoint link")] public string IncomingTrustSharePointLink { get; set; } - + [BindProperty] - [Required(ErrorMessage = "State if this project will be handed over to the Regional casework services team. Choose yes or no")] + [Required(ErrorMessage = + "State if this project will be handed over to the Regional casework services team. Choose yes or no")] [Display(Name = "Is Handing To RCS")] public bool? IsHandingToRCS { get; set; } - - [BindProperty] - public string HandoverComments { get; set; } - + + [BindProperty] public string? HandoverComments { get; set; } + [BindProperty] - [Required(ErrorMessage = "Select directive academy order or academy order, whichever has been used for this conversion")] + [Required(ErrorMessage = + "Select directive academy order or academy order, whichever has been used for this conversion")] [Display(Name = "Directive Academy Order")] public bool? DirectiveAcademyOrder { get; set; } - + [BindProperty] [Required(ErrorMessage = "State if the conversion is due to 2RI. Choose yes or no")] [Display(Name = "IsDueTo2RI")] - public bool? IsDueTo2RI { get; set; } - + public bool? IsDueTo2RI { get; set; } + public void OnGet() { - } - public async Task OnPost() + public async Task OnPost(CancellationToken cancellationToken) { + await CheckForExistingProjectWithTrust(cancellationToken); + if (!ModelState.IsValid) { errorService.AddErrors(ModelState); return Page(); } - - return Page(); + + var userAdId = User.Claims.SingleOrDefault(c => c.Type.Contains("objectidentifier"))?.Value; + + var createProjectCommand = new CreateMatConversionProjectCommand( + Urn: new Urn(int.Parse(URN)), + TrustName, + TrustReferenceNumber, + SignificantDate: ProvisionalConversionDate.HasValue + ? DateOnly.FromDateTime(ProvisionalConversionDate.Value) + : default, + IsSignificantDateProvisional: true, // will be set to false in the stakeholder kick off task + IncomingTrustSharepointLink: IncomingTrustSharePointLink, + EstablishmentSharepointLink: SchoolSharePointLink, //todo: is this correct? + IsDueTo2Ri: IsDueTo2RI ?? false, + AdvisoryBoardDate: AdvisoryBoardDate.HasValue ? DateOnly.FromDateTime(AdvisoryBoardDate.Value) : default, + AdvisoryBoardConditions: AdvisoryBoardConditions ?? string.Empty, + HasAcademyOrderBeenIssued: DirectiveAcademyOrder ?? default, + HandingOverToRegionalCaseworkService: IsHandingToRCS ?? default, + HandoverComments: HandoverComments, + UserAdId: userAdId + ); + + var createResponse = await sender.Send(createProjectCommand, cancellationToken); + + var projectId = createResponse.Value; + + return Redirect($"/projects/conversion-projects/{projectId}/created"); + } + + private async Task CheckForExistingProjectWithTrust(CancellationToken cancellationToken) + { + var result = await sender.Send(new GetProjectByTrnQuery(TrustReferenceNumber), cancellationToken); + var existingProject = result.Value; + + if (existingProject != null && !string.IsNullOrEmpty(existingProject.NewTrustName)) + { + ModelState.AddModelError(nameof(TrustName), + $"A trust with this TRN already exists. It is called {existingProject.NewTrustName}. Check the trust name you have entered for this conversion/transfer"); + } } - } \ No newline at end of file diff --git a/src/Frontend/Dfe.Complete/Services/TrustService.cs b/src/Frontend/Dfe.Complete/Services/TrustService.cs index 22f588dc..2cd8b24b 100644 --- a/src/Frontend/Dfe.Complete/Services/TrustService.cs +++ b/src/Frontend/Dfe.Complete/Services/TrustService.cs @@ -3,22 +3,15 @@ namespace Dfe.Complete.Services { - public class TrustService : AcademiesApiClient, ITrustService + public class TrustService(IHttpClientFactory httpClientFactory, ILogger logger) : AcademiesApiClient(httpClientFactory, logger), ITrustService { - private readonly IHttpClientFactory _httpClientFactory; - private readonly ILogger _logger; - private const string _url = @"v4/trusts"; - - public TrustService(IHttpClientFactory httpClientFactory, ILogger logger) : base(httpClientFactory, logger) - { - _httpClientFactory = httpClientFactory; - _logger = logger; - } + private readonly IHttpClientFactory _httpClientFactory = httpClientFactory; + private readonly ILogger _logger = logger; + private const string Url = "v4/trusts"; public async Task> GetTrustByUkprn(string ukprn) { - var result = await GetEnumerable($"{_url}?ukPrn={ukprn}"); - + var result = await GetEnumerable($"{Url}?ukPrn={ukprn}"); return result; } } diff --git a/src/Frontend/Dfe.Complete/StartupConfiguration/DependencyConfigurationExtensions.cs b/src/Frontend/Dfe.Complete/StartupConfiguration/DependencyConfigurationExtensions.cs index 96bce8d4..9bab1cba 100644 --- a/src/Frontend/Dfe.Complete/StartupConfiguration/DependencyConfigurationExtensions.cs +++ b/src/Frontend/Dfe.Complete/StartupConfiguration/DependencyConfigurationExtensions.cs @@ -16,7 +16,6 @@ public static IServiceCollection AddClientDependencies(this IServiceCollection s services.AddScoped(); - // services.AddScoped(typeof(ICompleteRepository<>), typeof(CompleteRepository<>)); return services; } } diff --git a/src/Frontend/Dfe.Complete/Validators/TransferUkprnAttribute.cs b/src/Frontend/Dfe.Complete/Validators/TransferUkprnAttribute.cs index 1a5ef199..7275520d 100644 --- a/src/Frontend/Dfe.Complete/Validators/TransferUkprnAttribute.cs +++ b/src/Frontend/Dfe.Complete/Validators/TransferUkprnAttribute.cs @@ -13,8 +13,7 @@ public TransferUkprnAttribute(string comparisonProperty) { _comparisonProperty = comparisonProperty; } - - + protected override ValidationResult IsValid(object value, ValidationContext validationContext) { // Fetch the display name if it is provided diff --git a/src/Frontend/Dfe.Complete/Validators/TrnAttribute.cs b/src/Frontend/Dfe.Complete/Validators/TrnAttribute.cs new file mode 100644 index 00000000..60301ebf --- /dev/null +++ b/src/Frontend/Dfe.Complete/Validators/TrnAttribute.cs @@ -0,0 +1,23 @@ +using System.ComponentModel.DataAnnotations; +using System.Text.RegularExpressions; + +namespace Dfe.Complete.Validators; + +public partial class TrnAttribute : ValidationAttribute +{ + protected override ValidationResult? IsValid(object? value, ValidationContext validationContext) + { + var trn = value as string; + + if (string.IsNullOrEmpty(trn)) + return new ValidationResult("Enter a Trust reference number (TRN)"); + + if (TrnRegex().IsMatch(trn) == false) + return new ValidationResult("The Trust reference number must be 'TR' followed by 5 numbers, e.g. TR01234"); + + return ValidationResult.Success; + } + + [GeneratedRegex("^TR\\d{5}$")] + private static partial Regex TrnRegex(); +} \ No newline at end of file diff --git a/src/Frontend/Dfe.Complete/Validators/UkprnAttribute.cs b/src/Frontend/Dfe.Complete/Validators/UkprnAttribute.cs index 2872a686..f86a1dbe 100644 --- a/src/Frontend/Dfe.Complete/Validators/UkprnAttribute.cs +++ b/src/Frontend/Dfe.Complete/Validators/UkprnAttribute.cs @@ -2,45 +2,38 @@ using System.ComponentModel.DataAnnotations; using System.Reflection; -namespace Dfe.Complete.Validators +namespace Dfe.Complete.Validators; + +public class UkprnAttribute : ValidationAttribute { - public class UkprnAttribute : ValidationAttribute + protected override ValidationResult IsValid(object value, ValidationContext validationContext) { - protected override ValidationResult IsValid(object value, ValidationContext validationContext) - { - // Fetch the display name if it is provided - var property = validationContext.ObjectType.GetProperty(validationContext.MemberName); - var displayAttribute = property?.GetCustomAttribute(); - var displayName = displayAttribute?.GetName() ?? validationContext.DisplayName; - - var ukprn = value as string; + // Fetch the display name if it is provided + var property = validationContext.ObjectType.GetProperty(validationContext.MemberName); + var displayAttribute = property?.GetCustomAttribute(); + var displayName = displayAttribute?.GetName() ?? validationContext.DisplayName; - if (string.IsNullOrEmpty(ukprn)) - { - var errorMessage = $"Enter a UKPRN"; + var ukprn = value as string; - return new ValidationResult(errorMessage); - } + if (string.IsNullOrEmpty(ukprn)) + return new ValidationResult("Enter a UKPRN"); - if (ukprn.Length != 8) - { - var errorMessage = $"The {displayName} must be 8 digits long and start with a 1. For example, 12345678."; + if (ukprn.Length != 8) + return new ValidationResult( + $"The {displayName} must be 8 digits long and start with a 1. For example, 12345678."); - return new ValidationResult(errorMessage); - } - var trustService = (ITrustService)validationContext.GetService(typeof(ITrustService)); - var result = trustService.GetTrustByUkprn(ukprn).Result; + var trustService = (ITrustService)validationContext.GetService(typeof(ITrustService)); + var result = trustService.GetTrustByUkprn(ukprn).Result; - if (!result.Any()) - { - var errorMessage = $"There's no trust with that UKPRN. Check the number you entered is correct"; - - return new ValidationResult(errorMessage); - } + if (!result.Any()) + { + var errorMessage = "There's no trust with that UKPRN. Check the number you entered is correct"; - // If valid, return success - return ValidationResult.Success; + return new ValidationResult(errorMessage); } + + // If valid, return success + return ValidationResult.Success; } -} +} \ No newline at end of file diff --git a/src/Tests/Dfe.Complete.Application.Tests/CommandHandlers/Project/CreateProjectCommandHandlerTests.cs b/src/Tests/Dfe.Complete.Application.Tests/CommandHandlers/Project/CreateConversionProjectCommandHandlerTests.cs similarity index 100% rename from src/Tests/Dfe.Complete.Application.Tests/CommandHandlers/Project/CreateProjectCommandHandlerTests.cs rename to src/Tests/Dfe.Complete.Application.Tests/CommandHandlers/Project/CreateConversionProjectCommandHandlerTests.cs diff --git a/src/Tests/Dfe.Complete.Application.Tests/CommandHandlers/Project/CreateMatConversionProjectCommandHandlerTests.cs b/src/Tests/Dfe.Complete.Application.Tests/CommandHandlers/Project/CreateMatConversionProjectCommandHandlerTests.cs new file mode 100644 index 00000000..c95f35ac --- /dev/null +++ b/src/Tests/Dfe.Complete.Application.Tests/CommandHandlers/Project/CreateMatConversionProjectCommandHandlerTests.cs @@ -0,0 +1,177 @@ +using System.Linq.Expressions; +using AutoFixture.Xunit2; +using DfE.CoreLibs.Testing.AutoFixture.Attributes; +using DfE.CoreLibs.Testing.AutoFixture.Customizations; +using Dfe.Complete.Application.Projects.Commands.CreateProject; +using Dfe.Complete.Domain.Entities; +using Dfe.Complete.Domain.Enums; +using Dfe.Complete.Domain.Interfaces.Repositories; +using Dfe.Complete.Domain.ValueObjects; +using Dfe.Complete.Tests.Common.Customizations.Behaviours; +using Dfe.Complete.Utils; +using NSubstitute; + +namespace Dfe.Complete.Application.Tests.CommandHandlers.Project +{ + public class CreateMatConversionProjectCommandHandlerTests + { + [Theory] + [CustomAutoData(typeof(DateOnlyCustomization), typeof(IgnoreVirtualMembersCustomisation))] + public async Task Handle_ShouldCreateAndReturnProjectId_WhenCommandIsValid( + [Frozen] ICompleteRepository mockProjectRepository, + [Frozen] ICompleteRepository mockConversionTaskRepository, + [Frozen] ICompleteRepository mockUserRepository, + CreateMatConversionProjectCommandHandler handler, + CreateMatConversionProjectCommand command + ) + { + // Arrange + const ProjectTeam userTeam = ProjectTeam.WestMidlands; + var user = new User + { + Id = new UserId(Guid.NewGuid()), + Team = userTeam.ToDescription() + }; + + var createdAt = DateTime.UtcNow; + var conversionTaskId = Guid.NewGuid(); + var conversionTask = new ConversionTasksData(new TaskDataId(conversionTaskId), createdAt, createdAt); + + mockUserRepository + .FindAsync(Arg.Any>>()) + .Returns(user); + + Domain.Entities.Project capturedProject = null!; + mockProjectRepository + .AddAsync(Arg.Do(proj => capturedProject = proj), Arg.Any()) + .Returns(callInfo => Task.FromResult(capturedProject)); + + mockConversionTaskRepository + .AddAsync(Arg.Any(), Arg.Any()) + .Returns(conversionTask); + + // Act + var projectId = await handler.Handle(command, default); + + // Assert + Assert.NotNull(projectId); + Assert.IsType(projectId); + + await mockProjectRepository.Received(1) + .AddAsync(capturedProject, Arg.Any()); + await mockConversionTaskRepository.Received(1) + .AddAsync(Arg.Any(), Arg.Any()); + + // Verify key fields are mapped correctly + Assert.Equal(command.Urn, capturedProject.Urn); + Assert.Equal(command.NewTrustName, capturedProject.NewTrustName); + Assert.Equal(command.NewTrustReferenceNumber, capturedProject.NewTrustReferenceNumber); + Assert.Equal(command.SignificantDate, capturedProject.SignificantDate); + Assert.Equal(command.IsSignificantDateProvisional, capturedProject.SignificantDateProvisional); + Assert.Equal(command.IsDueTo2Ri, capturedProject.TwoRequiresImprovement); + Assert.Equal(command.HasAcademyOrderBeenIssued, capturedProject.DirectiveAcademyOrder); + Assert.Equal(command.AdvisoryBoardDate, capturedProject.AdvisoryBoardDate); + Assert.Equal(command.AdvisoryBoardConditions, capturedProject.AdvisoryBoardConditions); + Assert.Equal(command.EstablishmentSharepointLink, capturedProject.EstablishmentSharepointLink); + Assert.Equal(command.IncomingTrustSharepointLink, capturedProject.IncomingTrustSharepointLink); + Assert.Equal(command.HandoverComments, capturedProject.Notes.FirstOrDefault()?.Body); + + Assert.Equal(command.NewTrustName, capturedProject.NewTrustName); + Assert.Equal(command.NewTrustReferenceNumber, capturedProject.NewTrustReferenceNumber); + } + + [Theory] + [CustomAutoData(typeof(DateOnlyCustomization), typeof(IgnoreVirtualMembersCustomisation))] + public async Task Handle_ShouldSetTeamToRcs_WhenHandoverToRcsTrue( + [Frozen] ICompleteRepository mockProjectRepository, + [Frozen] ICompleteRepository mockConversionTaskRepository, + [Frozen] ICompleteRepository mockUserRepository, + CreateMatConversionProjectCommandHandler handler, + CreateMatConversionProjectCommand command + ) + { + // Arrange + command = command with { HandingOverToRegionalCaseworkService = true }; + + var userTeam = ProjectTeam.WestMidlands; + var user = new User + { + Id = new UserId(Guid.NewGuid()), + Team = userTeam.ToDescription() + }; + + var createdAt = DateTime.UtcNow; + var conversionTaskId = Guid.NewGuid(); + var conversionTask = new ConversionTasksData(new TaskDataId(conversionTaskId), createdAt, createdAt); + + mockUserRepository + .FindAsync(Arg.Any>>()) + .Returns(user); + + Domain.Entities.Project capturedProject = null!; + mockProjectRepository + .AddAsync(Arg.Do(proj => capturedProject = proj), Arg.Any()) + .Returns(callInfo => Task.FromResult(capturedProject)); + + mockConversionTaskRepository + .AddAsync(Arg.Any(), Arg.Any()) + .Returns(conversionTask); + + // Act + var projectId = await handler.Handle(command, default); + + // Assert + Assert.NotNull(projectId); + Assert.Equal(ProjectTeam.RegionalCaseWorkerServices, capturedProject.Team); + Assert.Null(capturedProject.AssignedAt); + Assert.Null(capturedProject.AssignedToId); + } + + [Theory] + [CustomAutoData(typeof(DateOnlyCustomization), typeof(IgnoreVirtualMembersCustomisation))] + public async Task Handle_ShouldSetTeam_AssignedAt_AssignedTo_WhenNotHandingOverToRcs( + [Frozen] ICompleteRepository mockProjectRepository, + [Frozen] ICompleteRepository mockConversionTaskRepository, + [Frozen] ICompleteRepository mockUserRepository, + CreateMatConversionProjectCommandHandler handler, + CreateMatConversionProjectCommand command + ) + { + // Arrange + command = command with { HandingOverToRegionalCaseworkService = false }; + + const ProjectTeam userTeam = ProjectTeam.WestMidlands; + var user = new User + { + Id = new UserId(Guid.NewGuid()), + Team = userTeam.ToDescription() + }; + + var createdAt = DateTime.UtcNow; + var conversionTaskId = Guid.NewGuid(); + var conversionTask = new ConversionTasksData(new TaskDataId(conversionTaskId), createdAt, createdAt); + + mockUserRepository + .FindAsync(Arg.Any>>()) + .Returns(user); + + Domain.Entities.Project capturedProject = null!; + mockProjectRepository + .AddAsync(Arg.Do(proj => capturedProject = proj), Arg.Any()) + .Returns(callInfo => Task.FromResult(capturedProject)); + + mockConversionTaskRepository + .AddAsync(Arg.Any(), Arg.Any()) + .Returns(conversionTask); + + // Act + var projectId = await handler.Handle(command, default); + + // Assert + Assert.NotNull(projectId); + Assert.Equal(userTeam, capturedProject.Team); + Assert.NotNull(capturedProject.AssignedAt); + Assert.NotNull(capturedProject.AssignedToId); + } + } +} diff --git a/src/Tests/Dfe.Complete.Application.Tests/QueryHandlers/Project/GetProjectByTrnHandlerTests.cs b/src/Tests/Dfe.Complete.Application.Tests/QueryHandlers/Project/GetProjectByTrnHandlerTests.cs new file mode 100644 index 00000000..507992f9 --- /dev/null +++ b/src/Tests/Dfe.Complete.Application.Tests/QueryHandlers/Project/GetProjectByTrnHandlerTests.cs @@ -0,0 +1,83 @@ +using System.Linq.Expressions; +using AutoFixture.Xunit2; +using DfE.CoreLibs.Testing.AutoFixture.Attributes; +using DfE.CoreLibs.Testing.AutoFixture.Customizations; +using Dfe.Complete.Application.Projects.Queries.GetProject; +using Dfe.Complete.Domain.Interfaces.Repositories; +using Dfe.Complete.Tests.Common.Customizations.Behaviours; +using Dfe.Complete.Tests.Common.Customizations.Models; +using NSubstitute; +using NSubstitute.ExceptionExtensions; + +namespace Dfe.Complete.Application.Tests.QueryHandlers.Project +{ + public class GetProjectByTrnQueryHandlerTests + { + [Theory] + [CustomAutoData(typeof(DateOnlyCustomization), typeof(ProjectCustomization), typeof(IgnoreVirtualMembersCustomisation))] + public async Task Handle_ShouldReturnSuccess_WhenProjectIsFound( + [Frozen] ICompleteRepository mockRepository, + GetProjectByTrn handler, + Domain.Entities.Project project) + { + // Arrange + mockRepository + .FindAsync(Arg.Any>>(), Arg.Any()) + .Returns(project); + + var query = new GetProjectByTrnQuery(project.NewTrustReferenceNumber); + + // Act + var result = await handler.Handle(query, CancellationToken.None); + + // Assert + Assert.True(result.IsSuccess); + Assert.NotNull(result.Value); + Assert.Equal(project.Id.Value, result.Value.ProjectId); + Assert.Equal(project.NewTrustName, result.Value.NewTrustName); + } + + [Theory] + [CustomAutoData(typeof(DateOnlyCustomization), typeof(ProjectCustomization), typeof(IgnoreVirtualMembersCustomisation))] + public async Task Handle_ShouldReturnFailure_WhenRepositoryThrowsException( + [Frozen] ICompleteRepository mockRepository, + GetProjectByTrn handler, + Domain.Entities.Project project) + { + // Arrange + var expectedMessage = "Repository error"; + mockRepository + .FindAsync(Arg.Any>>(), Arg.Any()) + .Throws(new Exception(expectedMessage)); + + var query = new GetProjectByTrnQuery(project.NewTrustReferenceNumber); + + // Act + var result = await handler.Handle(query, CancellationToken.None); + + // Assert + Assert.False(result.IsSuccess); + Assert.Equal(expectedMessage, result.Error); + } + + [Theory] + [CustomAutoData(typeof(DateOnlyCustomization), typeof(ProjectCustomization), typeof(IgnoreVirtualMembersCustomisation))] + public async Task Handle_ShouldThrowNullReferenceException_WhenProjectIsNotFound( + [Frozen] ICompleteRepository mockRepository, + GetProjectByTrn handler, + Domain.Entities.Project project) + { + // Arrange + mockRepository + .FindAsync(Arg.Any>>(), Arg.Any())! + .Returns((Domain.Entities.Project?)null); + + var query = new GetProjectByTrnQuery(project.NewTrustReferenceNumber); + + // Act & Assert + var result = await handler.Handle(query, CancellationToken.None); + + Assert.False(result.IsSuccess); + } + } +} diff --git a/src/Tests/Dfe.Complete.Application.Tests/QueryHandlers/Project/GetProjectByUrnQueryHandlerTests.cs b/src/Tests/Dfe.Complete.Application.Tests/QueryHandlers/Project/GetProjectByUrnQueryHandlerTests.cs index f1245202..1180cec6 100644 --- a/src/Tests/Dfe.Complete.Application.Tests/QueryHandlers/Project/GetProjectByUrnQueryHandlerTests.cs +++ b/src/Tests/Dfe.Complete.Application.Tests/QueryHandlers/Project/GetProjectByUrnQueryHandlerTests.cs @@ -10,8 +10,6 @@ using System.Linq.Expressions; using Dfe.Complete.Domain.Enums; using Dfe.Complete.Domain.ValueObjects; -using Dfe.Complete.Utils; -using Microsoft.IdentityModel.Tokens; namespace Dfe.Complete.Application.Tests.QueryHandlers.Project { diff --git a/src/Tests/Dfe.Complete.Domain.Tests/Aggregates/ProjectTests.cs b/src/Tests/Dfe.Complete.Domain.Tests/Aggregates/ProjectTests.cs index 8020e73b..c5eabc7c 100644 --- a/src/Tests/Dfe.Complete.Domain.Tests/Aggregates/ProjectTests.cs +++ b/src/Tests/Dfe.Complete.Domain.Tests/Aggregates/ProjectTests.cs @@ -1,328 +1,316 @@ +using Dfe.Complete.Tests.Common.Customizations.Behaviours; using DfE.CoreLibs.Testing.AutoFixture.Attributes; using Dfe.Complete.Tests.Common.Customizations.Models; using DfE.CoreLibs.Testing.AutoFixture.Customizations; -using Note = Dfe.Complete.Domain.Entities.Note; using Project = Dfe.Complete.Domain.Entities.Project; -using ProjectId = Dfe.Complete.Domain.ValueObjects.ProjectId; -using ProjectTeam = Dfe.Complete.Domain.Enums.ProjectTeam; -using ProjectType = Dfe.Complete.Domain.Enums.ProjectType; -using Region = Dfe.Complete.Domain.Enums.Region; -using TaskType = Dfe.Complete.Domain.Enums.TaskType; -using Ukprn = Dfe.Complete.Domain.ValueObjects.Ukprn; -using Urn = Dfe.Complete.Domain.ValueObjects.Urn; -using UserId = Dfe.Complete.Domain.ValueObjects.UserId; -using System.Text.RegularExpressions; -using Microsoft.AspNetCore.Http.HttpResults; -using NSubstitute.ExceptionExtensions; namespace Dfe.Complete.Domain.Tests.Aggregates { public class ProjectTests { [Theory] - [CustomAutoData(typeof(ProjectCustomization), typeof(DateOnlyCustomization))] - public void Constructor_ShouldThrowArgumentNullException_WhenProjectUrnIsNull( - ProjectId id, - DateTime createdAt, - DateTime updatedAt, - TaskType taskType, - ProjectType projectType, - Guid tasksDataId, - DateOnly significantDate, - bool isSignificantDateProvisional, - Ukprn incomingTrustUkprn, - Region region, - bool isDueTo2RI, - bool hasAcademyOrderBeenIssued, - DateOnly advisoryBoardDate, - string advisoryBoardConditions, - string establishmentSharepointLink, - string incomingTrustSharepointLink, - Guid groupId, - ProjectTeam team, - UserId regionalDeliveryOfficerId, - UserId assignedToId, - DateTime? assignedAt - ) + [CustomAutoData(typeof(ProjectCustomization), typeof(DateOnlyCustomization), + typeof(IgnoreVirtualMembersCustomisation))] + public void Constructor_ShouldThrowArgumentNullException_WhenProjectUrnIsNull(Project projectCustomisation) { + // Arrange + projectCustomisation.Urn = null; + // Act & Assert var exception = Assert.Throws(() => new Project( - id, - null, - createdAt, - updatedAt, - taskType, - projectType, - tasksDataId, - significantDate, - isSignificantDateProvisional, - incomingTrustUkprn, - null, - region, - isDueTo2RI, - hasAcademyOrderBeenIssued, - advisoryBoardDate, - advisoryBoardConditions, - establishmentSharepointLink, - incomingTrustSharepointLink, - null, - groupId, - team, - regionalDeliveryOfficerId, - assignedToId, - assignedAt)); - - - + projectCustomisation.Id, + projectCustomisation.Urn, + projectCustomisation.CreatedAt, + projectCustomisation.UpdatedAt, + projectCustomisation.TasksDataType!.Value, + projectCustomisation.Type!.Value, + projectCustomisation.TasksDataId!.Value, + projectCustomisation.SignificantDate!.Value, + projectCustomisation.SignificantDateProvisional!.Value, + projectCustomisation.IncomingTrustUkprn, + projectCustomisation.OutgoingTrustUkprn, + projectCustomisation.Region, + projectCustomisation.TwoRequiresImprovement!.Value, + projectCustomisation.DirectiveAcademyOrder, + projectCustomisation.AdvisoryBoardDate!.Value, + projectCustomisation.AdvisoryBoardConditions!, + projectCustomisation.EstablishmentSharepointLink!, + projectCustomisation.IncomingTrustSharepointLink!, + projectCustomisation.OutgoingTrustSharepointLink, + projectCustomisation.GroupId, + projectCustomisation.Team, + projectCustomisation.RegionalDeliveryOfficerId, + projectCustomisation.AssignedToId, + projectCustomisation.AssignedAt, + projectCustomisation.NewTrustName, + projectCustomisation.NewTrustReferenceNumber + )); Assert.Equal("urn", exception.ParamName); } [Theory] - [CustomAutoData(typeof(ProjectCustomization), typeof(DateOnlyCustomization))] + [CustomAutoData(typeof(ProjectCustomization), typeof(DateOnlyCustomization), + typeof(IgnoreVirtualMembersCustomisation))] public void Constructor_ShouldThrowArgumentNullException_WhenProjectCreatedAtIsDefault( - ProjectId id, - Urn urn, - DateTime updatedAt, - TaskType taskType, - ProjectType projectType, - Guid tasksDataId, - DateOnly significantDate, - bool isSignificantDateProvisional, - Ukprn incomingTrustUkprn, - Region region, - bool isDueTo2RI, - bool hasAcademyOrderBeenIssued, - DateOnly advisoryBoardDate, - string advisoryBoardConditions, - string establishmentSharepointLink, - string incomingTrustSharepointLink, - Guid groupId, - ProjectTeam team, - UserId regionalDeliveryOfficerId, - UserId assignedToId, - DateTime? assignedAt - ) + Project projCustomisation) { + // Arrange + projCustomisation.CreatedAt = default; + // Act & Assert var exception = Assert.Throws(() => new Project( - id, - urn, - default, - updatedAt, - taskType, - projectType, - tasksDataId, - significantDate, - isSignificantDateProvisional, - incomingTrustUkprn, - null, - region, - isDueTo2RI, - hasAcademyOrderBeenIssued, - advisoryBoardDate, - advisoryBoardConditions, - establishmentSharepointLink, - incomingTrustSharepointLink, - null, - groupId, - team, - regionalDeliveryOfficerId, - assignedToId, - assignedAt)); + projCustomisation.Id, + projCustomisation.Urn!, + projCustomisation.CreatedAt, + projCustomisation.UpdatedAt, + projCustomisation.TasksDataType!.Value, + projCustomisation.Type!.Value, + projCustomisation.TasksDataId!.Value, + projCustomisation.SignificantDate!.Value, + projCustomisation.SignificantDateProvisional!.Value, + projCustomisation.IncomingTrustUkprn, + projCustomisation.OutgoingTrustUkprn, + projCustomisation.Region, + projCustomisation.TwoRequiresImprovement!.Value, + projCustomisation.DirectiveAcademyOrder, + projCustomisation.AdvisoryBoardDate!.Value, + projCustomisation.AdvisoryBoardConditions!, + projCustomisation.EstablishmentSharepointLink!, + projCustomisation.IncomingTrustSharepointLink!, + projCustomisation.OutgoingTrustSharepointLink, + projCustomisation.GroupId, + projCustomisation.Team, + projCustomisation.RegionalDeliveryOfficerId, + projCustomisation.AssignedToId, + projCustomisation.AssignedAt, + projCustomisation.NewTrustName, + projCustomisation.NewTrustReferenceNumber + )); Assert.Equal("createdAt", exception.ParamName); } [Theory] - [CustomAutoData(typeof(ProjectCustomization), typeof(DateOnlyCustomization))] + [CustomAutoData(typeof(ProjectCustomization), typeof(DateOnlyCustomization), + typeof(IgnoreVirtualMembersCustomisation))] public void Constructor_ShouldThrowArgumentNullException_WhenProjectUpdatedAtIsDefault( - ProjectId id, - Urn urn, - DateTime createdAt, - TaskType taskType, - ProjectType projectType, - Guid tasksDataId, - DateOnly significantDate, - bool isSignificantDateProvisional, - Ukprn incomingTrustUkprn, - Region region, - bool isDueTo2RI, - bool hasAcademyOrderBeenIssued, - DateOnly advisoryBoardDate, - string advisoryBoardConditions, - string establishmentSharepointLink, - string incomingTrustSharepointLink, - Guid groupId, - ProjectTeam team, - UserId regionalDeliveryOfficerId, - UserId assignedToId, - DateTime? assignedAt - ) + Project projCustomisation) { + // Arrange + projCustomisation.UpdatedAt = default; + // Act & Assert var exception = Assert.Throws(() => new Project( - id, - urn, - createdAt, - default, - taskType, - projectType, - tasksDataId, - significantDate, - isSignificantDateProvisional, - incomingTrustUkprn, - null, - region, - isDueTo2RI, - hasAcademyOrderBeenIssued, - advisoryBoardDate, - advisoryBoardConditions, - establishmentSharepointLink, - incomingTrustSharepointLink, - null, - groupId, - team, - regionalDeliveryOfficerId, - assignedToId, - assignedAt)); + projCustomisation.Id, + projCustomisation.Urn!, + projCustomisation.CreatedAt, + projCustomisation.UpdatedAt, + projCustomisation.TasksDataType!.Value, + projCustomisation.Type!.Value, + projCustomisation.TasksDataId!.Value, + projCustomisation.SignificantDate!.Value, + projCustomisation.SignificantDateProvisional!.Value, + projCustomisation.IncomingTrustUkprn, + projCustomisation.OutgoingTrustUkprn, + projCustomisation.Region, + projCustomisation.TwoRequiresImprovement!.Value, + projCustomisation.DirectiveAcademyOrder, + projCustomisation.AdvisoryBoardDate!.Value, + projCustomisation.AdvisoryBoardConditions!, + projCustomisation.EstablishmentSharepointLink!, + projCustomisation.IncomingTrustSharepointLink!, + projCustomisation.OutgoingTrustSharepointLink, + projCustomisation.GroupId, + projCustomisation.Team, + projCustomisation.RegionalDeliveryOfficerId, + projCustomisation.AssignedToId, + projCustomisation.AssignedAt, + projCustomisation.NewTrustName, + projCustomisation.NewTrustReferenceNumber + )); Assert.Equal("updatedAt", exception.ParamName); } - [Theory] - [CustomAutoData(typeof(ProjectCustomization), typeof(DateOnlyCustomization))] - public void Constructor_ShouldCorrectlySetFields( - ProjectId id, - Urn urn, - DateTime createdAt, - DateTime updatedAt, - TaskType taskType, - ProjectType projectType, - Guid tasksDataId, - DateOnly significantDate, - bool isSignificantDateProvisional, - Ukprn incomingTrustUkprn, - Region region, - bool isDueTo2RI, - bool hasAcademyOrderBeenIssued, - DateOnly advisoryBoardDate, - string advisoryBoardConditions, - string establishmentSharepointLink, - string incomingTrustSharepointLink, - Guid? groupId, - ProjectTeam team, - DateTime? assignedAt, - UserId? assignedToId, - UserId? regionalDeliveryOfficerId - ) + [CustomAutoData(typeof(ProjectCustomization), typeof(DateOnlyCustomization), + typeof(IgnoreVirtualMembersCustomisation))] + public void Constructor_ShouldCorrectlySetFields(Project projectCustomisation) { - // Act & Assert + // Act var project = new Project( - id, - urn, - createdAt, - updatedAt, - taskType, - projectType, - tasksDataId, - significantDate, - isSignificantDateProvisional, - incomingTrustUkprn, - null, - region, - isDueTo2RI, - hasAcademyOrderBeenIssued, - advisoryBoardDate, - advisoryBoardConditions, - establishmentSharepointLink, - incomingTrustSharepointLink, - null, - groupId, - team, - regionalDeliveryOfficerId, - assignedToId, - assignedAt); + projectCustomisation.Id, + projectCustomisation.Urn!, + projectCustomisation.CreatedAt, + projectCustomisation.UpdatedAt, + projectCustomisation.TasksDataType!.Value, + projectCustomisation.Type!.Value, + projectCustomisation.TasksDataId!.Value, + projectCustomisation.SignificantDate!.Value, + projectCustomisation.SignificantDateProvisional!.Value, + projectCustomisation.IncomingTrustUkprn, + projectCustomisation.OutgoingTrustUkprn, + projectCustomisation.Region, + projectCustomisation.TwoRequiresImprovement!.Value, + projectCustomisation.DirectiveAcademyOrder, + projectCustomisation.AdvisoryBoardDate!.Value, + projectCustomisation.AdvisoryBoardConditions!, + projectCustomisation.EstablishmentSharepointLink!, + projectCustomisation.IncomingTrustSharepointLink!, + projectCustomisation.OutgoingTrustSharepointLink, + projectCustomisation.GroupId, + projectCustomisation.Team, + projectCustomisation.RegionalDeliveryOfficerId, + projectCustomisation.AssignedToId, + projectCustomisation.AssignedAt, + projectCustomisation.NewTrustName, + projectCustomisation.NewTrustReferenceNumber + ); - Assert.Equal(urn, project.Urn); + // Assert + Assert.Equal(projectCustomisation.Urn, project.Urn); + Assert.Equal(projectCustomisation.CreatedAt, project.CreatedAt); + Assert.Equal(projectCustomisation.UpdatedAt, project.UpdatedAt); + Assert.Equal(projectCustomisation.TasksDataType, project.TasksDataType); + Assert.Equal(projectCustomisation.Type, project.Type); + Assert.Equal(projectCustomisation.TasksDataId, project.TasksDataId); + Assert.Equal(projectCustomisation.SignificantDate, project.SignificantDate); + Assert.Equal(projectCustomisation.SignificantDateProvisional, project.SignificantDateProvisional); + Assert.Equal(projectCustomisation.IncomingTrustUkprn, project.IncomingTrustUkprn); + Assert.Equal(projectCustomisation.OutgoingTrustUkprn, project.OutgoingTrustUkprn); + Assert.Equal(projectCustomisation.Region, project.Region); + Assert.Equal(projectCustomisation.TwoRequiresImprovement, project.TwoRequiresImprovement); + Assert.Equal(projectCustomisation.DirectiveAcademyOrder, project.DirectiveAcademyOrder); + Assert.Equal(projectCustomisation.AdvisoryBoardDate, project.AdvisoryBoardDate); + Assert.Equal(projectCustomisation.AdvisoryBoardConditions, project.AdvisoryBoardConditions); + Assert.Equal(projectCustomisation.EstablishmentSharepointLink, project.EstablishmentSharepointLink); + Assert.Equal(projectCustomisation.IncomingTrustSharepointLink, project.IncomingTrustSharepointLink); + Assert.Equal(projectCustomisation.OutgoingTrustSharepointLink, project.OutgoingTrustSharepointLink); + Assert.Equal(projectCustomisation.GroupId, project.GroupId); + Assert.Equal(projectCustomisation.Team, project.Team); + Assert.Equal(projectCustomisation.RegionalDeliveryOfficerId, project.RegionalDeliveryOfficerId); + Assert.Equal(projectCustomisation.AssignedToId, project.AssignedToId); + Assert.Equal(projectCustomisation.AssignedAt, project.AssignedAt); + Assert.Equal(projectCustomisation.NewTrustName, project.NewTrustName); + Assert.Equal(projectCustomisation.NewTrustReferenceNumber, project.NewTrustReferenceNumber); } [Theory] - [CustomAutoData(typeof(ProjectCustomization), typeof(DateOnlyCustomization))] - public void Factory_Create_ShouldCorrectlySetFields( - ProjectId id, - Urn urn, - DateTime createdAt, - DateTime updatedAt, - TaskType taskType, - ProjectType projectType, - Guid tasksDataId, - DateOnly significantDate, - bool isSignificantDateProvisional, - Ukprn incomingTrustUkprn, - Region region, - bool isDueTo2RI, - bool hasAcademyOrderBeenIssued, - DateOnly advisoryBoardDate, - string advisoryBoardConditions, - string establishmentSharepointLink, - string incomingTrustSharepointLink, - DateOnly provisionalConversionDate, - bool handingOverToRegionalCaseworkService, - Guid? groupId, - ProjectTeam team, - DateTime? assignedAt, - UserId? assignedToId, - UserId? regionalDeliveryOfficer) + [CustomAutoData(typeof(ProjectCustomization), typeof(DateOnlyCustomization), + typeof(IgnoreVirtualMembersCustomisation))] + public void Factory_CreateConversionProject_ShouldCorrectlySetFields(Project projCustomisation) { - // Act & Assert + // Arrange var handoverComment = "handover comment"; - + + // Act var project = Project.CreateConversionProject( - id, - urn, - createdAt, - updatedAt, - taskType, - projectType, - tasksDataId, - significantDate, - isSignificantDateProvisional, - incomingTrustUkprn, - region, - isDueTo2RI, - hasAcademyOrderBeenIssued, - advisoryBoardDate, - advisoryBoardConditions, - establishmentSharepointLink, - incomingTrustSharepointLink, - groupId, - team, - regionalDeliveryOfficer, - assignedToId, - assignedAt, - handoverComment); + projCustomisation.Id, + projCustomisation.Urn!, + projCustomisation.CreatedAt, + projCustomisation.UpdatedAt, + projCustomisation.TasksDataType!.Value, + projCustomisation.Type!.Value, + projCustomisation.TasksDataId!.Value, + projCustomisation.SignificantDate!.Value, + projCustomisation.SignificantDateProvisional!.Value, + projCustomisation.IncomingTrustUkprn, // The factory requires non-null + projCustomisation.Region, + projCustomisation.TwoRequiresImprovement!.Value, + projCustomisation.DirectiveAcademyOrder!.Value, + projCustomisation.AdvisoryBoardDate!.Value, + projCustomisation.AdvisoryBoardConditions!, + projCustomisation.EstablishmentSharepointLink!, + projCustomisation.IncomingTrustSharepointLink!, + projCustomisation.GroupId, + projCustomisation.Team!.Value, + projCustomisation.RegionalDeliveryOfficerId, + projCustomisation.AssignedToId, + projCustomisation.AssignedAt, + handoverComment + ); + + // Assert + Assert.Equal(projCustomisation.Urn, project.Urn); + Assert.Equal(projCustomisation.CreatedAt, project.CreatedAt); + Assert.Equal(projCustomisation.UpdatedAt, project.UpdatedAt); + Assert.Equal(projCustomisation.TasksDataType, project.TasksDataType); + Assert.Equal(projCustomisation.Type, project.Type); + Assert.Equal(projCustomisation.TasksDataId, project.TasksDataId); + Assert.Equal(projCustomisation.SignificantDate, project.SignificantDate); + Assert.Equal(projCustomisation.SignificantDateProvisional, project.SignificantDateProvisional); + Assert.Equal(projCustomisation.IncomingTrustUkprn, project.IncomingTrustUkprn); + Assert.Equal(projCustomisation.Region, project.Region); + Assert.Equal(projCustomisation.TwoRequiresImprovement, project.TwoRequiresImprovement); + Assert.Equal(projCustomisation.DirectiveAcademyOrder, project.DirectiveAcademyOrder); + Assert.Equal(projCustomisation.AdvisoryBoardDate, project.AdvisoryBoardDate); + Assert.Equal(projCustomisation.AdvisoryBoardConditions, project.AdvisoryBoardConditions); + Assert.Equal(projCustomisation.EstablishmentSharepointLink, project.EstablishmentSharepointLink); + Assert.Equal(projCustomisation.IncomingTrustSharepointLink, project.IncomingTrustSharepointLink); + Assert.Equal(handoverComment, project.Notes.FirstOrDefault()?.Body); + } + + [Theory] + [CustomAutoData(typeof(ProjectCustomization), typeof(DateOnlyCustomization), typeof(IgnoreVirtualMembersCustomisation))] + public void Factory_CreateMatConversionProject_ShouldCorrectlySetFields(Project projectCustomisation) + { + // Arrange + var handoverComment = "MAT Conversion handover comment"; + + // Act + var project = Project.CreateMatConversionProject( + projectCustomisation.Id, + projectCustomisation.Urn!, + projectCustomisation.CreatedAt, + projectCustomisation.UpdatedAt, + projectCustomisation.TasksDataType!.Value, + projectCustomisation.Type!.Value, + projectCustomisation.TasksDataId!.Value, + projectCustomisation.Region, + projectCustomisation.Team!.Value, + projectCustomisation.RegionalDeliveryOfficerId, + projectCustomisation.AssignedToId, + projectCustomisation.AssignedAt, + projectCustomisation.EstablishmentSharepointLink!, + projectCustomisation.IncomingTrustSharepointLink!, + projectCustomisation.AdvisoryBoardDate!.Value, + projectCustomisation.AdvisoryBoardConditions!, + projectCustomisation.SignificantDate!.Value, + projectCustomisation.SignificantDateProvisional!.Value, + projectCustomisation.TwoRequiresImprovement!.Value, + projectCustomisation.NewTrustName!, + projectCustomisation.NewTrustReferenceNumber!, + projectCustomisation.DirectiveAcademyOrder!.Value, + handoverComment + ); + + // Assert + Assert.Equal(projectCustomisation.Urn, project.Urn); + Assert.Equal(projectCustomisation.CreatedAt, project.CreatedAt); + Assert.Equal(projectCustomisation.UpdatedAt, project.UpdatedAt); + Assert.Equal(projectCustomisation.TasksDataType, project.TasksDataType); + Assert.Equal(projectCustomisation.Type, project.Type); + Assert.Equal(projectCustomisation.TasksDataId, project.TasksDataId); + Assert.Equal(projectCustomisation.Region, project.Region); + Assert.Equal(projectCustomisation.Team, project.Team); + Assert.Equal(projectCustomisation.RegionalDeliveryOfficerId, project.RegionalDeliveryOfficerId); + Assert.Equal(projectCustomisation.AssignedToId, project.AssignedToId); + Assert.Equal(projectCustomisation.AssignedAt, project.AssignedAt); + Assert.Equal(projectCustomisation.EstablishmentSharepointLink, project.EstablishmentSharepointLink); + Assert.Equal(projectCustomisation.IncomingTrustSharepointLink, project.IncomingTrustSharepointLink); + Assert.Equal(projectCustomisation.AdvisoryBoardDate, project.AdvisoryBoardDate); + Assert.Equal(projectCustomisation.AdvisoryBoardConditions, project.AdvisoryBoardConditions); + Assert.Equal(projectCustomisation.SignificantDate, project.SignificantDate); + Assert.Equal(projectCustomisation.SignificantDateProvisional, project.SignificantDateProvisional); + Assert.Equal(projectCustomisation.TwoRequiresImprovement, project.TwoRequiresImprovement); + Assert.Equal(projectCustomisation.NewTrustName, project.NewTrustName); + Assert.Equal(projectCustomisation.NewTrustReferenceNumber, project.NewTrustReferenceNumber); + Assert.Equal(projectCustomisation.DirectiveAcademyOrder, project.DirectiveAcademyOrder); - Assert.Equal(urn, project.Urn); - Assert.Equal(createdAt, project.CreatedAt); - Assert.Equal(updatedAt, project.UpdatedAt); - Assert.Equal(taskType, project.TasksDataType); - Assert.Equal(projectType, project.Type); - Assert.Equal(tasksDataId, project.TasksDataId); - Assert.Equal(significantDate, project.SignificantDate); - Assert.Equal(isSignificantDateProvisional, project.SignificantDateProvisional); - Assert.Equal(incomingTrustUkprn, project.IncomingTrustUkprn); - Assert.Equal(region, project.Region); - Assert.Equal(isDueTo2RI, project.TwoRequiresImprovement); - Assert.Equal(hasAcademyOrderBeenIssued, project.DirectiveAcademyOrder); - Assert.Equal(advisoryBoardDate, project.AdvisoryBoardDate); - Assert.Equal(advisoryBoardConditions, project.AdvisoryBoardConditions); - Assert.Equal(establishmentSharepointLink, project.EstablishmentSharepointLink); - Assert.Equal(incomingTrustSharepointLink, project.IncomingTrustSharepointLink); Assert.Equal(handoverComment, project.Notes.FirstOrDefault()?.Body); } }