diff --git a/CHANGELOG.md b/CHANGELOG.md index 6d1bf6bd2..24b590b09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Changed +- Overall effectiveness ofsted rating can now be 'not judged' - Improve performance of search page and search autocomplete - Minor performance improvement to all academies db database calls - Refactored and split up the program file into separate config files diff --git a/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb/Models/Mis/MisEstablishment.cs b/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb/Models/Mis/MisEstablishment.cs index 934832c4c..ec0a6b699 100644 --- a/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb/Models/Mis/MisEstablishment.cs +++ b/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb/Models/Mis/MisEstablishment.cs @@ -91,7 +91,7 @@ public class MisEstablishment public string? SchoolTypeAtTimeOfLatestFullInspection { get; set; } - public int? OverallEffectiveness { get; set; } + public string? OverallEffectiveness { get; set; } public string? CategoryOfConcern { get; set; } diff --git a/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb/Repositories/AcademyRepository.cs b/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb/Repositories/AcademyRepository.cs index 1d9576e78..f15b25f5f 100644 --- a/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb/Repositories/AcademyRepository.cs +++ b/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb/Repositories/AcademyRepository.cs @@ -1,9 +1,9 @@ -using System.Globalization; using DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.Contexts; using DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.Extensions; using DfE.FindInformationAcademiesTrusts.Data.Repositories.Academy; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; +using System.Globalization; namespace DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.Repositories; @@ -55,34 +55,32 @@ private async Task> GetOfstedRatings(in { // Ofsted data is held in MisEstablishments for most academies var ofstedRatings = - await academiesDbContext.MisEstablishments - .Where(me => urns.Contains(me.Urn!.Value)) - .Select(me => new AcademyOfstedRatings(me.Urn!.Value, - new OfstedRating( - (OfstedRatingScore?)me.OverallEffectiveness ?? OfstedRatingScore.None, - (OfstedRatingScore?)me.QualityOfEducation ?? OfstedRatingScore.None, - (OfstedRatingScore?)me.BehaviourAndAttitudes ?? OfstedRatingScore.None, - (OfstedRatingScore?)me.PersonalDevelopment ?? OfstedRatingScore.None, - (OfstedRatingScore?)me.EffectivenessOfLeadershipAndManagement ?? OfstedRatingScore.None, - (OfstedRatingScore?)me.EarlyYearsProvisionWhereApplicable ?? OfstedRatingScore.None, - (OfstedRatingScore?)me.SixthFormProvisionWhereApplicable ?? OfstedRatingScore.None, - OfstedRating.ConvertStringToCategoriesOfConcern(me.CategoryOfConcern), - OfstedRating.ConvertStringToSafeguardingScore(me.SafeguardingIsEffective), - me.InspectionStartDate.ParseAsNullableDate()), - new OfstedRating( - (OfstedRatingScore?)me.PreviousFullInspectionOverallEffectiveness.ParseAsNullableInt() ?? - OfstedRatingScore.None, - (OfstedRatingScore?)me.PreviousQualityOfEducation ?? OfstedRatingScore.None, - (OfstedRatingScore?)me.PreviousBehaviourAndAttitudes ?? OfstedRatingScore.None, - (OfstedRatingScore?)me.PreviousPersonalDevelopment ?? OfstedRatingScore.None, - (OfstedRatingScore?)me.PreviousEffectivenessOfLeadershipAndManagement ?? OfstedRatingScore.None, - (OfstedRatingScore?)me.PreviousEarlyYearsProvisionWhereApplicable ?? OfstedRatingScore.None, - (OfstedRatingScore?)me.PreviousSixthFormProvisionWhereApplicable.ParseAsNullableInt() ?? - OfstedRatingScore.None, - OfstedRating.ConvertStringToCategoriesOfConcern(me.PreviousCategoryOfConcern), - OfstedRating.ConvertStringToSafeguardingScore(me.PreviousSafeguardingIsEffective), - me.PreviousInspectionStartDate.ParseAsNullableDate()))) - .ToListAsync(); + await academiesDbContext.MisEstablishments + .Where(me => urns.Contains(me.Urn!.Value)) + .Select(me => new AcademyOfstedRatings(me.Urn!.Value, + new OfstedRating( + ConvertOverallEffectivenessToOfstedRatingScore(me.OverallEffectiveness), + (OfstedRatingScore?)me.QualityOfEducation ?? OfstedRatingScore.None, + (OfstedRatingScore?)me.BehaviourAndAttitudes ?? OfstedRatingScore.None, + (OfstedRatingScore?)me.PersonalDevelopment ?? OfstedRatingScore.None, + (OfstedRatingScore?)me.EffectivenessOfLeadershipAndManagement ?? OfstedRatingScore.None, + (OfstedRatingScore?)me.EarlyYearsProvisionWhereApplicable ?? OfstedRatingScore.None, + (OfstedRatingScore?)me.SixthFormProvisionWhereApplicable ?? OfstedRatingScore.None, + OfstedRating.ConvertStringToCategoriesOfConcern(me.CategoryOfConcern), + OfstedRating.ConvertStringToSafeguardingScore(me.SafeguardingIsEffective), + me.InspectionStartDate.ParseAsNullableDate()), + new OfstedRating( + ConvertOverallEffectivenessToOfstedRatingScore(me.PreviousFullInspectionOverallEffectiveness), + (OfstedRatingScore?)me.PreviousQualityOfEducation ?? OfstedRatingScore.None, + (OfstedRatingScore?)me.PreviousBehaviourAndAttitudes ?? OfstedRatingScore.None, + (OfstedRatingScore?)me.PreviousPersonalDevelopment ?? OfstedRatingScore.None, + (OfstedRatingScore?)me.PreviousEffectivenessOfLeadershipAndManagement ?? OfstedRatingScore.None, + (OfstedRatingScore?)me.PreviousEarlyYearsProvisionWhereApplicable ?? OfstedRatingScore.None, + (OfstedRatingScore?)me.PreviousSixthFormProvisionWhereApplicable.ParseAsNullableInt() ?? OfstedRatingScore.None, + OfstedRating.ConvertStringToCategoriesOfConcern(me.PreviousCategoryOfConcern), + OfstedRating.ConvertStringToSafeguardingScore(me.PreviousSafeguardingIsEffective), + me.PreviousInspectionStartDate.ParseAsNullableDate()))) + .ToListAsync(); // Look in MisFurtherEducationEstablishments for academies not found in MisEstablishments // Note: if an entry is in MisEstablishments then it will not be in MisFurtherEducationEstablishments, even if it has no ofsted data @@ -194,6 +192,25 @@ public async Task GetOverviewOfAcademiesInTrustAsync(string u )) .ToArrayAsync(); } + public static OfstedRatingScore ConvertOverallEffectivenessToOfstedRatingScore(string? rating) + { + if (string.IsNullOrWhiteSpace(rating)) + return OfstedRatingScore.None; + + // Check if it is 'Not judged' all other gradings are int based + if (rating.ToLower().Equals("not judged")) + { + return OfstedRatingScore.NoJudgement; + } + // Attempt to parse the string as an integer + if (int.TryParse(rating, out int intRating) && Enum.IsDefined(typeof(OfstedRatingScore), intRating)) + { + return (OfstedRatingScore)intRating; + } + + // Default case if parsing fails + return OfstedRatingScore.None; + } private sealed record AcademyOfstedRatings(int Urn, OfstedRating Current, OfstedRating Previous); } diff --git a/DfE.FindInformationAcademiesTrusts/Pages/Trusts/Academies/_OfstedRatingCell.cshtml.cs b/DfE.FindInformationAcademiesTrusts/Pages/Trusts/Academies/_OfstedRatingCell.cshtml.cs index 4710a833d..72e3ed36e 100644 --- a/DfE.FindInformationAcademiesTrusts/Pages/Trusts/Academies/_OfstedRatingCell.cshtml.cs +++ b/DfE.FindInformationAcademiesTrusts/Pages/Trusts/Academies/_OfstedRatingCell.cshtml.cs @@ -19,6 +19,7 @@ public class OfstedRatingCellModel OfstedRatingScore.Good => "Good", OfstedRatingScore.RequiresImprovement => "Requires improvement", OfstedRatingScore.Inadequate => "Inadequate", + OfstedRatingScore.NoJudgement => "No Judgement", _ => string.Empty }; diff --git a/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/Factory/MisEstablishmentFactory.cs b/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/Factory/MisEstablishmentFactory.cs index 695b05643..c89d8249d 100644 --- a/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/Factory/MisEstablishmentFactory.cs +++ b/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/Factory/MisEstablishmentFactory.cs @@ -12,23 +12,33 @@ public static MisEstablishment CreateMisEstablishment(int urn, int? grade, strin { return new MisEstablishment { - Urn = urn, PreviousFullInspectionOverallEffectiveness = grade.ToString(), - PreviousQualityOfEducation = grade, PreviousBehaviourAndAttitudes = grade, - PreviousPersonalDevelopment = grade, PreviousEffectivenessOfLeadershipAndManagement = grade, + Urn = urn, + PreviousFullInspectionOverallEffectiveness = grade.ToString(), + PreviousQualityOfEducation = grade, + PreviousBehaviourAndAttitudes = grade, + PreviousPersonalDevelopment = grade, + PreviousEffectivenessOfLeadershipAndManagement = grade, PreviousEarlyYearsProvisionWhereApplicable = grade, PreviousSixthFormProvisionWhereApplicable = grade.ToString(), - PreviousCategoryOfConcern = categoriesOfConcern, PreviousSafeguardingIsEffective = safeguarding, + PreviousCategoryOfConcern = categoriesOfConcern, + PreviousSafeguardingIsEffective = safeguarding, PreviousInspectionStartDate = dateString }; } return new MisEstablishment { - Urn = urn, OverallEffectiveness = grade, QualityOfEducation = grade, BehaviourAndAttitudes = grade, - PersonalDevelopment = grade, EffectivenessOfLeadershipAndManagement = grade, + Urn = urn, + OverallEffectiveness = grade.ToString(), + QualityOfEducation = grade, + BehaviourAndAttitudes = grade, + PersonalDevelopment = grade, + EffectivenessOfLeadershipAndManagement = grade, EarlyYearsProvisionWhereApplicable = grade, - SixthFormProvisionWhereApplicable = grade, CategoryOfConcern = categoriesOfConcern, - SafeguardingIsEffective = safeguarding, InspectionStartDate = dateString + SixthFormProvisionWhereApplicable = grade, + CategoryOfConcern = categoriesOfConcern, + SafeguardingIsEffective = safeguarding, + InspectionStartDate = dateString }; } } diff --git a/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/Repositories/AcademyRepositoryTests.cs b/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/Repositories/AcademyRepositoryTests.cs index 87d669d3e..5dfadb969 100644 --- a/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/Repositories/AcademyRepositoryTests.cs +++ b/tests/DfE.FindInformationAcademiesTrusts.Data.AcademiesDb.UnitTests/Repositories/AcademyRepositoryTests.cs @@ -66,7 +66,7 @@ public async Task GetAcademiesInTrustOfstedAsync_should_return_empty_array_when_ public async Task GetAcademiesInTrustOfstedAsync_should_only_return_academies_linked_to_trust() { _mockAcademiesDbContext.AddGiasGroupLink(new GiasGroupLink - { GroupUid = "some other trust", Urn = "some other academy" }); + { GroupUid = "some other trust", Urn = "some other academy" }); var giasGroupLinks = AddGiasGroupLinksToMockDb(6); @@ -279,7 +279,7 @@ public async Task GetNumberOfAcademiesInTrustAsync_should_return_zero_when_no_gr public async Task GetNumberOfAcademiesInTrustAsync_should_return_number_of_grouplinks_for_uid(int numAcademies) { _mockAcademiesDbContext.AddGiasGroupLink(new GiasGroupLink - { GroupUid = "some other trust", Urn = "some other academy" }); + { GroupUid = "some other trust", Urn = "some other academy" }); for (var i = 0; i < numAcademies; i++) { @@ -476,4 +476,116 @@ public async Task GetOverviewOfAcademiesInTrustAsync_should_return_empty_array_w result.Should().NotBeNull(); result.Should().BeEmpty(); } + + [Theory] + [InlineData("")] + [InlineData(" ")] + public void Should_Return_None_When_Rating_Is_NullOrWhitespace(string rating) + { + // Act + var result = AcademyRepository.ConvertOverallEffectivenessToOfstedRatingScore(rating); + + // Assert + result.Should().Be(OfstedRatingScore.None); + } + + [Theory] + [InlineData("Not judged")] + [InlineData("not judged")] + [InlineData("NOT JUDGED")] + [InlineData("NoT JuDgEd")] + public void Should_Return_NoJudgement_When_Rating_Is_NotJudged_CaseInsensitive(string rating) + { + // Act + var result = AcademyRepository.ConvertOverallEffectivenessToOfstedRatingScore(rating); + + // Assert + result.Should().Be(OfstedRatingScore.NoJudgement); + } + + [Theory] + [InlineData("1", OfstedRatingScore.Outstanding)] + [InlineData("2", OfstedRatingScore.Good)] + [InlineData("3", OfstedRatingScore.RequiresImprovement)] + [InlineData("4", OfstedRatingScore.Inadequate)] + [InlineData("8", OfstedRatingScore.DoesNotApply)] + [InlineData("9", OfstedRatingScore.NoJudgement)] + [InlineData("0", OfstedRatingScore.InsufficientEvidence)] + [InlineData("-1", OfstedRatingScore.None)] + public void Should_Return_Correct_OfstedRatingScore_When_Rating_Is_Valid_Integer_String(string rating, OfstedRatingScore expected) + { + // Act + var result = AcademyRepository.ConvertOverallEffectivenessToOfstedRatingScore(rating); + + // Assert + result.Should().Be(expected); + } + + [Theory] + [InlineData("5")] + [InlineData("10")] + [InlineData("-2")] + public void Should_Return_None_When_Rating_Is_Integer_Not_Defined_In_Enum(string rating) + { + // Act + var result = AcademyRepository.ConvertOverallEffectivenessToOfstedRatingScore(rating); + + // Assert + result.Should().Be(OfstedRatingScore.None); + } + + [Theory] + [InlineData("abc")] + [InlineData("Good")] + [InlineData("Outstanding")] + [InlineData("Requires Improvement")] + [InlineData("Inadequate")] + [InlineData("N/A")] + [InlineData("Unknown")] + public void Should_Return_None_When_Rating_Is_Invalid_String(string rating) + { + // Act + var result = AcademyRepository.ConvertOverallEffectivenessToOfstedRatingScore(rating); + + // Assert + result.Should().Be(OfstedRatingScore.None); + } + + [Theory] + [InlineData("1", "2", OfstedRatingScore.Outstanding, OfstedRatingScore.Good)] + [InlineData("Not judged", "Not judged", OfstedRatingScore.NoJudgement, OfstedRatingScore.NoJudgement)] + [InlineData("abc", "def", OfstedRatingScore.None, OfstedRatingScore.None)] + [InlineData("2", "Not judged", OfstedRatingScore.Good, OfstedRatingScore.NoJudgement)] + [InlineData("Not judged", "1", OfstedRatingScore.NoJudgement, OfstedRatingScore.Outstanding)] + public async Task GetAcademiesInTrustOfstedAsync_should_correctly_convert_OverallEffectiveness_and_PreviousFullInspectionOverallEffectiveness( + string overallEffectiveness, + string previousOverallEffectiveness, + OfstedRatingScore expectedCurrentScore, + OfstedRatingScore expectedPreviousScore) + { + // Arrange + var giasGroupLink = AddGiasGroupLinksToMockDb(1).Single(); + var urn = int.Parse(giasGroupLink.Urn!); + + var me = new MisEstablishment + { + Urn = urn, + OverallEffectiveness = overallEffectiveness, + PreviousFullInspectionOverallEffectiveness = previousOverallEffectiveness, + InspectionStartDate = "01/01/2022", + PreviousInspectionStartDate = "01/01/2021" + }; + _mockAcademiesDbContext.AddMisEstablishments(new[] { me }); + + // Act + var result = await _sut.GetAcademiesInTrustOfstedAsync("1234"); + + // Assert + var academyOfsted = result.Should().ContainSingle().Which; + academyOfsted.Urn.Should().Be(giasGroupLink.Urn); + academyOfsted.CurrentOfstedRating.OverallEffectiveness.Should().Be(expectedCurrentScore); + academyOfsted.PreviousOfstedRating.OverallEffectiveness.Should().Be(expectedPreviousScore); + } + + }