From cb175805284be102a700d250a09ecd89ba8fca16 Mon Sep 17 00:00:00 2001 From: Tayyab Fayyaz Janjua Date: Fri, 3 Jan 2025 10:27:38 +0100 Subject: [PATCH 1/2] chore(clearingHouse): Integrate the Tagus Release V2 Api Ref: 1217 --- docs/api/administration-service.yaml | 27 ++- .../IRegistrationBusinessLogic.cs | 3 +- .../RegistrationBusinessLogic.cs | 10 +- .../Controllers/RegistrationController.cs | 3 +- .../ClearinghouseBusinessLogic.cs | 64 +++---- .../Extensions/UniqueIdentifiersExtension.cs | 36 ++++ .../Models/ClearinghouseResponseData.cs | 12 +- .../Models/ClearinghouseResponseStatus.cs | 15 +- .../Models/ClearinghouseTransferData.cs | 15 +- .../Clearinghouse.Library/ValidationModes.cs | 36 ++++ .../ControllerExtensions.cs | 22 +++ .../Models/ClearinghouseData.cs | 24 ++- .../Repositories/ApplicationRepository.cs | 21 ++- .../RegistrationBusinessLogicTest.cs | 21 ++- .../Controllers/RegistrationControllerTest.cs | 3 +- .../ClearinghouseEndToEndTests.cs | 20 +- .../ClearinghouseBusinessLogicTests.cs | 171 ++---------------- .../ApplicationRepositoryTests.cs | 2 +- 18 files changed, 244 insertions(+), 261 deletions(-) create mode 100644 src/externalsystems/Clearinghouse.Library/Extensions/UniqueIdentifiersExtension.cs create mode 100644 src/externalsystems/Clearinghouse.Library/ValidationModes.cs diff --git a/docs/api/administration-service.yaml b/docs/api/administration-service.yaml index 825f60efeb..614ab84341 100644 --- a/docs/api/administration-service.yaml +++ b/docs/api/administration-service.yaml @@ -6030,18 +6030,18 @@ components: ClearinghouseResponseData: type: object properties: - bpn: - type: string - status: - $ref: '#/components/schemas/ClearinghouseResponseStatus' - message: + validationMode: type: string - nullable: true + validationUnits: + type: array + items: + $ref: '#/components/schemas/ValidationUnits' additionalProperties: false ClearinghouseResponseStatus: enum: - - CONFIRM - - DECLINE + - VALID + - INVALID + - INCONCLUSIVE type: string CompanyAddressDetailData: type: object @@ -7990,6 +7990,17 @@ components: items: $ref: '#/components/schemas/ErrorDetails' additionalProperties: false + ValidationUnits: + type: object + properties: + result: + $ref: '#/components/schemas/ClearinghouseResponseStatus' + type: + type: string + message: + type: string + nullable: true + additionalProperties: false securitySchemes: Bearer: type: apiKey diff --git a/src/administration/Administration.Service/BusinessLogic/IRegistrationBusinessLogic.cs b/src/administration/Administration.Service/BusinessLogic/IRegistrationBusinessLogic.cs index 8f9e27414b..c25134ffc3 100644 --- a/src/administration/Administration.Service/BusinessLogic/IRegistrationBusinessLogic.cs +++ b/src/administration/Administration.Service/BusinessLogic/IRegistrationBusinessLogic.cs @@ -53,8 +53,9 @@ public interface IRegistrationBusinessLogic /// Processes the clearinghouse response /// /// the response data + /// BusinessPartnerNumber of the responded data /// cancellation token - Task ProcessClearinghouseResponseAsync(ClearinghouseResponseData data, CancellationToken cancellationToken); + Task ProcessClearinghouseResponseAsync(ClearinghouseResponseData data, string bpn, CancellationToken cancellationToken); /// /// Processes the dim response diff --git a/src/administration/Administration.Service/BusinessLogic/RegistrationBusinessLogic.cs b/src/administration/Administration.Service/BusinessLogic/RegistrationBusinessLogic.cs index 50b7c6afc3..6f42d430bf 100644 --- a/src/administration/Administration.Service/BusinessLogic/RegistrationBusinessLogic.cs +++ b/src/administration/Administration.Service/BusinessLogic/RegistrationBusinessLogic.cs @@ -298,18 +298,18 @@ private async Task UpdateCompanyBpnInternal(Guid applicationId, string bpn) private ProcessStepTypeId CreateWalletStep() => _settings.UseDimWallet ? ProcessStepTypeId.CREATE_DIM_WALLET : ProcessStepTypeId.CREATE_IDENTITY_WALLET; /// - public async Task ProcessClearinghouseResponseAsync(ClearinghouseResponseData data, CancellationToken cancellationToken) + public async Task ProcessClearinghouseResponseAsync(ClearinghouseResponseData data, string bpn, CancellationToken cancellationToken) { - logger.LogInformation("Process SelfDescription called with the following data {Data}", data.ToString().Replace(Environment.NewLine, string.Empty)); - var result = await portalRepositories.GetInstance().GetSubmittedApplicationIdsByBpn(data.BusinessPartnerNumber.ToUpper()).ToListAsync(cancellationToken).ConfigureAwait(false); + logger.LogInformation("Process SelfDescription called with the following data {Data} and bpn {Bpn}", data.ToString().Replace(Environment.NewLine, string.Empty), bpn.ToString().Replace(Environment.NewLine, string.Empty)); + var result = await portalRepositories.GetInstance().GetSubmittedApplicationIdsByBpn(bpn.ToUpper()).ToListAsync(cancellationToken).ConfigureAwait(false); if (!result.Any()) { - throw NotFoundException.Create(AdministrationRegistrationErrors.REGISTRATION_NOT_COMP_APP_BPN_STATUS_SUBMIT, new ErrorParameter[] { new("businessPartnerNumber", data.BusinessPartnerNumber) }); + throw NotFoundException.Create(AdministrationRegistrationErrors.REGISTRATION_NOT_COMP_APP_BPN_STATUS_SUBMIT, new ErrorParameter[] { new("businessPartnerNumber", bpn) }); } if (result.Count > 1) { - throw ConflictException.Create(AdministrationRegistrationErrors.REGISTRATION_CONFLICT_APP_STATUS_STATUS_SUBMIT_FOUND_BPN, new ErrorParameter[] { new("businessPartnerNumber", data.BusinessPartnerNumber) }); + throw ConflictException.Create(AdministrationRegistrationErrors.REGISTRATION_CONFLICT_APP_STATUS_STATUS_SUBMIT_FOUND_BPN, new ErrorParameter[] { new("businessPartnerNumber", bpn) }); } await clearinghouseBusinessLogic.ProcessEndClearinghouse(result.Single(), data, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None); diff --git a/src/administration/Administration.Service/Controllers/RegistrationController.cs b/src/administration/Administration.Service/Controllers/RegistrationController.cs index b317ec3044..4307e6a88c 100644 --- a/src/administration/Administration.Service/Controllers/RegistrationController.cs +++ b/src/administration/Administration.Service/Controllers/RegistrationController.cs @@ -27,6 +27,7 @@ using Org.Eclipse.TractusX.Portal.Backend.Framework.Models; using Org.Eclipse.TractusX.Portal.Backend.Framework.Web; using Org.Eclipse.TractusX.Portal.Backend.IssuerComponent.Library.Models; +using Org.Eclipse.TractusX.Portal.Backend.Keycloak.Authentication; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; using Org.Eclipse.TractusX.Portal.Backend.SdFactory.Library.Models; @@ -183,7 +184,7 @@ public async Task DeclineApplication([FromRoute] Guid applicati [ProducesResponseType(typeof(ErrorResponse), StatusCodes.Status404NotFound)] public async Task ProcessClearinghouseResponse([FromBody] ClearinghouseResponseData responseData, CancellationToken cancellationToken) { - await logic.ProcessClearinghouseResponseAsync(responseData, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None); + await this.WithBpn(bpn => logic.ProcessClearinghouseResponseAsync(responseData, bpn, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None)); return NoContent(); } diff --git a/src/externalsystems/Clearinghouse.Library/BusinessLogic/ClearinghouseBusinessLogic.cs b/src/externalsystems/Clearinghouse.Library/BusinessLogic/ClearinghouseBusinessLogic.cs index ccffde8768..858610637b 100644 --- a/src/externalsystems/Clearinghouse.Library/BusinessLogic/ClearinghouseBusinessLogic.cs +++ b/src/externalsystems/Clearinghouse.Library/BusinessLogic/ClearinghouseBusinessLogic.cs @@ -33,7 +33,6 @@ namespace Org.Eclipse.TractusX.Portal.Backend.Clearinghouse.Library.BusinessLogi public class ClearinghouseBusinessLogic( IPortalRepositories portalRepositories, IClearinghouseService clearinghouseService, - ICustodianBusinessLogic custodianBusinessLogic, IApplicationChecklistService checklistService, IDateTimeProvider dateTimeProvider, IOptions options) @@ -43,37 +42,7 @@ public class ClearinghouseBusinessLogic( public async Task HandleClearinghouse(IApplicationChecklistService.WorkerChecklistProcessStepData context, CancellationToken cancellationToken) { - var overwrite = context.ProcessStepTypeId switch - { - ProcessStepTypeId.START_OVERRIDE_CLEARING_HOUSE => true, - ProcessStepTypeId.START_CLEARING_HOUSE => false, - _ => throw new UnexpectedConditionException($"HandleClearingHouse called for unexpected processStepTypeId {context.ProcessStepTypeId}. Expected {ProcessStepTypeId.START_CLEARING_HOUSE} or {ProcessStepTypeId.START_OVERRIDE_CLEARING_HOUSE}") - }; - - string companyDid; - if (_settings.UseDimWallet) - { - var (exists, did) = await portalRepositories.GetInstance() - .GetDidForApplicationId(context.ApplicationId).ConfigureAwait(ConfigureAwaitOptions.None); - if (!exists || string.IsNullOrWhiteSpace(did)) - { - throw new ConflictException($"Did must be set for Application {context.ApplicationId}"); - } - - companyDid = did; - } - else - { - var walletData = await custodianBusinessLogic.GetWalletByBpnAsync(context.ApplicationId, cancellationToken); - if (walletData == null || string.IsNullOrEmpty(walletData.Did)) - { - throw new ConflictException($"Decentralized Identifier for application {context.ApplicationId} is not set"); - } - - companyDid = walletData.Did; - } - - await TriggerCompanyDataPost(context.ApplicationId, companyDid, overwrite, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None); + await TriggerCompanyDataPost(context.ApplicationId, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None); return new IApplicationChecklistService.WorkerChecklistProcessStepExecutionResult( ProcessStepStatusId.DONE, @@ -84,7 +53,7 @@ public class ClearinghouseBusinessLogic( null); } - private async Task TriggerCompanyDataPost(Guid applicationId, string decentralizedIdentifier, bool overwrite, CancellationToken cancellationToken) + private async Task TriggerCompanyDataPost(Guid applicationId, CancellationToken cancellationToken) { var data = await portalRepositories.GetInstance() .GetClearinghouseDataForApplicationId(applicationId).ConfigureAwait(ConfigureAwaitOptions.None); @@ -98,16 +67,21 @@ private async Task TriggerCompanyDataPost(Guid applicationId, string decentraliz throw new ConflictException($"CompanyApplication {applicationId} is not in status SUBMITTED"); } - if (string.IsNullOrWhiteSpace(data.ParticipantDetails.Bpn)) + if (string.IsNullOrWhiteSpace(data.Bpn)) { throw new ConflictException("BusinessPartnerNumber is null"); } + var headers = new List> + { + new("Business-Partner-Number", data.Bpn) + }.AsEnumerable(); + var transferData = new ClearinghouseTransferData( - data.ParticipantDetails, - new IdentityDetails(decentralizedIdentifier, data.UniqueIds), - _settings.CallbackUrl, - overwrite); + data.LegalEntity, + ValidationModes.LEGAL_NAME, + new CallBack(_settings.CallbackUrl, headers) + ); await clearinghouseService.TriggerCompanyDataPost(transferData, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None); } @@ -123,19 +97,23 @@ public async Task ProcessEndClearinghouse(Guid applicationId, ClearinghouseRespo processStepTypeIds: [ProcessStepTypeId.START_SELF_DESCRIPTION_LP]) .ConfigureAwait(ConfigureAwaitOptions.None); - var declined = data.Status == ClearinghouseResponseStatus.DECLINE; - + var validData = data.ValidationUnits.FirstOrDefault(s => s.Status == ClearinghouseResponseStatus.VALID); + var isInvalid = validData == null; checklistService.FinalizeChecklistEntryAndProcessSteps( context, null, item => { - item.ApplicationChecklistEntryStatusId = declined + item.ApplicationChecklistEntryStatusId = isInvalid ? ApplicationChecklistEntryStatusId.FAILED : ApplicationChecklistEntryStatusId.DONE; - item.Comment = data.Message; + + // There is not "Message" param available in the response in case of VALID so, thats why saving ClearinghouseResponseStatus param into the Comments in case of VALID only. + item.Comment = isInvalid + ? data.ValidationUnits.FirstOrDefault(s => s.Status != ClearinghouseResponseStatus.VALID)!.Message + : validData!.Status.ToString(); }, - declined + isInvalid ? [ProcessStepTypeId.MANUAL_TRIGGER_OVERRIDE_CLEARING_HOUSE] : [ProcessStepTypeId.START_SELF_DESCRIPTION_LP]); } diff --git a/src/externalsystems/Clearinghouse.Library/Extensions/UniqueIdentifiersExtension.cs b/src/externalsystems/Clearinghouse.Library/Extensions/UniqueIdentifiersExtension.cs new file mode 100644 index 0000000000..438dc1a054 --- /dev/null +++ b/src/externalsystems/Clearinghouse.Library/Extensions/UniqueIdentifiersExtension.cs @@ -0,0 +1,36 @@ +/******************************************************************************** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; + +namespace Org.Eclipse.TractusX.Portal.Backend.Clearinghouse.Library.Extensions; + +public static class UniqueIdentifiersExtension +{ + public static string GetUniqueIdentifierValue(this UniqueIdentifierId uniqueIdentifierId) => + uniqueIdentifierId switch + { + UniqueIdentifierId.COMMERCIAL_REG_NUMBER => "schema:taxID", + UniqueIdentifierId.VAT_ID => "schema:vatID", + UniqueIdentifierId.LEI_CODE => "schema:leiCode", + UniqueIdentifierId.VIES => "EUID", + UniqueIdentifierId.EORI => "gx:eori", + _ => throw new ArgumentOutOfRangeException(nameof(uniqueIdentifierId), uniqueIdentifierId, "Unique Identifier not found for SdFactory Conversion") + }; +} diff --git a/src/externalsystems/Clearinghouse.Library/Models/ClearinghouseResponseData.cs b/src/externalsystems/Clearinghouse.Library/Models/ClearinghouseResponseData.cs index 5bbc66e570..86f4317a2c 100644 --- a/src/externalsystems/Clearinghouse.Library/Models/ClearinghouseResponseData.cs +++ b/src/externalsystems/Clearinghouse.Library/Models/ClearinghouseResponseData.cs @@ -23,6 +23,12 @@ namespace Org.Eclipse.TractusX.Portal.Backend.Clearinghouse.Library.Models; public record ClearinghouseResponseData( - [property: JsonPropertyName("bpn")] string BusinessPartnerNumber, - [property: JsonPropertyName("status")] ClearinghouseResponseStatus Status, - [property: JsonPropertyName("message")] string? Message); + [property: JsonPropertyName("validationMode")] string ValidationMode, + [property: JsonPropertyName("validationUnits")] IEnumerable ValidationUnits +); + +public record ValidationUnits( + [property: JsonPropertyName("result")] ClearinghouseResponseStatus Status, + [property: JsonPropertyName("type")] string Type, + [property: JsonPropertyName("message")] string? Message +); diff --git a/src/externalsystems/Clearinghouse.Library/Models/ClearinghouseResponseStatus.cs b/src/externalsystems/Clearinghouse.Library/Models/ClearinghouseResponseStatus.cs index f35e19f1cf..2c0ab8ccf3 100644 --- a/src/externalsystems/Clearinghouse.Library/Models/ClearinghouseResponseStatus.cs +++ b/src/externalsystems/Clearinghouse.Library/Models/ClearinghouseResponseStatus.cs @@ -22,7 +22,18 @@ namespace Org.Eclipse.TractusX.Portal.Backend.Clearinghouse.Library.Models; public enum ClearinghouseResponseStatus { - CONFIRM = 1, + /// + /// In case the identifier has been found in the trust sources of clearing house. + /// + VALID = 1, - DECLINE = 2 + /// + /// In case the identifier format is not valid or the identifier was not found in the trust source of clearing house. + /// + INVALID = 2, + + /// + /// In case the validation can't be performed, due to the unavailablity of the trust source of clearing house. + /// + INCONCLUSIVE = 3 } diff --git a/src/externalsystems/Clearinghouse.Library/Models/ClearinghouseTransferData.cs b/src/externalsystems/Clearinghouse.Library/Models/ClearinghouseTransferData.cs index 402389d281..43b971d7c3 100644 --- a/src/externalsystems/Clearinghouse.Library/Models/ClearinghouseTransferData.cs +++ b/src/externalsystems/Clearinghouse.Library/Models/ClearinghouseTransferData.cs @@ -24,11 +24,12 @@ namespace Org.Eclipse.TractusX.Portal.Backend.Clearinghouse.Library.Models; public record ClearinghouseTransferData( - [property: JsonPropertyName("participantDetails")] ParticipantDetails ParticipantDetails, - [property: JsonPropertyName("identityDetails")] IdentityDetails IdentityDetails, - [property: JsonPropertyName("callbackUrl")] string CallbackUrl, - [property: JsonPropertyName("exceptProfile")] bool ExceptProfile); + [property: JsonPropertyName("legalEntity")] LegalEntity LegalEntity, + [property: JsonPropertyName("validationMode")] string ValidationMode, + [property: JsonPropertyName("callback")] CallBack Callback +); -public record IdentityDetails( - [property: JsonPropertyName("did")] string Did, - [property: JsonPropertyName("uniqueIds")] IEnumerable UniqueIds); +public record CallBack( + [property: JsonPropertyName("url")] string Url, + [property: JsonPropertyName("headers")] IEnumerable> Headers +); diff --git a/src/externalsystems/Clearinghouse.Library/ValidationModes.cs b/src/externalsystems/Clearinghouse.Library/ValidationModes.cs new file mode 100644 index 0000000000..3b18c2b24b --- /dev/null +++ b/src/externalsystems/Clearinghouse.Library/ValidationModes.cs @@ -0,0 +1,36 @@ +/******************************************************************************** + * Copyright (c) 2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ + +namespace Org.Eclipse.TractusX.Portal.Backend.Clearinghouse.Library; + +public static class ValidationModes +{ + /// + /// DEFAULT - validates whether the identifiers themselves exists, indepenedent of their relationship to the legal entity provided + /// + public const string IDENTIFIER = "IDENTIFIER"; + /// + /// Validates whether the identifier is valid, and whether the name of the legal entity it is associated with matches the provided legal name + /// + public const string LEGAL_NAME = "LEGAL_NAME"; + /// + /// Validates whether the identifier is valid, and whether the name of the legal entity, as well as the addresss it is associated with matches the provided ones. + /// + public const string LEGAL_NAME_AND_ADDRESS = "LEGAL_NAME_AND_ADDRESS"; +} \ No newline at end of file diff --git a/src/keycloak/Keycloak.Authentication/ControllerExtensions.cs b/src/keycloak/Keycloak.Authentication/ControllerExtensions.cs index c1e25a613a..2a6498835f 100644 --- a/src/keycloak/Keycloak.Authentication/ControllerExtensions.cs +++ b/src/keycloak/Keycloak.Authentication/ControllerExtensions.cs @@ -18,6 +18,7 @@ ********************************************************************************/ using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Primitives; using Org.Eclipse.TractusX.Portal.Backend.Framework.ErrorHandling; namespace Org.Eclipse.TractusX.Portal.Backend.Keycloak.Authentication; @@ -30,6 +31,9 @@ public static class ControllerExtensions public static T WithBearerToken(this ControllerBase controller, Func tokenConsumingFunction) => tokenConsumingFunction(controller.GetBearerToken()); + public static T WithBpn(this ControllerBase controller, Func bpnConsumingFunction) => + bpnConsumingFunction(controller.GetBpn()); + private static string GetBearerToken(this ControllerBase controller) { var authorization = controller.Request.Headers.Authorization.FirstOrDefault(); @@ -47,4 +51,22 @@ private static string GetBearerToken(this ControllerBase controller) return bearer; } + + private static string GetBpn(this ControllerBase controller) + { + var headers = controller.Request.Headers.FirstOrDefault(x => x.Key == "Business-Partner-Number"); + if (headers.Equals(default(KeyValuePair))) + { + throw new ControllerArgumentException("Request does not contain Business-Partner-Number header", + nameof(headers.Key)); + } + + var bpn = headers.Value.FirstOrDefault(); + if (string.IsNullOrWhiteSpace(bpn)) + { + throw new ControllerArgumentException("Business-Partner-Number in header must not be empty", nameof(bpn)); + } + + return bpn; + } } diff --git a/src/portalbackend/PortalBackend.DBAccess/Models/ClearinghouseData.cs b/src/portalbackend/PortalBackend.DBAccess/Models/ClearinghouseData.cs index 5d80bce312..a356bbe976 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Models/ClearinghouseData.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Models/ClearinghouseData.cs @@ -25,18 +25,22 @@ namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; public record ClearinghouseData( CompanyApplicationStatusId ApplicationStatusId, - ParticipantDetails ParticipantDetails, - IEnumerable UniqueIds); + string Bpn, + LegalEntity LegalEntity +); + +public record LegalEntity( + [property: JsonPropertyName("legalName")] string LegalName, + [property: JsonPropertyName("Address")] LegalAddress Address, + [property: JsonPropertyName("identifiers")] IEnumerable Identifiers +); -public record ParticipantDetails( - [property: JsonPropertyName("name")] string Name, - [property: JsonPropertyName("city")] string? City, - [property: JsonPropertyName("street")] string Street, - [property: JsonPropertyName("bpn")] string? Bpn, +public record LegalAddress( + [property: JsonPropertyName("country")] string? CountryAlpha2Code, [property: JsonPropertyName("region")] string? Region, - [property: JsonPropertyName("zipCode")] string? ZipCode, - [property: JsonPropertyName("country")] string? Country, - [property: JsonPropertyName("countryAlpha2Code")] string CountryAlpha2Code + [property: JsonPropertyName("locality")] string? City, + [property: JsonPropertyName("postalCode")] string? ZipCode, + [property: JsonPropertyName("addressLine")] string AddressLine ); public record UniqueIdData([property: JsonPropertyName("type")] string Type, [property: JsonPropertyName("value")] string Value); diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/ApplicationRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/ApplicationRepository.cs index 0cf5d33c14..b778833255 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/ApplicationRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/ApplicationRepository.cs @@ -401,16 +401,19 @@ public IQueryable GetAllCompanyApplicationsDetailsQuery(stri .Select(ca => new { ca.ApplicationStatusId, ca.Company, ca.Company!.Address, ca.Company.CompanyIdentifiers }) .Select(ca => new ClearinghouseData( ca.ApplicationStatusId, - new ParticipantDetails( + ca.Company!.BusinessPartnerNumber!, + new LegalEntity( ca.Company!.Name, - ca.Address!.City, - ca.Address.Streetname, - ca.Company.BusinessPartnerNumber, - ca.Address.Region, - ca.Address.Zipcode, - ca.Address.Country!.CountryLongNames.Where(cln => cln.ShortName == "en").Select(cln => cln.LongName).SingleOrDefault(), - ca.Address.CountryAlpha2Code), - ca.CompanyIdentifiers.Select(ci => new UniqueIdData(ci.UniqueIdentifier!.Label, ci.Value)))) + new LegalAddress( + ca.Address!.CountryAlpha2Code, + ca.Address.Region, + ca.Address.City, + ca.Address.Zipcode, + !string.IsNullOrEmpty(ca.Address.Streetnumber) ? string.Format("{0} {1}", ca.Address.Streetname, ca.Address.Streetnumber) : ca.Address.Streetname + ), + ca.CompanyIdentifiers.Select(ci => new UniqueIdData(ci.UniqueIdentifier!.Label, ci.Value)) + ) + )) .SingleOrDefaultAsync(); /// diff --git a/tests/administration/Administration.Service.Tests/BusinessLogic/RegistrationBusinessLogicTest.cs b/tests/administration/Administration.Service.Tests/BusinessLogic/RegistrationBusinessLogicTest.cs index a012fc9d14..f32cf96f0b 100644 --- a/tests/administration/Administration.Service.Tests/BusinessLogic/RegistrationBusinessLogicTest.cs +++ b/tests/administration/Administration.Service.Tests/BusinessLogic/RegistrationBusinessLogicTest.cs @@ -377,8 +377,11 @@ public async Task ProcessClearinghouseResponseAsync_WithValidData_CallsExpected( .Returns(Enumerable.Repeat(ApplicationId, 1).ToAsyncEnumerable()); // Act - var data = new ClearinghouseResponseData(BusinessPartnerNumber, ClearinghouseResponseStatus.CONFIRM, null); - await _logic.ProcessClearinghouseResponseAsync(data, CancellationToken.None); + var validationUnits = new List { + new (ClearinghouseResponseStatus.VALID, "vatId", null) + }.AsEnumerable(); + var data = new ClearinghouseResponseData("COMPLETED", validationUnits); + await _logic.ProcessClearinghouseResponseAsync(data, BusinessPartnerNumber, CancellationToken.None); // Assert A.CallTo(() => _clearinghouseBusinessLogic.ProcessEndClearinghouse(ApplicationId, data, A._)) @@ -393,8 +396,11 @@ public async Task ProcessClearinghouseResponseAsync_WithMultipleApplications_Thr .Returns(new[] { CompanyId, Guid.NewGuid() }.ToAsyncEnumerable()); // Act - var data = new ClearinghouseResponseData(BusinessPartnerNumber, ClearinghouseResponseStatus.CONFIRM, null); - Task Act() => _logic.ProcessClearinghouseResponseAsync(data, CancellationToken.None); + var validationUnits = new List { + new (ClearinghouseResponseStatus.VALID, "vatId", null) + }.AsEnumerable(); + var data = new ClearinghouseResponseData("COMPLETED", validationUnits); + Task Act() => _logic.ProcessClearinghouseResponseAsync(data, BusinessPartnerNumber, CancellationToken.None); // Assert var ex = await Assert.ThrowsAsync(Act); @@ -409,8 +415,11 @@ public async Task ProcessClearinghouseResponseAsync_WithNoApplication_ThrowsNotF .Returns(Enumerable.Empty().ToAsyncEnumerable()); // Act - var data = new ClearinghouseResponseData(BusinessPartnerNumber, ClearinghouseResponseStatus.CONFIRM, null); - Task Act() => _logic.ProcessClearinghouseResponseAsync(data, CancellationToken.None); + var validationUnits = new List { + new (ClearinghouseResponseStatus.VALID, "vatId", null) + }.AsEnumerable(); + var data = new ClearinghouseResponseData("COMPLETED", validationUnits); + Task Act() => _logic.ProcessClearinghouseResponseAsync(data, BusinessPartnerNumber, CancellationToken.None); // Assert var ex = await Assert.ThrowsAsync(Act); diff --git a/tests/administration/Administration.Service.Tests/Controllers/RegistrationControllerTest.cs b/tests/administration/Administration.Service.Tests/Controllers/RegistrationControllerTest.cs index 856d684475..f2c63b4c9d 100644 --- a/tests/administration/Administration.Service.Tests/Controllers/RegistrationControllerTest.cs +++ b/tests/administration/Administration.Service.Tests/Controllers/RegistrationControllerTest.cs @@ -35,6 +35,7 @@ namespace Org.Eclipse.TractusX.Portal.Backend.Administration.Service.Tests.Contr public class RegistrationControllerTest { private static readonly string AccessToken = "THISISTHEACCESSTOKEN"; + private static readonly string Bpn = "CAXLSHAREDIDPZZ"; private readonly IRegistrationBusinessLogic _logic; private readonly RegistrationController _controller; private readonly IFixture _fixture; @@ -126,7 +127,7 @@ public async Task ProcessClearinghouseResponse_ReturnsExpectedResult() var result = await _controller.ProcessClearinghouseResponse(data, cancellationToken); //Assert - A.CallTo(() => _logic.ProcessClearinghouseResponseAsync(data, cancellationToken)).MustHaveHappenedOnceExactly(); + A.CallTo(() => _logic.ProcessClearinghouseResponseAsync(data, Bpn, cancellationToken)).MustHaveHappenedOnceExactly(); Assert.IsType(result); } diff --git a/tests/endtoend/InterfacePartnerHealthCheck/ClearinghouseEndToEndTests.cs b/tests/endtoend/InterfacePartnerHealthCheck/ClearinghouseEndToEndTests.cs index 1129f40778..97d0e2565b 100644 --- a/tests/endtoend/InterfacePartnerHealthCheck/ClearinghouseEndToEndTests.cs +++ b/tests/endtoend/InterfacePartnerHealthCheck/ClearinghouseEndToEndTests.cs @@ -18,6 +18,7 @@ ********************************************************************************/ using FluentAssertions; +using Org.Eclipse.TractusX.Portal.Backend.Clearinghouse.Library; using Org.Eclipse.TractusX.Portal.Backend.Clearinghouse.Library.Models; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; using RestAssured.Response.Logging; @@ -54,16 +55,17 @@ public async Task ClearinghouseInterface_HealthCheck() var body = DataHandleHelper.SerializeData( new ClearinghouseTransferData( - new ParticipantDetails( - "SmokeTest CH", "Stuttgart", "Test Street", "BPNL000SMOKE0011", "Bavaria", "01108", - "Germany", "DE" + new LegalEntity( + "SmokeTest CH", + new LegalAddress("DE", "Bavaria", "Stuttgart", "01108", "Abc Street"), + [new("local", "HB8272819")] ), - new IdentityDetails( - "did:sov:RPgthNMDkVdzYQhXzahh3P", // hardcode due to initial requirements in CPLP-2803 - new List { new("local", "HB8272819") } - ), - $"{TestResources.BasePortalBackendUrl}/api/administration/registration/clearinghouse", - false) + ValidationModes.LEGAL_NAME, + new CallBack( + $"{TestResources.BasePortalBackendUrl}/api/administration/registration/clearinghouse", + [new KeyValuePair("bpn", "BPNL000SMOKE0011")] + ) + ) ); var data = Given() diff --git a/tests/externalsystems/Clearinghouse.Library.Tests/ClearinghouseBusinessLogicTests.cs b/tests/externalsystems/Clearinghouse.Library.Tests/ClearinghouseBusinessLogicTests.cs index bed1807df9..74cc478d34 100644 --- a/tests/externalsystems/Clearinghouse.Library.Tests/ClearinghouseBusinessLogicTests.cs +++ b/tests/externalsystems/Clearinghouse.Library.Tests/ClearinghouseBusinessLogicTests.cs @@ -42,8 +42,6 @@ public class ClearinghouseBusinessLogicTests private static readonly Guid IdWithBpn = new("c244f79a-7faf-4c59-bb85-fbfdf72ce46f"); private const string ValidBpn = "BPNL123698762345"; - private const string ValidDid = "thisisavaliddid"; - private readonly IFixture _fixture; private readonly IApplicationRepository _applicationRepository; @@ -52,7 +50,6 @@ public class ClearinghouseBusinessLogicTests private readonly ClearinghouseBusinessLogic _logic; private readonly IClearinghouseService _clearinghouseService; private readonly IApplicationChecklistService _checklistService; - private readonly ICustodianBusinessLogic _custodianBusinessLogic; private readonly IDateTimeProvider _dateTimeProvider; private readonly IApplicationChecklistRepository _applicationChecklistRepository; @@ -67,7 +64,6 @@ public ClearinghouseBusinessLogicTests() _applicationChecklistRepository = A.Fake(); _portalRepositories = A.Fake(); _clearinghouseService = A.Fake(); - _custodianBusinessLogic = A.Fake(); _checklistService = A.Fake(); A.CallTo(() => _portalRepositories.GetInstance()).Returns(_applicationRepository); @@ -76,7 +72,7 @@ public ClearinghouseBusinessLogicTests() _dateTimeProvider = A.Fake(); A.CallTo(() => _dateTimeProvider.OffsetNow).Returns(DateTimeOffset.UtcNow); - _logic = new ClearinghouseBusinessLogic(_portalRepositories, _clearinghouseService, _custodianBusinessLogic, _checklistService, _dateTimeProvider, Options.Create(new ClearinghouseSettings + _logic = new ClearinghouseBusinessLogic(_portalRepositories, _clearinghouseService, _checklistService, _dateTimeProvider, Options.Create(new ClearinghouseSettings { CallbackUrl = "https://api.com", UseDimWallet = false @@ -85,36 +81,6 @@ public ClearinghouseBusinessLogicTests() #region HandleStartClearingHouse - [Theory] - [InlineData(ProcessStepTypeId.MANUAL_VERIFY_REGISTRATION)] - [InlineData(ProcessStepTypeId.CREATE_BUSINESS_PARTNER_NUMBER_PUSH)] - [InlineData(ProcessStepTypeId.CREATE_BUSINESS_PARTNER_NUMBER_PULL)] - [InlineData(ProcessStepTypeId.CREATE_BUSINESS_PARTNER_NUMBER_MANUAL)] - [InlineData(ProcessStepTypeId.CREATE_IDENTITY_WALLET)] - [InlineData(ProcessStepTypeId.RETRIGGER_IDENTITY_WALLET)] - [InlineData(ProcessStepTypeId.RETRIGGER_CLEARING_HOUSE)] - [InlineData(ProcessStepTypeId.AWAIT_CLEARING_HOUSE_RESPONSE)] - [InlineData(ProcessStepTypeId.START_SELF_DESCRIPTION_LP)] - [InlineData(ProcessStepTypeId.RETRIGGER_SELF_DESCRIPTION_LP)] - [InlineData(ProcessStepTypeId.ASSIGN_INITIAL_ROLES)] - [InlineData(ProcessStepTypeId.RETRIGGER_BUSINESS_PARTNER_NUMBER_PUSH)] - [InlineData(ProcessStepTypeId.RETRIGGER_BUSINESS_PARTNER_NUMBER_PULL)] - [InlineData(ProcessStepTypeId.MANUAL_TRIGGER_OVERRIDE_CLEARING_HOUSE)] - [InlineData(ProcessStepTypeId.AWAIT_SELF_DESCRIPTION_LP_RESPONSE)] - public async Task HandleStartClearingHouse_ForInvalidProcessStepTypeId_ThrowsUnexpectedCondition(ProcessStepTypeId stepTypeId) - { - // Arrange - var checklist = _fixture.Create>().ToImmutableDictionary(); - var context = new IApplicationChecklistService.WorkerChecklistProcessStepData(Guid.NewGuid(), stepTypeId, checklist, Enumerable.Empty()); - - // Act - async Task Act() => await _logic.HandleClearinghouse(context, CancellationToken.None); - - // Assert - var ex = await Assert.ThrowsAsync(Act); - ex.Message.Should().Be($"HandleClearingHouse called for unexpected processStepTypeId {stepTypeId}. Expected START_CLEARING_HOUSE or START_OVERRIDE_CLEARING_HOUSE"); - } - [Fact] public async Task HandleStartClearingHouse_WithNotExistingApplication_ThrowsConflictException() { @@ -136,7 +102,7 @@ public async Task HandleStartClearingHouse_WithNotExistingApplication_ThrowsConf // Assert var ex = await Assert.ThrowsAsync(Act); - ex.Message.Should().Be($"Decentralized Identifier for application {context.ApplicationId} is not set"); + ex.Message.Should().Be($"Application {context.ApplicationId} does not exists."); } [Fact] @@ -185,7 +151,6 @@ public async Task HandleStartClearingHouse_WithBpnNull_ThrowsConflictException() [Theory] [InlineData(ProcessStepTypeId.START_CLEARING_HOUSE, ApplicationChecklistEntryStatusId.IN_PROGRESS, ProcessStepTypeId.AWAIT_CLEARING_HOUSE_RESPONSE)] - [InlineData(ProcessStepTypeId.START_OVERRIDE_CLEARING_HOUSE, ApplicationChecklistEntryStatusId.IN_PROGRESS, ProcessStepTypeId.AWAIT_CLEARING_HOUSE_RESPONSE)] public async Task HandleStartClearingHouse_WithValidData_CallsExpected(ProcessStepTypeId stepTypeId, ApplicationChecklistEntryStatusId statusId, ProcessStepTypeId expectedProcessTypeId) { // Arrange @@ -216,106 +181,6 @@ public async Task HandleStartClearingHouse_WithValidData_CallsExpected(ProcessSt result.Modified.Should().BeTrue(); } - [Fact] - public async Task HandleStartClearingHouse_WithDimActiveAndNonExistingApplication_ThrowsConflictException() - { - // Arrange - var checklist = ImmutableDictionary.CreateRange([ - new(ApplicationChecklistEntryTypeId.REGISTRATION_VERIFICATION, ApplicationChecklistEntryStatusId.DONE), - new(ApplicationChecklistEntryTypeId.BUSINESS_PARTNER_NUMBER, ApplicationChecklistEntryStatusId.DONE), - new(ApplicationChecklistEntryTypeId.IDENTITY_WALLET, ApplicationChecklistEntryStatusId.DONE), - new(ApplicationChecklistEntryTypeId.CLEARING_HOUSE, ApplicationChecklistEntryStatusId.TO_DO) - ]); - - var context = new IApplicationChecklistService.WorkerChecklistProcessStepData(IdWithBpn, ProcessStepTypeId.START_CLEARING_HOUSE, checklist, Enumerable.Empty()); - A.CallTo(() => _applicationRepository.GetDidForApplicationId(A._)) - .Returns<(bool, string?)>(default); - var logic = new ClearinghouseBusinessLogic(_portalRepositories, _clearinghouseService, _custodianBusinessLogic, _checklistService, _dateTimeProvider, Options.Create(new ClearinghouseSettings - { - CallbackUrl = "https://api.com", - UseDimWallet = true - })); - async Task Act() => await logic.HandleClearinghouse(context, CancellationToken.None); - - // Act - var ex = await Assert.ThrowsAsync(Act); - - // Assert - ex.Message.Should().Be($"Did must be set for Application {context.ApplicationId}"); - A.CallTo(() => _applicationRepository.GetDidForApplicationId(context.ApplicationId)) - .MustHaveHappenedOnceExactly(); - } - - [Fact] - public async Task HandleStartClearingHouse_WithDimActiveAndDidNotSet_ThrowsConflictException() - { - // Arrange - var checklist = ImmutableDictionary.CreateRange([ - new(ApplicationChecklistEntryTypeId.REGISTRATION_VERIFICATION, ApplicationChecklistEntryStatusId.DONE), - new(ApplicationChecklistEntryTypeId.BUSINESS_PARTNER_NUMBER, ApplicationChecklistEntryStatusId.DONE), - new(ApplicationChecklistEntryTypeId.IDENTITY_WALLET, ApplicationChecklistEntryStatusId.DONE), - new(ApplicationChecklistEntryTypeId.CLEARING_HOUSE, ApplicationChecklistEntryStatusId.TO_DO) - ]); - - var context = new IApplicationChecklistService.WorkerChecklistProcessStepData(IdWithBpn, ProcessStepTypeId.START_CLEARING_HOUSE, checklist, Enumerable.Empty()); - A.CallTo(() => _applicationRepository.GetDidForApplicationId(A._)) - .Returns((true, null)); - var logic = new ClearinghouseBusinessLogic(_portalRepositories, _clearinghouseService, _custodianBusinessLogic, _checklistService, _dateTimeProvider, Options.Create(new ClearinghouseSettings - { - CallbackUrl = "https://api.com", - UseDimWallet = true - })); - async Task Act() => await logic.HandleClearinghouse(context, CancellationToken.None); - - // Act - var ex = await Assert.ThrowsAsync(Act); - - // Assert - ex.Message.Should().Be($"Did must be set for Application {context.ApplicationId}"); - A.CallTo(() => _applicationRepository.GetDidForApplicationId(context.ApplicationId)) - .MustHaveHappenedOnceExactly(); - } - - [Fact] - public async Task HandleStartClearingHouse_WithDimActive_CallsExpected() - { - // Arrange - var entry = new ApplicationChecklistEntry(Guid.NewGuid(), ApplicationChecklistEntryTypeId.CLEARING_HOUSE, ApplicationChecklistEntryStatusId.TO_DO, DateTimeOffset.UtcNow); - - var checklist = ImmutableDictionary.CreateRange([ - new(ApplicationChecklistEntryTypeId.REGISTRATION_VERIFICATION, ApplicationChecklistEntryStatusId.DONE), - new(ApplicationChecklistEntryTypeId.BUSINESS_PARTNER_NUMBER, ApplicationChecklistEntryStatusId.DONE), - new(ApplicationChecklistEntryTypeId.IDENTITY_WALLET, ApplicationChecklistEntryStatusId.DONE), - new(ApplicationChecklistEntryTypeId.CLEARING_HOUSE, ApplicationChecklistEntryStatusId.TO_DO) - ]); - - var context = new IApplicationChecklistService.WorkerChecklistProcessStepData(IdWithBpn, ProcessStepTypeId.START_CLEARING_HOUSE, checklist, Enumerable.Empty()); - A.CallTo(() => _applicationRepository.GetDidForApplicationId(A._)) - .Returns((true, "did:web:test123456")); - SetupForHandleStartClearingHouse(); - var logic = new ClearinghouseBusinessLogic(_portalRepositories, _clearinghouseService, _custodianBusinessLogic, _checklistService, _dateTimeProvider, Options.Create(new ClearinghouseSettings - { - CallbackUrl = "https://api.com", - UseDimWallet = true - })); - - // Act - var result = await logic.HandleClearinghouse(context, CancellationToken.None); - - // Assert - A.CallTo(() => _applicationRepository.GetDidForApplicationId(context.ApplicationId)) - .MustHaveHappenedOnceExactly(); - result.ModifyChecklistEntry.Should().NotBeNull(); - result.ModifyChecklistEntry!.Invoke(entry); - entry.ApplicationChecklistEntryStatusId.Should().Be(ApplicationChecklistEntryStatusId.IN_PROGRESS); - A.CallTo(() => _clearinghouseService.TriggerCompanyDataPost(A._, A._)) - .MustHaveHappenedOnceExactly(); - result.ScheduleStepTypeIds.Should().HaveCount(1); - result.ScheduleStepTypeIds.Should().Contain(ProcessStepTypeId.AWAIT_CLEARING_HOUSE_RESPONSE); - result.SkipStepTypeIds.Should().BeNull(); - result.Modified.Should().BeTrue(); - } - #endregion #region ProcessClearinghouseResponse @@ -325,10 +190,15 @@ public async Task ProcessClearinghouseResponseAsync_WithConfirmation_UpdatesEntr { // Arrange var entry = new ApplicationChecklistEntry(IdWithBpn, ApplicationChecklistEntryTypeId.IDENTITY_WALLET, ApplicationChecklistEntryStatusId.TO_DO, DateTimeOffset.UtcNow); - var data = _fixture.Build() - .With(x => x.Status, ClearinghouseResponseStatus.CONFIRM) + var validationUnits = _fixture.Build() + .With(x => x.Status, ClearinghouseResponseStatus.VALID) .With(x => x.Message, default(string?)) + .CreateMany(2); + + var data = _fixture.Build() + .With(x => x.ValidationUnits, validationUnits) .Create(); + SetupForProcessClearinghouseResponse(entry); // Act @@ -347,8 +217,8 @@ public async Task ProcessClearinghouseResponseAsync_WithDecline_UpdatesEntry() // Arrange var entry = new ApplicationChecklistEntry(IdWithBpn, ApplicationChecklistEntryTypeId.IDENTITY_WALLET, ApplicationChecklistEntryStatusId.TO_DO, DateTimeOffset.UtcNow); var data = _fixture.Build() - .With(x => x.Status, ClearinghouseResponseStatus.DECLINE) - .With(x => x.Message, "Comment about the error") + //.With(x => x.Status, ClearinghouseResponseStatus.INVALID) + //.With(x => x.Message, "Comment about the error") .Create(); SetupForProcessClearinghouseResponse(entry); @@ -391,26 +261,17 @@ public async Task CheckEndClearinghouseProcesses_WithEntry_CreatesProcessStep() private void SetupForHandleStartClearingHouse() { - A.CallTo(() => _custodianBusinessLogic.GetWalletByBpnAsync(A.That.Matches(x => x == IdWithoutBpn || x == IdWithBpn || x == IdWithApplicationCreated), A._)) - .Returns(new WalletData("Name", ValidBpn, ValidDid, DateTime.UtcNow, false, null)); - A.CallTo(() => _custodianBusinessLogic.GetWalletByBpnAsync(IdWithCustodianUnavailable, A._)) - .Returns(null); - A.CallTo(() => _custodianBusinessLogic.GetWalletByBpnAsync(A.That.Not.Matches(x => x == IdWithoutBpn || x == IdWithBpn || x == IdWithApplicationCreated || x == IdWithCustodianUnavailable), A._)) - .Returns(new WalletData("Name", ValidBpn, null, DateTime.UtcNow, false, null)); - - var participantDetailsWithoutBpn = _fixture.Build() - .With(x => x.Bpn, default(string?)) + var legalEntity = _fixture.Build() .Create(); var clearinghouseDataWithoutBpn = _fixture.Build() .With(x => x.ApplicationStatusId, CompanyApplicationStatusId.SUBMITTED) - .With(x => x.ParticipantDetails, participantDetailsWithoutBpn) - .Create(); - var participantDetails = _fixture.Build() - .With(x => x.Bpn, ValidBpn) + .With(x => x.LegalEntity, legalEntity) + .With(x => x.Bpn, default(string?)) .Create(); var clearinghouseData = _fixture.Build() .With(x => x.ApplicationStatusId, CompanyApplicationStatusId.SUBMITTED) - .With(x => x.ParticipantDetails, participantDetails) + .With(x => x.LegalEntity, legalEntity) + .With(x => x.Bpn, ValidBpn) .Create(); var chDataWithApplicationCreated = _fixture.Build() .With(x => x.ApplicationStatusId, CompanyApplicationStatusId.CREATED) diff --git a/tests/portalbackend/PortalBackend.DBAccess.Tests/ApplicationRepositoryTests.cs b/tests/portalbackend/PortalBackend.DBAccess.Tests/ApplicationRepositoryTests.cs index 23170fa938..c9ed18cc08 100644 --- a/tests/portalbackend/PortalBackend.DBAccess.Tests/ApplicationRepositoryTests.cs +++ b/tests/portalbackend/PortalBackend.DBAccess.Tests/ApplicationRepositoryTests.cs @@ -263,7 +263,7 @@ public async Task GetClearinghouseDataForApplicationId_WithValidApplicationId_Re // Assert data.Should().NotBeNull(); - data!.ParticipantDetails.Bpn.Should().Be("BPNL00000003CRHL"); + data!.Bpn.Should().Be("BPNL00000003CRHL"); data.ApplicationStatusId.Should().Be(CompanyApplicationStatusId.SUBMITTED); } From 8b7a205b3d57bb645de3e095d9a924bbe77b615b Mon Sep 17 00:00:00 2001 From: Tayyab Fayyaz Janjua Date: Wed, 8 Jan 2025 15:57:19 +0100 Subject: [PATCH 2/2] reverting back the override functionality --- .../ClearinghouseBusinessLogic.cs | 14 +++++-- .../Clearinghouse.Library/ValidationModes.cs | 2 +- .../Extensions/UniqueIdentifiersExtension.cs | 4 +- .../Repositories/ApplicationRepository.cs | 3 +- .../ClearinghouseBusinessLogicTests.cs | 41 +++++++++++++++++-- 5 files changed, 54 insertions(+), 10 deletions(-) rename src/{externalsystems/Clearinghouse.Library => portalbackend/PortalBackend.DBAccess}/Extensions/UniqueIdentifiersExtension.cs (93%) diff --git a/src/externalsystems/Clearinghouse.Library/BusinessLogic/ClearinghouseBusinessLogic.cs b/src/externalsystems/Clearinghouse.Library/BusinessLogic/ClearinghouseBusinessLogic.cs index 858610637b..111606397c 100644 --- a/src/externalsystems/Clearinghouse.Library/BusinessLogic/ClearinghouseBusinessLogic.cs +++ b/src/externalsystems/Clearinghouse.Library/BusinessLogic/ClearinghouseBusinessLogic.cs @@ -42,7 +42,14 @@ public class ClearinghouseBusinessLogic( public async Task HandleClearinghouse(IApplicationChecklistService.WorkerChecklistProcessStepData context, CancellationToken cancellationToken) { - await TriggerCompanyDataPost(context.ApplicationId, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None); + var validationMode = context.ProcessStepTypeId switch + { + ProcessStepTypeId.START_OVERRIDE_CLEARING_HOUSE => ValidationModes.IDENTIFIER, + ProcessStepTypeId.START_CLEARING_HOUSE => ValidationModes.LEGAL_NAME, + _ => throw new UnexpectedConditionException($"HandleClearingHouse called for unexpected processStepTypeId {context.ProcessStepTypeId}. Expected {ProcessStepTypeId.START_CLEARING_HOUSE} or {ProcessStepTypeId.START_OVERRIDE_CLEARING_HOUSE}") + }; + + await TriggerCompanyDataPost(context.ApplicationId, validationMode, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None); return new IApplicationChecklistService.WorkerChecklistProcessStepExecutionResult( ProcessStepStatusId.DONE, @@ -53,7 +60,7 @@ public class ClearinghouseBusinessLogic( null); } - private async Task TriggerCompanyDataPost(Guid applicationId, CancellationToken cancellationToken) + private async Task TriggerCompanyDataPost(Guid applicationId, string validationMode, CancellationToken cancellationToken) { var data = await portalRepositories.GetInstance() .GetClearinghouseDataForApplicationId(applicationId).ConfigureAwait(ConfigureAwaitOptions.None); @@ -79,7 +86,7 @@ private async Task TriggerCompanyDataPost(Guid applicationId, CancellationToken var transferData = new ClearinghouseTransferData( data.LegalEntity, - ValidationModes.LEGAL_NAME, + validationMode, new CallBack(_settings.CallbackUrl, headers) ); @@ -97,6 +104,7 @@ public async Task ProcessEndClearinghouse(Guid applicationId, ClearinghouseRespo processStepTypeIds: [ProcessStepTypeId.START_SELF_DESCRIPTION_LP]) .ConfigureAwait(ConfigureAwaitOptions.None); + // Company data is valid if any one of the provided identifiers was responded valid from CH var validData = data.ValidationUnits.FirstOrDefault(s => s.Status == ClearinghouseResponseStatus.VALID); var isInvalid = validData == null; checklistService.FinalizeChecklistEntryAndProcessSteps( diff --git a/src/externalsystems/Clearinghouse.Library/ValidationModes.cs b/src/externalsystems/Clearinghouse.Library/ValidationModes.cs index 3b18c2b24b..d473c1479f 100644 --- a/src/externalsystems/Clearinghouse.Library/ValidationModes.cs +++ b/src/externalsystems/Clearinghouse.Library/ValidationModes.cs @@ -33,4 +33,4 @@ public static class ValidationModes /// Validates whether the identifier is valid, and whether the name of the legal entity, as well as the addresss it is associated with matches the provided ones. /// public const string LEGAL_NAME_AND_ADDRESS = "LEGAL_NAME_AND_ADDRESS"; -} \ No newline at end of file +} diff --git a/src/externalsystems/Clearinghouse.Library/Extensions/UniqueIdentifiersExtension.cs b/src/portalbackend/PortalBackend.DBAccess/Extensions/UniqueIdentifiersExtension.cs similarity index 93% rename from src/externalsystems/Clearinghouse.Library/Extensions/UniqueIdentifiersExtension.cs rename to src/portalbackend/PortalBackend.DBAccess/Extensions/UniqueIdentifiersExtension.cs index 438dc1a054..94c42a4b7c 100644 --- a/src/externalsystems/Clearinghouse.Library/Extensions/UniqueIdentifiersExtension.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Extensions/UniqueIdentifiersExtension.cs @@ -19,7 +19,7 @@ using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Enums; -namespace Org.Eclipse.TractusX.Portal.Backend.Clearinghouse.Library.Extensions; +namespace Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Extensions; public static class UniqueIdentifiersExtension { @@ -31,6 +31,6 @@ public static string GetUniqueIdentifierValue(this UniqueIdentifierId uniqueIden UniqueIdentifierId.LEI_CODE => "schema:leiCode", UniqueIdentifierId.VIES => "EUID", UniqueIdentifierId.EORI => "gx:eori", - _ => throw new ArgumentOutOfRangeException(nameof(uniqueIdentifierId), uniqueIdentifierId, "Unique Identifier not found for SdFactory Conversion") + _ => throw new ArgumentOutOfRangeException(nameof(uniqueIdentifierId), uniqueIdentifierId, "Unique Identifier not found for Clearing House Conversion") }; } diff --git a/src/portalbackend/PortalBackend.DBAccess/Repositories/ApplicationRepository.cs b/src/portalbackend/PortalBackend.DBAccess/Repositories/ApplicationRepository.cs index b778833255..d4a2db164a 100644 --- a/src/portalbackend/PortalBackend.DBAccess/Repositories/ApplicationRepository.cs +++ b/src/portalbackend/PortalBackend.DBAccess/Repositories/ApplicationRepository.cs @@ -19,6 +19,7 @@ using Microsoft.EntityFrameworkCore; using Org.Eclipse.TractusX.Portal.Backend.Framework.DBAccess; +using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Extensions; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.DBAccess.Models; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities; using Org.Eclipse.TractusX.Portal.Backend.PortalBackend.PortalEntities.Entities; @@ -411,7 +412,7 @@ public IQueryable GetAllCompanyApplicationsDetailsQuery(stri ca.Address.Zipcode, !string.IsNullOrEmpty(ca.Address.Streetnumber) ? string.Format("{0} {1}", ca.Address.Streetname, ca.Address.Streetnumber) : ca.Address.Streetname ), - ca.CompanyIdentifiers.Select(ci => new UniqueIdData(ci.UniqueIdentifier!.Label, ci.Value)) + ca.CompanyIdentifiers.Select(ci => new UniqueIdData(ci.UniqueIdentifierId.GetUniqueIdentifierValue(), ci.Value)) ) )) .SingleOrDefaultAsync(); diff --git a/tests/externalsystems/Clearinghouse.Library.Tests/ClearinghouseBusinessLogicTests.cs b/tests/externalsystems/Clearinghouse.Library.Tests/ClearinghouseBusinessLogicTests.cs index 74cc478d34..de50310822 100644 --- a/tests/externalsystems/Clearinghouse.Library.Tests/ClearinghouseBusinessLogicTests.cs +++ b/tests/externalsystems/Clearinghouse.Library.Tests/ClearinghouseBusinessLogicTests.cs @@ -81,6 +81,36 @@ public ClearinghouseBusinessLogicTests() #region HandleStartClearingHouse + [Theory] + [InlineData(ProcessStepTypeId.MANUAL_VERIFY_REGISTRATION)] + [InlineData(ProcessStepTypeId.CREATE_BUSINESS_PARTNER_NUMBER_PUSH)] + [InlineData(ProcessStepTypeId.CREATE_BUSINESS_PARTNER_NUMBER_PULL)] + [InlineData(ProcessStepTypeId.CREATE_BUSINESS_PARTNER_NUMBER_MANUAL)] + [InlineData(ProcessStepTypeId.CREATE_IDENTITY_WALLET)] + [InlineData(ProcessStepTypeId.RETRIGGER_IDENTITY_WALLET)] + [InlineData(ProcessStepTypeId.RETRIGGER_CLEARING_HOUSE)] + [InlineData(ProcessStepTypeId.AWAIT_CLEARING_HOUSE_RESPONSE)] + [InlineData(ProcessStepTypeId.START_SELF_DESCRIPTION_LP)] + [InlineData(ProcessStepTypeId.RETRIGGER_SELF_DESCRIPTION_LP)] + [InlineData(ProcessStepTypeId.ASSIGN_INITIAL_ROLES)] + [InlineData(ProcessStepTypeId.RETRIGGER_BUSINESS_PARTNER_NUMBER_PUSH)] + [InlineData(ProcessStepTypeId.RETRIGGER_BUSINESS_PARTNER_NUMBER_PULL)] + [InlineData(ProcessStepTypeId.MANUAL_TRIGGER_OVERRIDE_CLEARING_HOUSE)] + [InlineData(ProcessStepTypeId.AWAIT_SELF_DESCRIPTION_LP_RESPONSE)] + public async Task HandleStartClearingHouse_ForInvalidProcessStepTypeId_ThrowsUnexpectedCondition(ProcessStepTypeId stepTypeId) + { + // Arrange + var checklist = _fixture.Create>().ToImmutableDictionary(); + var context = new IApplicationChecklistService.WorkerChecklistProcessStepData(Guid.NewGuid(), stepTypeId, checklist, Enumerable.Empty()); + + // Act + async Task Act() => await _logic.HandleClearinghouse(context, CancellationToken.None); + + // Assert + var ex = await Assert.ThrowsAsync(Act); + ex.Message.Should().Be($"HandleClearingHouse called for unexpected processStepTypeId {stepTypeId}. Expected START_CLEARING_HOUSE or START_OVERRIDE_CLEARING_HOUSE"); + } + [Fact] public async Task HandleStartClearingHouse_WithNotExistingApplication_ThrowsConflictException() { @@ -151,6 +181,7 @@ public async Task HandleStartClearingHouse_WithBpnNull_ThrowsConflictException() [Theory] [InlineData(ProcessStepTypeId.START_CLEARING_HOUSE, ApplicationChecklistEntryStatusId.IN_PROGRESS, ProcessStepTypeId.AWAIT_CLEARING_HOUSE_RESPONSE)] + [InlineData(ProcessStepTypeId.START_OVERRIDE_CLEARING_HOUSE, ApplicationChecklistEntryStatusId.IN_PROGRESS, ProcessStepTypeId.AWAIT_CLEARING_HOUSE_RESPONSE)] public async Task HandleStartClearingHouse_WithValidData_CallsExpected(ProcessStepTypeId stepTypeId, ApplicationChecklistEntryStatusId statusId, ProcessStepTypeId expectedProcessTypeId) { // Arrange @@ -207,7 +238,7 @@ public async Task ProcessClearinghouseResponseAsync_WithConfirmation_UpdatesEntr // Assert A.CallTo(() => _checklistService.FinalizeChecklistEntryAndProcessSteps(A._, A>._, A>._, A>.That.Matches(x => x.Count(y => y == ProcessStepTypeId.START_SELF_DESCRIPTION_LP) == 1))).MustHaveHappenedOnceExactly(); A.CallTo(() => _portalRepositories.SaveAsync()).MustNotHaveHappened(); - entry.Comment.Should().BeNull(); + entry.Comment.Should().Be("VALID"); entry.ApplicationChecklistEntryStatusId.Should().Be(ApplicationChecklistEntryStatusId.DONE); } @@ -216,9 +247,13 @@ public async Task ProcessClearinghouseResponseAsync_WithDecline_UpdatesEntry() { // Arrange var entry = new ApplicationChecklistEntry(IdWithBpn, ApplicationChecklistEntryTypeId.IDENTITY_WALLET, ApplicationChecklistEntryStatusId.TO_DO, DateTimeOffset.UtcNow); + var validationUnits = _fixture.Build() + .With(x => x.Status, ClearinghouseResponseStatus.INVALID) + .With(x => x.Message, "Comment about the error") + .CreateMany(2); + var data = _fixture.Build() - //.With(x => x.Status, ClearinghouseResponseStatus.INVALID) - //.With(x => x.Message, "Comment about the error") + .With(x => x.ValidationUnits, validationUnits) .Create(); SetupForProcessClearinghouseResponse(entry);