From eec81418b956ad8cb27edc33970804be4b867a26 Mon Sep 17 00:00:00 2001 From: "SHAKIR, Muhammad" Date: Tue, 10 Dec 2024 10:53:58 +0000 Subject: [PATCH] Expire Conversion Grant Changes --- .../ConversionGrantExpiryFeatureTests.cs | 87 ++++++++++++++++ .../MockSetUp/ConfigurationMock.cs | 16 +++ ...nversionApplicationCreationServiceTests.cs | 22 +++-- ...rievalServiceConversionStatusLogicTests.cs | 34 ++++--- ...ievalServiceDeclarationStatusLogicTests.cs | 19 ++-- ...versionApplicationRetrievalServiceTests.cs | 19 ++-- ...onRetrievalServiceTrustStatusLogicTests.cs | 19 ++-- .../CypressTests/package-lock.json | 98 +++++++++---------- .../CypressTests/package.json | 4 +- .../Dfe.Academies.External.Web.csproj | 1 + .../Dtos/ConversionApplication.cs | 1 + .../ConversionGrantExpiryFeature.cs | 37 +++++++ .../Pages/ApplicationOverview.cshtml | 24 ++++- .../Pages/ApplicationOverview.cshtml.cs | 41 +++----- Dfe.Academies.External.Web/Pages/Index.cshtml | 24 +++-- .../ApplicationPreOpeningSupportGrant.cshtml | 34 +++++-- ...cationPreOpeningSupportGrantSummary.cshtml | 14 +++ .../Pages/School/Declaration.cshtml | 9 +- Dfe.Academies.External.Web/Program.cs | 10 +- .../ConversionApplicationRetrievalService.cs | 29 ++++-- .../appsettings.Development.json | 32 +++--- .../appsettings.Staging.json | 4 + Dfe.Academies.External.Web/appsettings.json | 12 ++- 23 files changed, 425 insertions(+), 165 deletions(-) create mode 100644 Dfe.Academies.External.Web.UnitTest/FeatureManagement/ConversionGrantExpiryFeatureTests.cs create mode 100644 Dfe.Academies.External.Web.UnitTest/MockSetUp/ConfigurationMock.cs create mode 100644 Dfe.Academies.External.Web/FeatureManagement/ConversionGrantExpiryFeature.cs diff --git a/Dfe.Academies.External.Web.UnitTest/FeatureManagement/ConversionGrantExpiryFeatureTests.cs b/Dfe.Academies.External.Web.UnitTest/FeatureManagement/ConversionGrantExpiryFeatureTests.cs new file mode 100644 index 000000000..c31fb6e52 --- /dev/null +++ b/Dfe.Academies.External.Web.UnitTest/FeatureManagement/ConversionGrantExpiryFeatureTests.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using AutoFixture; +using Dfe.Academies.External.Web.FeatureManagement; +using Dfe.Academies.External.Web.UnitTest.MockSetUp; +using Microsoft.FeatureManagement; +using Moq; +using NUnit.Framework; + +namespace Dfe.Academies.External.Web.UnitTest.FeatureManagement +{ + [TestFixture] + public class ConversionGrantExpiryFeatureTests + { + private Mock _mockFeatureManager = null!; + private static readonly Fixture Fixture = new(); + [SetUp] + public void SetUp() + { + _mockFeatureManager = new Mock(); + } + + [TestCase(false, "3024-11-10T09:13:00Z")] + [TestCase(false, "")] + public async Task IsEnabledAsync_NotExpired_ReturnsFalseAsync(bool isConversionGrantExpired,string conversionGrantExpiry) + { + //Arrange + var inMemorySettings = new Dictionary + { + { "FeatureManagement:IsConversionGrantExpired", isConversionGrantExpired.ToString() }, + { "FeatureManagement:ConversionGrantExpiry", conversionGrantExpiry } + }; + _mockFeatureManager.Setup(x => x.IsEnabledAsync("IsConversionGrantExpired")).ReturnsAsync(isConversionGrantExpired); + + var feature = new ConversionGrantExpiryFeature(ConfigurationMock.GetMockedConfiguration(inMemorySettings), _mockFeatureManager.Object); + + //Action + var result = await feature.IsEnabledAsync(); + + //Assert + Assert.That(result, Is.False); + } + + [TestCase(true, "3024-11-10T09:13:00Z")] + [TestCase(false, "2024-11-10T09:13:00Z")] + public async Task IsEnabledAsync_Expired_ReturnsTrueAsync(bool isConversionGrantExpired, string conversionGrantExpiry) + { + //Arrange + var inMemorySettings = new Dictionary + { + { "FeatureManagement:IsConversionGrantExpired", isConversionGrantExpired.ToString() }, + { "FeatureManagement:ConversionGrantExpiry", conversionGrantExpiry } + }; + _mockFeatureManager.Setup(x => x.IsEnabledAsync("IsConversionGrantExpired")).ReturnsAsync(isConversionGrantExpired); + + var feature = new ConversionGrantExpiryFeature(ConfigurationMock.GetMockedConfiguration(inMemorySettings), _mockFeatureManager.Object); + + //Action + var result = await feature.IsEnabledAsync(); + + //Assert + Assert.That(result, Is.True); + } + + [TestCase("2024-11-13T09:13:00Z", "2024-11-10T09:13:00Z", true)] + [TestCase("2024-11-09T09:13:00Z", "2024-11-10T09:13:00Z", false)] + [TestCase("2024-11-09T09:13:00Z", "", false)] + public void IsNewApplication_Expired_Returns_CorrectResponse(string applicationCreatedOn, string conversionGrantExpiry, bool expectedResult) + { + //Arrange + var inMemorySettings = new Dictionary + { + { "FeatureManagement:ConversionGrantExpiry", conversionGrantExpiry } + }; + + var feature = new ConversionGrantExpiryFeature(ConfigurationMock.GetMockedConfiguration(inMemorySettings), _mockFeatureManager.Object); + DateTime.TryParse(applicationCreatedOn, out DateTime applicationCreatedDateTime); + + //Action + var result = feature.IsNewApplication(applicationCreatedDateTime); + + //Assert + Assert.That(result, Is.EqualTo(expectedResult)); + } + } +} diff --git a/Dfe.Academies.External.Web.UnitTest/MockSetUp/ConfigurationMock.cs b/Dfe.Academies.External.Web.UnitTest/MockSetUp/ConfigurationMock.cs new file mode 100644 index 000000000..30d1e9c60 --- /dev/null +++ b/Dfe.Academies.External.Web.UnitTest/MockSetUp/ConfigurationMock.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using Microsoft.Extensions.Configuration; + +namespace Dfe.Academies.External.Web.UnitTest.MockSetUp +{ + public class ConfigurationMock + { + public static IConfiguration GetMockedConfiguration(Dictionary settings) + { + var configuration = new ConfigurationBuilder() + .AddInMemoryCollection(settings!) + .Build(); + return configuration; + } + } +} diff --git a/Dfe.Academies.External.Web.UnitTest/Services/ConversionApplicationCreationServiceTests.cs b/Dfe.Academies.External.Web.UnitTest/Services/ConversionApplicationCreationServiceTests.cs index 86fc2793c..8b4e13c0a 100644 --- a/Dfe.Academies.External.Web.UnitTest/Services/ConversionApplicationCreationServiceTests.cs +++ b/Dfe.Academies.External.Web.UnitTest/Services/ConversionApplicationCreationServiceTests.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using AutoFixture; using Dfe.Academies.External.Web.Dtos; +using Dfe.Academies.External.Web.FeatureManagement; using Dfe.Academies.External.Web.Models; using Dfe.Academies.External.Web.Services; using Dfe.Academies.External.Web.UnitTest.Factories; @@ -98,7 +99,8 @@ public async Task AddSchoolToApplication___ApiReturns200___Ok() var mockLoggerCreationService = new Mock>(); var mockLoggerRetrievalService = new Mock>(); var mockFileUploadService = new Mock(); - var mockConversionApplicationRetrievalService = new ConversionApplicationRetrievalService(mockRetrievalHttpClientFactory.Object, mockLoggerRetrievalService.Object, mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var mockConversionApplicationRetrievalService = new ConversionApplicationRetrievalService(mockRetrievalHttpClientFactory.Object, mockLoggerRetrievalService.Object, mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); // act var conversionApplicationCreationService = new ConversionApplicationService(mockCreationHttpClientFactory.Object, @@ -130,7 +132,8 @@ public async Task AddSchoolToApplication___ApiReturns500___InternalServerError() var mockLoggerCreationService = new Mock>(); var mockLoggerRetrievalService = new Mock>(); var mockFileUploadService = new Mock(); - var mockConversionApplicationRetrievalService = new ConversionApplicationRetrievalService(mockRetrievalHttpClientFactory.Object, mockLoggerRetrievalService.Object, mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var mockConversionApplicationRetrievalService = new ConversionApplicationRetrievalService(mockRetrievalHttpClientFactory.Object, mockLoggerRetrievalService.Object, mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); // act var conversionApplicationCreationService = new ConversionApplicationService(mockCreationHttpClientFactory.Object, @@ -159,7 +162,8 @@ public async Task AddSchoolToApplication___InvalidApplicationId___ArgumentExcept var mockLoggerCreationService = new Mock>(); var mockLoggerRetrievalService = new Mock>(); var mockFileUploadService = new Mock(); - var mockConversionApplicationRetrievalService = new ConversionApplicationRetrievalService(mockRetrievalHttpClientFactory.Object, mockLoggerRetrievalService.Object, mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var mockConversionApplicationRetrievalService = new ConversionApplicationRetrievalService(mockRetrievalHttpClientFactory.Object, mockLoggerRetrievalService.Object, mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); // act var conversionApplicationCreationService = new ConversionApplicationService(mockCreationHttpClientFactory.Object, @@ -275,7 +279,8 @@ public async Task ApplicationSchoolNextFinancialYear___ApiReturns200___Ok() var mockLoggerCreationService = new Mock>(); var mockLoggerRetrievalService = new Mock>(); var mockFileUploadService = new Mock(); - var mockConversionApplicationRetrievalService = new ConversionApplicationRetrievalService(mockRetrievalHttpClientFactory.Object, mockLoggerRetrievalService.Object, mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var mockConversionApplicationRetrievalService = new ConversionApplicationRetrievalService(mockRetrievalHttpClientFactory.Object, mockLoggerRetrievalService.Object, mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); // act var conversionApplicationCreationService = new ConversionApplicationService(mockCreationHttpClientFactory.Object, @@ -307,7 +312,8 @@ public async Task ApplicationSchoolNextFinancialYear__ApiReturns500___InternalSe var mockLoggerCreationService = new Mock>(); var mockLoggerRetrievalService = new Mock>(); var mockFileUploadService = new Mock(); - var mockConversionApplicationRetrievalService = new ConversionApplicationRetrievalService(mockRetrievalHttpClientFactory.Object, mockLoggerRetrievalService.Object, mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var mockConversionApplicationRetrievalService = new ConversionApplicationRetrievalService(mockRetrievalHttpClientFactory.Object, mockLoggerRetrievalService.Object, mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); // act var conversionApplicationCreationService = new ConversionApplicationService(mockCreationHttpClientFactory.Object, @@ -341,7 +347,8 @@ public async Task ApplicationSchoolPreviousFinancialYear___ApiReturns200___Ok() var mockLoggerCreationService = new Mock>(); var mockLoggerRetrievalService = new Mock>(); var mockFileUploadService = new Mock(); - var mockConversionApplicationRetrievalService = new ConversionApplicationRetrievalService(mockRetrievalHttpClientFactory.Object, mockLoggerRetrievalService.Object, mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var mockConversionApplicationRetrievalService = new ConversionApplicationRetrievalService(mockRetrievalHttpClientFactory.Object, mockLoggerRetrievalService.Object, mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); // act var conversionApplicationCreationService = new ConversionApplicationService(mockCreationHttpClientFactory.Object, @@ -373,7 +380,8 @@ public async Task ApplicationSchoolPreviousFinancialYear__ApiReturns500___Intern var mockLoggerCreationService = new Mock>(); var mockLoggerRetrievalService = new Mock>(); var mockFileUploadService = new Mock(); - var mockConversionApplicationRetrievalService = new ConversionApplicationRetrievalService(mockRetrievalHttpClientFactory.Object, mockLoggerRetrievalService.Object, mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var mockConversionApplicationRetrievalService = new ConversionApplicationRetrievalService(mockRetrievalHttpClientFactory.Object, mockLoggerRetrievalService.Object, mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); // act var conversionApplicationCreationService = new ConversionApplicationService(mockCreationHttpClientFactory.Object, diff --git a/Dfe.Academies.External.Web.UnitTest/Services/ConversionApplicationRetrievalServiceConversionStatusLogicTests.cs b/Dfe.Academies.External.Web.UnitTest/Services/ConversionApplicationRetrievalServiceConversionStatusLogicTests.cs index 86386db10..0ac6e7509 100644 --- a/Dfe.Academies.External.Web.UnitTest/Services/ConversionApplicationRetrievalServiceConversionStatusLogicTests.cs +++ b/Dfe.Academies.External.Web.UnitTest/Services/ConversionApplicationRetrievalServiceConversionStatusLogicTests.cs @@ -13,6 +13,7 @@ using AutoFixture; using Dfe.Academies.External.Web.ViewModels; using Dfe.Academisation.CorrelationIdMiddleware; +using Dfe.Academies.External.Web.FeatureManagement; namespace Dfe.Academies.External.Web.UnitTest.Services { @@ -33,7 +34,8 @@ public async Task CalculateApplicationStatus___ApplicationTypeJoinAMatAndNoSchoo var mockLogger = new Mock>(); var mockFileUploadService = new Mock(); - var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); int applicationId = 25; // hard coded as per example JSON int URN = 113537; var conversionApplication = ConversionApplicationTestDataFactory.BuildNewJoinAMatConversionApplicationNoRoles(); @@ -69,7 +71,8 @@ public async Task CalculateApplicationStatus___ApplicationTypeJoinAMatAndSchool_ var mockLogger = new Mock>(); var mockFileUploadService = new Mock(); - var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); int applicationId = 25; // hard coded as per example JSON int URN = 113537; @@ -109,7 +112,8 @@ public async Task CalculateApplicationStatus___ApplicationTypeJoinAMatAndSchoolA var mockFactory = MockHttpClientFactory.SetupMockHttpClientFactory(HttpStatusCode.OK, expectedJson); var mockLogger = new Mock>(); var mockFileUploadService = new Mock(); - var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); int applicationId = 25; // hard coded as per example JSON int URN = 113537; @@ -139,7 +143,8 @@ public async Task CalculateApplicationStatus___ApplicationTypeJoinAMatAndSchoolA var mockFactory = MockHttpClientFactory.SetupMockHttpClientFactory(HttpStatusCode.OK, expectedJson); var mockLogger = new Mock>(); var mockFileUploadService = new Mock(); - var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); int applicationId = 25; // hard coded as per example JSON int URN = 113537; @@ -175,7 +180,8 @@ public async Task CalculateApplicationStatus___ApplicationTypeJoinAMatAndSchoolA var mockFactory = MockHttpClientFactory.SetupMockHttpClientFactory(HttpStatusCode.OK, expectedJson); var mockLogger = new Mock>(); var mockFileUploadService = new Mock(); - var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); int applicationId = 25; // hard coded as per example JSON int URN = 113537; @@ -211,7 +217,8 @@ public async Task CalculateApplicationStatus___ApplicationTypeJoinAMatTrustStatu var mockFactory = MockHttpClientFactory.SetupMockHttpClientFactory(HttpStatusCode.OK, expectedJson); var mockLogger = new Mock>(); var mockFileUploadService = new Mock(); - var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); int applicationId = 25; // hard coded as per example JSON int URN = 113537; @@ -248,7 +255,8 @@ public async Task CalculateApplicationStatus___ApplicationTypeJoinAMatTrustStatu var mockFactory = MockHttpClientFactory.SetupMockHttpClientFactory(HttpStatusCode.OK, expectedJson); var mockLogger = new Mock>(); var mockFileUploadService = new Mock(); - var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); int applicationId = 25; // hard coded as per example JSON int URN = 113537; @@ -284,7 +292,8 @@ public async Task CalculateApplicationStatus___ApplicationTypeJoinAMatTrustStatu var mockFactory = MockHttpClientFactory.SetupMockHttpClientFactory(HttpStatusCode.OK, expectedJson); var mockLogger = new Mock>(); var mockFileUploadService = new Mock(); - var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); int applicationId = 25; // hard coded as per example JSON int URN = 113537; @@ -320,7 +329,8 @@ public async Task CalculateApplicationStatus___ApplicationTypeJoinAMatTrustStatu var mockFactory = MockHttpClientFactory.SetupMockHttpClientFactory(HttpStatusCode.OK, expectedJson); var mockLogger = new Mock>(); var mockFileUploadService = new Mock(); - var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); int applicationId = 25; // hard coded as per example JSON int URN = 113537; @@ -356,7 +366,8 @@ public async Task CalculateApplicationStatus___ApplicationTypeJoinAMatTrustStatu var mockFactory = MockHttpClientFactory.SetupMockHttpClientFactory(HttpStatusCode.OK, expectedJson); var mockLogger = new Mock>(); var mockFileUploadService = new Mock(); - var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); int applicationId = 25; // hard coded as per example JSON int URN = 113537; @@ -392,7 +403,8 @@ public async Task CalculateApplicationStatus___ApplicationTypeJoinAMatTrustStatu var mockFactory = MockHttpClientFactory.SetupMockHttpClientFactory(HttpStatusCode.OK, expectedJson); var mockLogger = new Mock>(); var mockFileUploadService = new Mock(); - var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); int applicationId = 25; // hard coded as per example JSON int URN = 113537; diff --git a/Dfe.Academies.External.Web.UnitTest/Services/ConversionApplicationRetrievalServiceDeclarationStatusLogicTests.cs b/Dfe.Academies.External.Web.UnitTest/Services/ConversionApplicationRetrievalServiceDeclarationStatusLogicTests.cs index 131fe2571..96f03053e 100644 --- a/Dfe.Academies.External.Web.UnitTest/Services/ConversionApplicationRetrievalServiceDeclarationStatusLogicTests.cs +++ b/Dfe.Academies.External.Web.UnitTest/Services/ConversionApplicationRetrievalServiceDeclarationStatusLogicTests.cs @@ -10,6 +10,7 @@ using Dfe.Academies.External.Web.UnitTest.Factories; using Dfe.Academies.External.Web.Enums; using Dfe.Academisation.CorrelationIdMiddleware; +using Dfe.Academies.External.Web.FeatureManagement; namespace Dfe.Academies.External.Web.UnitTest.Services; @@ -30,7 +31,8 @@ public async Task CalculateDeclarationStatus___ConversionApplicationNullReturns_ var mockLogger = new Mock>(); var mockFileUploadService = new Mock(); - var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); // act var declarationStatus = applicationRetrievalService.CalculateApplicationDeclarationStatus(null); @@ -53,7 +55,8 @@ public async Task CalculateDeclarationStatus___ApplicationTypeJoinAMatAndNoSchoo var mockLogger = new Mock>(); var mockFileUploadService = new Mock(); - var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); var conversionApplication = ConversionApplicationTestDataFactory.BuildNewJoinAMatConversionApplicationNoRoles(); @@ -78,7 +81,8 @@ public async Task CalculateDeclarationStatus___ApplicationTypeJoinAMatAndSchool_ var mockLogger = new Mock>(); var mockFileUploadService = new Mock(); - var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); var conversionApplication = ConversionApplicationTestDataFactory.BuildJoinAMatConversionApplicationWithContributorWithSchool(null); @@ -103,7 +107,8 @@ public async Task CalculateDeclarationStatus___ApplicationTypeJoinAMatAndSchoolA var mockLogger = new Mock>(); var mockFileUploadService = new Mock(); - var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); var conversionApplication = ConversionApplicationTestDataFactory.BuildJoinAMatConversionApplicationWithContributorWithSchool(null); var applicationSchool = conversionApplication.Schools.FirstOrDefault()!.DeclarationBodyAgree = true; @@ -129,7 +134,8 @@ public async Task CalculateDeclarationStatus___ApplicationTypeFormAMatAndNoSchoo var mockLogger = new Mock>(); var mockFileUploadService = new Mock(); - var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); var conversionApplication = ConversionApplicationTestDataFactory.BuildMinimalFormAMatConversionApplicationNoContributors(); @@ -154,7 +160,8 @@ public async Task CalculateDeclarationStatus___ApplicationTypeFormAMatAndSchool_ var mockLogger = new Mock>(); var mockFileUploadService = new Mock(); - var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); var conversionApplication = ConversionApplicationTestDataFactory.BuildFormAMatConversionApplicationWithContributorWithSchool(); diff --git a/Dfe.Academies.External.Web.UnitTest/Services/ConversionApplicationRetrievalServiceTests.cs b/Dfe.Academies.External.Web.UnitTest/Services/ConversionApplicationRetrievalServiceTests.cs index c56f20916..e40f76cf9 100644 --- a/Dfe.Academies.External.Web.UnitTest/Services/ConversionApplicationRetrievalServiceTests.cs +++ b/Dfe.Academies.External.Web.UnitTest/Services/ConversionApplicationRetrievalServiceTests.cs @@ -4,6 +4,7 @@ using System.Net; using System.Threading.Tasks; using Dfe.Academies.External.Web.Enums; +using Dfe.Academies.External.Web.FeatureManagement; using Dfe.Academies.External.Web.Services; using Dfe.Academies.External.Web.UnitTest.Factories; using Dfe.Academisation.CorrelationIdMiddleware; @@ -99,7 +100,8 @@ public async Task GetPendingApplications___ApiReturns200___Success() // act var mockFileUploadService = new Mock(); - var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); var expectedExistingApplicationsTestData = await applicationRetrievalService.GetPendingApplications(userEmail); // assert @@ -169,7 +171,8 @@ public async Task GetCompletedApplications___ApiReturns200___Success() // act var mockFileUploadService = new Mock(); - var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); var expectedExistingApplicationsTestData = await applicationRetrievalService.GetCompletedApplications(userEmail); // assert @@ -190,7 +193,8 @@ public async Task GetConversionApplicationAuditEntries___ApiReturns200___Success // act var mockFileUploadService = new Mock(); - var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); var auditEntries = await applicationRetrievalService.GetConversionApplicationAuditEntries(applicationId); // assert @@ -213,7 +217,8 @@ public async Task GetSchoolApplicationComponents___ApiReturns200___Success() // act var mockFileUploadService = new Mock(); - var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); var applicationComponentStatuses = await applicationRetrievalService.GetSchoolApplicationComponents(applicationId, URN); // assert @@ -235,7 +240,8 @@ public async Task GetConversionApplicationContributors___ApiReturns200___Success // act var mockFileUploadService = new Mock(); - var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); var applicationContributors = await applicationRetrievalService.GetConversionApplicationContributors(applicationId); // assert @@ -258,7 +264,8 @@ public async Task GetApplication___JoinAMat___ApiReturns200___Success() // act var mockFileUploadService = new Mock(); - var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); var application = await applicationRetrievalService.GetApplication(GetApplicationId); // assert diff --git a/Dfe.Academies.External.Web.UnitTest/Services/ConversionApplicationRetrievalServiceTrustStatusLogicTests.cs b/Dfe.Academies.External.Web.UnitTest/Services/ConversionApplicationRetrievalServiceTrustStatusLogicTests.cs index 85de05aac..0ea54daf3 100644 --- a/Dfe.Academies.External.Web.UnitTest/Services/ConversionApplicationRetrievalServiceTrustStatusLogicTests.cs +++ b/Dfe.Academies.External.Web.UnitTest/Services/ConversionApplicationRetrievalServiceTrustStatusLogicTests.cs @@ -9,6 +9,7 @@ using Dfe.Academies.External.Web.UnitTest.Factories; using Dfe.Academies.External.Web.Enums; using Dfe.Academisation.CorrelationIdMiddleware; +using Dfe.Academies.External.Web.FeatureManagement; namespace Dfe.Academies.External.Web.UnitTest.Services; @@ -29,7 +30,8 @@ public async Task CalculateTrustStatus___ConversionApplicationNullReturns___NotS var mockLogger = new Mock>(); var mockFileUploadService = new Mock(); - var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); // act var trustStatus = applicationRetrievalService.CalculateTrustStatus(null); @@ -52,7 +54,8 @@ public async Task CalculateTrustStatus___JoinTrustDetailsNullReturns___NotStarte var mockLogger = new Mock>(); var mockFileUploadService = new Mock(); - var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); var conversionApplication = ConversionApplicationTestDataFactory.BuildNewJoinAMatConversionApplicationNoRoles(); @@ -80,7 +83,8 @@ public async Task CalculateTrustStatus___JoinTrustDetailsTrustNameOnlyReturns___ var mockLogger = new Mock>(); var mockFileUploadService = new Mock(); - var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); var conversionApplication = ConversionApplicationTestDataFactory.BuildNewJoinAMatConversionApplicationWithMinimalJoinTrustDetails(); @@ -105,7 +109,8 @@ public async Task CalculateTrustStatus___JoinTrustDetailsMinimalAndTrustChangesR var mockLogger = new Mock>(); var mockFileUploadService = new Mock(); - var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); var conversionApplication = ConversionApplicationTestDataFactory.BuildNewJoinAMatConversionApplicationWithMinimalAndTrustChangesJoinTrustDetails(null); @@ -130,7 +135,8 @@ public async Task CalculateTrustStatus___JoinTrustDetailsMinimalAndChangesToLaGo var mockLogger = new Mock>(); var mockFileUploadService = new Mock(); - var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); var conversionApplication = ConversionApplicationTestDataFactory.BuildNewJoinAMatConversionApplicationWithMinimalAndChangesToLaGovernanceJoinTrustDetails(); @@ -155,7 +161,8 @@ public async Task CalculateTrustStatus___JoinTrustDetailsReturns___Completed() var mockLogger = new Mock>(); var mockFileUploadService = new Mock(); - var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid())); + var mockConversionGrantExpiryFeature = new Mock(); + var applicationRetrievalService = new ConversionApplicationRetrievalService(mockFactory.Object, mockLogger.Object,mockFileUploadService.Object, Mock.Of(x => x.CorrelationId == Guid.NewGuid()), mockConversionGrantExpiryFeature.Object); var conversionApplication = ConversionApplicationTestDataFactory.BuildNewJoinAMatConversionApplicationWithCompleteJoinTrustDetails(null); diff --git a/Dfe.Academies.External.Web/CypressTests/package-lock.json b/Dfe.Academies.External.Web/CypressTests/package-lock.json index f201ffd8c..4f351266b 100644 --- a/Dfe.Academies.External.Web/CypressTests/package-lock.json +++ b/Dfe.Academies.External.Web/CypressTests/package-lock.json @@ -555,9 +555,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.15.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.15.0.tgz", - "integrity": "sha512-tMTqrY+EzbXmKJR5ToI8lxu7jaN5EdmrBFJpQk5JmSlyLsx6o4t27r883K5xsLuCYCpfKBCGswMSWXsM+jB7lg==", + "version": "9.16.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.16.0.tgz", + "integrity": "sha512-tw2HxzQkrbeuvyj1tG2Yqq+0H9wGoI2IMk4EOsQeX+vmd75FtJAzf+gTA69WF+baUKRYQ3x2kbLE08js5OsTVg==", "dev": true, "license": "MIT", "engines": { @@ -988,17 +988,17 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.16.0.tgz", - "integrity": "sha512-5YTHKV8MYlyMI6BaEG7crQ9BhSc8RxzshOReKwZwRWN0+XvvTOm+L/UYLCYxFpfwYuAAqhxiq4yae0CMFwbL7Q==", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.17.0.tgz", + "integrity": "sha512-HU1KAdW3Tt8zQkdvNoIijfWDMvdSweFYm4hWh+KwhPstv+sCmWb89hCIP8msFm9N1R/ooh9honpSuvqKWlYy3w==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.16.0", - "@typescript-eslint/type-utils": "8.16.0", - "@typescript-eslint/utils": "8.16.0", - "@typescript-eslint/visitor-keys": "8.16.0", + "@typescript-eslint/scope-manager": "8.17.0", + "@typescript-eslint/type-utils": "8.17.0", + "@typescript-eslint/utils": "8.17.0", + "@typescript-eslint/visitor-keys": "8.17.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", @@ -1022,16 +1022,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.16.0.tgz", - "integrity": "sha512-D7DbgGFtsqIPIFMPJwCad9Gfi/hC0PWErRRHFnaCWoEDYi5tQUDiJCTmGUbBiLzjqAck4KcXt9Ayj0CNlIrF+w==", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.17.0.tgz", + "integrity": "sha512-Drp39TXuUlD49F7ilHHCG7TTg8IkA+hxCuULdmzWYICxGXvDXmDmWEjJYZQYgf6l/TFfYNE167m7isnc3xlIEg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/scope-manager": "8.16.0", - "@typescript-eslint/types": "8.16.0", - "@typescript-eslint/typescript-estree": "8.16.0", - "@typescript-eslint/visitor-keys": "8.16.0", + "@typescript-eslint/scope-manager": "8.17.0", + "@typescript-eslint/types": "8.17.0", + "@typescript-eslint/typescript-estree": "8.17.0", + "@typescript-eslint/visitor-keys": "8.17.0", "debug": "^4.3.4" }, "engines": { @@ -1051,14 +1051,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.16.0.tgz", - "integrity": "sha512-mwsZWubQvBki2t5565uxF0EYvG+FwdFb8bMtDuGQLdCCnGPrDEDvm1gtfynuKlnpzeBRqdFCkMf9jg1fnAK8sg==", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.17.0.tgz", + "integrity": "sha512-/ewp4XjvnxaREtqsZjF4Mfn078RD/9GmiEAtTeLQ7yFdKnqwTOgRMSvFz4et9U5RiJQ15WTGXPLj89zGusvxBg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.16.0", - "@typescript-eslint/visitor-keys": "8.16.0" + "@typescript-eslint/types": "8.17.0", + "@typescript-eslint/visitor-keys": "8.17.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1069,14 +1069,14 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.16.0.tgz", - "integrity": "sha512-IqZHGG+g1XCWX9NyqnI/0CX5LL8/18awQqmkZSl2ynn8F76j579dByc0jhfVSnSnhf7zv76mKBQv9HQFKvDCgg==", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.17.0.tgz", + "integrity": "sha512-q38llWJYPd63rRnJ6wY/ZQqIzPrBCkPdpIsaCfkR3Q4t3p6sb422zougfad4TFW9+ElIFLVDzWGiGAfbb/v2qw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.16.0", - "@typescript-eslint/utils": "8.16.0", + "@typescript-eslint/typescript-estree": "8.17.0", + "@typescript-eslint/utils": "8.17.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -1097,9 +1097,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.16.0.tgz", - "integrity": "sha512-NzrHj6thBAOSE4d9bsuRNMvk+BvaQvmY4dDglgkgGC0EW/tB3Kelnp3tAKH87GEwzoxgeQn9fNGRyFJM/xd+GQ==", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.17.0.tgz", + "integrity": "sha512-gY2TVzeve3z6crqh2Ic7Cr+CAv6pfb0Egee7J5UAVWCpVvDI/F71wNfolIim4FE6hT15EbpZFVUj9j5i38jYXA==", "dev": true, "license": "MIT", "engines": { @@ -1111,14 +1111,14 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.16.0.tgz", - "integrity": "sha512-E2+9IzzXMc1iaBy9zmo+UYvluE3TW7bCGWSF41hVWUE01o8nzr1rvOQYSxelxr6StUvRcTMe633eY8mXASMaNw==", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.17.0.tgz", + "integrity": "sha512-JqkOopc1nRKZpX+opvKqnM3XUlM7LpFMD0lYxTqOTKQfCWAmxw45e3qlOCsEqEB2yuacujivudOFpCnqkBDNMw==", "dev": true, "license": "BSD-2-Clause", "dependencies": { - "@typescript-eslint/types": "8.16.0", - "@typescript-eslint/visitor-keys": "8.16.0", + "@typescript-eslint/types": "8.17.0", + "@typescript-eslint/visitor-keys": "8.17.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", @@ -1140,16 +1140,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.16.0.tgz", - "integrity": "sha512-C1zRy/mOL8Pj157GiX4kaw7iyRLKfJXBR3L82hk5kS/GyHcOFmy4YUq/zfZti72I9wnuQtA/+xzft4wCC8PJdA==", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.17.0.tgz", + "integrity": "sha512-bQC8BnEkxqG8HBGKwG9wXlZqg37RKSMY7v/X8VEWD8JG2JuTHuNK0VFvMPMUKQcbk6B+tf05k+4AShAEtCtJ/w==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.16.0", - "@typescript-eslint/types": "8.16.0", - "@typescript-eslint/typescript-estree": "8.16.0" + "@typescript-eslint/scope-manager": "8.17.0", + "@typescript-eslint/types": "8.17.0", + "@typescript-eslint/typescript-estree": "8.17.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -1168,13 +1168,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.16.0.tgz", - "integrity": "sha512-pq19gbaMOmFE3CbL0ZB8J8BFCo2ckfHBfaIsaOZgBIF4EoISJIdLX5xRhd0FGB0LlHReNRuzoJoMGpTjq8F2CQ==", + "version": "8.17.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.17.0.tgz", + "integrity": "sha512-1Hm7THLpO6ww5QU6H/Qp+AusUUl+z/CAm3cNZZ0jQvon9yicgO7Rwd+/WWRpMKLYV6p2UvdbR27c86rzCPpreg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.16.0", + "@typescript-eslint/types": "8.17.0", "eslint-visitor-keys": "^4.2.0" }, "engines": { @@ -2306,9 +2306,9 @@ } }, "node_modules/eslint": { - "version": "9.15.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.15.0.tgz", - "integrity": "sha512-7CrWySmIibCgT1Os28lUU6upBshZ+GxybLOrmRzi08kS8MBuO8QA7pXEgYgY5W8vK3e74xv0lpjo9DbaGU9Rkw==", + "version": "9.16.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.16.0.tgz", + "integrity": "sha512-whp8mSQI4C8VXd+fLgSM0lh3UlmcFtVwUQjyKCFfsp+2ItAIYhlq/hqGahGqHE6cv9unM41VlqKk2VtKYR2TaA==", "dev": true, "license": "MIT", "dependencies": { @@ -2317,7 +2317,7 @@ "@eslint/config-array": "^0.19.0", "@eslint/core": "^0.9.0", "@eslint/eslintrc": "^3.2.0", - "@eslint/js": "9.15.0", + "@eslint/js": "9.16.0", "@eslint/plugin-kit": "^0.2.3", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", diff --git a/Dfe.Academies.External.Web/CypressTests/package.json b/Dfe.Academies.External.Web/CypressTests/package.json index b6df2ed13..d667787ee 100644 --- a/Dfe.Academies.External.Web/CypressTests/package.json +++ b/Dfe.Academies.External.Web/CypressTests/package.json @@ -4,8 +4,8 @@ "description": "Cypress tests for the core journeys of the A2B service", "main": "index.js", "scripts": { - "cy:open": "cypress open --env URL=$URL,LOGIN_USERNAME=$LOGIN_USERNAME,LOGIN_PASSWORD=$LOGIN_PASSWORD,SIGNIN_URL=$SIGNIN_URL", - "cy:run": "cypress run --env URL=$URL,LOGIN_USERNAME=$LOGIN_USERNAME,LOGIN_PASSWORD=$LOGIN_PASSWORD,SIGNIN_URL=$SIGNIN_URL", + "cy:open": "cypress open --browser electron", + "cy:run": "cypress run --browser electron" , "cy:notify": "cypress-slack-reporter", "lint": "eslint ." }, diff --git a/Dfe.Academies.External.Web/Dfe.Academies.External.Web.csproj b/Dfe.Academies.External.Web/Dfe.Academies.External.Web.csproj index 3f4232585..4c11b5aff 100644 --- a/Dfe.Academies.External.Web/Dfe.Academies.External.Web.csproj +++ b/Dfe.Academies.External.Web/Dfe.Academies.External.Web.csproj @@ -28,6 +28,7 @@ + diff --git a/Dfe.Academies.External.Web/Dtos/ConversionApplication.cs b/Dfe.Academies.External.Web/Dtos/ConversionApplication.cs index 4bc1c7a2a..4c751d261 100644 --- a/Dfe.Academies.External.Web/Dtos/ConversionApplication.cs +++ b/Dfe.Academies.External.Web/Dtos/ConversionApplication.cs @@ -41,6 +41,7 @@ public string ApplicationTitle public ExistingTrust? JoinTrustDetails { get; set; } public DateTime? DeletedAt { get; set; } + public DateTime? CreatedOn { get; set; } public string TrustName => (ApplicationType == ApplicationTypes.JoinAMat ? JoinTrustDetails?.TrustName diff --git a/Dfe.Academies.External.Web/FeatureManagement/ConversionGrantExpiryFeature.cs b/Dfe.Academies.External.Web/FeatureManagement/ConversionGrantExpiryFeature.cs new file mode 100644 index 000000000..249230960 --- /dev/null +++ b/Dfe.Academies.External.Web/FeatureManagement/ConversionGrantExpiryFeature.cs @@ -0,0 +1,37 @@ +using System.Globalization; +using Microsoft.FeatureManagement; + +namespace Dfe.Academies.External.Web.FeatureManagement +{ + public interface IConversionGrantExpiryFeature + { + public bool IsNewApplication(DateTime? applicationCreatedOn); + public Task IsEnabledAsync(); + } + public class ConversionGrantExpiryFeature(IConfiguration configuration, IFeatureManager featureManager) : IConversionGrantExpiryFeature + { + private const string _forceToEnableFeatureName = "IsConversionGrantExpired"; + public async Task IsEnabledAsync() + { + if(await featureManager.IsEnabledAsync(_forceToEnableFeatureName)) + { + return true; + } + + if (DateTime.TryParse(configuration["FeatureManagement:ConversionGrantExpiry"], new CultureInfo("en-GB"), out DateTime activationDate)) + { + return DateTime.UtcNow >= activationDate; + } + return false; + } + + public bool IsNewApplication(DateTime? applicationCreatedOn) + { + if (DateTime.TryParse(configuration["FeatureManagement:ConversionGrantExpiry"], new CultureInfo("en-GB"), out DateTime activationDate)) + { + return applicationCreatedOn >= activationDate; + } + return false; + } + } +} diff --git a/Dfe.Academies.External.Web/Pages/ApplicationOverview.cshtml b/Dfe.Academies.External.Web/Pages/ApplicationOverview.cshtml index 43145e06f..1ecf3b39c 100644 --- a/Dfe.Academies.External.Web/Pages/ApplicationOverview.cshtml +++ b/Dfe.Academies.External.Web/Pages/ApplicationOverview.cshtml @@ -3,7 +3,9 @@ @using Dfe.Academies.External.Web.Extensions @using Dfe.Academies.External.Web.TagHelpers @using Dfe.Academies.External.Web.Enums +@using Dfe.Academies.External.Web.FeatureManagement; @model Dfe.Academies.External.Web.Pages.ApplicationOverviewModel +@inject IConversionGrantExpiryFeature ConversionGrantExpiryFeature; @{ ViewData["Title"] = "Apply to become an academy - Overview"; } @@ -19,8 +21,8 @@

@Model.ApplicationType.GetDescription()

- @if (Model.ApplicationStatus == ApplicationStatus.InProgress) - { + @if (Model.ApplicationStatus == ApplicationStatus.InProgress && !await ConversionGrantExpiryFeature.IsEnabledAsync()) + {

@@ -29,10 +31,26 @@

- You must submit the application by 11:55pm Friday 20 December 2024 to be eligible for the conversion support grant + The chair of governors must submit the application by 11:55pm Friday 20 December 2024 to be eligible for the conversion support grant

+ } + @if (Model.ApplicationStatus == ApplicationStatus.InProgress && await ConversionGrantExpiryFeature.IsEnabledAsync() && !ConversionGrantExpiryFeature.IsNewApplication(Model.ApplicationCreatedOn)) + { +
+
+

+ Important +

+
+
+

+ The conversion support grant has ended +

+

You are no longer eligible for this grant

+
+
}

@Model.HeaderText diff --git a/Dfe.Academies.External.Web/Pages/ApplicationOverview.cshtml.cs b/Dfe.Academies.External.Web/Pages/ApplicationOverview.cshtml.cs index 45238adb2..8ce9f47d4 100644 --- a/Dfe.Academies.External.Web/Pages/ApplicationOverview.cshtml.cs +++ b/Dfe.Academies.External.Web/Pages/ApplicationOverview.cshtml.cs @@ -1,7 +1,6 @@ using System.Security.Claims; using Dfe.Academies.External.Web.Dtos; -using Dfe.Academies.External.Web.Enums; -using Dfe.Academies.External.Web.Models; +using Dfe.Academies.External.Web.Enums; using Dfe.Academies.External.Web.Pages.Base; using Dfe.Academies.External.Web.Services; using Dfe.Academies.External.Web.ViewModels; @@ -9,11 +8,12 @@ namespace Dfe.Academies.External.Web.Pages { - public class ApplicationOverviewModel : BasePageEditModel + public class ApplicationOverviewModel(IConversionApplicationRetrievalService conversionApplicationRetrievalService, + IReferenceDataRetrievalService referenceDataRetrievalService, + IConversionApplicationService conversionApplicationCreationService, + ILogger logger + ) : BasePageEditModel(conversionApplicationRetrievalService, referenceDataRetrievalService) { - private readonly IConversionApplicationService _conversionApplicationCreationService; - private readonly ILogger logger; - [BindProperty] public int ApplicationId { get; set; } @@ -70,18 +70,8 @@ public class ApplicationOverviewModel : BasePageEditModel ///

/// UI text, set within here ONLY dependent on ApplicationType &&& user role !!! /// - public string HeaderText { get; private set; } = string.Empty; - - - public ApplicationOverviewModel(IConversionApplicationRetrievalService conversionApplicationRetrievalService, - IReferenceDataRetrievalService referenceDataRetrievalService, - IConversionApplicationService conversionApplicationCreationService, - ILogger logger - ) : base(conversionApplicationRetrievalService, referenceDataRetrievalService) - { - _conversionApplicationCreationService = conversionApplicationCreationService; - this.logger = logger; - } + public string HeaderText { get; private set; } = string.Empty; + public DateTime? ApplicationCreatedOn { get; set; } public async Task OnGetAsync(int appId) { @@ -126,22 +116,22 @@ private void PopulateUiModel(ConversionApplication? conversionApplication) HideDeleteButton = (email != firstContributorEmail); - this.logger.LogInformation($"Populating application overview for user | Email: { email }"); + logger.LogInformation($"Populating application overview for user | Email: { email }"); // look up user in contributors collection to find their role !!! if (!string.IsNullOrWhiteSpace(email)) { - foreach (var contributor in conversionApplication.Contributors) + foreach (var contributor in conversionApplication!.Contributors) { - this.logger.LogInformation($"Contrubutor email: {contributor.EmailAddress} | role: {contributor.Role}"); + logger.LogInformation($"Contrubutor email: {contributor.EmailAddress} | role: {contributor.Role}"); } // possible fix for not finding right user var currentUser = conversionApplication.Contributors.FirstOrDefault(x => x.EmailAddress.ToLower() == email.ToLower()); - this.logger.LogInformation($"User found, Id: { currentUser?.ContributorId } | Name: {currentUser?.FullName} | Email: {email}"); - this.logger.LogInformation($"User role: {currentUser?.Role } | Email: {email}"); + logger.LogInformation($"User found, Id: { currentUser?.ContributorId } | Name: {currentUser?.FullName} | Email: {email}"); + logger.LogInformation($"User role: {currentUser?.Role } | Email: {email}"); // set users role if (currentUser is { Role: SchoolRoles.ChairOfGovernors }) @@ -150,7 +140,7 @@ private void PopulateUiModel(ConversionApplication? conversionApplication) } } - this.logger.LogInformation($"Can user submit | UserHasSubmitApplicationRole: {UserHasSubmitApplicationRole}"); + logger.LogInformation($"Can user submit | UserHasSubmitApplicationRole: {UserHasSubmitApplicationRole}"); if (conversionApplication != null) { @@ -162,6 +152,7 @@ private void PopulateUiModel(ConversionApplication? conversionApplication) ApplicationType = conversionApplication.ApplicationType; ApplicationReferenceNumber = conversionApplication.ApplicationReference; ApplicationStatus = conversionApplication.ApplicationStatus; + ApplicationCreatedOn = conversionApplication.CreatedOn; SchoolOrSchoolsApplyingToConvert = new List(); foreach (var school in conversionApplication.Schools) @@ -229,7 +220,7 @@ public async Task OnPostAsync() draftConversionApplication.ApplicationStatus = ApplicationStatus.Submitted; - await _conversionApplicationCreationService.SubmitApplication(ApplicationId); + await conversionApplicationCreationService.SubmitApplication(ApplicationId); // update temp store for next step TempDataHelper.StoreSerialisedValue(TempDataHelper.DraftConversionApplicationKey, TempData, draftConversionApplication); diff --git a/Dfe.Academies.External.Web/Pages/Index.cshtml b/Dfe.Academies.External.Web/Pages/Index.cshtml index 61f7685fb..232163876 100644 --- a/Dfe.Academies.External.Web/Pages/Index.cshtml +++ b/Dfe.Academies.External.Web/Pages/Index.cshtml @@ -1,7 +1,9 @@ @page +@using Dfe.Academies.External.Web.FeatureManagement; +@inject IConversionGrantExpiryFeature ConversionGrantExpiryFeature; @model IndexModel @{ - ViewData["Title"] = "Home"; + ViewData["Title"] = "Home"; }
@@ -44,15 +46,17 @@ complete an Equality Impact Assessment (EIA) - -
- - - Warning - The conversion support grant is ending soon
-

To be eligible for funding you must submit the application by 11:55pm Friday 20 December 2024

-
-
+ @if (!await ConversionGrantExpiryFeature.IsEnabledAsync()) + { +
+ + + Warning + The conversion support grant is ending soon
+

The chair of governors must submit the application by 11:55pm Friday 20 December 2024 to be eligible for funding

+
+
+ } Start now diff --git a/Dfe.Academies.External.Web/Pages/School/ApplicationPreOpeningSupportGrant.cshtml b/Dfe.Academies.External.Web/Pages/School/ApplicationPreOpeningSupportGrant.cshtml index 1adfdecf7..805015271 100644 --- a/Dfe.Academies.External.Web/Pages/School/ApplicationPreOpeningSupportGrant.cshtml +++ b/Dfe.Academies.External.Web/Pages/School/ApplicationPreOpeningSupportGrant.cshtml @@ -1,8 +1,10 @@ @page @using Dfe.Academies.External.Web.Enums @using Dfe.Academies.External.Web.Extensions +@using Dfe.Academies.External.Web.FeatureManagement @using Microsoft.AspNetCore.Mvc.TagHelpers @model Dfe.Academies.External.Web.Pages.School.ApplicationPreOpeningSupportGrantModel +@inject IConversionGrantExpiryFeature ConversionGrantExpiryFeature; @{ ViewData["Title"] = "Apply to become an academy - conversion support grant"; } @@ -19,20 +21,36 @@

Academy conversion support grant

-
- - - Warning - The deadline to apply for the conversion support grant is 11:55pm Friday 20 December 2024 - -
+ @if (await ConversionGrantExpiryFeature.IsEnabledAsync()) + { +
+ + + Warning + The conversion support grant has ended +
+

You are no longer eligible for this grant

+
+
+ } + else + { +
+ + + Warning + The deadline to apply for the conversion support grant is 11:55pm Friday 20 December 2024 + +
+ } +

@if (Model.ApplicationType != ApplicationTypes.JoinAMat) {

Please go to provide information about your banking payments to DfE to add your bank details. -

+

Your application can be submitted without completing this action now, however please provide your bank details either before or shortly after submission of your application. diff --git a/Dfe.Academies.External.Web/Pages/School/ApplicationPreOpeningSupportGrantSummary.cshtml b/Dfe.Academies.External.Web/Pages/School/ApplicationPreOpeningSupportGrantSummary.cshtml index dea30861f..41a776c6c 100644 --- a/Dfe.Academies.External.Web/Pages/School/ApplicationPreOpeningSupportGrantSummary.cshtml +++ b/Dfe.Academies.External.Web/Pages/School/ApplicationPreOpeningSupportGrantSummary.cshtml @@ -1,8 +1,10 @@ @page @using Dfe.Academies.External.Web.Enums +@using Dfe.Academies.External.Web.FeatureManagement @using Dfe.Academies.External.Web.ViewModels @using Microsoft.AspNetCore.Mvc.TagHelpers @model Dfe.Academies.External.Web.Pages.School.ApplicationPreOpeningSupportGrantSummaryModel +@inject IConversionGrantExpiryFeature ConversionGrantExpiryFeature; @{ ViewData["Title"] = "Apply to become an academy - About the conversion"; } @@ -19,6 +21,18 @@

Conversion support grant

+ @if (await ConversionGrantExpiryFeature.IsEnabledAsync()) + { +
+ + + Warning + The conversion support grant has ended +
+

You are no longer eligible for this grant

+
+
+ } @foreach (var question in Model.ViewModel) { diff --git a/Dfe.Academies.External.Web/Pages/School/Declaration.cshtml b/Dfe.Academies.External.Web/Pages/School/Declaration.cshtml index 5ca110eb6..447d34f2b 100644 --- a/Dfe.Academies.External.Web/Pages/School/Declaration.cshtml +++ b/Dfe.Academies.External.Web/Pages/School/Declaration.cshtml @@ -1,5 +1,7 @@ @page -@model Dfe.Academies.External.Web.Pages.School.DeclarationModel +@using Dfe.Academies.External.Web.FeatureManagement +@model Dfe.Academies.External.Web.Pages.School.DeclarationModel +@inject IConversionGrantExpiryFeature ConversionGrantExpiryFeature; @{ ViewData["Title"] = "Apply to become an academy - About the conversion"; } @@ -38,7 +40,10 @@
  • The governing body has passed a resolution that the school should become an academy.
  • The school will complete a consultation with relevant stakeholders (such as parents, staff, the local communities and others), and consider their equality needs before they sign the funding agreement.
  • -
  • The school agrees to the terms set out in the academy conversion support grant certificate.
  • + @if (!await ConversionGrantExpiryFeature.IsEnabledAsync()) + { +
  • The school agrees to the terms set out in the academy conversion support grant certificate.
  • + }
  • The school agrees to provide any further information that the Department for Education needs to assess this application.
  • That if any information in this application is false or misleading, this application may be rejected or the academy order may be revoked if it has already been awarded.
diff --git a/Dfe.Academies.External.Web/Program.cs b/Dfe.Academies.External.Web/Program.cs index 5ad8c8601..57b415ee7 100644 --- a/Dfe.Academies.External.Web/Program.cs +++ b/Dfe.Academies.External.Web/Program.cs @@ -10,7 +10,6 @@ using Dfe.Academies.External.Web.Services; using Dfe.Academisation.CorrelationIdMiddleware; using GovUk.Frontend.AspNetCore; -using Microsoft.ApplicationInsights.Extensibility; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.OpenIdConnect; using Microsoft.AspNetCore.DataProtection; @@ -26,6 +25,8 @@ using Quartz; using Serilog; using StackExchange.Redis; +using Microsoft.FeatureManagement; +using Dfe.Academies.External.Web.FeatureManagement; namespace Dfe.Academies.External.Web { @@ -74,6 +75,8 @@ public static void Main(string[] args) }) .AddSessionStateTempDataProvider(); + builder.Services.AddFeatureManagement(); + builder.Services.AddAuthentication(options => { options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; @@ -179,7 +182,7 @@ public static void Main(string[] args) } ); builder.Services.AddSingleton(); - + builder.Services.AddSingleton(); builder.Services.AddAutoMapper(typeof(AutoMapperProfile)); builder.Services.AddTransient(x => new NotificationClient(builder.Configuration["emailnotifications:key"])); builder.Services.Configure(builder.Configuration.GetSection("govuk-notify")); @@ -221,7 +224,6 @@ static IAsyncPolicy GetRetryPolicy() options.SupportedUICultures = supportedCultures; }); - builder.Services.AddApplicationInsightsTelemetry(builder.Configuration); //var aiOptions = new Microsoft.ApplicationInsights.AspNetCore.Extensions.ApplicationInsightsServiceOptions(); @@ -235,7 +237,7 @@ static IAsyncPolicy GetRetryPolicy() builder.Host.UseSerilog((context, services, loggerConfiguration) => loggerConfiguration .WriteTo.ApplicationInsights( - services.GetRequiredService(), + services.GetRequiredService(), TelemetryConverter.Traces)); var localDevelopment = builder.Configuration.GetValue("local_development"); diff --git a/Dfe.Academies.External.Web/Services/ConversionApplicationRetrievalService.cs b/Dfe.Academies.External.Web/Services/ConversionApplicationRetrievalService.cs index 85bf35afc..759168534 100644 --- a/Dfe.Academies.External.Web/Services/ConversionApplicationRetrievalService.cs +++ b/Dfe.Academies.External.Web/Services/ConversionApplicationRetrievalService.cs @@ -3,6 +3,7 @@ using System.Text.Json.Serialization; using Dfe.Academies.External.Web.Dtos; using Dfe.Academies.External.Web.Enums; +using Dfe.Academies.External.Web.FeatureManagement; using Dfe.Academies.External.Web.Helpers; using Dfe.Academies.External.Web.ViewModels; using Dfe.Academisation.CorrelationIdMiddleware; @@ -14,14 +15,17 @@ public sealed class ConversionApplicationRetrievalService : BaseService, IConver private readonly ILogger _logger; private readonly ResilientRequestProvider _resilientRequestProvider; private readonly IFileUploadService _fileUploadService; + private readonly IConversionGrantExpiryFeature _conversionGrantExpiryFeature; public ConversionApplicationRetrievalService(IHttpClientFactory httpClientFactory, ILogger logger, IFileUploadService fileUploadService, - ICorrelationContext correlationContext) : base(httpClientFactory, correlationContext, AcademisationAPIHttpClientName) + ICorrelationContext correlationContext, + IConversionGrantExpiryFeature conversionGrantExpiryFeature) : base(httpClientFactory, correlationContext, AcademisationAPIHttpClientName) { _logger = logger; _fileUploadService = fileUploadService; _resilientRequestProvider = new ResilientRequestProvider(HttpClient, _logger); + _conversionGrantExpiryFeature = conversionGrantExpiryFeature; } /// @@ -116,7 +120,7 @@ public async Task> GetSchoolApplicationCompo try { var application = await GetApplication(applicationId); - + if (application?.ApplicationId != applicationId) { throw new ArgumentException("Application not found"); @@ -135,10 +139,19 @@ public async Task> GetSchoolApplicationCompo new("Finances", UriFormatter.SetSchoolApplicationComponentUriFromName("Finances"), CalculateFinanceSectionStatus(school)), new("Future pupil numbers", UriFormatter.SetSchoolApplicationComponentUriFromName("Future pupil numbers"), CalculateFuturePupilNumbersSectionStatus(school)), new("Land and buildings", UriFormatter.SetSchoolApplicationComponentUriFromName("Land and buildings"),CalculateLandAndBuildingsSectionStatus(school)), - new("Consultation", UriFormatter.SetSchoolApplicationComponentUriFromName("Consultation"),CalculateConsultationSectionStatus(school)), - new("Conversion support grant", UriFormatter.SetSchoolApplicationComponentUriFromName("Conversion support grant"),CalculatePreOpeningSupportGrantSectionStatus(school)), - new("Declaration", UriFormatter.SetSchoolApplicationComponentUriFromName("Declaration"),CalculateDeclarationSectionStatus(school)) + new("Consultation", UriFormatter.SetSchoolApplicationComponentUriFromName("Consultation"),CalculateConsultationSectionStatus(school)) + ]; + var conversionSupportGrantTask = "Conversion support grant"; + if (!await _conversionGrantExpiryFeature.IsEnabledAsync()) + { + conversionApplicationComponents.Add(new(conversionSupportGrantTask, UriFormatter.SetSchoolApplicationComponentUriFromName(conversionSupportGrantTask), CalculatePreOpeningSupportGrantSectionStatus(school))); + } + if (await _conversionGrantExpiryFeature.IsEnabledAsync() && !_conversionGrantExpiryFeature.IsNewApplication(application.CreatedOn)) + { + conversionApplicationComponents.Add(new(conversionSupportGrantTask, UriFormatter.SetSchoolApplicationComponentUriFromName(conversionSupportGrantTask), CalculatePreOpeningSupportGrantSectionStatus(school))); + } + conversionApplicationComponents.Add(new("Declaration", UriFormatter.SetSchoolApplicationComponentUriFromName("Declaration"), CalculateDeclarationSectionStatus(school))); return conversionApplicationComponents; } @@ -364,9 +377,9 @@ private Status CalculateAboutTheConversionSectionStatus(SchoolApplyingToConvert? /// private Status CalculateFurtherInformationSectionStatus(SchoolApplyingToConvert? selectedSchool, string applicationReference) { - var dioceseFileNames = _fileUploadService.GetFiles(FileUploadConstants.TopLevelSchoolFolderName, selectedSchool.EntityId.ToString(), applicationReference, FileUploadConstants.DioceseFilePrefixFieldName).Result ?? new(); - var foundationConsentFileNames = _fileUploadService.GetFiles(FileUploadConstants.TopLevelSchoolFolderName, selectedSchool.EntityId.ToString(), applicationReference, FileUploadConstants.FoundationConsentFilePrefixFieldName).Result ?? new(); - var resolutionConsentFileNames = _fileUploadService.GetFiles(FileUploadConstants.TopLevelSchoolFolderName, selectedSchool.EntityId.ToString(), applicationReference, FileUploadConstants.ResolutionConsentfilePrefixFieldName).Result ?? new(); + var dioceseFileNames = _fileUploadService.GetFiles(FileUploadConstants.TopLevelSchoolFolderName, selectedSchool!.EntityId.ToString(), applicationReference, FileUploadConstants.DioceseFilePrefixFieldName).Result ?? []; + var foundationConsentFileNames = _fileUploadService.GetFiles(FileUploadConstants.TopLevelSchoolFolderName, selectedSchool.EntityId.ToString(), applicationReference, FileUploadConstants.FoundationConsentFilePrefixFieldName).Result ?? []; + var resolutionConsentFileNames = _fileUploadService.GetFiles(FileUploadConstants.TopLevelSchoolFolderName, selectedSchool.EntityId.ToString(), applicationReference, FileUploadConstants.ResolutionConsentfilePrefixFieldName).Result ?? []; if (!string.IsNullOrEmpty(selectedSchool?.TrustBenefitDetails) && ((selectedSchool?.DioceseName == null) == (!dioceseFileNames.Any()) && (selectedSchool?.FoundationTrustOrBodyName == null) == (!foundationConsentFileNames.Any())) && diff --git a/Dfe.Academies.External.Web/appsettings.Development.json b/Dfe.Academies.External.Web/appsettings.Development.json index 6528e94b2..83d6623d5 100644 --- a/Dfe.Academies.External.Web/appsettings.Development.json +++ b/Dfe.Academies.External.Web/appsettings.Development.json @@ -1,16 +1,20 @@ { - "local_development": false, - "DetailedErrors": true, - "Logging": { - "LogLevel": { - "Default": "Information", - "Microsoft.AspNetCore": "Warning" - } - }, - "academies_api": { - "endpoint": "https://webapp-t1dv-sip-a2c.azurewebsites.net/" - }, - "academisation_api": { - "endpoint": "https://webapp-t1dv-sip-a2c.azurewebsites.net/" - } + "local_development": false, + "DetailedErrors": true, + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "academies_api": { + "endpoint": "replace-me" + }, + "academisation_api": { + "endpoint": "replace-me" + }, + "FeatureManagement": { + "IsConversionGrantExpired": false, + "ConversionGrantExpiry": "2024-12-12T13:00:00Z" + } } diff --git a/Dfe.Academies.External.Web/appsettings.Staging.json b/Dfe.Academies.External.Web/appsettings.Staging.json index 46a186c5a..6c7a88cf4 100644 --- a/Dfe.Academies.External.Web/appsettings.Staging.json +++ b/Dfe.Academies.External.Web/appsettings.Staging.json @@ -27,5 +27,9 @@ "Properties": { "Application": "Dfe.Academies.External.Web" } + }, + "FeatureManagement": { + "IsConversionGrantExpired": false, + "ConversionGrantExpiry": "2024-12-13T11:00:00Z" } } diff --git a/Dfe.Academies.External.Web/appsettings.json b/Dfe.Academies.External.Web/appsettings.json index 2a84a8fc3..26316b985 100644 --- a/Dfe.Academies.External.Web/appsettings.json +++ b/Dfe.Academies.External.Web/appsettings.json @@ -18,7 +18,7 @@ "emailnotifications": { "key": "API key from GOV UK notify", "SupportEmail": "dan.good@education.gov.uk", - "TestMode": true + "TestMode": true }, "Sharepoint": { @@ -36,7 +36,7 @@ "ProblemWithTheFormResponseNeededTemplateId": "c648434c-6f6a-4194-a8af-4974bbd1a7d7", "ProblemWithTheFormNoResponseNeededTemplateId": "28ab51f7-b576-486a-9f73-f9dcd6081f82", "FeedbackTemplateId": "19703095-3055-4c3c-a72c-cf000b45f8ed", - "ApplicationDeletedId" : "22854330-6ba6-473c-b19a-6d1e2b1dfbb4" + "ApplicationDeletedId": "22854330-6ba6-473c-b19a-6d1e2b1dfbb4" }, "ApplicationInsights": { @@ -73,6 +73,10 @@ "Application": "Dfe.Academies.External.Web" } }, - "MaintenanceMode" : false, - "NotificationBannerMessage": "" + "MaintenanceMode": false, + "NotificationBannerMessage": "", + "FeatureManagement": { + "IsConversionGrantExpired": false, + "ConversionGrantExpiry": "2024-12-21T00:00:00Z" + } }