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..111606397c 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,14 @@ public class ClearinghouseBusinessLogic(
public async Task HandleClearinghouse(IApplicationChecklistService.WorkerChecklistProcessStepData context, CancellationToken cancellationToken)
{
- var overwrite = context.ProcessStepTypeId switch
+ var validationMode = context.ProcessStepTypeId switch
{
- ProcessStepTypeId.START_OVERRIDE_CLEARING_HOUSE => true,
- ProcessStepTypeId.START_CLEARING_HOUSE => false,
+ 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}")
};
- 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, validationMode, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
return new IApplicationChecklistService.WorkerChecklistProcessStepExecutionResult(
ProcessStepStatusId.DONE,
@@ -84,7 +60,7 @@ public class ClearinghouseBusinessLogic(
null);
}
- private async Task TriggerCompanyDataPost(Guid applicationId, string decentralizedIdentifier, bool overwrite, CancellationToken cancellationToken)
+ private async Task TriggerCompanyDataPost(Guid applicationId, string validationMode, CancellationToken cancellationToken)
{
var data = await portalRepositories.GetInstance()
.GetClearinghouseDataForApplicationId(applicationId).ConfigureAwait(ConfigureAwaitOptions.None);
@@ -98,16 +74,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,
+ validationMode,
+ new CallBack(_settings.CallbackUrl, headers)
+ );
await clearinghouseService.TriggerCompanyDataPost(transferData, cancellationToken).ConfigureAwait(ConfigureAwaitOptions.None);
}
@@ -123,19 +104,24 @@ public async Task ProcessEndClearinghouse(Guid applicationId, ClearinghouseRespo
processStepTypeIds: [ProcessStepTypeId.START_SELF_DESCRIPTION_LP])
.ConfigureAwait(ConfigureAwaitOptions.None);
- var declined = data.Status == ClearinghouseResponseStatus.DECLINE;
-
+ // 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(
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/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..d473c1479f
--- /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";
+}
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/Extensions/UniqueIdentifiersExtension.cs b/src/portalbackend/PortalBackend.DBAccess/Extensions/UniqueIdentifiersExtension.cs
new file mode 100644
index 0000000000..94c42a4b7c
--- /dev/null
+++ b/src/portalbackend/PortalBackend.DBAccess/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.PortalBackend.DBAccess.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 Clearing House Conversion")
+ };
+}
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..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;
@@ -401,16 +402,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.UniqueIdentifierId.GetUniqueIdentifierValue(), 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..de50310822 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
@@ -136,7 +132,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]
@@ -216,106 +212,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 +221,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
@@ -337,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);
}
@@ -346,9 +247,13 @@ 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)
+ 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.ValidationUnits, validationUnits)
.Create();
SetupForProcessClearinghouseResponse(entry);
@@ -391,26 +296,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);
}