From 3345cbce437aaa9a57d95a7820cfc4b98d2c2c61 Mon Sep 17 00:00:00 2001 From: SujitMBRDI Date: Mon, 2 Dec 2024 14:44:45 +0530 Subject: [PATCH] fix(bpdm-gate): fetched and attached legal name of entity while performing partner upload process. --- CHANGELOG.md | 7 + .../bpdm/gate/service/PartnerUploadService.kt | 17 ++- .../bpdm/gate/util/PartnerFileUtil.kt | 8 +- .../controller/PartnerUploadControllerIT.kt | 121 +++++++++++++++++- 4 files changed, 144 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e38439bc3..c8e2f83bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,13 @@ For changes to the BPDM Helm charts please consult the [changelog](charts/bpdm/C ## [6.3.0] - tbd +### Added + + +### Changed + +- BPDM Gate: Fetched and updated legal name of legal entity from pool while performing partner upload process via CSV([#1141](https://github.com/eclipse-tractusx/bpdm/issues/1141)) + ## [6.2.0] - 2024-11-28 diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/PartnerUploadService.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/PartnerUploadService.kt index 4e9917c6d..c024ac0ff 100644 --- a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/PartnerUploadService.kt +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/PartnerUploadService.kt @@ -21,10 +21,13 @@ package org.eclipse.tractusx.bpdm.gate.service import com.opencsv.CSVWriter import mu.KotlinLogging +import org.eclipse.tractusx.bpdm.common.dto.PaginationRequest import org.eclipse.tractusx.bpdm.gate.api.model.response.BusinessPartnerInputDto import org.eclipse.tractusx.bpdm.gate.model.PartnerUploadFileHeader import org.eclipse.tractusx.bpdm.gate.model.PartnerUploadFileRow import org.eclipse.tractusx.bpdm.gate.util.PartnerFileUtil +import org.eclipse.tractusx.bpdm.pool.api.client.PoolApiClient +import org.eclipse.tractusx.bpdm.pool.api.model.request.LegalEntitySearchRequest import org.springframework.core.io.ByteArrayResource import org.springframework.http.ResponseEntity import org.springframework.stereotype.Service @@ -34,15 +37,25 @@ import java.io.OutputStreamWriter @Service class PartnerUploadService( - private val businessPartnerService: BusinessPartnerService + private val businessPartnerService: BusinessPartnerService, + private val poolApiClient: PoolApiClient ) { private val logger = KotlinLogging.logger { } fun processFile(file: MultipartFile, tenantBpnl: String?): ResponseEntity> { validateTenantBpnl(tenantBpnl) + val legalName = poolApiClient.legalEntities + .getLegalEntities( + LegalEntitySearchRequest(listOf(tenantBpnl!!)), + PaginationRequest(page = 0, size = 1) + ).content.also { entities -> + require(entities.isNotEmpty()) { "No legal entities found for tenantBpnl: $tenantBpnl" } + require(entities.size == 1) { "Multiple legal entities found for tenantBpnl: $tenantBpnl" } + } + .first().legalEntity.legalName val csvData: List = PartnerFileUtil.parseCsv(file) - val businessPartnerDtos = PartnerFileUtil.validateAndMapToBusinessPartnerInputRequests(csvData, tenantBpnl) + val businessPartnerDtos = PartnerFileUtil.validateAndMapToBusinessPartnerInputRequests(csvData, tenantBpnl, legalName) val result = businessPartnerService.upsertBusinessPartnersInput(businessPartnerDtos, tenantBpnl) return ResponseEntity.ok(result) } diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/util/PartnerFileUtil.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/util/PartnerFileUtil.kt index c03b46dbf..9bf7007dc 100644 --- a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/util/PartnerFileUtil.kt +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/util/PartnerFileUtil.kt @@ -67,7 +67,7 @@ object PartnerFileUtil { * @return A list of BusinessPartnerInputRequest objects derived from the valid CSV rows. * @throws BpdmInvalidPartnerUploadException if any validation errors are encountered during processing. */ - fun validateAndMapToBusinessPartnerInputRequests(csvData: List, tenantBpnl: String?): List { + fun validateAndMapToBusinessPartnerInputRequests(csvData: List, tenantBpnl: String?, legalName: String): List { val formatter = DateTimeFormatter.ISO_DATE_TIME val validator: Validator = Validation.buildDefaultValidatorFactory().validator val errors = mutableListOf() @@ -85,8 +85,10 @@ object PartnerFileUtil { states = emptyList(), roles = emptyList(), isOwnCompanyData = true, - // Legal entity's business partner number is nothing but tenant's partner number who is performing business partner upload action - legalEntity = LegalEntityRepresentationInputDto(legalEntityBpn = tenantBpnl?.takeIf { it.isNotEmpty() }), + legalEntity = LegalEntityRepresentationInputDto( + legalEntityBpn = tenantBpnl?.takeIf { it.isNotEmpty() }, + legalName = legalName + ), site = row.toSiteRepresentationInputDto(formatter, errors, index, row.externalId.orEmpty()), address = row.toAddressRepresentationInputDto(formatter, errors, index, row.externalId.orEmpty()) ) diff --git a/bpdm-gate/src/test/kotlin/org/eclipse/tractusx/bpdm/gate/controller/PartnerUploadControllerIT.kt b/bpdm-gate/src/test/kotlin/org/eclipse/tractusx/bpdm/gate/controller/PartnerUploadControllerIT.kt index 2edcb5d06..6f90b018f 100644 --- a/bpdm-gate/src/test/kotlin/org/eclipse/tractusx/bpdm/gate/controller/PartnerUploadControllerIT.kt +++ b/bpdm-gate/src/test/kotlin/org/eclipse/tractusx/bpdm/gate/controller/PartnerUploadControllerIT.kt @@ -19,10 +19,23 @@ 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.client.WireMock.okJson +import com.github.tomakehurst.wiremock.core.WireMockConfiguration +import com.github.tomakehurst.wiremock.junit5.WireMockExtension +import com.neovisionaries.i18n.CountryCode +import org.eclipse.tractusx.bpdm.common.dto.PageDto +import org.eclipse.tractusx.bpdm.common.dto.TypeKeyNameVerboseDto import org.eclipse.tractusx.bpdm.gate.api.client.GateClient import org.eclipse.tractusx.bpdm.gate.api.model.request.BusinessPartnerInputRequest import org.eclipse.tractusx.bpdm.gate.api.model.response.LegalEntityRepresentationInputDto import org.eclipse.tractusx.bpdm.gate.util.MockAndAssertUtils +import org.eclipse.tractusx.bpdm.pool.api.model.ConfidenceCriteriaDto +import org.eclipse.tractusx.bpdm.pool.api.model.LegalEntityVerboseDto +import org.eclipse.tractusx.bpdm.pool.api.model.LogisticAddressVerboseDto +import org.eclipse.tractusx.bpdm.pool.api.model.PhysicalPostalAddressVerboseDto +import org.eclipse.tractusx.bpdm.pool.api.model.response.LegalEntityWithLegalAddressVerboseDto import org.eclipse.tractusx.bpdm.test.containers.KeyCloakInitializer import org.eclipse.tractusx.bpdm.test.containers.PostgreSQLContextInitializer import org.eclipse.tractusx.bpdm.test.containers.SelfClientInitializer @@ -32,15 +45,20 @@ import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows +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.mock.web.MockMultipartFile 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.nio.file.Files import java.nio.file.Paths +import java.time.Instant +import java.time.LocalDateTime @SpringBootTest( webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, @@ -56,12 +74,32 @@ import java.nio.file.Paths class PartnerUploadControllerIT @Autowired constructor( val testHelpers: DbTestHelpers, val gateClient: GateClient, + val jacksonObjectMapper: ObjectMapper, val mockAndAssertUtils: MockAndAssertUtils ) { + companion object { + + const val TENANT_BPNL = KeyCloakInitializer.TENANT_BPNL + const val MOCKED_LEGAL_NAME = "Mocked Legal Name" + + @JvmField + @RegisterExtension + val poolWireMockApi: WireMockExtension = WireMockExtension.newInstance().options(WireMockConfiguration.wireMockConfig().dynamicPort()).build() + + @JvmStatic + @DynamicPropertySource + fun properties(registry: DynamicPropertyRegistry) { + registry.add("bpdm.client.pool.base-url") { poolWireMockApi.baseUrl() } + } + + } + @BeforeEach fun beforeEach() { testHelpers.truncateDbTables() + poolWireMockApi.resetAll() + poolMockGetLegalEntitiesApi(TENANT_BPNL, MOCKED_LEGAL_NAME) } @Test @@ -88,8 +126,8 @@ class PartnerUploadControllerIT @Autowired constructor( // Only Site and Address expected to be updated from upload partner process. val expectedSiteAndAddressPartner = BusinessPartnerVerboseValues.bpUploadRequestFull.copy( legalEntity = LegalEntityRepresentationInputDto( - legalEntityBpn = KeyCloakInitializer.TENANT_BPNL, - legalName = null, + legalEntityBpn = TENANT_BPNL, + legalName = MOCKED_LEGAL_NAME, shortName = null, legalForm = null, states = emptyList() @@ -132,8 +170,8 @@ class PartnerUploadControllerIT @Autowired constructor( val expectedSiteAndAddressPartner = BusinessPartnerVerboseValues.bpUploadRequestFull.copy( legalEntity = LegalEntityRepresentationInputDto( - legalEntityBpn = KeyCloakInitializer.TENANT_BPNL, - legalName = null, + legalEntityBpn = TENANT_BPNL, + legalName = MOCKED_LEGAL_NAME, shortName = null, legalForm = null, states = emptyList() @@ -156,6 +194,81 @@ class PartnerUploadControllerIT @Autowired constructor( this.mockAndAssertUtils.assertUpsertResponsesMatchRequests(searchResponsePage, expectedResponse) } + fun poolMockGetLegalEntitiesApi(tenantBpnl: String, legalName: String) { + val legalEntity1 = LegalEntityVerboseDto( + bpnl = tenantBpnl, + legalName = legalName, + legalShortName = null, + legalFormVerbose = null, + identifiers = emptyList(), + states = emptyList(), + relations = emptyList(), + currentness = Instant.now(), + confidenceCriteria = ConfidenceCriteriaDto( + sharedByOwner = true, + checkedByExternalDataSource = true, + numberOfSharingMembers = 0, + lastConfidenceCheckAt = LocalDateTime.of(2023, 10, 10, 10, 10, 10), + nextConfidenceCheckAt = LocalDateTime.of(2024, 10, 10, 10, 10, 10), + confidenceLevel = 0 + ), + isCatenaXMemberData = false, + createdAt = Instant.now(), + updatedAt = Instant.now() + ) + + val legalAddress1 = LogisticAddressVerboseDto( + bpna = "BPNA00000000009W", + physicalPostalAddress = PhysicalPostalAddressVerboseDto( + geographicCoordinates = null, + countryVerbose = TypeKeyNameVerboseDto(CountryCode.DE, CountryCode.DE.getName()), + postalCode = null, + city = "Stuttgart", + administrativeAreaLevel1Verbose = null, + administrativeAreaLevel2 = null, + administrativeAreaLevel3 = null, + district = null, + companyPostalCode = null, + industrialZone = null, + building = null, + floor = null, + door = null, + street = null, + taxJurisdictionCode = null + ), + bpnLegalEntity = null, + bpnSite = null, + confidenceCriteria = ConfidenceCriteriaDto( + sharedByOwner = true, + checkedByExternalDataSource = true, + numberOfSharingMembers = 0, + lastConfidenceCheckAt = LocalDateTime.of(2023, 10, 10, 10, 10, 10), + nextConfidenceCheckAt = LocalDateTime.of(2024, 10, 10, 10, 10, 10), + confidenceLevel = 0 + ), + isCatenaXMemberData = false, + createdAt = Instant.now(), + updatedAt = Instant.now() + ) + + val responseBody = PageDto( + 1, 1, 0, 1, + listOf( + LegalEntityWithLegalAddressVerboseDto(legalEntity = legalEntity1, legalAddress = legalAddress1) + ) + ) + + poolWireMockApi.stubFor( + WireMock.get(WireMock.urlPathEqualTo("/v6/legal-entities")) + .withQueryParam("bpnLs", WireMock.equalTo(tenantBpnl)) + .withQueryParam("page", WireMock.equalTo("0")) + .withQueryParam("size", WireMock.equalTo("1")) + .willReturn( + okJson(jacksonObjectMapper.writeValueAsString(responseBody)) + ) + ) + } + private fun testFileUpload(filePath: String, expectedStatus: HttpStatus) { val bytes = Files.readAllBytes(Paths.get(filePath))