From 6556aa0e4e23f21b437e757adfa45da2d67f1cfd Mon Sep 17 00:00:00 2001 From: cezaralexandremorais Date: Mon, 9 Oct 2023 10:50:16 +0100 Subject: [PATCH] feat(gate): Request Cleaning for Own Business Partner Update,Persist cleaning task identifier and associate with business partner in the SharingStateDto and update sharing state of business partner to Pending --- .../api/model/response/SharingStateDto.kt | 5 +- bpdm-gate/pom.xml | 4 + .../bpdm/gate/config/BpnConfigProperties.kt | 3 +- .../gate/config/OrchestratorClientConfig.kt | 52 ++++++ .../config/OrchestratorConfigProperties.kt | 28 +++ .../tractusx/bpdm/gate/entity/SharingState.kt | 5 +- .../gate/service/BusinessPartnerMappings.kt | 6 + .../gate/service/BusinessPartnerService.kt | 35 +++- .../bpdm/gate/service/OrchestratorMappings.kt | 130 +++++++++++++ .../bpdm/gate/service/SharingStateService.kt | 8 +- .../src/main/resources/application.properties | 3 + ...7__add_cleaning_task_id_sharing_states.sql | 2 + .../controller/BusinessPartnerControllerIT.kt | 173 +++++++++++++++++- 13 files changed, 442 insertions(+), 12 deletions(-) create mode 100644 bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/config/OrchestratorClientConfig.kt create mode 100644 bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/config/OrchestratorConfigProperties.kt create mode 100644 bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/OrchestratorMappings.kt create mode 100644 bpdm-gate/src/main/resources/db/migration/V4_0_0_17__add_cleaning_task_id_sharing_states.sql diff --git a/bpdm-gate-api/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/api/model/response/SharingStateDto.kt b/bpdm-gate-api/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/api/model/response/SharingStateDto.kt index 9fa452340..149e68a96 100644 --- a/bpdm-gate-api/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/api/model/response/SharingStateDto.kt +++ b/bpdm-gate-api/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/api/model/response/SharingStateDto.kt @@ -54,5 +54,8 @@ data class SharingStateDto( val bpn: String? = null, @get:Schema(description = "The date and time when the sharing process was started.") - val sharingProcessStarted: LocalDateTime? = null + val sharingProcessStarted: LocalDateTime? = null, + + @get:Schema(description = "The orchestrator task identifier that was created") + val taskId: String? = null, ) diff --git a/bpdm-gate/pom.xml b/bpdm-gate/pom.xml index f5a9a42e0..5efe1960e 100644 --- a/bpdm-gate/pom.xml +++ b/bpdm-gate/pom.xml @@ -152,6 +152,10 @@ spring-security-test test + + org.eclipse.tractusx + bpdm-orchestrator-api + diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/config/BpnConfigProperties.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/config/BpnConfigProperties.kt index 09ba0eb94..aad99a3c4 100644 --- a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/config/BpnConfigProperties.kt +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/config/BpnConfigProperties.kt @@ -26,5 +26,6 @@ import org.springframework.boot.context.properties.ConfigurationProperties data class BpnConfigProperties( val agencyName: String = "Catena-X", var name: String = "Business Partner Number", - val id: String = "CX_BPN" + val id: String = "CX_BPN", + val ownerBpnL: String? = null ) \ No newline at end of file diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/config/OrchestratorClientConfig.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/config/OrchestratorClientConfig.kt new file mode 100644 index 000000000..971e24454 --- /dev/null +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/config/OrchestratorClientConfig.kt @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2021,2023 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 + ******************************************************************************/ + +package org.eclipse.tractusx.bpdm.gate.config + +import org.eclipse.tractusx.orchestrator.api.client.OrchestrationApiClient +import org.eclipse.tractusx.orchestrator.api.client.OrchestrationApiClientImpl +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.http.HttpHeaders +import org.springframework.http.MediaType +import org.springframework.web.reactive.function.client.WebClient + + +@Configuration +class OrchestratorClientConfig { + + // Orchestrator-Client without authentication + @Bean + @ConditionalOnProperty( + value = ["bpdm.orchestrator.security-enabled"], + havingValue = "false", + matchIfMissing = true + ) + fun orchestratorClientNoAuth(orchestratorConfigProperties: OrchestratorConfigProperties): OrchestrationApiClient { + val url = orchestratorConfigProperties.baseUrl + return OrchestrationApiClientImpl { webClientBuilder(url).build() } + } + + private fun webClientBuilder(url: String) = + WebClient.builder() + .baseUrl(url) + .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + +} \ No newline at end of file diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/config/OrchestratorConfigProperties.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/config/OrchestratorConfigProperties.kt new file mode 100644 index 000000000..1ed241343 --- /dev/null +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/config/OrchestratorConfigProperties.kt @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2021,2023 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 + ******************************************************************************/ + +package org.eclipse.tractusx.bpdm.gate.config + +import org.springframework.boot.context.properties.ConfigurationProperties + + +@ConfigurationProperties(prefix = "bpdm.orchestrator") +data class OrchestratorConfigProperties( + val baseUrl: String = "http://localhost:8085", +) diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/entity/SharingState.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/entity/SharingState.kt index a29e2a374..fa3bb5dfb 100644 --- a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/entity/SharingState.kt +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/entity/SharingState.kt @@ -53,7 +53,10 @@ class SharingState( var bpn: String? = null, @Column(name = "sharing_process_started", nullable = true) - var sharingProcessStarted: LocalDateTime? = null + var sharingProcessStarted: LocalDateTime? = null, + + @Column(name = "task_id", nullable = true) + var taskId: String? = null ) : BaseEntity() diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/BusinessPartnerMappings.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/BusinessPartnerMappings.kt index 3566e600a..362941083 100644 --- a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/BusinessPartnerMappings.kt +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/BusinessPartnerMappings.kt @@ -187,6 +187,7 @@ class BusinessPartnerMappings { door = dto.door ) + private fun toAlternativePostalAddressDto(entity: AlternativePostalAddress) = AlternativePostalAddressGateDto( geographicCoordinates = entity.geographicCoordinates?.let(::toGeoCoordinateDto), @@ -211,6 +212,7 @@ class BusinessPartnerMappings { deliveryServiceNumber = dto.deliveryServiceNumber ) + private fun toStreetDto(entity: Street) = StreetGateDto( name = entity.name, @@ -223,6 +225,7 @@ class BusinessPartnerMappings { additionalNameSuffix = entity.additionalNameSuffix ) + private fun toStreet(dto: StreetGateDto) = Street( name = dto.name, @@ -256,6 +259,9 @@ class BusinessPartnerMappings { private fun toGeoCoordinateDto(entity: GeographicCoordinate) = GeoCoordinateDto(latitude = entity.latitude, longitude = entity.longitude, altitude = entity.altitude) + private fun toGeographicCoordinate(dto: GeoCoordinateDto) = GeographicCoordinate(latitude = dto.latitude, longitude = dto.longitude, altitude = dto.altitude) + + } diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/BusinessPartnerService.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/BusinessPartnerService.kt index 4c0111cdf..97bd85d37 100644 --- a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/BusinessPartnerService.kt +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/BusinessPartnerService.kt @@ -36,6 +36,8 @@ import org.eclipse.tractusx.bpdm.gate.entity.generic.* import org.eclipse.tractusx.bpdm.gate.exception.BpdmMissingStageException import org.eclipse.tractusx.bpdm.gate.repository.ChangelogRepository import org.eclipse.tractusx.bpdm.gate.repository.generic.BusinessPartnerRepository +import org.eclipse.tractusx.orchestrator.api.client.OrchestrationApiClient +import org.eclipse.tractusx.orchestrator.api.model.* import org.springframework.data.domain.Page import org.springframework.data.domain.PageRequest import org.springframework.stereotype.Service @@ -46,7 +48,9 @@ class BusinessPartnerService( private val businessPartnerRepository: BusinessPartnerRepository, private val businessPartnerMappings: BusinessPartnerMappings, private val sharingStateService: SharingStateService, - private val changelogRepository: ChangelogRepository + private val changelogRepository: ChangelogRepository, + private val orchestrationApiClient: OrchestrationApiClient, + private val orchestratorMappings: OrchestratorMappings ) { @Transactional @@ -79,7 +83,16 @@ class BusinessPartnerService( saveChangelog(resolutionResults) val partners = resolutionResults.map { it.businessPartner } - partners.forEach { entity -> initSharingState(entity) } + val orchestratorBusinessPartnersDto = resolutionResults.map { orchestratorMappings.toBusinessPartnerGenericDto(it.businessPartner) } + partners.forEach { entity -> + initSharingState(entity) + } + + val taskCreateResponse = requestNewCleaning(orchestratorBusinessPartnersDto) + + for (i in partners.indices) { + updateSharingState(partners[i], taskCreateResponse.createdTasks[i]) + } return businessPartnerRepository.saveAll(partners) } @@ -209,6 +222,24 @@ class BusinessPartnerService( } + private fun requestNewCleaning(orchestratorBusinessPartnersDto: List): TaskCreateResponse { + return orchestrationApiClient.goldenRecordTasks.createTasks( + TaskCreateRequest( + TaskMode.UpdateFromSharingMember, orchestratorBusinessPartnersDto + ) + ) + } + + private fun updateSharingState(entity: BusinessPartner, stateDto: TaskClientStateDto) { + sharingStateService.upsertSharingState( + SharingStateDto( + BusinessPartnerType.ADDRESS, + entity.externalId, + sharingStateType = orchestratorMappings.toSharingStateType(stateDto.processingState.resultState), + taskId = stateDto.taskId + ) + ) + } } diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/OrchestratorMappings.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/OrchestratorMappings.kt new file mode 100644 index 000000000..1f9064b9f --- /dev/null +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/OrchestratorMappings.kt @@ -0,0 +1,130 @@ +/******************************************************************************* + * Copyright (c) 2021,2023 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 + ******************************************************************************/ + +package org.eclipse.tractusx.bpdm.gate.service + +import mu.KotlinLogging +import org.eclipse.tractusx.bpdm.common.dto.BusinessPartnerIdentifierDto +import org.eclipse.tractusx.bpdm.common.dto.BusinessPartnerStateDto +import org.eclipse.tractusx.bpdm.common.dto.ClassificationDto +import org.eclipse.tractusx.bpdm.common.dto.GeoCoordinateDto +import org.eclipse.tractusx.bpdm.gate.api.model.SharingStateType +import org.eclipse.tractusx.bpdm.gate.config.BpnConfigProperties +import org.eclipse.tractusx.bpdm.gate.entity.AlternativePostalAddress +import org.eclipse.tractusx.bpdm.gate.entity.GeographicCoordinate +import org.eclipse.tractusx.bpdm.gate.entity.PhysicalPostalAddress +import org.eclipse.tractusx.bpdm.gate.entity.Street +import org.eclipse.tractusx.bpdm.gate.entity.generic.* +import org.eclipse.tractusx.orchestrator.api.model.* +import org.springframework.stereotype.Service + +@Service +class OrchestratorMappings( + private val bpnConfigProperties: BpnConfigProperties +) { + private val logger = KotlinLogging.logger { } + fun toBusinessPartnerGenericDto(entity: BusinessPartner) = BusinessPartnerGenericDto( + nameParts = entity.nameParts, + shortName = entity.shortName, + identifiers = entity.identifiers.map { toIdentifierDto(it) }, + legalForm = entity.legalForm, + states = entity.states.map { toStateDto(it) }, + classifications = entity.classifications.map { toClassificationDto(it) }, + roles = entity.roles, + postalAddress = toBusinessPartnerGenericPostalAddressDto(entity.postalAddress), + bpnL = entity.bpnL, + bpnS = entity.bpnS, + bpnA = entity.bpnA, + ownerBpnL = getOwnerBpnL(entity) + ) + + private fun toClassificationDto(entity: Classification) = + ClassificationDto(type = entity.type, code = entity.code, value = entity.value) + + private fun toBusinessPartnerGenericPostalAddressDto(entity: PostalAddress) = + PostalAddressDto( + addressType = entity.addressType, + physicalPostalAddress = entity.physicalPostalAddress?.let(::toBusinessPartnerGenericPhysicalPostalAddressDto), + alternativePostalAddress = entity.alternativePostalAddress?.let(::toBusinessPartnerGenericAlternativePostalAddressDto) + ) + + private fun toBusinessPartnerGenericPhysicalPostalAddressDto(entity: PhysicalPostalAddress) = + PhysicalPostalAddressDto( + geographicCoordinates = entity.geographicCoordinates?.let(::toBusinessPartnerGenericGeoCoordinateDto), + country = entity.country, + administrativeAreaLevel1 = entity.administrativeAreaLevel1, + administrativeAreaLevel2 = entity.administrativeAreaLevel2, + administrativeAreaLevel3 = entity.administrativeAreaLevel3, + postalCode = entity.postalCode, + city = entity.city, + district = entity.district, + street = entity.street?.let(::toGenericBusinessPartnerStreetDto), + companyPostalCode = entity.companyPostalCode, + industrialZone = entity.industrialZone, + building = entity.building, + floor = entity.floor, + door = entity.door + ) + + private fun toBusinessPartnerGenericAlternativePostalAddressDto(entity: AlternativePostalAddress): AlternativePostalAddressDto = + AlternativePostalAddressDto( + geographicCoordinates = entity.geographicCoordinates?.let(::toBusinessPartnerGenericGeoCoordinateDto), + country = entity.country, + administrativeAreaLevel1 = entity.administrativeAreaLevel1, + postalCode = entity.postalCode, + city = entity.city, + deliveryServiceType = entity.deliveryServiceType, + deliveryServiceQualifier = entity.deliveryServiceQualifier, + deliveryServiceNumber = entity.deliveryServiceNumber + ) + + private fun toGenericBusinessPartnerStreetDto(entity: Street) = + StreetDto( + name = entity.name, + houseNumber = entity.houseNumber, + milestone = entity.milestone, + direction = entity.direction, + namePrefix = entity.namePrefix, + additionalNamePrefix = entity.additionalNamePrefix, + nameSuffix = entity.nameSuffix, + additionalNameSuffix = entity.additionalNameSuffix + ) + + private fun toStateDto(entity: State) = + BusinessPartnerStateDto(type = entity.type, validFrom = entity.validFrom, validTo = entity.validTo, description = entity.description) + + private fun toIdentifierDto(entity: Identifier) = + BusinessPartnerIdentifierDto(type = entity.type, value = entity.value, issuingBody = entity.issuingBody) + + private fun toBusinessPartnerGenericGeoCoordinateDto(entity: GeographicCoordinate) = + GeoCoordinateDto(latitude = entity.latitude, longitude = entity.longitude, altitude = entity.altitude) + + private fun getOwnerBpnL(entity: BusinessPartner): String? { + return if (entity.isOwnCompanyData) bpnConfigProperties.ownerBpnL else { + logger.warn { "Owner BPNL property is not configured" } + null + } + } + + fun toSharingStateType(resultState: ResultState) = when (resultState) { + ResultState.Pending -> SharingStateType.Pending + ResultState.Success -> SharingStateType.Success + ResultState.Error -> SharingStateType.Error + } +} \ No newline at end of file diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/SharingStateService.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/SharingStateService.kt index a02a961fe..a58d4d574 100644 --- a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/SharingStateService.kt +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/SharingStateService.kt @@ -54,7 +54,8 @@ class SharingStateService(private val stateRepository: SharingStateRepository) { sharingErrorCode = dto.sharingErrorCode, sharingErrorMessage = dto.sharingErrorMessage, bpn = dto.bpn, - sharingProcessStarted = dto.sharingProcessStarted + sharingProcessStarted = dto.sharingProcessStarted, + taskId = dto.taskId ) ) } @@ -65,10 +66,10 @@ class SharingStateService(private val stateRepository: SharingStateRepository) { entity.sharingErrorCode = dto.sharingErrorCode entity.sharingErrorMessage = dto.sharingErrorMessage entity.bpn = dto.bpn + entity.taskId = dto.taskId if (dto.sharingProcessStarted != null) { entity.sharingProcessStarted = dto.sharingProcessStarted } - this.stateRepository.save(entity) } @@ -90,7 +91,8 @@ class SharingStateService(private val stateRepository: SharingStateRepository) { sharingErrorCode = it.sharingErrorCode, sharingErrorMessage = it.sharingErrorMessage, bpn = it.bpn, - sharingProcessStarted = it.sharingProcessStarted + sharingProcessStarted = it.sharingProcessStarted, + taskId = it.taskId ) }) diff --git a/bpdm-gate/src/main/resources/application.properties b/bpdm-gate/src/main/resources/application.properties index f8dc76597..e1e65a3ce 100644 --- a/bpdm-gate/src/main/resources/application.properties +++ b/bpdm-gate/src/main/resources/application.properties @@ -28,6 +28,7 @@ bpdm.api.upsert-limit=100 bpdm.bpn.agency-name=Catena-X bpdm.bpn.name=Business Partner Number bpdm.bpn.id=CX_BPN +bpdm.bpn.owner-bpn-l=# Insert owner BPNL here #Springdoc swagger configuration springdoc.swagger-ui.disable-swagger-default-url=true springdoc.swagger-ui.path=/ui/swagger-ui @@ -42,6 +43,8 @@ management.health.readinessState.enabled=true # No auth on default bpdm.gate-security.pool-security-enabled=false bpdm.pool.base-url=http://localhost:8080/api/catena +bpdm.orchestrator.security-enabled=false +bpdm.orchestrator.base-url=http://localhost:8085 #No security on default bpdm.security.enabled=false #Datasource configuration diff --git a/bpdm-gate/src/main/resources/db/migration/V4_0_0_17__add_cleaning_task_id_sharing_states.sql b/bpdm-gate/src/main/resources/db/migration/V4_0_0_17__add_cleaning_task_id_sharing_states.sql new file mode 100644 index 000000000..e83e449eb --- /dev/null +++ b/bpdm-gate/src/main/resources/db/migration/V4_0_0_17__add_cleaning_task_id_sharing_states.sql @@ -0,0 +1,2 @@ +ALTER TABLE sharing_states +ADD COLUMN task_id VARCHAR(255); \ No newline at end of file diff --git a/bpdm-gate/src/test/kotlin/org/eclipse/tractusx/bpdm/gate/controller/BusinessPartnerControllerIT.kt b/bpdm-gate/src/test/kotlin/org/eclipse/tractusx/bpdm/gate/controller/BusinessPartnerControllerIT.kt index f9efcc9cf..c7dd6e1a6 100644 --- a/bpdm-gate/src/test/kotlin/org/eclipse/tractusx/bpdm/gate/controller/BusinessPartnerControllerIT.kt +++ b/bpdm-gate/src/test/kotlin/org/eclipse/tractusx/bpdm/gate/controller/BusinessPartnerControllerIT.kt @@ -19,26 +19,37 @@ package org.eclipse.tractusx.bpdm.gate.controller +import com.fasterxml.jackson.databind.ObjectMapper +import com.github.tomakehurst.wiremock.client.WireMock +import com.github.tomakehurst.wiremock.core.WireMockConfiguration +import com.github.tomakehurst.wiremock.junit5.WireMockExtension import org.assertj.core.api.Assertions import org.eclipse.tractusx.bpdm.common.dto.BusinessPartnerIdentifierDto import org.eclipse.tractusx.bpdm.common.dto.BusinessPartnerStateDto +import org.eclipse.tractusx.bpdm.common.dto.BusinessPartnerType import org.eclipse.tractusx.bpdm.common.dto.ClassificationDto import org.eclipse.tractusx.bpdm.common.dto.request.PaginationRequest import org.eclipse.tractusx.bpdm.gate.api.client.GateClient +import org.eclipse.tractusx.bpdm.gate.api.model.SharingStateType import org.eclipse.tractusx.bpdm.gate.api.model.request.BusinessPartnerInputRequest import org.eclipse.tractusx.bpdm.gate.api.model.response.BusinessPartnerInputDto +import org.eclipse.tractusx.bpdm.gate.api.model.response.SharingStateDto import org.eclipse.tractusx.bpdm.gate.util.BusinessPartnerNonVerboseValues import org.eclipse.tractusx.bpdm.gate.util.BusinessPartnerVerboseValues import org.eclipse.tractusx.bpdm.gate.util.DbTestHelpers import org.eclipse.tractusx.bpdm.gate.util.PostgreSQLContextInitializer +import org.eclipse.tractusx.orchestrator.api.model.* import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.RegisterExtension import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.http.HttpStatus import org.springframework.test.context.ActiveProfiles import org.springframework.test.context.ContextConfiguration +import org.springframework.test.context.DynamicPropertyRegistry +import org.springframework.test.context.DynamicPropertySource import org.springframework.web.reactive.function.client.WebClientResponseException import java.time.Instant @@ -51,15 +62,35 @@ import java.time.Instant class BusinessPartnerControllerIT @Autowired constructor( val testHelpers: DbTestHelpers, val gateClient: GateClient, + val objectMapper: ObjectMapper ) { + companion object { + const val ORCHESTRATOR_REQUEST_NEW_CLEANING = "/api/golden-record-tasks" + + @JvmField + @RegisterExtension + val gateWireMockServer: WireMockExtension = WireMockExtension.newInstance() + .options(WireMockConfiguration.wireMockConfig().dynamicPort()) + .build() + + @JvmStatic + @DynamicPropertySource + fun properties(registry: DynamicPropertyRegistry) { + registry.add("bpdm.orchestrator.base-url") { gateWireMockServer.baseUrl() } + } + } @BeforeEach fun beforeEach() { testHelpers.truncateDbTables() + gateWireMockServer.resetAll() + this.mockOrchestratorApi() } @Test fun `insert minimal business partner`() { + + val upsertRequests = listOf(BusinessPartnerNonVerboseValues.bpInputRequestMinimal) val upsertResponses = gateClient.businessParters.upsertBusinessPartnersInput(upsertRequests).body!! assertUpsertResponsesMatchRequests(upsertResponses, upsertRequests) @@ -71,7 +102,11 @@ class BusinessPartnerControllerIT @Autowired constructor( @Test fun `insert three business partners`() { - val upsertRequests = listOf(BusinessPartnerNonVerboseValues.bpInputRequestFull, BusinessPartnerNonVerboseValues.bpInputRequestMinimal, BusinessPartnerNonVerboseValues.bpInputRequestChina) + val upsertRequests = listOf( + BusinessPartnerNonVerboseValues.bpInputRequestFull, + BusinessPartnerNonVerboseValues.bpInputRequestMinimal, + BusinessPartnerNonVerboseValues.bpInputRequestChina + ) val upsertResponses = gateClient.businessParters.upsertBusinessPartnersInput(upsertRequests).body!! assertUpsertResponsesMatchRequests(upsertResponses, upsertRequests) @@ -80,8 +115,63 @@ class BusinessPartnerControllerIT @Autowired constructor( testHelpers.assertRecursively(searchResponsePage.content).isEqualTo(upsertResponses) } + @Test + fun `insert three business partners and check sharing state is pending and has taskid`() { + val upsertRequests = listOf( + BusinessPartnerNonVerboseValues.bpInputRequestFull, + BusinessPartnerNonVerboseValues.bpInputRequestMinimal, + BusinessPartnerNonVerboseValues.bpInputRequestChina + ) + gateClient.businessParters.upsertBusinessPartnersInput(upsertRequests).body!! + val upsertExternalIds = listOf( + BusinessPartnerNonVerboseValues.bpInputRequestFull.externalId, + BusinessPartnerNonVerboseValues.bpInputRequestMinimal.externalId, + BusinessPartnerNonVerboseValues.bpInputRequestChina.externalId + ) + val upsertSharingStatesRequests = listOf( + SharingStateDto( + businessPartnerType = BusinessPartnerType.ADDRESS, + externalId = "external-1", + sharingStateType = SharingStateType.Pending, + sharingErrorCode = null, + sharingErrorMessage = null, + bpn = null, + sharingProcessStarted = null, + taskId = "0" + ), + SharingStateDto( + businessPartnerType = BusinessPartnerType.ADDRESS, + externalId = "external-2", + sharingStateType = SharingStateType.Pending, + sharingErrorCode = null, + sharingErrorMessage = null, + bpn = null, + sharingProcessStarted = null, + taskId = "1" + ), + SharingStateDto( + businessPartnerType = BusinessPartnerType.ADDRESS, + externalId = "external-3", + sharingStateType = SharingStateType.Pending, + sharingErrorCode = null, + sharingErrorMessage = null, + bpn = null, + sharingProcessStarted = null, + taskId = "2" + ) + ) + + val upsertSharingStateResponses = readSharingStates(BusinessPartnerType.ADDRESS, upsertExternalIds) + + + testHelpers.assertRecursively(upsertSharingStateResponses).isEqualTo(upsertSharingStatesRequests) + + } + + @Test fun `insert and then update business partner`() { + val insertRequests = listOf(BusinessPartnerNonVerboseValues.bpInputRequestMinimal) val externalId = insertRequests.first().externalId val insertResponses = gateClient.businessParters.upsertBusinessPartnersInput(insertRequests).body!! @@ -138,7 +228,8 @@ class BusinessPartnerControllerIT @Autowired constructor( ) gateClient.businessParters.upsertBusinessPartnersInput(upsertRequests) - val searchResponsePage = gateClient.businessParters.getBusinessPartnersInput(listOf(BusinessPartnerVerboseValues.externalId1, BusinessPartnerVerboseValues.externalId3)) + val searchResponsePage = + gateClient.businessParters.getBusinessPartnersInput(listOf(BusinessPartnerVerboseValues.externalId1, BusinessPartnerVerboseValues.externalId3)) assertUpsertResponsesMatchRequests(searchResponsePage.content, listOf(upsertRequests[0], upsertRequests[2])) } @@ -152,14 +243,18 @@ class BusinessPartnerControllerIT @Autowired constructor( gateClient.businessParters.upsertBusinessPartnersInput(upsertRequests) // missing externalIds are just ignored in the response - val searchResponsePage = gateClient.businessParters.getBusinessPartnersInput(listOf(BusinessPartnerVerboseValues.externalId2, BusinessPartnerVerboseValues.externalId4)) + val searchResponsePage = + gateClient.businessParters.getBusinessPartnersInput(listOf(BusinessPartnerVerboseValues.externalId2, BusinessPartnerVerboseValues.externalId4)) assertUpsertResponsesMatchRequests(searchResponsePage.content, listOf(upsertRequests[1])) } @Test fun `query business partners using paging`() { val upsertRequests = listOf( - BusinessPartnerNonVerboseValues.bpInputRequestFull.copy(externalId = BusinessPartnerNonVerboseValues.bpInputRequestFull.externalId, shortName = "1"), + BusinessPartnerNonVerboseValues.bpInputRequestFull.copy( + externalId = BusinessPartnerNonVerboseValues.bpInputRequestFull.externalId, + shortName = "1" + ), BusinessPartnerNonVerboseValues.bpInputRequestMinimal.copy(externalId = BusinessPartnerVerboseValues.externalId2, shortName = "2"), BusinessPartnerNonVerboseValues.bpInputRequestMinimal.copy(externalId = BusinessPartnerVerboseValues.externalId3, shortName = "3") ) @@ -224,4 +319,74 @@ class BusinessPartnerControllerIT @Autowired constructor( ClassificationDto::code, ClassificationDto::value ) + + private fun mockOrchestratorApi() { + val responseOrchestratorTaskResponse = + TaskCreateResponse( + listOf( + TaskClientStateDto( + taskId = "0", + businessPartnerResult = null, + processingState = TaskProcessingStateDto( + resultState = ResultState.Pending, + step = TaskStep.CleanAndSync, + stepState = StepState.Queued, + errors = emptyList(), + createdAt = Instant.now(), + modifiedAt = Instant.now() + ) + ), + TaskClientStateDto( + taskId = "1", + businessPartnerResult = null, + processingState = TaskProcessingStateDto( + resultState = ResultState.Pending, + step = TaskStep.CleanAndSync, + stepState = StepState.Queued, + errors = emptyList(), + createdAt = Instant.now(), + modifiedAt = Instant.now() + ) + ), + TaskClientStateDto( + taskId = "2", + businessPartnerResult = null, + processingState = TaskProcessingStateDto( + resultState = ResultState.Pending, + step = TaskStep.CleanAndSync, + stepState = StepState.Queued, + errors = emptyList(), + createdAt = Instant.now(), + modifiedAt = Instant.now() + ) + ), + TaskClientStateDto( + taskId = "3", + businessPartnerResult = null, + processingState = TaskProcessingStateDto( + resultState = ResultState.Pending, + step = TaskStep.CleanAndSync, + stepState = StepState.Queued, + errors = emptyList(), + createdAt = Instant.now(), + modifiedAt = Instant.now() + ) + ) + ) + ) + + // Orchestrator request new cleaning endpoint + gateWireMockServer.stubFor( + WireMock.post(WireMock.urlPathEqualTo(ORCHESTRATOR_REQUEST_NEW_CLEANING)) + .willReturn( + WireMock.okJson(objectMapper.writeValueAsString(responseOrchestratorTaskResponse)) + ) + ) + } + + fun readSharingStates(businessPartnerType: BusinessPartnerType?, externalIds: Collection?): Collection { + + return gateClient.sharingState.getSharingStates(PaginationRequest(), businessPartnerType, externalIds).content + } + }