diff --git a/src/Dfe.PlanTech.Application/Persistence/Interfaces/IPlanTechDbContext.cs b/src/Dfe.PlanTech.Application/Persistence/Interfaces/IPlanTechDbContext.cs index 8e25d43bd..7b3ce4121 100644 --- a/src/Dfe.PlanTech.Application/Persistence/Interfaces/IPlanTechDbContext.cs +++ b/src/Dfe.PlanTech.Application/Persistence/Interfaces/IPlanTechDbContext.cs @@ -26,7 +26,7 @@ public interface IPlanTechDbContext Task CallStoredProcedureWithReturnInt(string sprocName, IEnumerable parameters, CancellationToken cancellationToken = default); - IQueryable GetSectionStatuses(string categoryId, int establishmentId); + IQueryable GetSectionStatuses(string sectionIds, int establishmentId); Task GetUserBy(Expression> predicate); diff --git a/src/Dfe.PlanTech.Application/Submissions/Queries/GetSubmissionStatusesQuery.cs b/src/Dfe.PlanTech.Application/Submissions/Queries/GetSubmissionStatusesQuery.cs index 43fd7cccf..3dde5af1e 100644 --- a/src/Dfe.PlanTech.Application/Submissions/Queries/GetSubmissionStatusesQuery.cs +++ b/src/Dfe.PlanTech.Application/Submissions/Queries/GetSubmissionStatusesQuery.cs @@ -1,5 +1,6 @@ using Dfe.PlanTech.Application.Persistence.Interfaces; using Dfe.PlanTech.Domain.Questionnaire.Interfaces; +using Dfe.PlanTech.Domain.Questionnaire.Models; using Dfe.PlanTech.Domain.Submissions.Enums; using Dfe.PlanTech.Domain.Submissions.Interfaces; using Dfe.PlanTech.Domain.Submissions.Models; @@ -10,11 +11,13 @@ namespace Dfe.PlanTech.Application.Submissions.Queries; public class GetSubmissionStatusesQuery(IPlanTechDbContext db, IUser userHelper) : IGetSubmissionStatusesQuery { - public async Task> GetSectionSubmissionStatuses(string categoryId) + public async Task> GetSectionSubmissionStatuses(IEnumerable
sections) { int establishmentId = await userHelper.GetEstablishmentId(); - return await db.ToListAsync(db.GetSectionStatuses(categoryId, establishmentId)); + var sectionIds = String.Join(',', sections.Select(section => section.Sys.Id)); + + return await db.ToListAsync(db.GetSectionStatuses(sectionIds, establishmentId)); } public async Task GetSectionSubmissionStatusAsync(int establishmentId, @@ -39,8 +42,8 @@ public async Task GetSectionSubmissionStatusAsync(int establishme } /// - /// For each submission, convert to SectionStatus, - /// group by Section, + /// For each submission, convert to SectionStatus, + /// group by Section, /// then return latest for each grouping /// optionally choosing from completed submissions first /// diff --git a/src/Dfe.PlanTech.DatabaseUpgrader/Scripts/2024/20241104_1200_RemoveContentfulDependencies.sql b/src/Dfe.PlanTech.DatabaseUpgrader/Scripts/2024/20241104_1200_RemoveContentfulDependencies.sql new file mode 100644 index 000000000..8fe1e3863 --- /dev/null +++ b/src/Dfe.PlanTech.DatabaseUpgrader/Scripts/2024/20241104_1200_RemoveContentfulDependencies.sql @@ -0,0 +1,46 @@ +ALTER PROCEDURE dbo.GetSectionStatuses @sectionIds NVARCHAR(MAX), @establishmentId INT +AS + +SELECT + Value sectionId +INTO #SectionIds +FROM STRING_SPLIT(@sectionIds, ',') + +SELECT + CurrentSubmission.sectionId, + CurrentSubmission.completed, + LastCompleteSubmission.maturity AS lastMaturity, + CurrentSubmission.dateCreated, + CurrentSubmission.dateLastUpdated AS dateUpdated +FROM #SectionIds SI +-- The current submission +CROSS APPLY ( + SELECT TOP 1 + sectionId, + completed, + S.id, + dateCreated, + dateLastUpdated + FROM [dbo].submission S + WHERE + SI.sectionId = S.sectionId + AND S.establishmentId = @establishmentId + AND S.deleted = 0 + ORDER BY S.dateCreated DESC +) CurrentSubmission +-- Use maturity from most recent complete submission (if there is one) so that user always sees recommendation +OUTER APPLY ( + SELECT TOP 1 + maturity + FROM [dbo].submission S + WHERE + SI.sectionId = S.sectionId + AND S.establishmentId = @establishmentId + AND S.deleted = 0 + AND s.completed = 1 + ORDER BY S.dateCreated DESC +) LastCompleteSubmission + +DROP TABLE #SectionIds + +GO diff --git a/src/Dfe.PlanTech.Domain/Submissions/Interfaces/IGetSubmissionStatusesQuery.cs b/src/Dfe.PlanTech.Domain/Submissions/Interfaces/IGetSubmissionStatusesQuery.cs index 61a63319d..8dce50746 100644 --- a/src/Dfe.PlanTech.Domain/Submissions/Interfaces/IGetSubmissionStatusesQuery.cs +++ b/src/Dfe.PlanTech.Domain/Submissions/Interfaces/IGetSubmissionStatusesQuery.cs @@ -1,11 +1,12 @@ using Dfe.PlanTech.Domain.Questionnaire.Interfaces; +using Dfe.PlanTech.Domain.Questionnaire.Models; using Dfe.PlanTech.Domain.Submissions.Models; namespace Dfe.PlanTech.Domain.Submissions.Interfaces; public interface IGetSubmissionStatusesQuery { - Task> GetSectionSubmissionStatuses(string categoryId); + Task> GetSectionSubmissionStatuses(IEnumerable
sections); Task GetSectionSubmissionStatusAsync(int establishmentId, ISectionComponent section, diff --git a/src/Dfe.PlanTech.Infrastructure.Data/PlanTechDbContext.cs b/src/Dfe.PlanTech.Infrastructure.Data/PlanTechDbContext.cs index 974dc9f8a..9bca2eff9 100644 --- a/src/Dfe.PlanTech.Infrastructure.Data/PlanTechDbContext.cs +++ b/src/Dfe.PlanTech.Infrastructure.Data/PlanTechDbContext.cs @@ -111,7 +111,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) }); } - public IQueryable GetSectionStatuses(string categoryId, int establishmentId) => SectionStatusesSp.FromSqlInterpolated($"{DatabaseConstants.GetSectionStatuses} {categoryId} , {establishmentId}"); + public IQueryable GetSectionStatuses(string sectionIds, int establishmentId) => SectionStatusesSp.FromSqlInterpolated($"{DatabaseConstants.GetSectionStatuses} {sectionIds} , {establishmentId}"); public void AddUser(User user) => Users.Add(user); diff --git a/src/Dfe.PlanTech.Web/ViewComponents/CategorySectionViewComponent.cs b/src/Dfe.PlanTech.Web/ViewComponents/CategorySectionViewComponent.cs index 856343c99..7df502e49 100644 --- a/src/Dfe.PlanTech.Web/ViewComponents/CategorySectionViewComponent.cs +++ b/src/Dfe.PlanTech.Web/ViewComponents/CategorySectionViewComponent.cs @@ -76,7 +76,7 @@ public async Task RetrieveSectionStatuses(Category category) { try { - category.SectionStatuses = await _query.GetSectionSubmissionStatuses(category.Sys.Id); + category.SectionStatuses = await _query.GetSectionSubmissionStatuses(category.Sections); category.Completed = category.SectionStatuses.Count(x => x.Completed); category.RetrievalError = false; return category; diff --git a/tests/Dfe.PlanTech.Application.UnitTests/Submissions/Queries/GetSubmissionStatusesQueryTests.cs b/tests/Dfe.PlanTech.Application.UnitTests/Submissions/Queries/GetSubmissionStatusesQueryTests.cs index bd19dbb71..0c40611c8 100644 --- a/tests/Dfe.PlanTech.Application.UnitTests/Submissions/Queries/GetSubmissionStatusesQueryTests.cs +++ b/tests/Dfe.PlanTech.Application.UnitTests/Submissions/Queries/GetSubmissionStatusesQueryTests.cs @@ -25,7 +25,7 @@ public class GetSubmissionStatusesQueryTests private const int establishmentId = 1; private const string maturity = "High"; - private readonly static Section completeSection = new() + private static readonly Section completeSection = new() { Sys = new SystemDetails() { @@ -34,7 +34,7 @@ public class GetSubmissionStatusesQueryTests Name = "section one" }; - private readonly static Section inprogressSection = new() + private static readonly Section inprogressSection = new() { Sys = new SystemDetails() { @@ -43,7 +43,7 @@ public class GetSubmissionStatusesQueryTests Name = "section two" }; - private readonly static Section notstartedSection = new() + private static readonly Section notstartedSection = new() { Sys = new SystemDetails() { @@ -106,7 +106,6 @@ public class GetSubmissionStatusesQueryTests } }; - private GetSubmissionStatusesQuery CreateStrut() => new GetSubmissionStatusesQuery(Db, user); public GetSubmissionStatusesQueryTests() @@ -114,10 +113,8 @@ public GetSubmissionStatusesQueryTests() Db.GetSectionStatuses(Arg.Any(), Arg.Any()) .Returns((callinfo) => { - var categoryId = callinfo.ArgAt(0); - var category = categories.FirstOrDefault(category => category.Sys.Id == categoryId); - Assert.NotNull(category); - return SectionStatuses.Where(sectionStatus => category.Sections.Select(section => section.Sys.Id).Any(id => id == sectionStatus.SectionId)).AsQueryable(); + var sectionIds = callinfo.ArgAt(0).Split(","); + return SectionStatuses.Where(sectionStatus => sectionIds.Contains(sectionStatus.SectionId)).AsQueryable(); }); @@ -146,7 +143,7 @@ public async Task GetSectionSubmissionStatuses_ReturnsListOfStatuses() { var category = categories[0]; var sections = category.Sections; - var result = await CreateStrut().GetSectionSubmissionStatuses(category.Sys.Id); + var result = await CreateStrut().GetSectionSubmissionStatuses(category.Sections); Assert.Equal(result.Count, sections.Count); diff --git a/tests/Dfe.PlanTech.Web.UnitTests/ViewComponents/CategorySectionViewComponentTests.cs b/tests/Dfe.PlanTech.Web.UnitTests/ViewComponents/CategorySectionViewComponentTests.cs index c90a64f09..654063aa3 100644 --- a/tests/Dfe.PlanTech.Web.UnitTests/ViewComponents/CategorySectionViewComponentTests.cs +++ b/tests/Dfe.PlanTech.Web.UnitTests/ViewComponents/CategorySectionViewComponentTests.cs @@ -222,7 +222,7 @@ public async Task Returns_CategorySectionInfo_If_Slug_Exists_And_SectionIsComple DateUpdated = DateTime.Parse(utcTime), }); - _getSubmissionStatusesQuery.GetSectionSubmissionStatuses(_category.Sys.Id).Returns([.. _category.SectionStatuses]); + _getSubmissionStatusesQuery.GetSectionSubmissionStatuses(_category.Sections).Returns([.. _category.SectionStatuses]); var result = await _categorySectionViewComponent.InvokeAsync(_category) as ViewViewComponentResult; @@ -271,7 +271,7 @@ public async Task Returns_CategorySelectionInfo_If_Slug_Exists_And_SectionIsNotC DateUpdated = DateTime.Parse(utcTime) }); - _getSubmissionStatusesQuery.GetSectionSubmissionStatuses(_category.Sys.Id).Returns([.. _category.SectionStatuses]); + _getSubmissionStatusesQuery.GetSectionSubmissionStatuses(_category.Sections).Returns([.. _category.SectionStatuses]); var result = await _categorySectionViewComponent.InvokeAsync(_category) as ViewViewComponentResult; @@ -310,7 +310,7 @@ public async Task Returns_CategorySelectionInfo_If_Section_IsNotStarted() { _category.Completed = 0; - _getSubmissionStatusesQuery.GetSectionSubmissionStatuses(_category.Sys.Id).Returns([.. _category.SectionStatuses]); + _getSubmissionStatusesQuery.GetSectionSubmissionStatuses(_category.Sections).Returns([.. _category.SectionStatuses]); var result = await _categorySectionViewComponent.InvokeAsync(_category) as ViewViewComponentResult; @@ -363,7 +363,7 @@ public async Task Returns_NullSlug_And_ErrorMessage_In_CategorySectionInfo_If_Sl Completed = true }); - _ = _getSubmissionStatusesQuery.GetSectionSubmissionStatuses(_category.Sys.Id).Returns([.. _category.SectionStatuses]); + _ = _getSubmissionStatusesQuery.GetSectionSubmissionStatuses(_category.Sections).Returns([.. _category.SectionStatuses]); var result = await _categorySectionViewComponent.InvokeAsync(_category) as ViewViewComponentResult; @@ -401,7 +401,7 @@ public async Task Returns_NullSlug_And_ErrorMessage_In_CategorySectionInfo_If_Sl [Fact] public async Task Returns_ProgressRetrievalError_When_ProgressCanNotBeRetrieved() { - _getSubmissionStatusesQuery.GetSectionSubmissionStatuses(Arg.Any()) + _getSubmissionStatusesQuery.GetSectionSubmissionStatuses(Arg.Any>()) .ThrowsAsync(new Exception("Error occurred fection sections")); var result = await _categorySectionViewComponent.InvokeAsync(_category) as ViewViewComponentResult; @@ -447,7 +447,7 @@ public async Task Returns_NoSectionsErrorRedirectUrl_If_SectionsAreEmpty() } }; - _getSubmissionStatusesQuery.GetSectionSubmissionStatuses(_category.Sys.Id).Returns([.. _category.SectionStatuses]); + _getSubmissionStatusesQuery.GetSectionSubmissionStatuses(_category.Sections).Returns([.. _category.SectionStatuses]); var result = await _categorySectionViewComponent.InvokeAsync(_category) as ViewViewComponentResult; @@ -479,7 +479,7 @@ public async Task Returns_RecommendationInfo_If_It_Exists_ForMaturity() }); _getSubTopicRecommendationQuery.GetSubTopicRecommendation(Arg.Any()).Returns(_subtopic); - _getSubmissionStatusesQuery.GetSectionSubmissionStatuses(_category.Sys.Id).Returns(_category.SectionStatuses.ToList()); + _getSubmissionStatusesQuery.GetSectionSubmissionStatuses(_category.Sections).Returns(_category.SectionStatuses.ToList()); var result = await _categorySectionViewComponent.InvokeAsync(_category) as ViewViewComponentResult; @@ -509,7 +509,7 @@ public async Task Returns_RecommendationInfo_And_Logs_Error_If_Exception_Thrown_ }); _getSubTopicRecommendationQuery.GetSubTopicRecommendation(Arg.Any()).Returns(_subtopic); - _getSubmissionStatusesQuery.GetSectionSubmissionStatuses(_category.Sys.Id).Throws(new Exception("test")); + _getSubmissionStatusesQuery.GetSectionSubmissionStatuses(_category.Sections).Throws(new Exception("test")); var result = await _categorySectionViewComponent.InvokeAsync(_category) as ViewViewComponentResult; @@ -541,7 +541,7 @@ public async Task Returns_NullRecommendationInfo_If_No_RecommendationPage_Exists LastMaturity = "Low", }); - _getSubmissionStatusesQuery.GetSectionSubmissionStatuses(_category.Sys.Id).Returns(_category.SectionStatuses.ToList()); + _getSubmissionStatusesQuery.GetSectionSubmissionStatuses(_category.Sections).Returns(_category.SectionStatuses.ToList()); var result = await _categorySectionViewComponent.InvokeAsync(_category) as ViewViewComponentResult; @@ -572,7 +572,7 @@ public async Task DoesNotReturn_RecommendationInfo_If_Section_Has_Never_Been_Com LastMaturity = null }); - _getSubmissionStatusesQuery.GetSectionSubmissionStatuses(_category.Sys.Id).Returns(_category.SectionStatuses.ToList()); + _getSubmissionStatusesQuery.GetSectionSubmissionStatuses(_category.Sections).Returns(_category.SectionStatuses.ToList()); var result = await _categorySectionViewComponent.InvokeAsync(_category) as ViewViewComponentResult; @@ -602,7 +602,7 @@ public async Task Returns_RecommendationInfo_If_Incomplete_Section_Is_Previously }); _getSubTopicRecommendationQuery.GetSubTopicRecommendation(Arg.Any()).Returns(_subtopic); - _getSubmissionStatusesQuery.GetSectionSubmissionStatuses(_category.Sys.Id).Returns(_category.SectionStatuses.ToList()); + _getSubmissionStatusesQuery.GetSectionSubmissionStatuses(_category.Sections).Returns(_category.SectionStatuses.ToList()); var result = await _categorySectionViewComponent.InvokeAsync(_category) as ViewViewComponentResult;