From 5cd9cdf816fba8e81f0ee9765e4478c68f901cee Mon Sep 17 00:00:00 2001 From: Gavin Lilley Date: Fri, 23 Aug 2024 10:45:17 +0100 Subject: [PATCH 1/4] DP-516 BE- Share my information - Data sharing endpoint (API) - Form answers --- .../DataSharingClientIntegrationTest.cs | 5 +- .../EntityFactory.cs | 2 +- .../UseCase/GenerateShareCodeUseCaseTest.cs | 7 +- .../UseCase/GetShareCodesUseCaseTest.cs | 6 +- .../Api/DataSharing.cs | 164 +- .../AutoMapper/DataSharingProfile.cs | 3 +- .../Model/AssociatedPerson.cs | 2 +- .../Model/Details.cs | 2 +- .../CO.CDP.DataSharing.WebApi/Model/Form.cs | 4 +- .../Model/FormAnswer.cs | 2 +- .../Model/FormQuestion.cs | 2 +- .../Model/FormQuestionOption.cs | 2 +- .../Model/FormQuestionType.cs | 2 +- .../Model/SharedConsent.cs | 2 +- .../Model/SupplierInformation.cs | 2 +- .../Model/SupplierInformationData.cs | 2 +- Services/CO.CDP.DataSharing.WebApi/Program.cs | 3 +- .../UseCase/GenerateShareCodeUseCase.cs | 3 +- .../UseCase/GetShareCodesUseCase.cs | 4 +- .../UseCase/GetSharedDataUseCase.cs | 22 + .../UpdateFormSectionAnswersUseCaseTest.cs | 8 - .../DatabaseFormRepositoryTest.cs | 65 - .../ShareCodeRepositoryTest.cs | 299 +++ .../DatabaseFormRepository.cs | 7 - .../DatabaseShareCodeRepository.cs | 50 + .../Forms/FormAnswer.cs | 1 + .../IFormRepository.cs | 2 - .../IShareCodeRepository.cs | 9 + ..._AddSharerCodetoSharedConsents.Designer.cs | 1699 +++++++++++++++++ ...822151919_AddSharerCodetoSharedConsents.cs | 28 + ...nisationInformationContextModelSnapshot.cs | 4 + 31 files changed, 2150 insertions(+), 263 deletions(-) create mode 100644 Services/CO.CDP.DataSharing.WebApi/UseCase/GetSharedDataUseCase.cs create mode 100644 Services/CO.CDP.OrganisationInformation.Persistence.Tests/ShareCodeRepositoryTest.cs create mode 100644 Services/CO.CDP.OrganisationInformation.Persistence/DatabaseShareCodeRepository.cs create mode 100644 Services/CO.CDP.OrganisationInformation.Persistence/IShareCodeRepository.cs create mode 100644 Services/CO.CDP.OrganisationInformation.Persistence/Migrations/20240822151919_AddSharerCodetoSharedConsents.Designer.cs create mode 100644 Services/CO.CDP.OrganisationInformation.Persistence/Migrations/20240822151919_AddSharerCodetoSharedConsents.cs diff --git a/Libraries/CO.CDP.DataSharing.WebApiClient.Tests/DataSharingClientIntegrationTest.cs b/Libraries/CO.CDP.DataSharing.WebApiClient.Tests/DataSharingClientIntegrationTest.cs index f4427fe6f..1c9b4108c 100644 --- a/Libraries/CO.CDP.DataSharing.WebApiClient.Tests/DataSharingClientIntegrationTest.cs +++ b/Libraries/CO.CDP.DataSharing.WebApiClient.Tests/DataSharingClientIntegrationTest.cs @@ -20,8 +20,9 @@ public async Task ItTalksToTheDataSharingApi() Func act = async () => { await client.GetSharedDataAsync("HDJ2123F"); }; - var exception = await act.Should().NotThrowAsync>(); + var exception = await act.Should().ThrowAsync>(); - exception.Should().NotBe(404); + exception.And.StatusCode.Should().Be(404); + exception.And.Result!.Title.Should().Contain("SharedConsentNotFoundException"); } } \ No newline at end of file diff --git a/Services/CO.CDP.DataSharing.WebApi.Tests/EntityFactory.cs b/Services/CO.CDP.DataSharing.WebApi.Tests/EntityFactory.cs index 37f1d34a1..b273545a8 100644 --- a/Services/CO.CDP.DataSharing.WebApi.Tests/EntityFactory.cs +++ b/Services/CO.CDP.DataSharing.WebApi.Tests/EntityFactory.cs @@ -17,7 +17,7 @@ internal static ShareRequest GetShareRequest(Guid organisationGuid, Guid formId) internal static OrganisationInformation.Persistence.Forms.SharedConsent GetSharedConsent(int organisationId, Guid organisationGuid, Guid formId) { - var form = new Form + var form = new CO.CDP.OrganisationInformation.Persistence.Forms.Form { Guid = formId, Name = string.Empty, diff --git a/Services/CO.CDP.DataSharing.WebApi.Tests/UseCase/GenerateShareCodeUseCaseTest.cs b/Services/CO.CDP.DataSharing.WebApi.Tests/UseCase/GenerateShareCodeUseCaseTest.cs index 7acea0573..6bdf6f132 100644 --- a/Services/CO.CDP.DataSharing.WebApi.Tests/UseCase/GenerateShareCodeUseCaseTest.cs +++ b/Services/CO.CDP.DataSharing.WebApi.Tests/UseCase/GenerateShareCodeUseCaseTest.cs @@ -13,7 +13,8 @@ public class GenerateShareCodeUseCaseTest(AutoMapperFixture mapperFixture) : ICl private readonly Mock _claimService = new(); private readonly Mock _organisationRepository = new(); private readonly Mock _formRepository = new(); - private GenerateShareCodeUseCase UseCase => new(_claimService.Object, _organisationRepository.Object, _formRepository.Object, mapperFixture.Mapper); + private readonly Mock _shareCodeRepository = new(); + private GenerateShareCodeUseCase UseCase => new(_claimService.Object, _organisationRepository.Object, _formRepository.Object, _shareCodeRepository.Object, mapperFixture.Mapper); [Fact] public async Task ThrowsInvalidOrganisationRequestedException_WhenShareCodeRequestedForNonExistentOrganisation() @@ -61,7 +62,7 @@ public async Task ThrowsSharedConsentNotFoundException_WhenNoSharedConsentOrNone _claimService.Setup(x => x.HaveAccessToOrganisation(organisationGuid)).Returns(true); _organisationRepository.Setup(x => x.Find(organisationGuid)).ReturnsAsync(sharedConsent.Organisation); - _formRepository.Setup(r => r.GetSharedConsentDraftAsync(shareRequest.FormId, shareRequest.OrganisationId)).ReturnsAsync((OrganisationInformation.Persistence.Forms.SharedConsent?)null); + _shareCodeRepository.Setup(r => r.GetSharedConsentDraftAsync(shareRequest.FormId, shareRequest.OrganisationId)).ReturnsAsync((OrganisationInformation.Persistence.Forms.SharedConsent?)null); var shareReceipt = async () => await UseCase.Execute(shareRequest); @@ -81,7 +82,7 @@ public async Task ReturnsRelevantShareReceipt_WhenAuthorisedAndShareRequestForVa _claimService.Setup(x => x.HaveAccessToOrganisation(organisationGuid)).Returns(true); _organisationRepository.Setup(x => x.Find(organisationGuid)).ReturnsAsync(sharedConsent.Organisation); - _formRepository.Setup(r => r.GetSharedConsentDraftAsync(shareRequest.FormId, shareRequest.OrganisationId)).ReturnsAsync(sharedConsent); + _shareCodeRepository.Setup(r => r.GetSharedConsentDraftAsync(shareRequest.FormId, shareRequest.OrganisationId)).ReturnsAsync(sharedConsent); var found = await UseCase.Execute(shareRequest); diff --git a/Services/CO.CDP.DataSharing.WebApi.Tests/UseCase/GetShareCodesUseCaseTest.cs b/Services/CO.CDP.DataSharing.WebApi.Tests/UseCase/GetShareCodesUseCaseTest.cs index df939f513..de865a59b 100644 --- a/Services/CO.CDP.DataSharing.WebApi.Tests/UseCase/GetShareCodesUseCaseTest.cs +++ b/Services/CO.CDP.DataSharing.WebApi.Tests/UseCase/GetShareCodesUseCaseTest.cs @@ -10,8 +10,8 @@ namespace CO.CDP.DataSharing.WebApi.Tests.UseCase; public class GetShareCodesUseCaseTest(AutoMapperFixture mapperFixture) : IClassFixture { - private readonly Mock _formRepository = new(); - private GetShareCodesUseCase UseCase => new(_formRepository.Object, mapperFixture.Mapper); + private readonly Mock _shareCodeRepository = new(); + private GetShareCodesUseCase UseCase => new(_shareCodeRepository.Object, mapperFixture.Mapper); [Fact] public async Task ItReturnsEmptyIfNoSharedCodeIsFound() @@ -36,7 +36,7 @@ public async Task ItReturnsTheSharedCodeList() sharedConsent.SubmissionState = SubmissionState.Submitted; sharedConsent.SubmittedAt = DateTime.UtcNow; - _formRepository.Setup(r => r.GetShareCodesAsync(shareRequest.OrganisationId)).ReturnsAsync(new List { sharedConsent }); + _shareCodeRepository.Setup(r => r.GetShareCodesAsync(shareRequest.OrganisationId)).ReturnsAsync(new List { sharedConsent }); var result = await UseCase.Execute(sharedConsent.Organisation.Guid); diff --git a/Services/CO.CDP.DataSharing.WebApi/Api/DataSharing.cs b/Services/CO.CDP.DataSharing.WebApi/Api/DataSharing.cs index 2cb72c478..4b4a352e3 100644 --- a/Services/CO.CDP.DataSharing.WebApi/Api/DataSharing.cs +++ b/Services/CO.CDP.DataSharing.WebApi/Api/DataSharing.cs @@ -17,156 +17,9 @@ public static class EndpointExtensions { public static void UseDataSharingEndpoints(this WebApplication app) { - app.MapGet("/share/data/{sharecode}", (string sharecode) => new SupplierInformation - { - Id = Guid.Parse("1e39d0ce-3abd-43c5-9f23-78c92e437f2a"), - Name = "Acme Corporation", - AssociatedPersons = - [ - new AssociatedPerson - { - Id = Guid.Parse("c16f9f7b-3f10-42db-86f8-93607b034a4c"), - Name = "Alice Doe", - Relationship = "Company Director", - Uri = new Uri( - "https://cdp.cabinetoffice.gov.uk/persons/c16f9f7b-3f10-42db-86f8-93607b034a4c"), - Roles = [PartyRole.Tenderer] - } - ], - AdditionalParties = - [ - new OrganisationReference - { - Id = Guid.Parse("f4596cdd-12e5-4f25-9db1-4312474e516f"), - Name = "Acme Group Ltd", - Roles = [PartyRole.Tenderer], - Uri = new Uri( - "https://cdp.cabinetoffice.gov.uk/organisations/f4596cdd-12e5-4f25-9db1-4312474e516f") - } - ], - AdditionalEntities = - [ - new OrganisationReference - { - Id = Guid.Parse("f4596cdd-12e5-4f25-9db1-4312474e516f"), - Name = "Acme Group Ltd", - Roles = [PartyRole.Tenderer], - Uri = new Uri( - "https://cdp.cabinetoffice.gov.uk/organisations/f4596cdd-12e5-4f25-9db1-4312474e516f") - } - ], - Identifier = new Identifier - { - Scheme = "CDP-PPON", - Id = "1e39d0ce-3abd-43c5-9f23-78c92e437f2a", - LegalName = "Acme Corporation Ltd", - Uri = new Uri( - "https://cdp.cabinetoffice.gov.uk/organisations/1e39d0ce-3abd-43c5-9f23-78c92e437f2a") - }, - AdditionalIdentifiers = - [ - new Identifier - { - Id = "06368740", - Scheme = "GB-COH", - LegalName = "Acme Corporation Ltd", - Uri = new Uri("http://data.companieshouse.gov.uk/doc/company/06368740") - } - ], - Address = new Address - { - StreetAddress = "82 St. John’s Road", - Locality = "CHESTER", - Region = "Lancashire", - PostalCode = "CH43 7UR", - CountryName = "United Kingdom", - Type = AddressType.Registered, - }, - ContactPoint = new ContactPoint - { - Name = "Procurement Team", - Email = "info@example.com", - Telephone = "+441234567890" - }, - Roles = [PartyRole.Tenderer], - Details = new Details(), - SupplierInformationData = new SupplierInformationData - { - Form = new Form - { - Name = "Standard Questions", - SubmissionState = FormSubmissionState.Submitted, - SubmittedAt = DateTime.Parse("2024-03-28T18:24:00.000Z"), - OrganisationId = Guid.Parse("1e39d0ce-3abd-43c5-9f23-78c92e437f2a"), - FormId = Guid.Parse("f174b921-0c58-4644-80f1-8707d8300130"), - FormVersionId = "20240309", - IsRequired = true, - BookingReference = "AGMT-2024-XYZ", - Scope = 0, - Type = 0 - }, - Questions = - [ - new FormQuestion - { - Name = "_Steel01", - Type = FormQuestionType.Text, - Text = - "Central Government Only - UK

For contracts which relate to projects/programmes (i) with a value of \u00a310 million or more; or (ii) a value of less than \u00a310 million where it is anticipated that the project will require in excess of 500 tonnes of steel; please describe the steel specific supply chain management systems, policies, standards and procedures you have in place to ensure robust supply chain management and compliance with relevant legislation.

Please provide details of previous similar projects where you have demonstrated a high level of competency and effectiveness in managing all supply chain members involved in steel supply or production to ensure a sustainable and resilient supply of steel.", - IsRequired = false, - SectionName = "Steel" - }, - new FormQuestion - { - Name = "_Steel02", - Type = FormQuestionType.Text, - Text = - "

Please provide all the relevant details of previous breaches of health and safety legislation in the last 5 years, applicable to the country in which you operate, on comparable projects, for both: Your organisation

All your supply chain members involved in the production or supply of steel", - IsRequired = true, - SectionName = "Steel" - }, - new FormQuestion - { - Name = "_ModernSlavery01", - Type = FormQuestionType.Text, - Text = - "Central Government Only - Tackling Modern Slavery in Supply Chains
If you are a relevant commercial organisation subject to Section 54 of the Modern Slavery Act 2015, and if your latest statement is available electronically please provide:


iii. If your latest statement is not available electronically, please provide a copy.", - IsRequired = true, - SectionName = "Modern slavery" - }, - new FormQuestion - { - Name = "_CarbonNetZero01", - Type = FormQuestionType.Boolean, - Text = - "Please confirm that you have detailed your environmental management measures by completing and publishing a Carbon Reduction Plan which meets the required reporting standard.", - IsRequired = true, - SectionName = "Carbon Net Zero" - } - ], - Answers = - [ - new FormAnswer - { - QuestionName = "_Steel02", - TextValue = "Answer to question 1.", - }, - - new FormAnswer - { - QuestionName = "_CarbonNetZero01", - BoolValue = true - }, - - // Use GeneratePresignedUrl method from IFileHostManager to Get PresignedUrl for a file - //new FormAnswer - //{ - // QuestionName = "_FinancialAccountFile", - // TextValue = CO.CDP.AwsServices.IFileHostManager.GeneratePresignedUrl(fileName, urlExpiryInMinutes) - //} - ] - }, - }) + app.MapGet("/share/data/{sharecode}", async (string sharecode, + IUseCase useCase) => await useCase.Execute(sharecode) + .AndThen(supplierInformation => supplierInformation != null ? Results.Ok(supplierInformation) : Results.NotFound())) .Produces(StatusCodes.Status200OK, "application/json") .Produces(StatusCodes.Status401Unauthorized) .Produces(StatusCodes.Status404NotFound) @@ -175,15 +28,14 @@ public static void UseDataSharingEndpoints(this WebApplication app) { operation.OperationId = "GetSharedData"; operation.Description = - "[STUB] Operation to obtain Supplier information which has been shared as part of a notice. [STUB]"; - operation.Summary = "[STUB] Request Supplier Submitted Information. [STUB]"; + "Operation to obtain Supplier information which has been shared as part of a notice. "; + operation.Summary = "Request Supplier Submitted Information. "; operation.Responses["200"].Description = "Organisation Information including Form Answers."; operation.Responses["401"].Description = "Valid authentication credentials are missing in the request."; operation.Responses["404"].Description = "Share code not found or the caller is not authorised to use it."; operation.Responses["500"].Description = "Internal server error."; return operation; - }) - .RequireAuthorization(Constants.OrganisationApiKeyPolicy); + }); app.MapPost("/share/data", async (ShareRequest shareRequest, IUseCase useCase) => await useCase.Execute(shareRequest) @@ -221,8 +73,8 @@ await useCase.Execute(shareRequest) { operation.OperationId = "VerifySharedData"; operation.Description = - "[STUB] Operation to verify if shared data is the latest version available. [STUB]"; - operation.Summary = "[STUB] Create Supplier Submitted Information. [STUB]"; + "Operation to verify if shared data is the latest version available. "; + operation.Summary = "Create Supplier Submitted Information. "; operation.Responses["200"].Description = "Share code and version verification."; operation.Responses["401"].Description = "Valid authentication credentials are missing in the request."; operation.Responses["404"].Description = "Share code not found or the caller is not authorised to use it."; diff --git a/Services/CO.CDP.DataSharing.WebApi/AutoMapper/DataSharingProfile.cs b/Services/CO.CDP.DataSharing.WebApi/AutoMapper/DataSharingProfile.cs index e87c6f4c9..c013592f8 100644 --- a/Services/CO.CDP.DataSharing.WebApi/AutoMapper/DataSharingProfile.cs +++ b/Services/CO.CDP.DataSharing.WebApi/AutoMapper/DataSharingProfile.cs @@ -2,6 +2,7 @@ using CO.CDP.DataSharing.WebApi.Model; using CO.CDP.OrganisationInformation.Persistence.Forms; using Persistence = CO.CDP.OrganisationInformation.Persistence.Forms; + namespace CO.CDP.DataSharing.WebApi.AutoMapper; public class DataSharingProfile : Profile @@ -24,7 +25,7 @@ public DataSharingProfile() CreateMap() .ForMember(m => m.SubmittedAt, o => o.MapFrom(m => m.SubmittedAt)) - .ForMember(m => m.ShareCode, o => o.MapFrom(m => m.ShareCode)); + .ForMember(m => m.ShareCode, o => o.MapFrom(m => m.ShareCode)); } } public class CustomResolver : IValueResolver diff --git a/Services/CO.CDP.DataSharing.WebApi/Model/AssociatedPerson.cs b/Services/CO.CDP.DataSharing.WebApi/Model/AssociatedPerson.cs index e584d56c2..24fd8b060 100644 --- a/Services/CO.CDP.DataSharing.WebApi/Model/AssociatedPerson.cs +++ b/Services/CO.CDP.DataSharing.WebApi/Model/AssociatedPerson.cs @@ -3,7 +3,7 @@ namespace CO.CDP.DataSharing.WebApi.Model; -internal record AssociatedPerson +public record AssociatedPerson { /// "c16f9f7b-3f10-42db-86f8-93607b034a4c" [Required] public required Guid Id { get; init; } diff --git a/Services/CO.CDP.DataSharing.WebApi/Model/Details.cs b/Services/CO.CDP.DataSharing.WebApi/Model/Details.cs index e69718341..4649b61de 100644 --- a/Services/CO.CDP.DataSharing.WebApi/Model/Details.cs +++ b/Services/CO.CDP.DataSharing.WebApi/Model/Details.cs @@ -1,3 +1,3 @@ namespace CO.CDP.DataSharing.WebApi.Model; -internal record Details; \ No newline at end of file +public record Details; \ No newline at end of file diff --git a/Services/CO.CDP.DataSharing.WebApi/Model/Form.cs b/Services/CO.CDP.DataSharing.WebApi/Model/Form.cs index 34d6749f7..c033dd735 100644 --- a/Services/CO.CDP.DataSharing.WebApi/Model/Form.cs +++ b/Services/CO.CDP.DataSharing.WebApi/Model/Form.cs @@ -3,13 +3,13 @@ namespace CO.CDP.DataSharing.WebApi.Model; [JsonConverter(typeof(JsonStringEnumConverter))] -internal enum FormSubmissionState +public enum FormSubmissionState { Draft, Submitted } -internal record Form +public record Form { /// "Standard Questions" public required string Name { get; init; } diff --git a/Services/CO.CDP.DataSharing.WebApi/Model/FormAnswer.cs b/Services/CO.CDP.DataSharing.WebApi/Model/FormAnswer.cs index cb783d125..7c945c542 100644 --- a/Services/CO.CDP.DataSharing.WebApi/Model/FormAnswer.cs +++ b/Services/CO.CDP.DataSharing.WebApi/Model/FormAnswer.cs @@ -1,6 +1,6 @@ namespace CO.CDP.DataSharing.WebApi.Model; -internal record FormAnswer +public record FormAnswer { /// "_Steel01" public required string QuestionName { get; init; } diff --git a/Services/CO.CDP.DataSharing.WebApi/Model/FormQuestion.cs b/Services/CO.CDP.DataSharing.WebApi/Model/FormQuestion.cs index 847d099ed..75c96ba71 100644 --- a/Services/CO.CDP.DataSharing.WebApi/Model/FormQuestion.cs +++ b/Services/CO.CDP.DataSharing.WebApi/Model/FormQuestion.cs @@ -1,6 +1,6 @@ namespace CO.CDP.DataSharing.WebApi.Model; -internal record FormQuestion +public record FormQuestion { public required FormQuestionType Type { get; init; } diff --git a/Services/CO.CDP.DataSharing.WebApi/Model/FormQuestionOption.cs b/Services/CO.CDP.DataSharing.WebApi/Model/FormQuestionOption.cs index 6b97915e9..088e3ae5b 100644 --- a/Services/CO.CDP.DataSharing.WebApi/Model/FormQuestionOption.cs +++ b/Services/CO.CDP.DataSharing.WebApi/Model/FormQuestionOption.cs @@ -2,7 +2,7 @@ namespace CO.CDP.DataSharing.WebApi.Model; -internal record FormQuestionOption +public record FormQuestionOption { [Required] public required Guid Id { get; init; } /// "3fa85f64-5717-4562-b3fc-2c963f66afa6" diff --git a/Services/CO.CDP.DataSharing.WebApi/Model/FormQuestionType.cs b/Services/CO.CDP.DataSharing.WebApi/Model/FormQuestionType.cs index 6c125e8a9..b3b04dd35 100644 --- a/Services/CO.CDP.DataSharing.WebApi/Model/FormQuestionType.cs +++ b/Services/CO.CDP.DataSharing.WebApi/Model/FormQuestionType.cs @@ -3,7 +3,7 @@ namespace CO.CDP.DataSharing.WebApi.Model; [JsonConverter(typeof(JsonStringEnumConverter))] -internal enum FormQuestionType +public enum FormQuestionType { Boolean, Numeric, diff --git a/Services/CO.CDP.DataSharing.WebApi/Model/SharedConsent.cs b/Services/CO.CDP.DataSharing.WebApi/Model/SharedConsent.cs index c6f7106b8..ebc7d411b 100644 --- a/Services/CO.CDP.DataSharing.WebApi/Model/SharedConsent.cs +++ b/Services/CO.CDP.DataSharing.WebApi/Model/SharedConsent.cs @@ -2,6 +2,6 @@ namespace CO.CDP.DataSharing.WebApi.Model; public class SharedConsent { - public DateTimeOffset SubmittedAt { get; set; } + public DateTimeOffset SubmittedAt { get; set; } public string? ShareCode { get; set; } } \ No newline at end of file diff --git a/Services/CO.CDP.DataSharing.WebApi/Model/SupplierInformation.cs b/Services/CO.CDP.DataSharing.WebApi/Model/SupplierInformation.cs index 939ea3461..0280c1a08 100644 --- a/Services/CO.CDP.DataSharing.WebApi/Model/SupplierInformation.cs +++ b/Services/CO.CDP.DataSharing.WebApi/Model/SupplierInformation.cs @@ -6,7 +6,7 @@ namespace CO.CDP.DataSharing.WebApi.Model; /// /// Based on OCDS Parties. /// -internal record SupplierInformation +public record SupplierInformation { /// "47e6a363-11c0-4cf4-bce6-dea03034e4bb" [Required] public required Guid Id { get; init; } diff --git a/Services/CO.CDP.DataSharing.WebApi/Model/SupplierInformationData.cs b/Services/CO.CDP.DataSharing.WebApi/Model/SupplierInformationData.cs index 0aed2c507..ce1139a11 100644 --- a/Services/CO.CDP.DataSharing.WebApi/Model/SupplierInformationData.cs +++ b/Services/CO.CDP.DataSharing.WebApi/Model/SupplierInformationData.cs @@ -1,6 +1,6 @@ namespace CO.CDP.DataSharing.WebApi.Model; -internal record SupplierInformationData +public record SupplierInformationData { public required Form Form { get; init; } public required List Answers { get; init; } = new(); diff --git a/Services/CO.CDP.DataSharing.WebApi/Program.cs b/Services/CO.CDP.DataSharing.WebApi/Program.cs index 9c8a09da8..49afb694d 100644 --- a/Services/CO.CDP.DataSharing.WebApi/Program.cs +++ b/Services/CO.CDP.DataSharing.WebApi/Program.cs @@ -27,10 +27,11 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); builder.Services.AddScoped, GenerateShareCodeUseCase>(); - builder.Services.AddScoped?>, GetShareCodesUseCase>(); builder.Services.AddScoped, GetShareCodeDetailsUseCase>(); +builder.Services.AddScoped, GetSharedDataUseCase>(); builder.Services.AddDataSharingProblemDetails(); builder.Services.AddJwtBearerAndApiKeyAuthentication(builder.Configuration, builder.Environment); //builder.Services.AddAuthorization(); diff --git a/Services/CO.CDP.DataSharing.WebApi/UseCase/GenerateShareCodeUseCase.cs b/Services/CO.CDP.DataSharing.WebApi/UseCase/GenerateShareCodeUseCase.cs index f1d2558ee..55aa89405 100644 --- a/Services/CO.CDP.DataSharing.WebApi/UseCase/GenerateShareCodeUseCase.cs +++ b/Services/CO.CDP.DataSharing.WebApi/UseCase/GenerateShareCodeUseCase.cs @@ -11,6 +11,7 @@ public class GenerateShareCodeUseCase( IClaimService claimService, IOrganisationRepository organisationRepository, IFormRepository formRepository, + IShareCodeRepository shareCodeRepository, IMapper mapper) : IUseCase { @@ -22,7 +23,7 @@ public async Task Execute(ShareRequest shareRequest) throw new InvalidOrganisationRequestedException("Invalid Organisation requested."); } - var result = await formRepository.GetSharedConsentDraftAsync(shareRequest.FormId, shareRequest.OrganisationId); + var result = await shareCodeRepository.GetSharedConsentDraftAsync(shareRequest.FormId, shareRequest.OrganisationId); if (result == null) { throw new SharedConsentNotFoundException("Shared Consent not found."); diff --git a/Services/CO.CDP.DataSharing.WebApi/UseCase/GetShareCodesUseCase.cs b/Services/CO.CDP.DataSharing.WebApi/UseCase/GetShareCodesUseCase.cs index 949b39678..caea1eb0e 100644 --- a/Services/CO.CDP.DataSharing.WebApi/UseCase/GetShareCodesUseCase.cs +++ b/Services/CO.CDP.DataSharing.WebApi/UseCase/GetShareCodesUseCase.cs @@ -6,14 +6,14 @@ namespace CO.CDP.DataSharing.WebApi.UseCase; public class GetShareCodesUseCase( - IFormRepository formRepository, + IShareCodeRepository shareCodeRepository, IMapper mapper) : IUseCase?> { public async Task?> Execute(Guid organisationId) { - return await formRepository.GetShareCodesAsync(organisationId) + return await shareCodeRepository.GetShareCodesAsync(organisationId) .AndThen(mapper.Map>); } } \ No newline at end of file diff --git a/Services/CO.CDP.DataSharing.WebApi/UseCase/GetSharedDataUseCase.cs b/Services/CO.CDP.DataSharing.WebApi/UseCase/GetSharedDataUseCase.cs new file mode 100644 index 000000000..82bd7ee1a --- /dev/null +++ b/Services/CO.CDP.DataSharing.WebApi/UseCase/GetSharedDataUseCase.cs @@ -0,0 +1,22 @@ +using AutoMapper; +using CO.CDP.DataSharing.WebApi.Model; +using CO.CDP.OrganisationInformation.Persistence; + +namespace CO.CDP.DataSharing.WebApi.UseCase; + +public class GetSharedDataUseCase( + IShareCodeRepository shareCodeRepository, + IMapper mapper) + : IUseCase +{ + public async Task Execute(string sharecode) + { + var organisation = await shareCodeRepository.GetByShareCode(sharecode); + if (organisation == null) + { + throw new SharedConsentNotFoundException("Shared Consent not found."); + } + + return mapper.Map(organisation); + } +} \ No newline at end of file diff --git a/Services/CO.CDP.Forms.WebApi.Tests/UseCase/UpdateFormSectionAnswersUseCaseTest.cs b/Services/CO.CDP.Forms.WebApi.Tests/UseCase/UpdateFormSectionAnswersUseCaseTest.cs index 5f2dd4305..64d5a68da 100644 --- a/Services/CO.CDP.Forms.WebApi.Tests/UseCase/UpdateFormSectionAnswersUseCaseTest.cs +++ b/Services/CO.CDP.Forms.WebApi.Tests/UseCase/UpdateFormSectionAnswersUseCaseTest.cs @@ -148,8 +148,6 @@ public async Task Execute_ShouldCreateNewSharedConsent_WhenNoDraftSharedConsentE var command = (formId: section.Form.Guid, sectionId: section.Guid, answerSetId, organisationId: organisation.Guid, answers); - GivenSharedConsentDoesNotExist(section.Form.Guid, organisation.Guid); - await UseCase.Execute(command); _repository.Verify(r => r.SaveSharedConsentAsync(It.Is(sc => @@ -287,12 +285,6 @@ Persistence.Form form return sharedConsent; } - private void GivenSharedConsentDoesNotExist(Guid formId, Guid organisationId) - { - _repository.Setup(r => r.GetSharedConsentDraftAsync(formId, organisationId)) - .ReturnsAsync((Persistence.SharedConsent?)null); - } - private Persistence.SharedConsent GivenSharedConsent( Organisation organisation, Persistence.Form form diff --git a/Services/CO.CDP.OrganisationInformation.Persistence.Tests/DatabaseFormRepositoryTest.cs b/Services/CO.CDP.OrganisationInformation.Persistence.Tests/DatabaseFormRepositoryTest.cs index 69ca5342c..dd3018a96 100644 --- a/Services/CO.CDP.OrganisationInformation.Persistence.Tests/DatabaseFormRepositoryTest.cs +++ b/Services/CO.CDP.OrganisationInformation.Persistence.Tests/DatabaseFormRepositoryTest.cs @@ -183,35 +183,6 @@ public async Task GetFormAnswerSetsAsync_WhenFormAnswerSetDoesNotExist_ReturnsNu foundAnswerSets.Should().BeEmpty(); } - [Fact] - public async Task GetSharedConsentDraftAsync_WhenSharedConsentDoesNotExist_ReturnsNull() - { - using var repository = FormRepository(); - - var foundConsent = await repository.GetSharedConsentDraftAsync(Guid.NewGuid(), Guid.NewGuid()); - - foundConsent.Should().BeNull(); - } - - [Fact] - public async Task GetSharedConsentDraftAsync_WhenItDoesExist_ReturnsIt() - { - var sharedConsent = GivenSharedConsent(); - - await using var context = postgreSql.OrganisationInformationContext(); - await context.SharedConsents.AddAsync(sharedConsent); - await context.SaveChangesAsync(); - - using var repository = FormRepository(); - - var found = await repository.GetSharedConsentDraftAsync(sharedConsent.Form.Guid, sharedConsent.Organisation.Guid); - - found.Should().NotBeNull(); - found.As().OrganisationId.Should().Be(sharedConsent.OrganisationId); - found.As().SubmissionState.Should().Be(SubmissionState.Draft); - found.As().BookingReference.Should().BeNull(); - } - [Fact] public async Task GetSharedConsentDraftWithAnswersAsync_WhenSharedConsentDoesNotExist_ReturnsNull() { @@ -271,42 +242,6 @@ public async Task GetSharedConsentDraftWithAnswersAsync_WhenSharedConsentWithAns found.As().AnswerSets.First().Answers.First().Guid.Should().Be(answer.Guid); } - [Fact] - public async Task GetShareCodesAsync_WhenCodesDoesNotExist_ReturnsEmptyList() - { - using var repository = FormRepository(); - - var foundSection = await repository.GetShareCodesAsync(Guid.NewGuid()); - - foundSection.Should().BeEmpty(); - } - - [Fact] - public async Task GetShareCodesAsync_WhenCodesExist_ReturnsList() - { - var sharedConsent = GivenSharedConsent(); - Random rand = new Random(); - var bookingref = rand.Next(10000000, 99999999).ToString(); - - sharedConsent.BookingReference = bookingref; - sharedConsent.SubmissionState = SubmissionState.Submitted; - sharedConsent.SubmittedAt = DateTime.UtcNow; - - await using var context = postgreSql.OrganisationInformationContext(); - await context.SharedConsents.AddAsync(sharedConsent); - await context.SaveChangesAsync(); - - using var repository = FormRepository(); - - var found = await repository.GetShareCodesAsync(sharedConsent.Organisation.Guid); - - found.Should().NotBeEmpty(); - found.Should().HaveCount(1); - - found.First().As().OrganisationId.Should().Be(sharedConsent.OrganisationId); - found.First().As().SubmissionState.Should().Be(SubmissionState.Submitted); - found.First().As().BookingReference.Should().Be(bookingref); - } [Fact] public async Task DeleteAnswerSetAsync_ShouldReturnFalse_WhenAnswerSetNotFound() diff --git a/Services/CO.CDP.OrganisationInformation.Persistence.Tests/ShareCodeRepositoryTest.cs b/Services/CO.CDP.OrganisationInformation.Persistence.Tests/ShareCodeRepositoryTest.cs new file mode 100644 index 000000000..13f189f9a --- /dev/null +++ b/Services/CO.CDP.OrganisationInformation.Persistence.Tests/ShareCodeRepositoryTest.cs @@ -0,0 +1,299 @@ +using CO.CDP.OrganisationInformation.Persistence.Forms; +using CO.CDP.Testcontainers.PostgreSql; +using FluentAssertions; +using static CO.CDP.OrganisationInformation.Persistence.Tests.EntityFactory; + +namespace CO.CDP.OrganisationInformation.Persistence.Tests; + +public class ShareCodeRepositoryTest(PostgreSqlFixture postgreSql) : IClassFixture +{ + + [Fact] + public async Task GetSharedConsentDraftAsync_WhenSharedConsentDoesNotExist_ReturnsNull() + { + using var repository = ShareCodeRepository(); + + var foundConsent = await repository.GetSharedConsentDraftAsync(Guid.NewGuid(), Guid.NewGuid()); + + foundConsent.Should().BeNull(); + } + + [Fact] + public async Task GetSharedConsentDraftAsync_WhenItDoesExist_ReturnsIt() + { + var sharedConsent = GivenSharedConsent(); + + await using var context = postgreSql.OrganisationInformationContext(); + await context.SharedConsents.AddAsync(sharedConsent); + await context.SaveChangesAsync(); + + using var repository = ShareCodeRepository(); + + var found = await repository.GetSharedConsentDraftAsync(sharedConsent.Form.Guid, sharedConsent.Organisation.Guid); + + found.Should().NotBeNull(); + found.As().OrganisationId.Should().Be(sharedConsent.OrganisationId); + found.As().SubmissionState.Should().Be(SubmissionState.Draft); + found.As().BookingReference.Should().BeNull(); + } + + [Fact] + public async Task GetShareCodesAsync_WhenCodesDoesNotExist_ReturnsEmptyList() + { + using var repository = ShareCodeRepository(); + + var foundSection = await repository.GetShareCodesAsync(Guid.NewGuid()); + + foundSection.Should().BeEmpty(); + } + + [Fact] + public async Task GetShareCodesAsync_WhenCodesExist_ReturnsList() + { + var sharedConsent = GivenSharedConsent(); + Random rand = new Random(); + var bookingref = rand.Next(10000000, 99999999).ToString(); + + sharedConsent.BookingReference = bookingref; + sharedConsent.SubmissionState = SubmissionState.Submitted; + sharedConsent.SubmittedAt = DateTime.UtcNow; + + await using var context = postgreSql.OrganisationInformationContext(); + await context.SharedConsents.AddAsync(sharedConsent); + await context.SaveChangesAsync(); + + using var repository = ShareCodeRepository(); + + var found = await repository.GetShareCodesAsync(sharedConsent.Organisation.Guid); + + found.Should().NotBeEmpty(); + found.Should().HaveCount(1); + + found.First().As().OrganisationId.Should().Be(sharedConsent.OrganisationId); + found.First().As().SubmissionState.Should().Be(SubmissionState.Submitted); + found.First().As().BookingReference.Should().Be(bookingref); + } + + + [Fact] + public async Task GetByShareCode_WhenShareCodeDoesNotExist_ReturnsNull() + { + using var repository = ShareCodeRepository(); + + var foundConsent = await repository.GetByShareCode("NONEXISTENTCODE"); + + foundConsent.Should().BeNull(); + } + + [Fact] + public async Task GetByShareCode_WhenShareCodeExists_ReturnsSharedConsent() + { + var form = GivenForm(Guid.NewGuid()); + var section = GivenSection(Guid.NewGuid(), form); + var question = GivenYesOrNoQuestion(section); + var sharedConsent = GivenSharedConsent(form); + var answerSet = GivenAnswerSet(sharedConsent, section); + var answer = GivenAnswer(question, answerSet); + + sharedConsent.SubmissionState = SubmissionState.Submitted; + sharedConsent.SubmittedAt = DateTime.UtcNow; + var shareCode = "EXISTENTCODE"; + sharedConsent.BookingReference = shareCode; + + await using var context = postgreSql.OrganisationInformationContext(); + await context.SharedConsents.AddAsync(sharedConsent); + await context.SaveChangesAsync(); + + using var repository = ShareCodeRepository(); + + var foundConsent = await repository.GetByShareCode(shareCode); + + foundConsent.Should().NotBeNull(); + foundConsent!.BookingReference.Should().Be(shareCode); + foundConsent.Organisation.Name.Should().StartWith("Acme Corporation"); + foundConsent.Organisation.Identifiers.Should().ContainSingle(i => i.LegalName == "Acme Corporation Ltd"); + foundConsent.Organisation.ContactPoints.Should().ContainSingle(cp => cp.Name == "Procurement Team"); + + var registeredAddress = foundConsent.Organisation.Addresses.FirstOrDefault(a => a.Type == AddressType.Registered); + registeredAddress.Should().NotBeNull(); + registeredAddress!.Address.Should().NotBeNull(); + registeredAddress!.Address.StreetAddress.Should().Be("82 St. John’s Road"); + registeredAddress!.Address.PostalCode.Should().Be("CH43 7UR"); + + foundConsent.AnswerSets.Should().ContainSingle(); + + var retrievedAnswerSet = foundConsent.AnswerSets.First(); + retrievedAnswerSet.Answers.Should().ContainSingle(a => a.BoolValue == true && a.Question.Title == "Yes or no?"); + + var retrievedForm = foundConsent.Form; + retrievedForm.Should().NotBeNull(); + retrievedForm.Name.Should().Be("Test Form"); + retrievedForm.Sections.Should().ContainSingle(s => s.Title == "Test Section"); + + var retrievedSection = retrievedForm.Sections.First(); + retrievedSection.Questions.Should().ContainSingle(q => q.Title == "Yes or no?"); + } + + private static SharedConsent GivenSharedConsent( + Form? form = null, + Organisation? organisation = null) + { + form ??= GivenForm(Guid.NewGuid()); + organisation ??= GivenOrganisation(); + + return new SharedConsent + { + Guid = Guid.NewGuid(), + OrganisationId = organisation.Id, + Organisation = organisation, + FormId = form.Id, + Form = form, + AnswerSets = [], + SubmissionState = SubmissionState.Draft, + SubmittedAt = null, + FormVersionId = "202404", + BookingReference = null + }; + } + + private static Form GivenForm(Guid formId) + { + return new Form + { + Guid = formId, + Name = "Test Form", + Version = "1.0", + IsRequired = true, + Scope = FormScope.SupplierInformation, + Sections = new List() + }; + } + + private static Organisation GivenOrganisation() + { + return new Organisation + { + Guid = Guid.NewGuid(), + Name = "Acme Corporation " + Guid.NewGuid().ToString(), // Ensure unique name + Tenant = GivenTenant(), + Identifiers = new List + { + new Organisation.Identifier + { + IdentifierId = Guid.NewGuid().ToString(), // Generate a unique IdentifierId + Scheme = "CDP-PPON", + LegalName = "Acme Corporation Ltd", + Uri = "https://cdp.cabinetoffice.gov.uk/organisations/" + Guid.NewGuid().ToString(), // Ensure unique URI + Primary = true + } + }, + ContactPoints = new List + { + new Organisation.ContactPoint + { + Name = "Procurement Team", + Email = "info@example.com", + Telephone = "+441234567890" + } + }, + Addresses = new List + { + new Organisation.OrganisationAddress + { + Type = AddressType.Registered, + Address = new OrganisationInformation.Persistence.Address + { + StreetAddress = "82 St. John’s Road", + Locality = "CHESTER", + Region = "Lancashire", + PostalCode = "CH43 7UR", + CountryName = "United Kingdom" + } + } + } + }; + } + + private static Tenant GivenTenant() + { + return new Tenant + { + Guid = Guid.NewGuid(), + Name = "Acme Tenant " + Guid.NewGuid().ToString() + }; + } + + private static FormSection GivenSection(Guid sectionId, Form form) + { + return new FormSection + { + Guid = sectionId, + FormId = form.Id, + Form = form, + Questions = new List(), + Title = "Test Section", + Type = FormSectionType.Standard, + AllowsMultipleAnswerSets = true, + Configuration = new FormSectionConfiguration + { + PluralSummaryHeadingFormat = "You have added {0} files", + SingularSummaryHeading = "You have added 1 file", + AddAnotherAnswerLabel = "Add another file?", + RemoveConfirmationCaption = "Economic and Financial Standing", + RemoveConfirmationHeading = "Are you sure you want to remove this file?" + } + }; + } + + private static FormAnswer GivenAnswer(FormQuestion question, FormAnswerSet answerSet) + { + var answer = new FormAnswer + { + Guid = Guid.NewGuid(), + Question = question, + FormAnswerSet = answerSet, + BoolValue = true + }; + answerSet.Answers.Add(answer); + return answer; + } + + private static FormAnswerSet GivenAnswerSet(SharedConsent sharedConsent, FormSection section) + { + var answerSet = new FormAnswerSet + { + Guid = Guid.NewGuid(), + SharedConsentId = sharedConsent.Id, + SharedConsent = sharedConsent, + SectionId = section.Id, + Section = section, + Answers = [], + }; + sharedConsent.AnswerSets.Add(answerSet); + return answerSet; + } + + private static FormQuestion GivenYesOrNoQuestion(FormSection section) + { + var question = new FormQuestion + { + Guid = Guid.NewGuid(), + Section = section, + Type = FormQuestionType.YesOrNo, + IsRequired = true, + Title = "Yes or no?", + Description = "Please answer.", + NextQuestion = null, + NextQuestionAlternative = null, + Caption = null, + Options = new() + }; + section.Questions.Add(question); + return question; + } + + private IShareCodeRepository ShareCodeRepository() + { + return new DatabaseShareCodeRepository(postgreSql.OrganisationInformationContext()); + } +} \ No newline at end of file diff --git a/Services/CO.CDP.OrganisationInformation.Persistence/DatabaseFormRepository.cs b/Services/CO.CDP.OrganisationInformation.Persistence/DatabaseFormRepository.cs index d5cd4aef3..5bfdf95e4 100644 --- a/Services/CO.CDP.OrganisationInformation.Persistence/DatabaseFormRepository.cs +++ b/Services/CO.CDP.OrganisationInformation.Persistence/DatabaseFormRepository.cs @@ -67,13 +67,6 @@ public async Task SaveSharedConsentAsync(SharedConsent sharedConsent) .FirstOrDefaultAsync(s => s.Guid == sectionId); } - public async Task GetSharedConsentDraftAsync(Guid formId, Guid organisationId) - { - return await context.Set() - .Where(x => x.SubmissionState == SubmissionState.Draft) - .FirstOrDefaultAsync(s => s.Form.Guid == formId && s.Organisation.Guid == organisationId); - } - public async Task GetSharedConsentDraftWithAnswersAsync(Guid formId, Guid organisationId) { return await context.Set() diff --git a/Services/CO.CDP.OrganisationInformation.Persistence/DatabaseShareCodeRepository.cs b/Services/CO.CDP.OrganisationInformation.Persistence/DatabaseShareCodeRepository.cs new file mode 100644 index 000000000..f62e15a29 --- /dev/null +++ b/Services/CO.CDP.OrganisationInformation.Persistence/DatabaseShareCodeRepository.cs @@ -0,0 +1,50 @@ +using CO.CDP.OrganisationInformation.Persistence.Forms; +using Microsoft.EntityFrameworkCore; + +namespace CO.CDP.OrganisationInformation.Persistence; + +public class DatabaseShareCodeRepository(OrganisationInformationContext context) : IShareCodeRepository +{ + public async Task> GetShareCodesAsync(Guid organisationId) + { + return await context.Set() + .Where(x => x.SubmissionState == SubmissionState.Submitted && x.Organisation.Guid == organisationId) + .OrderByDescending(y => y.SubmittedAt).ToListAsync(); + } + + public async Task GetSharedConsentDraftAsync(Guid formId, Guid organisationId) + { + return await context.Set() + .Where(x => x.SubmissionState == SubmissionState.Draft) + .FirstOrDefaultAsync(s => s.Form.Guid == formId && s.Organisation.Guid == organisationId); + } + + public async Task GetByShareCode(string sharecode) + { + return await context.SharedConsents + .Where(sc => sc.BookingReference == sharecode) + .Include(sc => sc.Organisation) + .ThenInclude(o => o.Identifiers) + .Include(sc => sc.Organisation) + .ThenInclude(o => o.ContactPoints) + .Include(sc => sc.Organisation) + .ThenInclude(o => o.Addresses) + .ThenInclude(p => p.Address) + .Include(sc => sc.Organisation) + .ThenInclude(o => o.OrganisationPersons) + .ThenInclude(op => op.Person) + .Include(sc => sc.AnswerSets) + .ThenInclude(sa => sa.Answers) + .Include(sc => sc.Form) + .ThenInclude(f => f.Sections) + .ThenInclude(s => s.Questions) + .FirstOrDefaultAsync(); + } + + + public void Dispose() + { + context.Dispose(); + } + +} diff --git a/Services/CO.CDP.OrganisationInformation.Persistence/Forms/FormAnswer.cs b/Services/CO.CDP.OrganisationInformation.Persistence/Forms/FormAnswer.cs index c41ee967d..a5af98e30 100644 --- a/Services/CO.CDP.OrganisationInformation.Persistence/Forms/FormAnswer.cs +++ b/Services/CO.CDP.OrganisationInformation.Persistence/Forms/FormAnswer.cs @@ -20,6 +20,7 @@ public class SharedConsent : IEntityDate public DateTimeOffset? SubmittedAt { get; set; } public required string FormVersionId { get; init; } public string? BookingReference { get; set; } + public string? ShareCode { get; set; } public DateTimeOffset CreatedOn { get; set; } public DateTimeOffset UpdatedOn { get; set; } } diff --git a/Services/CO.CDP.OrganisationInformation.Persistence/IFormRepository.cs b/Services/CO.CDP.OrganisationInformation.Persistence/IFormRepository.cs index 69573e3df..770398f92 100644 --- a/Services/CO.CDP.OrganisationInformation.Persistence/IFormRepository.cs +++ b/Services/CO.CDP.OrganisationInformation.Persistence/IFormRepository.cs @@ -8,8 +8,6 @@ public interface IFormRepository : IDisposable Task SaveFormAsync(Form formSection); Task SaveSharedConsentAsync(SharedConsent sharedConsent); Task GetSectionAsync(Guid formId, Guid sectionId); - - Task GetSharedConsentDraftAsync(Guid formId, Guid organisationId); Task GetSharedConsentDraftWithAnswersAsync(Guid formId, Guid organisationId); Task> GetShareCodesAsync(Guid organisationId); Task GetShareCodeDetailsAsync(Guid organisationId, string shareCode); diff --git a/Services/CO.CDP.OrganisationInformation.Persistence/IShareCodeRepository.cs b/Services/CO.CDP.OrganisationInformation.Persistence/IShareCodeRepository.cs new file mode 100644 index 000000000..bf297d716 --- /dev/null +++ b/Services/CO.CDP.OrganisationInformation.Persistence/IShareCodeRepository.cs @@ -0,0 +1,9 @@ +using CO.CDP.OrganisationInformation.Persistence.Forms; + +namespace CO.CDP.OrganisationInformation.Persistence; +public interface IShareCodeRepository : IDisposable +{ + Task> GetShareCodesAsync(Guid organisationId); + Task GetSharedConsentDraftAsync(Guid formId, Guid organisationId); + Task GetByShareCode(string sharecode); +} diff --git a/Services/CO.CDP.OrganisationInformation.Persistence/Migrations/20240822151919_AddSharerCodetoSharedConsents.Designer.cs b/Services/CO.CDP.OrganisationInformation.Persistence/Migrations/20240822151919_AddSharerCodetoSharedConsents.Designer.cs new file mode 100644 index 000000000..d0f942e19 --- /dev/null +++ b/Services/CO.CDP.OrganisationInformation.Persistence/Migrations/20240822151919_AddSharerCodetoSharedConsents.Designer.cs @@ -0,0 +1,1699 @@ +// +using System; +using CO.CDP.OrganisationInformation.Persistence; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace CO.CDP.OrganisationInformation.Persistence.Migrations +{ + [DbContext(typeof(OrganisationInformationContext))] + [Migration("20240822151919_AddSharerCodetoSharedConsents")] + partial class AddSharerCodetoSharedConsents + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.7") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "connected_entity_type", new[] { "organisation", "individual", "trust_or_trustee" }); + NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "connected_organisation_category", new[] { "registered_company", "director_or_the_same_responsibilities", "parent_or_subsidiary_company", "a_company_your_organisation_has_taken_over", "any_other_organisation_with_significant_influence_or_control" }); + NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "connected_person_category", new[] { "person_with_significant_control", "director_or_individual_with_the_same_responsibilities", "any_other_individual_with_significant_influence_or_control" }); + NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "connected_person_type", new[] { "individual", "trust_or_trustee" }); + NpgsqlModelBuilderExtensions.HasPostgresEnum(modelBuilder, "control_condition", new[] { "none", "owns_shares", "has_voting_rights", "can_appoint_or_remove_directors", "has_other_significant_influence_or_control" }); + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.Address", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CountryName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("country_name"); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("Locality") + .IsRequired() + .HasColumnType("text") + .HasColumnName("locality"); + + b.Property("PostalCode") + .IsRequired() + .HasColumnType("text") + .HasColumnName("postal_code"); + + b.Property("Region") + .HasColumnType("text") + .HasColumnName("region"); + + b.Property("StreetAddress") + .IsRequired() + .HasColumnType("text") + .HasColumnName("street_address"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.HasKey("Id") + .HasName("pk_addresses"); + + b.ToTable("addresses", (string)null); + }); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.AuthenticationKey", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("Key") + .IsRequired() + .HasColumnType("text") + .HasColumnName("key"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("OrganisationId") + .HasColumnType("integer") + .HasColumnName("organisation_id"); + + b.Property("Scopes") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("scopes"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.HasKey("Id") + .HasName("pk_authentication_keys"); + + b.HasIndex("Key") + .IsUnique() + .HasDatabaseName("ix_authentication_keys_key"); + + b.HasIndex("OrganisationId") + .HasDatabaseName("ix_authentication_keys_organisation_id"); + + b.ToTable("authentication_keys", (string)null); + }); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.ConnectedEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CompanyHouseNumber") + .HasColumnType("text") + .HasColumnName("company_house_number"); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("EndDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("end_date"); + + b.Property("EntityType") + .HasColumnType("integer") + .HasColumnName("entity_type"); + + b.Property("Guid") + .HasColumnType("uuid") + .HasColumnName("guid"); + + b.Property("HasCompnayHouseNumber") + .HasColumnType("boolean") + .HasColumnName("has_compnay_house_number"); + + b.Property("OverseasCompanyNumber") + .HasColumnType("text") + .HasColumnName("overseas_company_number"); + + b.Property("RegisterName") + .HasColumnType("text") + .HasColumnName("register_name"); + + b.Property("RegisteredDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("registered_date"); + + b.Property("StartDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("start_date"); + + b.Property("SupplierOrganisationId") + .HasColumnType("integer") + .HasColumnName("supplier_organisation_id"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.HasKey("Id") + .HasName("pk_connected_entities"); + + b.HasIndex("Guid") + .IsUnique() + .HasDatabaseName("ix_connected_entities_guid"); + + b.HasIndex("SupplierOrganisationId") + .HasDatabaseName("ix_connected_entities_supplier_organisation_id"); + + b.ToTable("connected_entities", (string)null); + }); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.Forms.Form", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("Guid") + .HasColumnType("uuid") + .HasColumnName("guid"); + + b.Property("IsRequired") + .HasColumnType("boolean") + .HasColumnName("is_required"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Scope") + .HasColumnType("integer") + .HasColumnName("scope"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("Version") + .IsRequired() + .HasColumnType("text") + .HasColumnName("version"); + + b.HasKey("Id") + .HasName("pk_forms"); + + b.ToTable("forms", (string)null); + }); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.Forms.FormAnswer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AddressValue") + .HasColumnType("jsonb") + .HasColumnName("address_value"); + + b.Property("BoolValue") + .HasColumnType("boolean") + .HasColumnName("bool_value"); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("DateValue") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_value"); + + b.Property("EndValue") + .HasColumnType("timestamp with time zone") + .HasColumnName("end_value"); + + b.Property("FormAnswerSetId") + .HasColumnType("integer") + .HasColumnName("form_answer_set_id"); + + b.Property("Guid") + .HasColumnType("uuid") + .HasColumnName("guid"); + + b.Property("NumericValue") + .HasColumnType("double precision") + .HasColumnName("numeric_value"); + + b.Property("OptionValue") + .HasColumnType("text") + .HasColumnName("option_value"); + + b.Property("QuestionId") + .HasColumnType("integer") + .HasColumnName("question_id"); + + b.Property("StartValue") + .HasColumnType("timestamp with time zone") + .HasColumnName("start_value"); + + b.Property("TextValue") + .HasColumnType("text") + .HasColumnName("text_value"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.HasKey("Id") + .HasName("pk_form_answers"); + + b.HasIndex("FormAnswerSetId") + .HasDatabaseName("ix_form_answers_form_answer_set_id"); + + b.HasIndex("QuestionId") + .HasDatabaseName("ix_form_answers_question_id"); + + b.ToTable("form_answers", (string)null); + }); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.Forms.FormAnswerSet", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("Deleted") + .ValueGeneratedOnAdd() + .HasColumnType("boolean") + .HasDefaultValue(false) + .HasColumnName("deleted"); + + b.Property("Guid") + .HasColumnType("uuid") + .HasColumnName("guid"); + + b.Property("SectionId") + .HasColumnType("integer") + .HasColumnName("section_id"); + + b.Property("SharedConsentId") + .HasColumnType("integer") + .HasColumnName("shared_consent_id"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.HasKey("Id") + .HasName("pk_form_answer_sets"); + + b.HasIndex("SectionId") + .HasDatabaseName("ix_form_answer_sets_section_id"); + + b.HasIndex("SharedConsentId") + .HasDatabaseName("ix_form_answer_sets_shared_consent_id"); + + b.ToTable("form_answer_sets", (string)null); + }); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.Forms.FormQuestion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Caption") + .HasColumnType("text") + .HasColumnName("caption"); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("Description") + .HasColumnType("text") + .HasColumnName("description"); + + b.Property("Guid") + .HasColumnType("uuid") + .HasColumnName("guid"); + + b.Property("IsRequired") + .HasColumnType("boolean") + .HasColumnName("is_required"); + + b.Property("NextQuestionAlternativeId") + .HasColumnType("integer") + .HasColumnName("next_question_alternative_id"); + + b.Property("NextQuestionId") + .HasColumnType("integer") + .HasColumnName("next_question_id"); + + b.Property("Options") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("options"); + + b.Property("SectionId") + .HasColumnType("integer") + .HasColumnName("section_id"); + + b.Property("SummaryTitle") + .HasColumnType("text") + .HasColumnName("summary_title"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text") + .HasColumnName("title"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.HasKey("Id") + .HasName("pk_form_questions"); + + b.HasIndex("NextQuestionAlternativeId") + .HasDatabaseName("ix_form_questions_next_question_alternative_id"); + + b.HasIndex("NextQuestionId") + .HasDatabaseName("ix_form_questions_next_question_id"); + + b.HasIndex("SectionId") + .HasDatabaseName("ix_form_questions_section_id"); + + b.ToTable("form_questions", (string)null); + }); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.Forms.FormSection", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AllowsMultipleAnswerSets") + .HasColumnType("boolean") + .HasColumnName("allows_multiple_answer_sets"); + + b.Property("Configuration") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("configuration"); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("FormId") + .HasColumnType("integer") + .HasColumnName("form_id"); + + b.Property("Guid") + .HasColumnType("uuid") + .HasColumnName("guid"); + + b.Property("Title") + .IsRequired() + .HasColumnType("text") + .HasColumnName("title"); + + b.Property("Type") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasDefaultValue(0) + .HasColumnName("type"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.HasKey("Id") + .HasName("pk_form_sections"); + + b.HasIndex("FormId") + .HasDatabaseName("ix_form_sections_form_id"); + + b.ToTable("form_sections", (string)null); + }); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.Forms.SharedConsent", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("BookingReference") + .HasColumnType("text") + .HasColumnName("booking_reference"); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("FormId") + .HasColumnType("integer") + .HasColumnName("form_id"); + + b.Property("FormVersionId") + .IsRequired() + .HasColumnType("text") + .HasColumnName("form_version_id"); + + b.Property("Guid") + .HasColumnType("uuid") + .HasColumnName("guid"); + + b.Property("OrganisationId") + .HasColumnType("integer") + .HasColumnName("organisation_id"); + + b.Property("ShareCode") + .HasColumnType("text") + .HasColumnName("share_code"); + + b.Property("SubmissionState") + .HasColumnType("integer") + .HasColumnName("submission_state"); + + b.Property("SubmittedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("submitted_at"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.HasKey("Id") + .HasName("pk_shared_consents"); + + b.HasIndex("FormId") + .HasDatabaseName("ix_shared_consents_form_id"); + + b.HasIndex("OrganisationId") + .HasDatabaseName("ix_shared_consents_organisation_id"); + + b.ToTable("shared_consents", (string)null); + }); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.Organisation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("Guid") + .HasColumnType("uuid") + .HasColumnName("guid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Roles") + .IsRequired() + .HasColumnType("integer[]") + .HasColumnName("roles"); + + b.Property("TenantId") + .HasColumnType("integer") + .HasColumnName("tenant_id"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.HasKey("Id") + .HasName("pk_organisations"); + + b.HasIndex("Guid") + .IsUnique() + .HasDatabaseName("ix_organisations_guid"); + + b.HasIndex("Name") + .IsUnique() + .HasDatabaseName("ix_organisations_name"); + + b.HasIndex("TenantId") + .HasDatabaseName("ix_organisations_tenant_id"); + + b.ToTable("organisations", (string)null); + }); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.OrganisationPerson", b => + { + b.Property("OrganisationId") + .HasColumnType("integer") + .HasColumnName("organisation_id"); + + b.Property("PersonId") + .HasColumnType("integer") + .HasColumnName("person_id"); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("Scopes") + .IsRequired() + .HasColumnType("jsonb") + .HasColumnName("scopes"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.HasKey("OrganisationId", "PersonId") + .HasName("pk_organisation_person"); + + b.HasIndex("PersonId") + .HasDatabaseName("ix_organisation_person_person_id"); + + b.ToTable("organisation_person", (string)null); + }); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.Person", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("Email") + .IsRequired() + .HasColumnType("text") + .HasColumnName("email"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("first_name"); + + b.Property("Guid") + .HasColumnType("uuid") + .HasColumnName("guid"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("last_name"); + + b.Property("Phone") + .HasColumnType("text") + .HasColumnName("phone"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("UserUrn") + .HasColumnType("text") + .HasColumnName("user_urn"); + + b.HasKey("Id") + .HasName("pk_persons"); + + b.HasIndex("Email") + .IsUnique() + .HasDatabaseName("ix_persons_email"); + + b.HasIndex("Guid") + .IsUnique() + .HasDatabaseName("ix_persons_guid"); + + b.ToTable("persons", (string)null); + }); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.RefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("ExpiryDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("expiry_date"); + + b.Property("Revoked") + .HasColumnType("boolean") + .HasColumnName("revoked"); + + b.Property("TokenHash") + .IsRequired() + .HasColumnType("text") + .HasColumnName("token_hash"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.HasKey("Id") + .HasName("pk_refresh_tokens"); + + b.HasIndex("TokenHash") + .IsUnique() + .HasDatabaseName("ix_refresh_tokens_token_hash"); + + b.ToTable("refresh_tokens", (string)null); + }); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.Tenant", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("Guid") + .HasColumnType("uuid") + .HasColumnName("guid"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.HasKey("Id") + .HasName("pk_tenants"); + + b.HasIndex("Guid") + .IsUnique() + .HasDatabaseName("ix_tenants_guid"); + + b.HasIndex("Name") + .IsUnique() + .HasDatabaseName("ix_tenants_name"); + + b.ToTable("tenants", (string)null); + }); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.TenantPerson", b => + { + b.Property("PersonId") + .HasColumnType("integer") + .HasColumnName("person_id"); + + b.Property("TenantId") + .HasColumnType("integer") + .HasColumnName("tenant_id"); + + b.HasKey("PersonId", "TenantId") + .HasName("pk_tenant_person"); + + b.HasIndex("TenantId") + .HasDatabaseName("ix_tenant_person_tenant_id"); + + b.ToTable("tenant_person", (string)null); + }); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.AuthenticationKey", b => + { + b.HasOne("CO.CDP.OrganisationInformation.Persistence.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .HasConstraintName("fk_authentication_keys_organisations_organisation_id"); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.ConnectedEntity", b => + { + b.HasOne("CO.CDP.OrganisationInformation.Persistence.Organisation", "SupplierOrganisation") + .WithMany() + .HasForeignKey("SupplierOrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_connected_entities_organisations_supplier_organisation_id"); + + b.OwnsMany("CO.CDP.OrganisationInformation.Persistence.ConnectedEntity+ConnectedEntityAddress", "Addresses", b1 => + { + b1.Property("ConnectedEntityId") + .HasColumnType("integer") + .HasColumnName("connected_entity_id"); + + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property("Id")); + + b1.Property("AddressId") + .HasColumnType("integer") + .HasColumnName("address_id"); + + b1.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b1.HasKey("ConnectedEntityId", "Id") + .HasName("pk_connected_entity_address"); + + b1.HasIndex("AddressId") + .HasDatabaseName("ix_connected_entity_address_address_id"); + + b1.ToTable("connected_entity_address", (string)null); + + b1.HasOne("CO.CDP.OrganisationInformation.Persistence.Address", "Address") + .WithMany() + .HasForeignKey("AddressId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_connected_entity_address_address_address_id"); + + b1.WithOwner() + .HasForeignKey("ConnectedEntityId") + .HasConstraintName("fk_connected_entity_address_connected_entities_connected_entit"); + + b1.Navigation("Address"); + }); + + b.OwnsOne("CO.CDP.OrganisationInformation.Persistence.ConnectedEntity+ConnectedIndividualTrust", "IndividualOrTrust", b1 => + { + b1.Property("Id") + .HasColumnType("integer") + .HasColumnName("connected_individual_trust_id"); + + b1.Property("Category") + .HasColumnType("integer") + .HasColumnName("category"); + + b1.Property("ConnectedType") + .HasColumnType("integer") + .HasColumnName("connected_type"); + + b1.Property("ControlCondition") + .IsRequired() + .HasColumnType("integer[]") + .HasColumnName("control_condition"); + + b1.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b1.Property("DateOfBirth") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_of_birth"); + + b1.Property("FirstName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("first_name"); + + b1.Property("LastName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("last_name"); + + b1.Property("Nationality") + .HasColumnType("text") + .HasColumnName("nationality"); + + b1.Property("PersonId") + .HasColumnType("uuid") + .HasColumnName("person_id"); + + b1.Property("ResidentCountry") + .HasColumnType("text") + .HasColumnName("resident_country"); + + b1.Property("UpdatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b1.HasKey("Id") + .HasName("pk_connected_individual_trust"); + + b1.ToTable("connected_individual_trust", (string)null); + + b1.WithOwner() + .HasForeignKey("Id") + .HasConstraintName("fk_connected_individual_trust_connected_entities_connected_ind"); + }); + + b.OwnsOne("CO.CDP.OrganisationInformation.Persistence.ConnectedEntity+ConnectedOrganisation", "Organisation", b1 => + { + b1.Property("Id") + .HasColumnType("integer") + .HasColumnName("connected_organisation_id"); + + b1.Property("Category") + .HasColumnType("integer") + .HasColumnName("category"); + + b1.Property("ControlCondition") + .IsRequired() + .HasColumnType("integer[]") + .HasColumnName("control_condition"); + + b1.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b1.Property("InsolvencyDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("insolvency_date"); + + b1.Property("LawRegistered") + .HasColumnType("text") + .HasColumnName("law_registered"); + + b1.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b1.Property("OrganisationId") + .HasColumnType("uuid") + .HasColumnName("organisation_id"); + + b1.Property("RegisteredLegalForm") + .HasColumnType("text") + .HasColumnName("registered_legal_form"); + + b1.Property("UpdatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b1.HasKey("Id") + .HasName("pk_connected_organisation"); + + b1.ToTable("connected_organisation", (string)null); + + b1.WithOwner() + .HasForeignKey("Id") + .HasConstraintName("fk_connected_organisation_connected_entities_connected_organis"); + }); + + b.Navigation("Addresses"); + + b.Navigation("IndividualOrTrust"); + + b.Navigation("Organisation"); + + b.Navigation("SupplierOrganisation"); + }); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.Forms.FormAnswer", b => + { + b.HasOne("CO.CDP.OrganisationInformation.Persistence.Forms.FormAnswerSet", "FormAnswerSet") + .WithMany("Answers") + .HasForeignKey("FormAnswerSetId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_form_answers_form_answer_sets_form_answer_set_id"); + + b.HasOne("CO.CDP.OrganisationInformation.Persistence.Forms.FormQuestion", "Question") + .WithMany() + .HasForeignKey("QuestionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_form_answers_form_questions_question_id"); + + b.Navigation("FormAnswerSet"); + + b.Navigation("Question"); + }); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.Forms.FormAnswerSet", b => + { + b.HasOne("CO.CDP.OrganisationInformation.Persistence.Forms.FormSection", "Section") + .WithMany() + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_form_answer_sets_form_section_section_id"); + + b.HasOne("CO.CDP.OrganisationInformation.Persistence.Forms.SharedConsent", "SharedConsent") + .WithMany("AnswerSets") + .HasForeignKey("SharedConsentId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_form_answer_sets_shared_consents_shared_consent_id"); + + b.Navigation("Section"); + + b.Navigation("SharedConsent"); + }); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.Forms.FormQuestion", b => + { + b.HasOne("CO.CDP.OrganisationInformation.Persistence.Forms.FormQuestion", "NextQuestionAlternative") + .WithMany() + .HasForeignKey("NextQuestionAlternativeId") + .HasConstraintName("fk_form_questions_form_questions_next_question_alternative_id"); + + b.HasOne("CO.CDP.OrganisationInformation.Persistence.Forms.FormQuestion", "NextQuestion") + .WithMany() + .HasForeignKey("NextQuestionId") + .HasConstraintName("fk_form_questions_form_questions_next_question_id"); + + b.HasOne("CO.CDP.OrganisationInformation.Persistence.Forms.FormSection", "Section") + .WithMany("Questions") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_form_questions_form_sections_section_id"); + + b.Navigation("NextQuestion"); + + b.Navigation("NextQuestionAlternative"); + + b.Navigation("Section"); + }); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.Forms.FormSection", b => + { + b.HasOne("CO.CDP.OrganisationInformation.Persistence.Forms.Form", "Form") + .WithMany("Sections") + .HasForeignKey("FormId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_form_sections_forms_form_id"); + + b.Navigation("Form"); + }); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.Forms.SharedConsent", b => + { + b.HasOne("CO.CDP.OrganisationInformation.Persistence.Forms.Form", "Form") + .WithMany() + .HasForeignKey("FormId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_shared_consents_forms_form_id"); + + b.HasOne("CO.CDP.OrganisationInformation.Persistence.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_shared_consents_organisations_organisation_id"); + + b.Navigation("Form"); + + b.Navigation("Organisation"); + }); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.Organisation", b => + { + b.HasOne("CO.CDP.OrganisationInformation.Persistence.Tenant", "Tenant") + .WithMany("Organisations") + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_organisations_tenants_tenant_id"); + + b.OwnsOne("CO.CDP.OrganisationInformation.Persistence.Organisation+BuyerInformation", "BuyerInfo", b1 => + { + b1.Property("OrganisationId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("BuyerType") + .HasColumnType("text") + .HasColumnName("buyer_type"); + + b1.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b1.Property("DevolvedRegulations") + .IsRequired() + .HasColumnType("integer[]") + .HasColumnName("devolved_regulations"); + + b1.Property("UpdatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b1.HasKey("OrganisationId") + .HasName("pk_buyer_information"); + + b1.ToTable("buyer_information", (string)null); + + b1.WithOwner() + .HasForeignKey("OrganisationId") + .HasConstraintName("fk_buyer_information_organisations_id"); + }); + + b.OwnsMany("CO.CDP.OrganisationInformation.Persistence.Organisation+ContactPoint", "ContactPoints", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property("Id")); + + b1.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b1.Property("Email") + .HasColumnType("text") + .HasColumnName("email"); + + b1.Property("Name") + .HasColumnType("text") + .HasColumnName("name"); + + b1.Property("OrganisationId") + .HasColumnType("integer") + .HasColumnName("organisation_id"); + + b1.Property("Telephone") + .HasColumnType("text") + .HasColumnName("telephone"); + + b1.Property("UpdatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b1.Property("Url") + .HasColumnType("text") + .HasColumnName("url"); + + b1.HasKey("Id") + .HasName("pk_contact_points"); + + b1.HasIndex("OrganisationId") + .HasDatabaseName("ix_contact_points_organisation_id"); + + b1.ToTable("contact_points", (string)null); + + b1.WithOwner() + .HasForeignKey("OrganisationId") + .HasConstraintName("fk_contact_points_organisations_organisation_id"); + }); + + b.OwnsMany("CO.CDP.OrganisationInformation.Persistence.Organisation+Identifier", "Identifiers", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property("Id")); + + b1.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b1.Property("IdentifierId") + .HasColumnType("text") + .HasColumnName("identifier_id"); + + b1.Property("LegalName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("legal_name"); + + b1.Property("OrganisationId") + .HasColumnType("integer") + .HasColumnName("organisation_id"); + + b1.Property("Primary") + .HasColumnType("boolean") + .HasColumnName("primary"); + + b1.Property("Scheme") + .IsRequired() + .HasColumnType("text") + .HasColumnName("scheme"); + + b1.Property("UpdatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b1.Property("Uri") + .HasColumnType("text") + .HasColumnName("uri"); + + b1.HasKey("Id") + .HasName("pk_identifiers"); + + b1.HasIndex("OrganisationId") + .HasDatabaseName("ix_identifiers_organisation_id"); + + b1.HasIndex("IdentifierId", "Scheme") + .IsUnique() + .HasDatabaseName("ix_identifiers_identifier_id_scheme"); + + b1.ToTable("identifiers", (string)null); + + b1.WithOwner() + .HasForeignKey("OrganisationId") + .HasConstraintName("fk_identifiers_organisations_organisation_id"); + }); + + b.OwnsMany("CO.CDP.OrganisationInformation.Persistence.Organisation+OrganisationAddress", "Addresses", b1 => + { + b1.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b1.Property("Id")); + + b1.Property("AddressId") + .HasColumnType("integer") + .HasColumnName("address_id"); + + b1.Property("OrganisationId") + .HasColumnType("integer") + .HasColumnName("organisation_id"); + + b1.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b1.HasKey("Id") + .HasName("pk_organisation_address"); + + b1.HasIndex("AddressId") + .HasDatabaseName("ix_organisation_address_address_id"); + + b1.HasIndex("OrganisationId") + .HasDatabaseName("ix_organisation_address_organisation_id"); + + b1.ToTable("organisation_address", (string)null); + + b1.HasOne("CO.CDP.OrganisationInformation.Persistence.Address", "Address") + .WithMany() + .HasForeignKey("AddressId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_organisation_address_address_address_id"); + + b1.WithOwner() + .HasForeignKey("OrganisationId") + .HasConstraintName("fk_organisation_address_organisations_organisation_id"); + + b1.Navigation("Address"); + }); + + b.OwnsOne("CO.CDP.OrganisationInformation.Persistence.Organisation+SupplierInformation", "SupplierInfo", b1 => + { + b1.Property("OrganisationId") + .HasColumnType("integer") + .HasColumnName("id"); + + b1.Property("CompletedConnectedPerson") + .HasColumnType("boolean") + .HasColumnName("completed_connected_person"); + + b1.Property("CompletedEmailAddress") + .HasColumnType("boolean") + .HasColumnName("completed_email_address"); + + b1.Property("CompletedLegalForm") + .HasColumnType("boolean") + .HasColumnName("completed_legal_form"); + + b1.Property("CompletedOperationType") + .HasColumnType("boolean") + .HasColumnName("completed_operation_type"); + + b1.Property("CompletedPostalAddress") + .HasColumnType("boolean") + .HasColumnName("completed_postal_address"); + + b1.Property("CompletedQualification") + .HasColumnType("boolean") + .HasColumnName("completed_qualification"); + + b1.Property("CompletedRegAddress") + .HasColumnType("boolean") + .HasColumnName("completed_reg_address"); + + b1.Property("CompletedTradeAssurance") + .HasColumnType("boolean") + .HasColumnName("completed_trade_assurance"); + + b1.Property("CompletedVat") + .HasColumnType("boolean") + .HasColumnName("completed_vat"); + + b1.Property("CompletedWebsiteAddress") + .HasColumnType("boolean") + .HasColumnName("completed_website_address"); + + b1.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b1.Property("OperationTypes") + .IsRequired() + .HasColumnType("integer[]") + .HasColumnName("operation_types"); + + b1.Property("SupplierType") + .HasColumnType("integer") + .HasColumnName("supplier_type"); + + b1.Property("UpdatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b1.HasKey("OrganisationId") + .HasName("pk_supplier_information"); + + b1.ToTable("supplier_information", (string)null); + + b1.WithOwner() + .HasForeignKey("OrganisationId") + .HasConstraintName("fk_supplier_information_organisations_id"); + + b1.OwnsOne("CO.CDP.OrganisationInformation.Persistence.Organisation+LegalForm", "LegalForm", b2 => + { + b2.Property("SupplierInformationOrganisationId") + .HasColumnType("integer") + .HasColumnName("id"); + + b2.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b2.Property("LawRegistered") + .IsRequired() + .HasColumnType("text") + .HasColumnName("law_registered"); + + b2.Property("RegisteredLegalForm") + .IsRequired() + .HasColumnType("text") + .HasColumnName("registered_legal_form"); + + b2.Property("RegisteredUnderAct2006") + .HasColumnType("boolean") + .HasColumnName("registered_under_act2006"); + + b2.Property("RegistrationDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("registration_date"); + + b2.Property("UpdatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b2.HasKey("SupplierInformationOrganisationId") + .HasName("pk_legal_forms"); + + b2.ToTable("legal_forms", (string)null); + + b2.WithOwner() + .HasForeignKey("SupplierInformationOrganisationId") + .HasConstraintName("fk_legal_forms_supplier_information_id"); + }); + + b1.OwnsMany("CO.CDP.OrganisationInformation.Persistence.Organisation+Qualification", "Qualifications", b2 => + { + b2.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b2.Property("Id")); + + b2.Property("AwardedByPersonOrBodyName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("awarded_by_person_or_body_name"); + + b2.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b2.Property("DateAwarded") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_awarded"); + + b2.Property("Guid") + .HasColumnType("uuid") + .HasColumnName("guid"); + + b2.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b2.Property("SupplierInformationOrganisationId") + .HasColumnType("integer") + .HasColumnName("supplier_information_organisation_id"); + + b2.Property("UpdatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b2.HasKey("Id") + .HasName("pk_qualifications"); + + b2.HasIndex("Guid") + .IsUnique() + .HasDatabaseName("ix_qualifications_guid"); + + b2.HasIndex("SupplierInformationOrganisationId") + .HasDatabaseName("ix_qualifications_supplier_information_organisation_id"); + + b2.ToTable("qualifications", (string)null); + + b2.WithOwner() + .HasForeignKey("SupplierInformationOrganisationId") + .HasConstraintName("fk_qualifications_supplier_information_supplier_information_or"); + }); + + b1.OwnsMany("CO.CDP.OrganisationInformation.Persistence.Organisation+TradeAssurance", "TradeAssurances", b2 => + { + b2.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b2.Property("Id")); + + b2.Property("AwardedByPersonOrBodyName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("awarded_by_person_or_body_name"); + + b2.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b2.Property("DateAwarded") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_awarded"); + + b2.Property("Guid") + .HasColumnType("uuid") + .HasColumnName("guid"); + + b2.Property("ReferenceNumber") + .IsRequired() + .HasColumnType("text") + .HasColumnName("reference_number"); + + b2.Property("SupplierInformationOrganisationId") + .HasColumnType("integer") + .HasColumnName("supplier_information_organisation_id"); + + b2.Property("UpdatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b2.HasKey("Id") + .HasName("pk_trade_assurances"); + + b2.HasIndex("Guid") + .IsUnique() + .HasDatabaseName("ix_trade_assurances_guid"); + + b2.HasIndex("SupplierInformationOrganisationId") + .HasDatabaseName("ix_trade_assurances_supplier_information_organisation_id"); + + b2.ToTable("trade_assurances", (string)null); + + b2.WithOwner() + .HasForeignKey("SupplierInformationOrganisationId") + .HasConstraintName("fk_trade_assurances_supplier_information_supplier_information_"); + }); + + b1.Navigation("LegalForm"); + + b1.Navigation("Qualifications"); + + b1.Navigation("TradeAssurances"); + }); + + b.Navigation("Addresses"); + + b.Navigation("BuyerInfo"); + + b.Navigation("ContactPoints"); + + b.Navigation("Identifiers"); + + b.Navigation("SupplierInfo"); + + b.Navigation("Tenant"); + }); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.OrganisationPerson", b => + { + b.HasOne("CO.CDP.OrganisationInformation.Persistence.Organisation", "Organisation") + .WithMany("OrganisationPersons") + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_organisation_person_organisations_organisation_id"); + + b.HasOne("CO.CDP.OrganisationInformation.Persistence.Person", "Person") + .WithMany("PersonOrganisations") + .HasForeignKey("PersonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_organisation_person_persons_person_id"); + + b.Navigation("Organisation"); + + b.Navigation("Person"); + }); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.TenantPerson", b => + { + b.HasOne("CO.CDP.OrganisationInformation.Persistence.Person", null) + .WithMany() + .HasForeignKey("PersonId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_tenant_person_persons_person_id"); + + b.HasOne("CO.CDP.OrganisationInformation.Persistence.Tenant", null) + .WithMany() + .HasForeignKey("TenantId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_tenant_person_tenants_tenant_id"); + }); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.Forms.Form", b => + { + b.Navigation("Sections"); + }); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.Forms.FormAnswerSet", b => + { + b.Navigation("Answers"); + }); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.Forms.FormSection", b => + { + b.Navigation("Questions"); + }); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.Forms.SharedConsent", b => + { + b.Navigation("AnswerSets"); + }); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.Organisation", b => + { + b.Navigation("OrganisationPersons"); + }); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.Person", b => + { + b.Navigation("PersonOrganisations"); + }); + + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.Tenant", b => + { + b.Navigation("Organisations"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Services/CO.CDP.OrganisationInformation.Persistence/Migrations/20240822151919_AddSharerCodetoSharedConsents.cs b/Services/CO.CDP.OrganisationInformation.Persistence/Migrations/20240822151919_AddSharerCodetoSharedConsents.cs new file mode 100644 index 000000000..c90ac883d --- /dev/null +++ b/Services/CO.CDP.OrganisationInformation.Persistence/Migrations/20240822151919_AddSharerCodetoSharedConsents.cs @@ -0,0 +1,28 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace CO.CDP.OrganisationInformation.Persistence.Migrations +{ + /// + public partial class AddSharerCodetoSharedConsents : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "share_code", + table: "shared_consents", + type: "text", + nullable: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "share_code", + table: "shared_consents"); + } + } +} diff --git a/Services/CO.CDP.OrganisationInformation.Persistence/Migrations/OrganisationInformationContextModelSnapshot.cs b/Services/CO.CDP.OrganisationInformation.Persistence/Migrations/OrganisationInformationContextModelSnapshot.cs index d9a0d7dc2..9f87e7622 100644 --- a/Services/CO.CDP.OrganisationInformation.Persistence/Migrations/OrganisationInformationContextModelSnapshot.cs +++ b/Services/CO.CDP.OrganisationInformation.Persistence/Migrations/OrganisationInformationContextModelSnapshot.cs @@ -559,6 +559,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("integer") .HasColumnName("organisation_id"); + b.Property("ShareCode") + .HasColumnType("text") + .HasColumnName("share_code"); + b.Property("SubmissionState") .HasColumnType("integer") .HasColumnName("submission_state"); From 880a1f9ffd557d85b6b54d9f707a66a617bc534d Mon Sep 17 00:00:00 2001 From: Gavin Lilley Date: Fri, 23 Aug 2024 10:56:12 +0100 Subject: [PATCH 2/4] DP-516 post rebase fixes --- .../CO.CDP.DataSharing.WebApi/AutoMapper/DataSharingProfile.cs | 3 +-- .../ShareCodeRepositoryTest.cs | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Services/CO.CDP.DataSharing.WebApi/AutoMapper/DataSharingProfile.cs b/Services/CO.CDP.DataSharing.WebApi/AutoMapper/DataSharingProfile.cs index c013592f8..fbac7571c 100644 --- a/Services/CO.CDP.DataSharing.WebApi/AutoMapper/DataSharingProfile.cs +++ b/Services/CO.CDP.DataSharing.WebApi/AutoMapper/DataSharingProfile.cs @@ -1,6 +1,5 @@ using AutoMapper; using CO.CDP.DataSharing.WebApi.Model; -using CO.CDP.OrganisationInformation.Persistence.Forms; using Persistence = CO.CDP.OrganisationInformation.Persistence.Forms; namespace CO.CDP.DataSharing.WebApi.AutoMapper; @@ -48,7 +47,7 @@ public class CustomResolver : IValueResolver{source.Locality}
{source.PostalCode}
{source.Region}
{source.CountryName}"; } diff --git a/Services/CO.CDP.OrganisationInformation.Persistence.Tests/ShareCodeRepositoryTest.cs b/Services/CO.CDP.OrganisationInformation.Persistence.Tests/ShareCodeRepositoryTest.cs index 13f189f9a..b8005adfc 100644 --- a/Services/CO.CDP.OrganisationInformation.Persistence.Tests/ShareCodeRepositoryTest.cs +++ b/Services/CO.CDP.OrganisationInformation.Persistence.Tests/ShareCodeRepositoryTest.cs @@ -250,7 +250,9 @@ private static FormAnswer GivenAnswer(FormQuestion question, FormAnswerSet answe var answer = new FormAnswer { Guid = Guid.NewGuid(), + QuestionId = question.Id, Question = question, + FormAnswerSetId = answerSet.Id, FormAnswerSet = answerSet, BoolValue = true }; From a9a5b388b3acabf76fd1ee9031148cc5e6b80494 Mon Sep 17 00:00:00 2001 From: Gavin Lilley Date: Fri, 23 Aug 2024 13:42:12 +0100 Subject: [PATCH 3/4] DP-516 replace BookingReference with ShareCode --- .../EntityFactory.cs | 2 +- .../UseCase/GetShareCodeDetailsUseCaseTest.cs | 2 - .../UseCase/GetShareCodesUseCaseTest.cs | 6 +- .../AutoMapper/DataSharingProfile.cs | 6 +- .../CO.CDP.DataSharing.WebApi/Model/Form.cs | 2 +- .../UseCase/GenerateShareCodeUseCase.cs | 2 +- .../UpdateFormSectionAnswersUseCaseTest.cs | 4 +- .../Model/SharedConsent.cs | 4 +- .../DatabaseFormRepositoryTest.cs | 8 +- .../ShareCodeRepositoryTest.cs | 110 +++++++++--------- .../DatabaseFormRepository.cs | 10 +- .../DatabaseShareCodeRepository.cs | 3 +- .../Forms/FormAnswer.cs | 3 +- ...ithSharerCodeInSharedConsents.Designer.cs} | 101 +++++++++++++++- ...okingRefWithSharerCodeInSharedConsents.cs} | 14 +-- ...nisationInformationContextModelSnapshot.cs | 92 +++++++-------- 16 files changed, 224 insertions(+), 145 deletions(-) rename Services/CO.CDP.OrganisationInformation.Persistence/Migrations/{20240822151919_AddSharerCodetoSharedConsents.Designer.cs => 20240823120456_ReplaceBookingRefWithSharerCodeInSharedConsents.Designer.cs} (95%) rename Services/CO.CDP.OrganisationInformation.Persistence/Migrations/{20240822151919_AddSharerCodetoSharedConsents.cs => 20240823120456_ReplaceBookingRefWithSharerCodeInSharedConsents.cs} (58%) diff --git a/Services/CO.CDP.DataSharing.WebApi.Tests/EntityFactory.cs b/Services/CO.CDP.DataSharing.WebApi.Tests/EntityFactory.cs index b273545a8..bb405a3f8 100644 --- a/Services/CO.CDP.DataSharing.WebApi.Tests/EntityFactory.cs +++ b/Services/CO.CDP.DataSharing.WebApi.Tests/EntityFactory.cs @@ -48,7 +48,7 @@ internal static OrganisationInformation.Persistence.Forms.SharedConsent GetShare SubmissionState = SubmissionState.Draft, SubmittedAt = DateTime.UtcNow, FormVersionId = string.Empty, - BookingReference = string.Empty + ShareCode = string.Empty }; } } diff --git a/Services/CO.CDP.DataSharing.WebApi.Tests/UseCase/GetShareCodeDetailsUseCaseTest.cs b/Services/CO.CDP.DataSharing.WebApi.Tests/UseCase/GetShareCodeDetailsUseCaseTest.cs index b9b29b2cb..f34fed60a 100644 --- a/Services/CO.CDP.DataSharing.WebApi.Tests/UseCase/GetShareCodeDetailsUseCaseTest.cs +++ b/Services/CO.CDP.DataSharing.WebApi.Tests/UseCase/GetShareCodeDetailsUseCaseTest.cs @@ -1,10 +1,8 @@ -using CO.CDP.DataSharing.WebApi.Model; using CO.CDP.DataSharing.WebApi.UseCase; using CO.CDP.DataSharing.WebApi.Tests.AutoMapper; using CO.CDP.OrganisationInformation.Persistence; using FluentAssertions; using Moq; -using CO.CDP.OrganisationInformation.Persistence.Forms; using CO.CDP.DataSharing.WebApi.Extensions; diff --git a/Services/CO.CDP.DataSharing.WebApi.Tests/UseCase/GetShareCodesUseCaseTest.cs b/Services/CO.CDP.DataSharing.WebApi.Tests/UseCase/GetShareCodesUseCaseTest.cs index de865a59b..c2e5821e2 100644 --- a/Services/CO.CDP.DataSharing.WebApi.Tests/UseCase/GetShareCodesUseCaseTest.cs +++ b/Services/CO.CDP.DataSharing.WebApi.Tests/UseCase/GetShareCodesUseCaseTest.cs @@ -32,7 +32,7 @@ public async Task ItReturnsTheSharedCodeList() var sharedConsent = EntityFactory.GetSharedConsent(organisationId: organisationId, organisationGuid: organisationGuid, formId: formId); var shareCode = ShareCodeExtensions.GenerateShareCode(); - sharedConsent.BookingReference = shareCode; + sharedConsent.ShareCode = shareCode; sharedConsent.SubmissionState = SubmissionState.Submitted; sharedConsent.SubmittedAt = DateTime.UtcNow; @@ -43,7 +43,7 @@ public async Task ItReturnsTheSharedCodeList() result?.Should().NotBeEmpty(); result?.Should().HaveCount(1); - result?.First().As().SubmittedAt.Should().Be(sharedConsent.SubmittedAt); - result?.First().As().ShareCode.Should().Be(sharedConsent.BookingReference); + result?.First().As().SubmittedAt.Should().Be(sharedConsent.SubmittedAt); + result?.First().As().ShareCode.Should().Be(sharedConsent.ShareCode); } } \ No newline at end of file diff --git a/Services/CO.CDP.DataSharing.WebApi/AutoMapper/DataSharingProfile.cs b/Services/CO.CDP.DataSharing.WebApi/AutoMapper/DataSharingProfile.cs index fbac7571c..46ca2cae2 100644 --- a/Services/CO.CDP.DataSharing.WebApi/AutoMapper/DataSharingProfile.cs +++ b/Services/CO.CDP.DataSharing.WebApi/AutoMapper/DataSharingProfile.cs @@ -10,12 +10,10 @@ public DataSharingProfile() { CreateMap() .ForMember(m => m.FormId, o => o.MapFrom(m => m.Guid)) - .ForMember(m => m.FormVersionId, o => o.MapFrom(m => m.FormVersionId)) - .ForMember(m => m.ShareCode, o => o.MapFrom(m => m.BookingReference)); + .ForMember(m => m.FormVersionId, o => o.MapFrom(m => m.FormVersionId)); CreateMap() - .ForMember(m => m.SubmittedAt, o => o.MapFrom(m => m.SubmittedAt)) - .ForMember(m => m.ShareCode, o => o.MapFrom(m => m.BookingReference)); + .ForMember(m => m.SubmittedAt, o => o.MapFrom(m => m.SubmittedAt)); CreateMap() .ForMember(m => m.QuestionId, o => o.MapFrom(m => m.QuestionId)) diff --git a/Services/CO.CDP.DataSharing.WebApi/Model/Form.cs b/Services/CO.CDP.DataSharing.WebApi/Model/Form.cs index c033dd735..d2392d2ee 100644 --- a/Services/CO.CDP.DataSharing.WebApi/Model/Form.cs +++ b/Services/CO.CDP.DataSharing.WebApi/Model/Form.cs @@ -33,7 +33,7 @@ public record Form public required bool IsRequired { get; init; } /// "AGMT-2024-XYZ" - public required string BookingReference { get; init; } + public required string ShareCode { get; init; } /// 0 public required int Scope { get; init; } diff --git a/Services/CO.CDP.DataSharing.WebApi/UseCase/GenerateShareCodeUseCase.cs b/Services/CO.CDP.DataSharing.WebApi/UseCase/GenerateShareCodeUseCase.cs index 55aa89405..ce5dfee1d 100644 --- a/Services/CO.CDP.DataSharing.WebApi/UseCase/GenerateShareCodeUseCase.cs +++ b/Services/CO.CDP.DataSharing.WebApi/UseCase/GenerateShareCodeUseCase.cs @@ -30,7 +30,7 @@ public async Task Execute(ShareRequest shareRequest) } var shareCode = ShareCodeExtensions.GenerateShareCode(); - result.BookingReference = shareCode; + result.ShareCode = shareCode; result.SubmittedAt = DateTime.UtcNow; result.SubmissionState = SubmissionState.Submitted; diff --git a/Services/CO.CDP.Forms.WebApi.Tests/UseCase/UpdateFormSectionAnswersUseCaseTest.cs b/Services/CO.CDP.Forms.WebApi.Tests/UseCase/UpdateFormSectionAnswersUseCaseTest.cs index 64d5a68da..424f400b4 100644 --- a/Services/CO.CDP.Forms.WebApi.Tests/UseCase/UpdateFormSectionAnswersUseCaseTest.cs +++ b/Services/CO.CDP.Forms.WebApi.Tests/UseCase/UpdateFormSectionAnswersUseCaseTest.cs @@ -301,7 +301,7 @@ Persistence.Form form SubmissionState = Persistence.SubmissionState.Draft, SubmittedAt = null, FormVersionId = "202405", - BookingReference = null + ShareCode = null }; } -} \ No newline at end of file +} diff --git a/Services/CO.CDP.Forms.WebApi/Model/SharedConsent.cs b/Services/CO.CDP.Forms.WebApi/Model/SharedConsent.cs index 7e8d98fcb..657c9257d 100644 --- a/Services/CO.CDP.Forms.WebApi/Model/SharedConsent.cs +++ b/Services/CO.CDP.Forms.WebApi/Model/SharedConsent.cs @@ -10,7 +10,7 @@ public class SharedConsent public SubmissionState SubmissionState { get; set; } public DateTimeOffset SubmittedAt { get; set; } public string? FormVersionId { get; set; } - public string? BookingReference { get; set; } + public string? ShareCode { get; set; } } @@ -19,4 +19,4 @@ public enum SubmissionState { Draft, Submitted -} \ No newline at end of file +} diff --git a/Services/CO.CDP.OrganisationInformation.Persistence.Tests/DatabaseFormRepositoryTest.cs b/Services/CO.CDP.OrganisationInformation.Persistence.Tests/DatabaseFormRepositoryTest.cs index dd3018a96..88720036f 100644 --- a/Services/CO.CDP.OrganisationInformation.Persistence.Tests/DatabaseFormRepositoryTest.cs +++ b/Services/CO.CDP.OrganisationInformation.Persistence.Tests/DatabaseFormRepositoryTest.cs @@ -209,7 +209,7 @@ public async Task GetSharedConsentDraftWithAnswersAsync_WhenSharedConsentDoesExi found.Should().NotBeNull(); found.As().OrganisationId.Should().Be(sharedConsent.OrganisationId); found.As().SubmissionState.Should().Be(SubmissionState.Draft); - found.As().BookingReference.Should().BeNull(); + found.As().ShareCode.Should().BeNull(); } [Fact] @@ -575,7 +575,7 @@ public async Task UpdateFormAnswerSet_ShouldUpdateExistingAnswerSet() SubmissionState = SubmissionState.Draft, SubmittedAt = DateTimeOffset.UtcNow, FormVersionId = "1.0", - BookingReference = string.Empty, + ShareCode = string.Empty, CreatedOn = DateTimeOffset.UtcNow, UpdatedOn = DateTimeOffset.UtcNow }; @@ -750,7 +750,7 @@ private static SharedConsent GivenSharedConsent( SubmissionState = SubmissionState.Draft, SubmittedAt = null, FormVersionId = "202404", - BookingReference = null + ShareCode = null }; } @@ -812,4 +812,4 @@ private IOrganisationRepository OrganisationRepository() { return new DatabaseOrganisationRepository(postgreSql.OrganisationInformationContext()); } -} \ No newline at end of file +} diff --git a/Services/CO.CDP.OrganisationInformation.Persistence.Tests/ShareCodeRepositoryTest.cs b/Services/CO.CDP.OrganisationInformation.Persistence.Tests/ShareCodeRepositoryTest.cs index b8005adfc..6a98f6334 100644 --- a/Services/CO.CDP.OrganisationInformation.Persistence.Tests/ShareCodeRepositoryTest.cs +++ b/Services/CO.CDP.OrganisationInformation.Persistence.Tests/ShareCodeRepositoryTest.cs @@ -34,7 +34,7 @@ public async Task GetSharedConsentDraftAsync_WhenItDoesExist_ReturnsIt() found.Should().NotBeNull(); found.As().OrganisationId.Should().Be(sharedConsent.OrganisationId); found.As().SubmissionState.Should().Be(SubmissionState.Draft); - found.As().BookingReference.Should().BeNull(); + found.As().ShareCode.Should().BeNull(); } [Fact] @@ -54,7 +54,7 @@ public async Task GetShareCodesAsync_WhenCodesExist_ReturnsList() Random rand = new Random(); var bookingref = rand.Next(10000000, 99999999).ToString(); - sharedConsent.BookingReference = bookingref; + sharedConsent.ShareCode = bookingref; sharedConsent.SubmissionState = SubmissionState.Submitted; sharedConsent.SubmittedAt = DateTime.UtcNow; @@ -71,7 +71,7 @@ public async Task GetShareCodesAsync_WhenCodesExist_ReturnsList() found.First().As().OrganisationId.Should().Be(sharedConsent.OrganisationId); found.First().As().SubmissionState.Should().Be(SubmissionState.Submitted); - found.First().As().BookingReference.Should().Be(bookingref); + found.First().As().ShareCode.Should().Be(bookingref); } @@ -98,7 +98,7 @@ public async Task GetByShareCode_WhenShareCodeExists_ReturnsSharedConsent() sharedConsent.SubmissionState = SubmissionState.Submitted; sharedConsent.SubmittedAt = DateTime.UtcNow; var shareCode = "EXISTENTCODE"; - sharedConsent.BookingReference = shareCode; + sharedConsent.ShareCode = shareCode; await using var context = postgreSql.OrganisationInformationContext(); await context.SharedConsents.AddAsync(sharedConsent); @@ -109,9 +109,9 @@ public async Task GetByShareCode_WhenShareCodeExists_ReturnsSharedConsent() var foundConsent = await repository.GetByShareCode(shareCode); foundConsent.Should().NotBeNull(); - foundConsent!.BookingReference.Should().Be(shareCode); - foundConsent.Organisation.Name.Should().StartWith("Acme Corporation"); - foundConsent.Organisation.Identifiers.Should().ContainSingle(i => i.LegalName == "Acme Corporation Ltd"); + foundConsent!.ShareCode.Should().Be(shareCode); + foundConsent.Organisation.Name.Should().StartWith("New Corporation"); + foundConsent.Organisation.Identifiers.Should().ContainSingle(i => i.LegalName == "New Corporation Ltd"); foundConsent.Organisation.ContactPoints.Should().ContainSingle(cp => cp.Name == "Procurement Team"); var registeredAddress = foundConsent.Organisation.Addresses.FirstOrDefault(a => a.Type == AddressType.Registered); @@ -152,7 +152,7 @@ private static SharedConsent GivenSharedConsent( SubmissionState = SubmissionState.Draft, SubmittedAt = null, FormVersionId = "202404", - BookingReference = null + ShareCode = null }; } @@ -168,52 +168,6 @@ private static Form GivenForm(Guid formId) Sections = new List() }; } - - private static Organisation GivenOrganisation() - { - return new Organisation - { - Guid = Guid.NewGuid(), - Name = "Acme Corporation " + Guid.NewGuid().ToString(), // Ensure unique name - Tenant = GivenTenant(), - Identifiers = new List - { - new Organisation.Identifier - { - IdentifierId = Guid.NewGuid().ToString(), // Generate a unique IdentifierId - Scheme = "CDP-PPON", - LegalName = "Acme Corporation Ltd", - Uri = "https://cdp.cabinetoffice.gov.uk/organisations/" + Guid.NewGuid().ToString(), // Ensure unique URI - Primary = true - } - }, - ContactPoints = new List - { - new Organisation.ContactPoint - { - Name = "Procurement Team", - Email = "info@example.com", - Telephone = "+441234567890" - } - }, - Addresses = new List - { - new Organisation.OrganisationAddress - { - Type = AddressType.Registered, - Address = new OrganisationInformation.Persistence.Address - { - StreetAddress = "82 St. John’s Road", - Locality = "CHESTER", - Region = "Lancashire", - PostalCode = "CH43 7UR", - CountryName = "United Kingdom" - } - } - } - }; - } - private static Tenant GivenTenant() { return new Tenant @@ -294,8 +248,54 @@ private static FormQuestion GivenYesOrNoQuestion(FormSection section) return question; } + private static Organisation GivenOrganisation() + { + return new Organisation + { + Guid = Guid.NewGuid(), + Name = "New Corporation " + Guid.NewGuid().ToString(), + Tenant = GivenTenant(), + Identifiers = new List + { + new Organisation.Identifier + { + IdentifierId = Guid.NewGuid().ToString(), + Scheme = "CDP-PPON", + LegalName = "New Corporation Ltd", + Uri = "https://cdp.cabinetoffice.gov.uk/organisations/" + Guid.NewGuid().ToString(), + Primary = true + } + }, + ContactPoints = new List + { + new Organisation.ContactPoint + { + Name = "Procurement Team", + Email = "info@example.com", + Telephone = "+441234567890" + } + }, + Addresses = new List + { + new Organisation.OrganisationAddress + { + Type = AddressType.Registered, + Address = new OrganisationInformation.Persistence.Address + { + StreetAddress = "82 St. John’s Road", + Locality = "CHESTER", + Region = "Lancashire", + PostalCode = "CH43 7UR", + CountryName = "United Kingdom" + } + } + } + }; + } + + private IShareCodeRepository ShareCodeRepository() { return new DatabaseShareCodeRepository(postgreSql.OrganisationInformationContext()); } -} \ No newline at end of file +} diff --git a/Services/CO.CDP.OrganisationInformation.Persistence/DatabaseFormRepository.cs b/Services/CO.CDP.OrganisationInformation.Persistence/DatabaseFormRepository.cs index 5bfdf95e4..fd13e9c06 100644 --- a/Services/CO.CDP.OrganisationInformation.Persistence/DatabaseFormRepository.cs +++ b/Services/CO.CDP.OrganisationInformation.Persistence/DatabaseFormRepository.cs @@ -95,12 +95,12 @@ join o in context.Organisations on s.OrganisationId equals o.Id fs.Type == FormSectionType.Declaration && fas.Deleted == false && o.Guid == organisationId - && s.BookingReference == shareCode + && s.ShareCode == shareCode select new { FormAnswerSetId = fas.Id, FormAnswerSetUpdate=fas.UpdatedOn, - s.BookingReference, + s.ShareCode, s.SubmittedAt, QuestionId = fq.Guid, QuestionType = fq.Type, @@ -109,12 +109,12 @@ join o in context.Organisations on s.OrganisationId equals o.Id }; var data = await query.ToListAsync(); - var sharedCodeResult = data.OrderByDescending(x=>x.FormAnswerSetUpdate).GroupBy(g => new { g.BookingReference, g.FormAnswerSetId, g.SubmittedAt }).FirstOrDefault(); + var sharedCodeResult = data.OrderByDescending(x=>x.FormAnswerSetUpdate).GroupBy(g => new { g.ShareCode, g.FormAnswerSetId, g.SubmittedAt }).FirstOrDefault(); if (sharedCodeResult == null) return null; return new SharedConsentDetails { - ShareCode = sharedCodeResult.Key.BookingReference, + ShareCode = sharedCodeResult.Key.ShareCode, SubmittedAt = sharedCodeResult.Key.SubmittedAt!.Value, QuestionAnswers = sharedCodeResult.Select(a => new SharedConsentQuestionAnswer @@ -197,4 +197,4 @@ private static void HandleDbUpdateException(FormAnswerSet answerSet, DbUpdateExc throw cause; } } -} \ No newline at end of file +} diff --git a/Services/CO.CDP.OrganisationInformation.Persistence/DatabaseShareCodeRepository.cs b/Services/CO.CDP.OrganisationInformation.Persistence/DatabaseShareCodeRepository.cs index f62e15a29..382a10856 100644 --- a/Services/CO.CDP.OrganisationInformation.Persistence/DatabaseShareCodeRepository.cs +++ b/Services/CO.CDP.OrganisationInformation.Persistence/DatabaseShareCodeRepository.cs @@ -22,7 +22,7 @@ public async Task> GetShareCodesAsync(Guid organisati public async Task GetByShareCode(string sharecode) { return await context.SharedConsents - .Where(sc => sc.BookingReference == sharecode) + .Where(sc => sc.ShareCode == sharecode) .Include(sc => sc.Organisation) .ThenInclude(o => o.Identifiers) .Include(sc => sc.Organisation) @@ -41,7 +41,6 @@ public async Task> GetShareCodesAsync(Guid organisati .FirstOrDefaultAsync(); } - public void Dispose() { context.Dispose(); diff --git a/Services/CO.CDP.OrganisationInformation.Persistence/Forms/FormAnswer.cs b/Services/CO.CDP.OrganisationInformation.Persistence/Forms/FormAnswer.cs index a5af98e30..0988c11be 100644 --- a/Services/CO.CDP.OrganisationInformation.Persistence/Forms/FormAnswer.cs +++ b/Services/CO.CDP.OrganisationInformation.Persistence/Forms/FormAnswer.cs @@ -19,7 +19,6 @@ public class SharedConsent : IEntityDate public required SubmissionState SubmissionState { get; set; } = SubmissionState.Draft; public DateTimeOffset? SubmittedAt { get; set; } public required string FormVersionId { get; init; } - public string? BookingReference { get; set; } public string? ShareCode { get; set; } public DateTimeOffset CreatedOn { get; set; } public DateTimeOffset UpdatedOn { get; set; } @@ -76,4 +75,4 @@ public class FormAnswerSet : IEntityDate public bool Deleted { get; set; } = false; public DateTimeOffset CreatedOn { get; set; } public DateTimeOffset UpdatedOn { get; set; } -} \ No newline at end of file +} diff --git a/Services/CO.CDP.OrganisationInformation.Persistence/Migrations/20240822151919_AddSharerCodetoSharedConsents.Designer.cs b/Services/CO.CDP.OrganisationInformation.Persistence/Migrations/20240823120456_ReplaceBookingRefWithSharerCodeInSharedConsents.Designer.cs similarity index 95% rename from Services/CO.CDP.OrganisationInformation.Persistence/Migrations/20240822151919_AddSharerCodetoSharedConsents.Designer.cs rename to Services/CO.CDP.OrganisationInformation.Persistence/Migrations/20240823120456_ReplaceBookingRefWithSharerCodeInSharedConsents.Designer.cs index d0f942e19..594be19aa 100644 --- a/Services/CO.CDP.OrganisationInformation.Persistence/Migrations/20240822151919_AddSharerCodetoSharedConsents.Designer.cs +++ b/Services/CO.CDP.OrganisationInformation.Persistence/Migrations/20240823120456_ReplaceBookingRefWithSharerCodeInSharedConsents.Designer.cs @@ -1,5 +1,6 @@ // using System; +using System.Collections.Generic; using CO.CDP.OrganisationInformation.Persistence; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; @@ -12,8 +13,8 @@ namespace CO.CDP.OrganisationInformation.Persistence.Migrations { [DbContext(typeof(OrganisationInformationContext))] - [Migration("20240822151919_AddSharerCodetoSharedConsents")] - partial class AddSharerCodetoSharedConsents + [Migration("20240823120456_ReplaceBookingRefWithSharerCodeInSharedConsents")] + partial class ReplaceBookingRefWithSharerCodeInSharedConsents { /// protected override void BuildTargetModel(ModelBuilder modelBuilder) @@ -534,10 +535,6 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - b.Property("BookingReference") - .HasColumnType("text") - .HasColumnName("booking_reference"); - b.Property("CreatedOn") .ValueGeneratedOnAdd() .HasColumnType("timestamp with time zone") @@ -745,6 +742,79 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.ToTable("persons", (string)null); }); + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.PersonInvite", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("Email") + .IsRequired() + .HasColumnType("text") + .HasColumnName("email"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("first_name"); + + b.Property("Guid") + .HasColumnType("uuid") + .HasColumnName("guid"); + + b.Property("InviteSentOn") + .HasColumnType("timestamp with time zone") + .HasColumnName("invite_sent_on"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("last_name"); + + b.Property("OrganisationId") + .HasColumnType("integer") + .HasColumnName("organisation_id"); + + b.Property("PersonId") + .HasColumnType("integer") + .HasColumnName("person_id"); + + b.Property>("Scopes") + .IsRequired() + .HasColumnType("text[]") + .HasColumnName("scopes"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.HasKey("Id") + .HasName("pk_person_invites"); + + b.HasIndex("Guid") + .IsUnique() + .HasDatabaseName("ix_person_invites_guid"); + + b.HasIndex("OrganisationId") + .HasDatabaseName("ix_person_invites_organisation_id"); + + b.HasIndex("PersonId") + .HasDatabaseName("ix_person_invites_person_id"); + + b.ToTable("person_invites", (string)null); + }); + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.RefreshToken", b => { b.Property("Id") @@ -1642,6 +1712,25 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) b.Navigation("Person"); }); + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.PersonInvite", b => + { + b.HasOne("CO.CDP.OrganisationInformation.Persistence.Organisation", "Organisation") + .WithMany() + .HasForeignKey("OrganisationId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_person_invites_organisations_organisation_id"); + + b.HasOne("CO.CDP.OrganisationInformation.Persistence.Person", "Person") + .WithMany() + .HasForeignKey("PersonId") + .HasConstraintName("fk_person_invites_persons_person_id"); + + b.Navigation("Organisation"); + + b.Navigation("Person"); + }); + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.TenantPerson", b => { b.HasOne("CO.CDP.OrganisationInformation.Persistence.Person", null) diff --git a/Services/CO.CDP.OrganisationInformation.Persistence/Migrations/20240822151919_AddSharerCodetoSharedConsents.cs b/Services/CO.CDP.OrganisationInformation.Persistence/Migrations/20240823120456_ReplaceBookingRefWithSharerCodeInSharedConsents.cs similarity index 58% rename from Services/CO.CDP.OrganisationInformation.Persistence/Migrations/20240822151919_AddSharerCodetoSharedConsents.cs rename to Services/CO.CDP.OrganisationInformation.Persistence/Migrations/20240823120456_ReplaceBookingRefWithSharerCodeInSharedConsents.cs index c90ac883d..dd1a24436 100644 --- a/Services/CO.CDP.OrganisationInformation.Persistence/Migrations/20240822151919_AddSharerCodetoSharedConsents.cs +++ b/Services/CO.CDP.OrganisationInformation.Persistence/Migrations/20240823120456_ReplaceBookingRefWithSharerCodeInSharedConsents.cs @@ -5,24 +5,24 @@ namespace CO.CDP.OrganisationInformation.Persistence.Migrations { /// - public partial class AddSharerCodetoSharedConsents : Migration + public partial class ReplaceBookingRefWithSharerCodeInSharedConsents : Migration { /// protected override void Up(MigrationBuilder migrationBuilder) { - migrationBuilder.AddColumn( - name: "share_code", + migrationBuilder.RenameColumn( + name: "booking_reference", table: "shared_consents", - type: "text", - nullable: true); + newName: "share_code"); } /// protected override void Down(MigrationBuilder migrationBuilder) { - migrationBuilder.DropColumn( + migrationBuilder.RenameColumn( name: "share_code", - table: "shared_consents"); + table: "shared_consents", + newName: "booking_reference"); } } } diff --git a/Services/CO.CDP.OrganisationInformation.Persistence/Migrations/OrganisationInformationContextModelSnapshot.cs b/Services/CO.CDP.OrganisationInformation.Persistence/Migrations/OrganisationInformationContextModelSnapshot.cs index 9f87e7622..9a74ab84d 100644 --- a/Services/CO.CDP.OrganisationInformation.Persistence/Migrations/OrganisationInformationContextModelSnapshot.cs +++ b/Services/CO.CDP.OrganisationInformation.Persistence/Migrations/OrganisationInformationContextModelSnapshot.cs @@ -532,10 +532,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - b.Property("BookingReference") - .HasColumnType("text") - .HasColumnName("booking_reference"); - b.Property("CreatedOn") .ValueGeneratedOnAdd() .HasColumnType("timestamp with time zone") @@ -743,50 +739,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("persons", (string)null); }); - modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.RefreshToken", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("integer") - .HasColumnName("id"); - - NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); - - b.Property("CreatedOn") - .ValueGeneratedOnAdd() - .HasColumnType("timestamp with time zone") - .HasColumnName("created_on") - .HasDefaultValueSql("CURRENT_TIMESTAMP"); - - b.Property("ExpiryDate") - .HasColumnType("timestamp with time zone") - .HasColumnName("expiry_date"); - - b.Property("Revoked") - .HasColumnType("boolean") - .HasColumnName("revoked"); - - b.Property("TokenHash") - .IsRequired() - .HasColumnType("text") - .HasColumnName("token_hash"); - - b.Property("UpdatedOn") - .ValueGeneratedOnAdd() - .HasColumnType("timestamp with time zone") - .HasColumnName("updated_on") - .HasDefaultValueSql("CURRENT_TIMESTAMP"); - - b.HasKey("Id") - .HasName("pk_refresh_tokens"); - - b.HasIndex("TokenHash") - .IsUnique() - .HasDatabaseName("ix_refresh_tokens_token_hash"); - - b.ToTable("refresh_tokens", (string)null); - }); - modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.PersonInvite", b => { b.Property("Id") @@ -860,6 +812,50 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("person_invites", (string)null); }); + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.RefreshToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.Property("ExpiryDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("expiry_date"); + + b.Property("Revoked") + .HasColumnType("boolean") + .HasColumnName("revoked"); + + b.Property("TokenHash") + .IsRequired() + .HasColumnType("text") + .HasColumnName("token_hash"); + + b.Property("UpdatedOn") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_on") + .HasDefaultValueSql("CURRENT_TIMESTAMP"); + + b.HasKey("Id") + .HasName("pk_refresh_tokens"); + + b.HasIndex("TokenHash") + .IsUnique() + .HasDatabaseName("ix_refresh_tokens_token_hash"); + + b.ToTable("refresh_tokens", (string)null); + }); + modelBuilder.Entity("CO.CDP.OrganisationInformation.Persistence.Tenant", b => { b.Property("Id") From bd3915e3e692db30857776afbc04d1912238961d Mon Sep 17 00:00:00 2001 From: Gavin Lilley Date: Fri, 23 Aug 2024 14:07:35 +0100 Subject: [PATCH 4/4] DP-516 rename tests for consistency --- ...CodeRepositoryTest.cs => DatabaseShareCodeRepositoryTest.cs} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename Services/CO.CDP.OrganisationInformation.Persistence.Tests/{ShareCodeRepositoryTest.cs => DatabaseShareCodeRepositoryTest.cs} (98%) diff --git a/Services/CO.CDP.OrganisationInformation.Persistence.Tests/ShareCodeRepositoryTest.cs b/Services/CO.CDP.OrganisationInformation.Persistence.Tests/DatabaseShareCodeRepositoryTest.cs similarity index 98% rename from Services/CO.CDP.OrganisationInformation.Persistence.Tests/ShareCodeRepositoryTest.cs rename to Services/CO.CDP.OrganisationInformation.Persistence.Tests/DatabaseShareCodeRepositoryTest.cs index 6a98f6334..3212429af 100644 --- a/Services/CO.CDP.OrganisationInformation.Persistence.Tests/ShareCodeRepositoryTest.cs +++ b/Services/CO.CDP.OrganisationInformation.Persistence.Tests/DatabaseShareCodeRepositoryTest.cs @@ -5,7 +5,7 @@ namespace CO.CDP.OrganisationInformation.Persistence.Tests; -public class ShareCodeRepositoryTest(PostgreSqlFixture postgreSql) : IClassFixture +public class DatabaseShareCodeRepositoryTest(PostgreSqlFixture postgreSql) : IClassFixture { [Fact]