diff --git a/Services/CO.CDP.DataSharing.WebApi.Tests/DataSharingFactory.cs b/Services/CO.CDP.DataSharing.WebApi.Tests/DataSharingFactory.cs index c7b942b54..44ca39c27 100644 --- a/Services/CO.CDP.DataSharing.WebApi.Tests/DataSharingFactory.cs +++ b/Services/CO.CDP.DataSharing.WebApi.Tests/DataSharingFactory.cs @@ -178,7 +178,7 @@ public static List CreateMockConnectedPersonInformat "British", DateTimeOffset.Now.AddYears(-30), ConnectedPersonType.Individual, - ConnectedPersonCategory.PersonWithSignificantControl, + ConnectedEntityIndividualAndTrustCategoryType.PersonWithSignificantControlForIndividual, "UK", new List { diff --git a/Services/CO.CDP.DataSharing.WebApi.Tests/EntityFactory.cs b/Services/CO.CDP.DataSharing.WebApi.Tests/EntityFactory.cs index 4b1af7f13..85ad98351 100644 --- a/Services/CO.CDP.DataSharing.WebApi.Tests/EntityFactory.cs +++ b/Services/CO.CDP.DataSharing.WebApi.Tests/EntityFactory.cs @@ -1,10 +1,10 @@ using CO.CDP.DataSharing.WebApi.Model; using CO.CDP.OrganisationInformation; using CO.CDP.OrganisationInformation.Persistence; +using static CO.CDP.OrganisationInformation.Persistence.ConnectedEntity; using static CO.CDP.OrganisationInformation.Persistence.Organisation; using ConnectedEntityType = CO.CDP.OrganisationInformation.Persistence.ConnectedEntity.ConnectedEntityType; using ConnectedOrganisationCategory = CO.CDP.OrganisationInformation.Persistence.ConnectedEntity.ConnectedOrganisationCategory; -using ConnectedPersonCategory = CO.CDP.OrganisationInformation.Persistence.ConnectedEntity.ConnectedPersonCategory; using PersistenceForms = CO.CDP.OrganisationInformation.Persistence.Forms; namespace CO.CDP.DataSharing.WebApi.Tests; @@ -83,7 +83,7 @@ internal static PersistenceForms.SharedConsent GetSharedConsent(int organisation return sharedConsent; } - internal static List GetMockAssociatedPersons() + internal static List GetMockIndividuals() { var mockPersons = new List { @@ -96,7 +96,7 @@ internal static List GetMockAssociatedPersons() Id = 1, FirstName = "John", LastName = "Doe", - Category = ConnectedPersonCategory.PersonWithSignificantControl, + Category = ConnectedEntityIndividualAndTrustCategoryType.PersonWithSignificantControlForIndividual, CreatedOn = DateTimeOffset.UtcNow, UpdatedOn = DateTimeOffset.UtcNow }, @@ -134,6 +134,32 @@ internal static List GetMockAdditionalEntities() return mockEntities; } + internal static List GetMockTrustsOrTrustees() + { + var mockPersons = new List + { + new ConnectedEntity + { + Guid = Guid.NewGuid(), + EntityType = ConnectedEntityType.TrustOrTrustee, + IndividualOrTrust = new ConnectedEntity.ConnectedIndividualTrust + { + Id = 2, + FirstName = "John", + LastName = "Smith", + Category = ConnectedEntityIndividualAndTrustCategoryType.PersonWithSignificantControlForTrust, + CreatedOn = DateTimeOffset.UtcNow, + UpdatedOn = DateTimeOffset.UtcNow + }, + SupplierOrganisation = GivenOrganisation(), + CreatedOn = DateTimeOffset.UtcNow, + UpdatedOn = DateTimeOffset.UtcNow + } + }; + + return mockPersons; + } + internal static Organisation.LegalForm GetLegalForm() { var mockLegalForm = new Organisation.LegalForm diff --git a/Services/CO.CDP.DataSharing.WebApi.Tests/UseCase/GetSharedDataUseCaseTest.cs b/Services/CO.CDP.DataSharing.WebApi.Tests/UseCase/GetSharedDataUseCaseTest.cs index 218382261..79840b7d2 100644 --- a/Services/CO.CDP.DataSharing.WebApi.Tests/UseCase/GetSharedDataUseCaseTest.cs +++ b/Services/CO.CDP.DataSharing.WebApi.Tests/UseCase/GetSharedDataUseCaseTest.cs @@ -86,17 +86,21 @@ public async Task ItReturnsMappedSupplierInformationWhenSharedConsentIsFound() _shareCodeRepository.Setup(repo => repo.GetByShareCode(shareCode)).ReturnsAsync(sharedConsent); - var mockAssociatedPersons = EntityFactory.GetMockAssociatedPersons(); + var mockIndividuals = EntityFactory.GetMockIndividuals(); var mockAdditionalEntities = EntityFactory.GetMockAdditionalEntities(); + var mockTrustOrTrustees = EntityFactory.GetMockTrustsOrTrustees(); var mockLegalForm = EntityFactory.GetLegalForm(); var mockOperationTypes = EntityFactory.GetOperationTypes(); _organisationRepository.Setup(repo => repo.GetConnectedIndividualTrusts(organisationId)) - .ReturnsAsync(mockAssociatedPersons); + .ReturnsAsync(mockIndividuals); _organisationRepository.Setup(repo => repo.GetConnectedOrganisations(organisationId)) .ReturnsAsync(mockAdditionalEntities); + _organisationRepository.Setup(repo => repo.GetConnectedTrustsOrTrustees(organisationId)) + .ReturnsAsync(mockTrustOrTrustees); + _organisationRepository.Setup(repo => repo.GetLegalForm(organisationId)) .ReturnsAsync(mockLegalForm); @@ -127,8 +131,9 @@ private void AssertAddress(Address? address) private void AssertAssociatedPersons(IEnumerable? associatedPersons) { associatedPersons.Should().NotBeNull(); - associatedPersons.Should().HaveCount(1); + associatedPersons.Should().HaveCount(2); associatedPersons?.First().Name.Should().Be("John Doe"); + associatedPersons?.Should().Contain(x => x.Name == "John Smith"); } private void AssertAdditionalEntities(IEnumerable? additionalEntities) diff --git a/Services/CO.CDP.DataSharing.WebApi/DataService/DataService.cs b/Services/CO.CDP.DataSharing.WebApi/DataService/DataService.cs index 5cb126eed..c93dff951 100644 --- a/Services/CO.CDP.DataSharing.WebApi/DataService/DataService.cs +++ b/Services/CO.CDP.DataSharing.WebApi/DataService/DataService.cs @@ -169,13 +169,23 @@ public static List MapToConnectedPersonInformation(I { if (entity != null) { + var connectedPersonType = entity.IndividualOrTrust?.ConnectedType != null ? + entity.IndividualOrTrust.ConnectedType : + ConnectedPersonType.Individual; + + var connectedEntityIndividualAndTrustCategoryType = entity.IndividualOrTrust?.Category != null ? + entity.IndividualOrTrust.Category : + (connectedPersonType == ConnectedPersonType.Individual ? + ConnectedEntityIndividualAndTrustCategoryType.PersonWithSignificantControlForIndividual : + ConnectedEntityIndividualAndTrustCategoryType.PersonWithSignificantControlForTrust); + var individualTrust = entity.IndividualOrTrust != null ? new ConnectedIndividualTrust( entity.IndividualOrTrust.FirstName, entity.IndividualOrTrust.LastName, entity.IndividualOrTrust.DateOfBirth, entity.IndividualOrTrust.Nationality, - entity.IndividualOrTrust?.Category != null ? entity.IndividualOrTrust.Category : ConnectedPersonCategory.PersonWithSignificantControl, - entity.IndividualOrTrust?.ConnectedType != null ? entity.IndividualOrTrust.ConnectedType : ConnectedPersonType.Individual, + connectedEntityIndividualAndTrustCategoryType, + connectedPersonType, entity.IndividualOrTrust?.ControlCondition.Select(c => c.ToString()).ToList() ?? new List(), entity.IndividualOrTrust?.ResidentCountry ) : null; @@ -206,8 +216,8 @@ public static List MapToConnectedPersonInformation(I entity.IndividualOrTrust?.LastName ?? string.Empty, entity.IndividualOrTrust?.Nationality, entity.IndividualOrTrust?.DateOfBirth, - entity.IndividualOrTrust?.ConnectedType != null ? entity.IndividualOrTrust.ConnectedType : ConnectedPersonType.Individual, - entity.IndividualOrTrust?.Category != null ? entity.IndividualOrTrust.Category : ConnectedPersonCategory.PersonWithSignificantControl, + connectedPersonType, + connectedEntityIndividualAndTrustCategoryType, entity.IndividualOrTrust?.ResidentCountry, addresses, entity.IndividualOrTrust?.ControlCondition.Select(c => c.ToString()).ToList() ?? new List(), diff --git a/Services/CO.CDP.DataSharing.WebApi/Model/ConnectedPersonInformation.cs b/Services/CO.CDP.DataSharing.WebApi/Model/ConnectedPersonInformation.cs index 34f5680c6..1d555d9db 100644 --- a/Services/CO.CDP.DataSharing.WebApi/Model/ConnectedPersonInformation.cs +++ b/Services/CO.CDP.DataSharing.WebApi/Model/ConnectedPersonInformation.cs @@ -11,7 +11,7 @@ public record ConnectedPersonInformation string? Nationality, DateTimeOffset? DateOfBirth, ConnectedPersonType PersonType, - ConnectedPersonCategory Category, + ConnectedEntityIndividualAndTrustCategoryType Category, string? ResidentCountry, List Addresses, List ControlConditions, @@ -26,7 +26,7 @@ public record ConnectedIndividualTrust string LastName, DateTimeOffset? DateOfBirth, string? Nationality, - ConnectedPersonCategory Category, + ConnectedEntityIndividualAndTrustCategoryType Category, ConnectedPersonType PersonType, List ControlConditions, string? ResidentCountry diff --git a/Services/CO.CDP.DataSharing.WebApi/UseCase/GetSharedDataUseCase.cs b/Services/CO.CDP.DataSharing.WebApi/UseCase/GetSharedDataUseCase.cs index 701c576c6..203dbdf67 100644 --- a/Services/CO.CDP.DataSharing.WebApi/UseCase/GetSharedDataUseCase.cs +++ b/Services/CO.CDP.DataSharing.WebApi/UseCase/GetSharedDataUseCase.cs @@ -56,20 +56,23 @@ private async Task
GetDetails(SharedConsent sharedConsent) private async Task> AssociatedPersons(SharedConsent sharedConsent) { - var associatedPersons = await organisationRepository.GetConnectedIndividualTrusts(sharedConsent.OrganisationId); - return associatedPersons.Select(x => new AssociatedPerson + var individuals = await organisationRepository.GetConnectedIndividualTrusts(sharedConsent.OrganisationId); + var trustsOrTrustees = await organisationRepository.GetConnectedTrustsOrTrustees(sharedConsent.OrganisationId); + + return individuals.Union(trustsOrTrustees).Select(x => new AssociatedPerson { Id = x.Guid, Name = string.Format($"{x.IndividualOrTrust?.FirstName} {x.IndividualOrTrust?.LastName}"), Relationship = x.IndividualOrTrust?.Category.ToString() ?? string.Empty, Uri = null, - Roles = [] + Roles = x.SupplierOrganisation.Roles }).ToList(); } private async Task> AdditionalEntities(SharedConsent sharedConsent) { var additionalEntities = await organisationRepository.GetConnectedOrganisations(sharedConsent.OrganisationId); + return additionalEntities.Select(x => new OrganisationReference { Id = x.Guid, diff --git a/Services/CO.CDP.OrganisationInformation.Persistence.Tests/DatabaseConnectedEntityRepositoryTests.cs b/Services/CO.CDP.OrganisationInformation.Persistence.Tests/DatabaseConnectedEntityRepositoryTests.cs index 33a517e71..d0b51ff28 100644 --- a/Services/CO.CDP.OrganisationInformation.Persistence.Tests/DatabaseConnectedEntityRepositoryTests.cs +++ b/Services/CO.CDP.OrganisationInformation.Persistence.Tests/DatabaseConnectedEntityRepositoryTests.cs @@ -83,7 +83,7 @@ public async Task GetSummary_ShouldReturnConnectedEntityLookups_WhenEntitiesExis { FirstName = "First Name", LastName = "Last Name", - Category = ConnectedEntity.ConnectedPersonCategory.DirectorOrIndividualWithTheSameResponsibilities, + Category = ConnectedEntity.ConnectedEntityIndividualAndTrustCategoryType.DirectorOrIndividualWithTheSameResponsibilitiesForIndividual, ConnectedType = ConnectedEntity.ConnectedPersonType.Individual }, SupplierOrganisation = organisation diff --git a/Services/CO.CDP.OrganisationInformation.Persistence.Tests/DatabaseOrganisationRepositoryTest.cs b/Services/CO.CDP.OrganisationInformation.Persistence.Tests/DatabaseOrganisationRepositoryTest.cs index d3fd5d304..851bc115a 100644 --- a/Services/CO.CDP.OrganisationInformation.Persistence.Tests/DatabaseOrganisationRepositoryTest.cs +++ b/Services/CO.CDP.OrganisationInformation.Persistence.Tests/DatabaseOrganisationRepositoryTest.cs @@ -375,6 +375,50 @@ public async Task GetConnectedOrganisations_WhenNoConnectedEntitiesExist_Returns result.Should().BeEmpty(); } + [Fact] + public async Task GetConnectedTrustsOrTrustees_WhenConnectedEntitiesExist_ReturnsConnectedEntities() + { + using var repository = OrganisationRepository(); + + var supplierOrganisation = GivenOrganisation(); + var connectedEntity = GivenConnectedTrustsOrTrustees(supplierOrganisation); + + using var context = postgreSql.OrganisationInformationContext(); + await context.Organisations.AddAsync(supplierOrganisation); + await context.ConnectedEntities.AddAsync(connectedEntity); + await context.SaveChangesAsync(); + + var result = await repository.GetConnectedTrustsOrTrustees(supplierOrganisation.Id); + + result.Should().NotBeEmpty(); + result.Should().HaveCount(1); + result.Should().Contain(x => x.EntityType == ConnectedEntity.ConnectedEntityType.TrustOrTrustee); + + var organisation = result.First().Organisation; + organisation.Should().BeEquivalentTo(connectedEntity.Organisation, options => + options + .Using(ctx => ctx.Subject.Should().BeCloseTo(ctx.Expectation, TimeSpan.FromMilliseconds(100))) + .WhenTypeIs() + ); + } + + [Fact] + public async Task GetConnectedTrustsOrTrustees_WhenNoConnectedEntitiesExist_ReturnsEmptyList() + { + using var repository = OrganisationRepository(); + + var organisationId = 1; + var organisation = GivenOrganisation(); + + using var context = postgreSql.OrganisationInformationContext(); + await context.Organisations.AddAsync(organisation); + await context.SaveChangesAsync(); + + var result = await repository.GetConnectedTrustsOrTrustees(organisationId); + + result.Should().BeEmpty(); + } + [Fact] public async Task GetLegalForm_WhenNoLegalFormExists_ReturnNull() { diff --git a/Services/CO.CDP.OrganisationInformation.Persistence.Tests/EntityFactory.cs b/Services/CO.CDP.OrganisationInformation.Persistence.Tests/EntityFactory.cs index c7c19ca0a..4eb8966f5 100644 --- a/Services/CO.CDP.OrganisationInformation.Persistence.Tests/EntityFactory.cs +++ b/Services/CO.CDP.OrganisationInformation.Persistence.Tests/EntityFactory.cs @@ -240,10 +240,10 @@ public static ConnectedEntity GivenConnectedOrganisation( Guid? organisationId = null ) { - var connectedOrganisation = new ConnectedEntity.ConnectedOrganisation + var connectedOrganisation = new ConnectedOrganisation { Id = 1, - Category = (ConnectedEntity.ConnectedOrganisationCategory)category, + Category = category, Name = name, OrganisationId = organisationId, CreatedOn = DateTimeOffset.UtcNow, @@ -265,15 +265,16 @@ public static ConnectedEntity GivenConnectedIndividualTrust( Organisation supplierOrganisation, string firstName = "John", string lastName = "Doe", - ConnectedPersonCategory category = ConnectedPersonCategory.PersonWithSignificantControl + ConnectedEntityIndividualAndTrustCategoryType category = ConnectedEntityIndividualAndTrustCategoryType.PersonWithSignificantControlForIndividual ) { - var individualTrust = new ConnectedEntity.ConnectedIndividualTrust + var individualTrust = new ConnectedIndividualTrust { Id = 1, FirstName = firstName, LastName = lastName, - Category = (ConnectedEntity.ConnectedPersonCategory)category, + Category = category, + ConnectedType = ConnectedPersonType.Individual, CreatedOn = DateTimeOffset.UtcNow, UpdatedOn = DateTimeOffset.UtcNow }; @@ -289,5 +290,32 @@ public static ConnectedEntity GivenConnectedIndividualTrust( }; } + public static ConnectedEntity GivenConnectedTrustsOrTrustees( + Organisation supplierOrganisation, + string firstName = "John", + string lastName = "Doe", + ConnectedEntityIndividualAndTrustCategoryType category = ConnectedEntityIndividualAndTrustCategoryType.PersonWithSignificantControlForTrust + ) + { + var trustOrTrustee = new ConnectedIndividualTrust + { + Id = 1, + FirstName = firstName, + LastName = lastName, + Category = category, + ConnectedType = ConnectedPersonType.TrustOrTrustee, + CreatedOn = DateTimeOffset.UtcNow, + UpdatedOn = DateTimeOffset.UtcNow + }; + return new ConnectedEntity + { + Guid = Guid.NewGuid(), + EntityType = (ConnectedEntity.ConnectedEntityType)ConnectedEntityType.TrustOrTrustee, + IndividualOrTrust = trustOrTrustee, + SupplierOrganisation = supplierOrganisation, + CreatedOn = DateTimeOffset.UtcNow, + UpdatedOn = DateTimeOffset.UtcNow + }; + } } \ No newline at end of file diff --git a/Services/CO.CDP.OrganisationInformation.Persistence/ConnectedEntity.cs b/Services/CO.CDP.OrganisationInformation.Persistence/ConnectedEntity.cs index 30665d354..a0f093052 100644 --- a/Services/CO.CDP.OrganisationInformation.Persistence/ConnectedEntity.cs +++ b/Services/CO.CDP.OrganisationInformation.Persistence/ConnectedEntity.cs @@ -41,7 +41,7 @@ public record ConnectedEntityAddress public record ConnectedIndividualTrust : IEntityDate { public int Id { get; set; } - public required ConnectedPersonCategory Category { get; set; } + public required ConnectedEntityIndividualAndTrustCategoryType Category { get; set; } public required string FirstName { get; set; } public required string LastName { get; set; } public DateTimeOffset? DateOfBirth { get; set; } @@ -91,11 +91,14 @@ public enum ConnectedPersonType TrustOrTrustee } - public enum ConnectedPersonCategory + public enum ConnectedEntityIndividualAndTrustCategoryType { - PersonWithSignificantControl = 1, - DirectorOrIndividualWithTheSameResponsibilities, - AnyOtherIndividualWithSignificantInfluenceOrControl + PersonWithSignificantControlForIndividual = 1, + DirectorOrIndividualWithTheSameResponsibilitiesForIndividual, + AnyOtherIndividualWithSignificantInfluenceOrControlForIndividual, + PersonWithSignificantControlForTrust, + DirectorOrIndividualWithTheSameResponsibilitiesForTrust, + AnyOtherIndividualWithSignificantInfluenceOrControlForTrust } public enum ConnectedOrganisationCategory diff --git a/Services/CO.CDP.OrganisationInformation.Persistence/DatabaseOrganisationRepository.cs b/Services/CO.CDP.OrganisationInformation.Persistence/DatabaseOrganisationRepository.cs index 16935477b..e7d970802 100644 --- a/Services/CO.CDP.OrganisationInformation.Persistence/DatabaseOrganisationRepository.cs +++ b/Services/CO.CDP.OrganisationInformation.Persistence/DatabaseOrganisationRepository.cs @@ -106,6 +106,16 @@ public async Task> GetConnectedOrganisations(int organisa return await result.ToListAsync(); } + public async Task> GetConnectedTrustsOrTrustees(int organisationId) + { + var result = context.ConnectedEntities + .Include(x => x.IndividualOrTrust) + .Where(x => x.IndividualOrTrust != null && x.EntityType == ConnectedEntity.ConnectedEntityType.TrustOrTrustee) + .Where(x => x.SupplierOrganisation != null && x.SupplierOrganisation.Id == organisationId); + + return await result.ToListAsync(); + } + public async Task GetLegalForm(int organisationId) { var organisation = await context.Organisations diff --git a/Services/CO.CDP.OrganisationInformation.Persistence/IOrganisationRepository.cs b/Services/CO.CDP.OrganisationInformation.Persistence/IOrganisationRepository.cs index 677133eda..f60782a35 100644 --- a/Services/CO.CDP.OrganisationInformation.Persistence/IOrganisationRepository.cs +++ b/Services/CO.CDP.OrganisationInformation.Persistence/IOrganisationRepository.cs @@ -30,6 +30,8 @@ public class DuplicateOrganisationException(string message, Exception? cause = n public Task> GetConnectedOrganisations(int organisationId); + public Task> GetConnectedTrustsOrTrustees(int organisationId); + public Task GetLegalForm(int organisationId); public Task> GetOperationTypes(int organisationId); diff --git a/Services/CO.CDP.OrganisationInformation.Persistence/OrganisationInformationContext.cs b/Services/CO.CDP.OrganisationInformation.Persistence/OrganisationInformationContext.cs index 641fd8dc5..db92b448b 100644 --- a/Services/CO.CDP.OrganisationInformation.Persistence/OrganisationInformationContext.cs +++ b/Services/CO.CDP.OrganisationInformation.Persistence/OrganisationInformationContext.cs @@ -32,7 +32,7 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) modelBuilder.HasPostgresEnum(); modelBuilder.HasPostgresEnum(); modelBuilder.HasPostgresEnum(); - modelBuilder.HasPostgresEnum(); + modelBuilder.HasPostgresEnum(); modelBuilder.HasPostgresEnum(); modelBuilder.Entity(entity =>