diff --git a/Dfe.Academies.Api.Infrastructure/MstrContext.cs b/Dfe.Academies.Api.Infrastructure/MstrContext.cs index d2cb9e7de..13a2a19b4 100644 --- a/Dfe.Academies.Api.Infrastructure/MstrContext.cs +++ b/Dfe.Academies.Api.Infrastructure/MstrContext.cs @@ -19,6 +19,7 @@ public MstrContext(DbContextOptions options) : base(options) public DbSet TrustTypes { get; set; } = null!; public DbSet Establishments { get; set; } = null!; public DbSet EstablishmentTypes { get; set; } = null!; + public DbSet EducationEstablishmentTrusts { get; set; } = null!; public DbSet LocalAuthorities { get; set; } = null!; public DbSet IfdPipelines { get; set; } = null!; @@ -31,6 +32,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) modelBuilder.Entity(ConfigureEstablishment); modelBuilder.Entity(ConfigureEstablishmentType); + modelBuilder.Entity(ConfigureEducationEstablishmentTrust); modelBuilder.Entity(ConfigureLocalAuthority); modelBuilder.Entity(ConfigureIfdPipeline); @@ -211,7 +213,12 @@ void ConfigureTrustType(EntityTypeBuilder trustTypeConfiguration) trustTypeConfiguration.ToTable("Ref_TrustType", DEFAULT_SCHEMA); } - + private void ConfigureEducationEstablishmentTrust(EntityTypeBuilder entityBuilder) + { + entityBuilder.HasKey(e => e.SK); + entityBuilder.ToTable("EducationEstablishmentTrust", DEFAULT_SCHEMA); + + } void ConfigureLocalAuthority(EntityTypeBuilder localAuthorityConfiguration) { localAuthorityConfiguration.HasKey(e => e.SK).HasName("SK"); diff --git a/Dfe.Academies.Api.Infrastructure/Repositories/EstablishmentRepository.cs b/Dfe.Academies.Api.Infrastructure/Repositories/EstablishmentRepository.cs index 36de3a02c..a47a33b8c 100644 --- a/Dfe.Academies.Api.Infrastructure/Repositories/EstablishmentRepository.cs +++ b/Dfe.Academies.Api.Infrastructure/Repositories/EstablishmentRepository.cs @@ -2,6 +2,7 @@ using Dfe.Academies.Academisation.Data.Repositories; using Dfe.Academies.Domain.Establishment; using Microsoft.EntityFrameworkCore; +using System.ComponentModel; using static System.Net.Mime.MediaTypeNames; namespace Dfe.Academies.Infrastructure.Repositories @@ -26,23 +27,23 @@ public EstablishmentRepository(MstrContext context) : base(context) } public async Task> Search(string name, string ukPrn, string urn, CancellationToken cancellationToken) { - IQueryable query = DefaultIncludes(); - - query = !string.IsNullOrEmpty(name) - ? query.Where(establishment => establishment.EstablishmentName.Contains(name)) - : query; - - query = !string.IsNullOrEmpty(ukPrn) - ? query.Where(establishment => establishment.UKPRN.Contains(ukPrn)) - : query; - - query = !string.IsNullOrEmpty(urn) - ? query.Where(establishment => establishment.URN.ToString().Contains(urn)) - : query; - - return await query.OrderBy(establishment => establishment.SK) - .ToListAsync(cancellationToken) - .ConfigureAwait(false); + IQueryable query = DefaultIncludes().AsNoTracking(); + if (!string.IsNullOrEmpty(name)) + { + query = query.Where(e => e.EstablishmentName.Contains(name)); + } + if (!string.IsNullOrEmpty(ukPrn)) + { + query = query.Where(e => e.UKPRN == ukPrn); + } + if (!string.IsNullOrEmpty(urn)) + { + if (int.TryParse(urn, out var urnAsNumber)) + { + query = query.Where(e => e.URN == urnAsNumber); + } + } + return await query.ToListAsync(cancellationToken); } public async Task> GetURNsByRegion(string[] regions, CancellationToken cancellationToken) { @@ -62,6 +63,25 @@ public async Task> GetByUrns(int[] urns, CancellationToken c .ToListAsync(cancellationToken); } + public async Task> GetByTrust(long? trustId, CancellationToken cancellationToken) + { + var establishmentIds = await context.EducationEstablishmentTrusts + .Where(eet => eet.FK_Trust == Convert.ToInt32(trustId)) + .Select(eet => (long)eet.FK_EducationEstablishment) + .ToListAsync(cancellationToken) + .ConfigureAwait(false); + + var establishments = await DefaultIncludes() + .Where(e => establishmentIds.Contains(e.SK)) + .ToListAsync(cancellationToken) + .ConfigureAwait(false); + + + return establishments; + } + + + private IQueryable DefaultIncludes() { var x = dbSet diff --git a/Dfe.Academies.Api.Infrastructure/Repositories/TrustRepository.cs b/Dfe.Academies.Api.Infrastructure/Repositories/TrustRepository.cs index 25a245bbd..3647ea4ae 100644 --- a/Dfe.Academies.Api.Infrastructure/Repositories/TrustRepository.cs +++ b/Dfe.Academies.Api.Infrastructure/Repositories/TrustRepository.cs @@ -19,6 +19,14 @@ public TrustRepository(MstrContext context) : base(context) return trust; } + public async Task GetTrustByCompaniesHouseNumber(string companiesHouseNumber, CancellationToken cancellationToken) + { + var trust = await dbSet + .Include(x => x.TrustType) + .SingleOrDefaultAsync(x => x.CompaniesHouseNumber == companiesHouseNumber).ConfigureAwait(false); + + return trust; + } public async Task> GetTrustsByUkprns(string[] ukprns, CancellationToken cancellationToken) { diff --git a/Dfe.Academies.Application.Tests/Queries/Establishment/EstablishmentQueriesTests.cs b/Dfe.Academies.Application.Tests/Queries/Establishment/EstablishmentQueriesTests.cs index b2aa15f92..df6a9421a 100644 --- a/Dfe.Academies.Application.Tests/Queries/Establishment/EstablishmentQueriesTests.cs +++ b/Dfe.Academies.Application.Tests/Queries/Establishment/EstablishmentQueriesTests.cs @@ -27,11 +27,13 @@ public async Task GetByUkprn_WhenEstablishmentReturnedFromRepo_EstablishmentDtoI // Arrange var establishment = _fixture.Create(); var mockRepo = new Mock(); + var mockTrustRepo = new Mock(); + string ukprn = "1010101"; mockRepo.Setup(x => x.GetEstablishmentByUkprn(It.Is(v => v == ukprn), It.IsAny())).Returns(Task.FromResult(establishment)); var establishmentQueries = new EstablishmentQueries( - mockRepo.Object); + mockRepo.Object, mockTrustRepo.Object); CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); @@ -51,11 +53,12 @@ public async Task GetByUrn_WhenEstablishmentReturnedFromRepo_EstablishmentDtoIsR // Arrange var establishment = _fixture.Create(); var mockRepo = new Mock(); + var mockTrustRepo = new Mock(); string urn = "1010101"; mockRepo.Setup(x => x.GetEstablishmentByUrn(It.Is(v => v == urn), It.IsAny())).Returns(Task.FromResult(establishment)); var establishmentQueries = new EstablishmentQueries( - mockRepo.Object); + mockRepo.Object, mockTrustRepo.Object); CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); @@ -75,13 +78,14 @@ public async Task Search_WhenEstablishmentsReturnedFromRepo_EstablishmentDtoList // Arrange var establishments = _fixture.Create>(); var mockRepo = new Mock(); + var mockTrustRepo = new Mock(); string urn = "1010101"; string name = "Test name"; string ukPrn = "Test UkPrn"; mockRepo.Setup(x => x.Search(It.Is(v => v == name), It.Is(v => v == ukPrn), It.Is(v => v == urn), It.IsAny())).Returns(Task.FromResult(establishments)); var establishmentQueries = new EstablishmentQueries( - mockRepo.Object); + mockRepo.Object, mockTrustRepo.Object); CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); @@ -107,10 +111,11 @@ public async Task GetURNsByRegion_WhenEstablishmentUrnsReturnedFromRepo_IEnumebr string[] regions = _fixture.Create(); var establishmentUrns = _fixture.Create>().AsEnumerable(); var mockRepo = new Mock(); + var mockTrustRepo = new Mock(); mockRepo.Setup(x => x.GetURNsByRegion(It.Is(v => v == regions), It.IsAny())).Returns(Task.FromResult(establishmentUrns)); var establishmentQueries = new EstablishmentQueries( - mockRepo.Object); + mockRepo.Object, mockTrustRepo.Object); CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); // Act @@ -131,10 +136,11 @@ public async Task GetByUrns_WhenEstablishmentsReturnedFromRepo_ListOfEstablishme int[] Urns = _fixture.Create(); var establishments = _fixture.Create>(); var mockRepo = new Mock(); + var mockTrustRepo = new Mock(); mockRepo.Setup(x => x.GetByUrns(It.Is(v => v == Urns), It.IsAny())).Returns(Task.FromResult(establishments)); var establishmentQueries = new EstablishmentQueries( - mockRepo.Object); + mockRepo.Object, mockTrustRepo.Object); CancellationToken cancellationToken = default(global::System.Threading.CancellationToken); // Act var result = await establishmentQueries.GetByUrns( diff --git a/Dfe.Academies.Application/Queries/Establishment/EstablishmentQueries.cs b/Dfe.Academies.Application/Queries/Establishment/EstablishmentQueries.cs index 108d873ce..a2509a9ba 100644 --- a/Dfe.Academies.Application/Queries/Establishment/EstablishmentQueries.cs +++ b/Dfe.Academies.Application/Queries/Establishment/EstablishmentQueries.cs @@ -4,16 +4,19 @@ using System.Threading; using System; using Dfe.Academies.Application.Builders; +using Dfe.Academies.Domain.Trust; namespace Dfe.Academies.Application.Queries.Establishment { public class EstablishmentQueries : IEstablishmentQueries { private readonly IEstablishmentRepository _establishmentRepository; + private readonly ITrustRepository _trustRepository; - public EstablishmentQueries(IEstablishmentRepository establishmentRepository) + public EstablishmentQueries(IEstablishmentRepository establishmentRepository, ITrustRepository trustRepository) { _establishmentRepository = establishmentRepository; + _trustRepository = trustRepository; } public async Task GetByUkprn(string ukprn, CancellationToken cancellationToken) { @@ -37,6 +40,12 @@ public async Task> GetURNsByRegion(string[] regions, Cancellati return URNs; } + public async Task> GetByTrust(string trustUkprn, CancellationToken cancellationToken) + { + var trust = await _trustRepository.GetTrustByUkprn(trustUkprn, cancellationToken); + var establishments = await _establishmentRepository.GetByTrust(trust.SK, cancellationToken).ConfigureAwait(false); + return establishments.Select(MapToEstablishmentDto).ToList(); + } public async Task> GetByUrns(int[] Urns, CancellationToken cancellationToken) { var establishments = await _establishmentRepository.GetByUrns(Urns, cancellationToken).ConfigureAwait(false); diff --git a/Dfe.Academies.Application/Queries/Establishment/IEstablishmentQueries.cs b/Dfe.Academies.Application/Queries/Establishment/IEstablishmentQueries.cs index 229ad2a27..569946379 100644 --- a/Dfe.Academies.Application/Queries/Establishment/IEstablishmentQueries.cs +++ b/Dfe.Academies.Application/Queries/Establishment/IEstablishmentQueries.cs @@ -14,6 +14,7 @@ public interface IEstablishmentQueries Task GetByUrn(string urn, CancellationToken cancellationToken); Task<(List, int)> Search(string name, string ukPrn, string urn, CancellationToken cancellationToken); Task> GetURNsByRegion(string[] regions, CancellationToken cancellationToken); - Task> GetByUrns(int[] Urns, CancellationToken cancellationToken); + Task> GetByUrns(int[] Urns, CancellationToken cancellationToken); + Task> GetByTrust(string trustUkprn, CancellationToken cancellationToken); } } diff --git a/Dfe.Academies.Application/Queries/Trust/ITrustQueries.cs b/Dfe.Academies.Application/Queries/Trust/ITrustQueries.cs index 3b03a8875..7f0836cf4 100644 --- a/Dfe.Academies.Application/Queries/Trust/ITrustQueries.cs +++ b/Dfe.Academies.Application/Queries/Trust/ITrustQueries.cs @@ -5,6 +5,7 @@ namespace Dfe.Academies.Application.Queries.Trust public interface ITrustQueries { Task GetByUkprn(string ukprn, CancellationToken cancellationToken); + Task GetByCompaniesHouseNumber(string companiesHouseNumber, CancellationToken cancellationToken); Task> GetByUkprns(string[] ukprns, CancellationToken cancellationToken); Task<(List, int)> Search(int page, int count, string name, string ukPrn, string companiesHouseNumber, CancellationToken cancellationToken); } diff --git a/Dfe.Academies.Application/Queries/Trust/TrustQueries.cs b/Dfe.Academies.Application/Queries/Trust/TrustQueries.cs index 251b26e49..139a3bb1a 100644 --- a/Dfe.Academies.Application/Queries/Trust/TrustQueries.cs +++ b/Dfe.Academies.Application/Queries/Trust/TrustQueries.cs @@ -16,6 +16,11 @@ public TrustQueries(ITrustRepository trustRepository) var trust = await _trustRepository.GetTrustByUkprn(ukprn, cancellationToken).ConfigureAwait(false); return trust == null ? null : MapToTrustDto(trust); } + public async Task GetByCompaniesHouseNumber(string companiesHouseNumber, CancellationToken cancellationToken) + { + var trust = await _trustRepository.GetTrustByCompaniesHouseNumber(companiesHouseNumber, cancellationToken).ConfigureAwait(false); + return trust == null ? null : MapToTrustDto(trust); + } public async Task<(List, int)> Search(int page, int count, string name, string ukPrn, string companiesHouseNumber, CancellationToken cancellationToken) { diff --git a/Dfe.Academies.Domain/Establishment/EducationEstablishmentTrust.cs b/Dfe.Academies.Domain/Establishment/EducationEstablishmentTrust.cs new file mode 100644 index 000000000..4df672b92 --- /dev/null +++ b/Dfe.Academies.Domain/Establishment/EducationEstablishmentTrust.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Dfe.Academies.Domain.Establishment +{ + public class EducationEstablishmentTrust + { + public int SK { get; set; } + + // Foreign keys + public int FK_Trust { get; set; } + public int FK_EducationEstablishment { get; set; } + + // Navigation properties + public virtual Trust.Trust Trust { get; set; } + public virtual Establishment Establishment { get; set; } + } + +} diff --git a/Dfe.Academies.Domain/Establishment/IEstablishmentRepository.cs b/Dfe.Academies.Domain/Establishment/IEstablishmentRepository.cs index 2046e1ddb..8c48ed4e6 100644 --- a/Dfe.Academies.Domain/Establishment/IEstablishmentRepository.cs +++ b/Dfe.Academies.Domain/Establishment/IEstablishmentRepository.cs @@ -8,7 +8,8 @@ public interface IEstablishmentRepository : IGenericRepository Task GetEstablishmentByUrn(string urn, CancellationToken cancellationToken); Task> Search(string name, string ukPrn, string urn, CancellationToken cancellationToken); - Task> GetURNsByRegion(string[] regions, CancellationToken cancellationToken); + Task> GetURNsByRegion(string[] regions, CancellationToken cancellationToken); + Task> GetByTrust(long? trustId, CancellationToken cancellationToken); Task> GetByUrns(int[] Urns, CancellationToken cancellationToken); } } diff --git a/Dfe.Academies.Domain/Trust/ITrustRepository.cs b/Dfe.Academies.Domain/Trust/ITrustRepository.cs index 6908e5c9f..ad2dcc9a5 100644 --- a/Dfe.Academies.Domain/Trust/ITrustRepository.cs +++ b/Dfe.Academies.Domain/Trust/ITrustRepository.cs @@ -5,6 +5,7 @@ namespace Dfe.Academies.Domain.Trust public interface ITrustRepository : IGenericRepository { Task GetTrustByUkprn(string ukprn, CancellationToken cancellationToken); + Task GetTrustByCompaniesHouseNumber(string companiesHouseNumber, CancellationToken cancellationToken); Task> GetTrustsByUkprns(string[] ukprns, CancellationToken cancellationToken); Task> Search(int page, int count, string name, string ukPrn, string companiesHouseNumber, CancellationToken cancellationToken); diff --git a/TramsDataApi/Controllers/V4/EstablishmentsController.cs b/TramsDataApi/Controllers/V4/EstablishmentsController.cs index 9533393c3..abd404dc2 100644 --- a/TramsDataApi/Controllers/V4/EstablishmentsController.cs +++ b/TramsDataApi/Controllers/V4/EstablishmentsController.cs @@ -168,5 +168,33 @@ public async Task>> GetByUrns([FromQuery] in var response = new List(establishments); return Ok(response); } + /// + /// Retrieves a list of establishments by their Trust UK Provider Reference Number (UKPRN) identifier. + /// + /// Contains the Trust UK Provider Reference Number (UKPRN) identifier of the establishments. + /// /// + /// List of establishments or NotFound if none are available. + [HttpGet] + [Route("establishments/trust")] + [SwaggerOperation(Summary = "Get Establishments by Trust", Description = "Returns a list of establishments specified by Trust UKPRN.")] + [SwaggerResponse(200, "Successfully found and returned the establishments.")] + [SwaggerResponse(404, "Establishments with specified Trust UKPRN not found.")] + public async Task>> GetByTrust([FromQuery] string trustUkprn, CancellationToken cancellationToken) + { + var commaSeparatedRequestTrust = string.Join(",", trustUkprn); + _logger.LogInformation($"Attemping to get establishments by Trust UKPRN : {commaSeparatedRequestTrust}"); + + var establishments = await _establishmentQueries.GetByTrust(trustUkprn, cancellationToken).ConfigureAwait(false); + + if (establishments == null) + { + _logger.LogInformation($"No establishment was found with the requested Trust UKPRN : {commaSeparatedRequestTrust}"); + return NotFound(); + } + + _logger.LogInformation($"Returning Establishments for Trust with specific UKPRN : {commaSeparatedRequestTrust}"); + var response = new List(establishments); + return Ok(response); + } } } \ No newline at end of file diff --git a/TramsDataApi/Controllers/V4/TrustsController.cs b/TramsDataApi/Controllers/V4/TrustsController.cs index 6a8b46247..3537eaae5 100644 --- a/TramsDataApi/Controllers/V4/TrustsController.cs +++ b/TramsDataApi/Controllers/V4/TrustsController.cs @@ -55,6 +55,32 @@ public async Task> GetTrustByUkprn(string ukprn, Cancella _logger.LogDebug(JsonSerializer.Serialize(trust)); return Ok(trust); } + /// + /// Retrieves a Trust by its Companies House Number. + /// + /// The Companies House Number identifier. + /// + /// A Trust or NotFound if not available. + [HttpGet] + [Route("trust/{companiesHouseNumber}")] + [SwaggerOperation(Summary = "Retrieve Trust by Companies House Number", Description = "Returns a Trust identified by Companies House Number.")] + [SwaggerResponse(200, "Successfully found and returned the Trust.")] + [SwaggerResponse(404, "Trust with specified Companies House Number not found.")] + public async Task> GetTrustByCompaniesHouseNumber(string companiesHouseNumber, CancellationToken cancellationToken) + { + _logger.LogInformation($"Attempting to get trust by Companies House Number {companiesHouseNumber}"); + var trust = await _trustQueries.GetByCompaniesHouseNumber(companiesHouseNumber, cancellationToken).ConfigureAwait(false); + + if (trust == null) + { + _logger.LogInformation($"No trust found for Companies House Number {companiesHouseNumber}"); + return NotFound(); + } + + _logger.LogInformation($"Returning trust found by Companies House Number {companiesHouseNumber}"); + _logger.LogDebug(JsonSerializer.Serialize(trust)); + return Ok(trust); + } /// /// Searches for Trusts based on query parameters.