Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: endpoint to return bpnl/s/a based on the requested identifiers #1146

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions DEPENDENCIES
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,12 @@ maven/mavencentral/org.awaitility/awaitility/4.2.2, Apache-2.0, approved, #14178
maven/mavencentral/org.checkerframework/checker-qual/3.42.0, MIT, approved, clearlydefined
maven/mavencentral/org.eclipse.angus/angus-activation/2.0.2, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.angus
maven/mavencentral/org.eclipse.angus/angus-mail/2.0.3, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.angus
maven/mavencentral/org.eclipse.tractusx/bpdm-common-test/6.2.0-SNAPSHOT, Apache-2.0, approved, automotive.tractusx
maven/mavencentral/org.eclipse.tractusx/bpdm-common/6.2.0-SNAPSHOT, Apache-2.0, approved, automotive.tractusx
maven/mavencentral/org.eclipse.tractusx/bpdm-gate-api/6.2.0-SNAPSHOT, Apache-2.0, approved, automotive.tractusx
maven/mavencentral/org.eclipse.tractusx/bpdm-orchestrator-api/6.2.0-SNAPSHOT, Apache-2.0, approved, automotive.tractusx
maven/mavencentral/org.eclipse.tractusx/bpdm-orchestrator/6.2.0-SNAPSHOT, Apache-2.0, approved, automotive.tractusx
maven/mavencentral/org.eclipse.tractusx/bpdm-pool-api/6.2.0-SNAPSHOT, Apache-2.0, approved, automotive.tractusx
maven/mavencentral/org.eclipse.tractusx/bpdm-common-test/6.3.0-SNAPSHOT, Apache-2.0, approved, automotive.tractusx
maven/mavencentral/org.eclipse.tractusx/bpdm-common/6.3.0-SNAPSHOT, Apache-2.0, approved, automotive.tractusx
maven/mavencentral/org.eclipse.tractusx/bpdm-gate-api/6.3.0-SNAPSHOT, Apache-2.0, approved, automotive.tractusx
maven/mavencentral/org.eclipse.tractusx/bpdm-orchestrator-api/6.3.0-SNAPSHOT, Apache-2.0, approved, automotive.tractusx
maven/mavencentral/org.eclipse.tractusx/bpdm-orchestrator/6.3.0-SNAPSHOT, Apache-2.0, approved, automotive.tractusx
maven/mavencentral/org.eclipse.tractusx/bpdm-pool-api/6.3.0-SNAPSHOT, Apache-2.0, approved, automotive.tractusx
maven/mavencentral/org.flywaydb/flyway-core/10.10.0, Apache-2.0, approved, #14163
maven/mavencentral/org.flywaydb/flyway-database-postgresql/10.10.0, Apache-2.0, approved, #14158
maven/mavencentral/org.glassfish.jaxb/codemodel/4.0.5, BSD-3-Clause, approved, ee4j.jaxb-impl
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,11 @@ import org.eclipse.tractusx.bpdm.common.model.BusinessStateType
import org.eclipse.tractusx.bpdm.common.model.ClassificationType
import org.eclipse.tractusx.bpdm.common.service.toDto
import org.eclipse.tractusx.bpdm.pool.api.model.*
import org.eclipse.tractusx.bpdm.pool.api.model.response.AddressPartnerCreateVerboseDto
import org.eclipse.tractusx.bpdm.pool.api.model.response.LegalEntityPartnerCreateVerboseDto
import org.eclipse.tractusx.bpdm.pool.api.model.response.LegalEntityWithLegalAddressVerboseDto
import org.eclipse.tractusx.bpdm.pool.api.model.response.SitePartnerCreateVerboseDto
import org.eclipse.tractusx.bpdm.pool.api.model.response.*
import java.time.Instant
import java.time.LocalDateTime
import java.time.ZoneOffset
import java.util.UUID

/**
* Test values for response DTOs
Expand Down Expand Up @@ -68,6 +66,10 @@ object BusinessPartnerVerboseValues {
val identifierType3 = TypeKeyNameVerboseDto("VAT_FR", "VAT France")
val identifierType4 = TypeKeyNameVerboseDto("VAT_NL", "VAT Netherlands")

val bpnLRequestMapping = BpnRequestIdentifierMappingDto(UUID.randomUUID().toString(), bpn = secondBpnL)
val bpnSRequestMapping = BpnRequestIdentifierMappingDto(UUID.randomUUID().toString(), bpn = secondBpnS)
val bpnARequestMapping = BpnRequestIdentifierMappingDto(UUID.randomUUID().toString(), bpn = secondBpnA)

val identifierTypeAbbreviation1 = "abbreviation1"
val identifierTypeAbbreviation2 = "abbreviation2"
val identifierTypeAbbreviation3 = "abbreviation3"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import org.eclipse.tractusx.bpdm.common.util.CommonApiPathNames
import org.eclipse.tractusx.bpdm.pool.api.PoolBpnApi.Companion.BPN_PATH
import org.eclipse.tractusx.bpdm.pool.api.model.request.IdentifiersSearchRequest
import org.eclipse.tractusx.bpdm.pool.api.model.response.BpnIdentifierMappingDto
import org.eclipse.tractusx.bpdm.pool.api.model.response.BpnRequestIdentifierMappingDto
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.PostMapping
Expand Down Expand Up @@ -62,4 +63,17 @@ interface PoolBpnApi {
@Tag(name = ApiCommons.BPN_NAME, description = ApiCommons.BPN_DESCRIPTION)
@PostMapping(CommonApiPathNames.SUBPATH_SEARCH)
fun findBpnsByIdentifiers(@RequestBody request: IdentifiersSearchRequest): ResponseEntity<Set<BpnIdentifierMappingDto>>

@Operation(
summary = "Return BPNL/S/A based on the requested identifiers",
description = "Find business partner numbers by requested-identifiers."
)
@ApiResponses(
value = [
ApiResponse(responseCode = "200", description = "Found bpn to based on the requested identifiers"),
]
)
@Tag(name = ApiCommons.BPN_NAME, description = ApiCommons.BPN_DESCRIPTION)
@PostMapping("/request-ids")
dilipdhankecha2530 marked this conversation as resolved.
Show resolved Hide resolved
fun findBpnByRequestedIdentifiers(@RequestBody request: Set<String>): ResponseEntity<Set<BpnRequestIdentifierMappingDto>>
dilipdhankecha2530 marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import org.eclipse.tractusx.bpdm.common.util.CommonApiPathNames
import org.eclipse.tractusx.bpdm.pool.api.PoolBpnApi
import org.eclipse.tractusx.bpdm.pool.api.model.request.IdentifiersSearchRequest
import org.eclipse.tractusx.bpdm.pool.api.model.response.BpnIdentifierMappingDto
import org.eclipse.tractusx.bpdm.pool.api.model.response.BpnRequestIdentifierMappingDto
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.service.annotation.HttpExchange
Expand All @@ -32,4 +33,7 @@ import org.springframework.web.service.annotation.PostExchange
interface BpnApiClient: PoolBpnApi {
@PostExchange(CommonApiPathNames.SUBPATH_SEARCH)
override fun findBpnsByIdentifiers(@RequestBody request: IdentifiersSearchRequest): ResponseEntity<Set<BpnIdentifierMappingDto>>

@PostExchange(value = "/request-ids")
override fun findBpnByRequestedIdentifiers(@RequestBody identifiers: Set<String>): ResponseEntity<Set<BpnRequestIdentifierMappingDto>>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*******************************************************************************
* Copyright (c) 2021,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
******************************************************************************/

package org.eclipse.tractusx.bpdm.pool.api.model.response

import io.swagger.v3.oas.annotations.media.Schema

@Schema(name = "BpnRequestIdentifierMappingDto", description = "Mapping of Business Partner Number to requested-identifier value")
data class BpnRequestIdentifierMappingDto(

@Schema(description = "Value of the requested-identifier")
val requestedIdentifier: String,

@Schema(description = "Business Partner Number")
val bpn: String
)
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ package org.eclipse.tractusx.bpdm.pool.controller
import org.eclipse.tractusx.bpdm.pool.api.PoolBpnApi
import org.eclipse.tractusx.bpdm.pool.api.model.request.IdentifiersSearchRequest
import org.eclipse.tractusx.bpdm.pool.api.model.response.BpnIdentifierMappingDto
import org.eclipse.tractusx.bpdm.pool.api.model.response.BpnRequestIdentifierMappingDto
import org.eclipse.tractusx.bpdm.pool.config.ControllerConfigProperties
import org.eclipse.tractusx.bpdm.pool.config.PermissionConfigProperties
import org.eclipse.tractusx.bpdm.pool.service.BusinessPartnerFetchService
Expand All @@ -45,4 +46,13 @@ class BpnController(
val bpnIdentifierMappings = businessPartnerFetchService.findBpnsByIdentifiers(request.idType, request.businessPartnerType, request.idValues)
return ResponseEntity(bpnIdentifierMappings, HttpStatus.OK)
}

@PreAuthorize("hasAuthority(${PermissionConfigProperties.READ_PARTNER})")
override fun findBpnByRequestedIdentifiers(@RequestBody request: Set<String>): ResponseEntity<Set<BpnRequestIdentifierMappingDto>> {
if (request.size > controllerConfigProperties.searchRequestLimit) {
return ResponseEntity(HttpStatus.BAD_REQUEST)
}
val bpnIdentifierMappings = businessPartnerFetchService.findBpnByRequestedIdentifiers(request)
return ResponseEntity(bpnIdentifierMappings, HttpStatus.OK)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,17 @@ import org.eclipse.tractusx.bpdm.common.dto.PaginationRequest
import org.eclipse.tractusx.bpdm.common.exception.BpdmNotFoundException
import org.eclipse.tractusx.bpdm.pool.api.model.IdentifierBusinessPartnerType
import org.eclipse.tractusx.bpdm.pool.api.model.response.BpnIdentifierMappingDto
import org.eclipse.tractusx.bpdm.pool.api.model.response.BpnRequestIdentifierMappingDto
import org.eclipse.tractusx.bpdm.pool.api.model.response.LegalEntityWithLegalAddressVerboseDto
import org.eclipse.tractusx.bpdm.pool.entity.IdentifierTypeDb
import org.eclipse.tractusx.bpdm.pool.entity.LegalEntityDb
import org.eclipse.tractusx.bpdm.pool.entity.LegalEntityIdentifierDb
import org.eclipse.tractusx.bpdm.pool.repository.AddressIdentifierRepository
import org.eclipse.tractusx.bpdm.pool.repository.IdentifierTypeRepository
import org.eclipse.tractusx.bpdm.pool.repository.LegalEntityIdentifierRepository
import org.eclipse.tractusx.bpdm.pool.repository.LegalEntityRepository
import org.eclipse.tractusx.bpdm.pool.repository.*
import org.springframework.data.domain.PageRequest
import org.springframework.data.jpa.domain.Specification
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.util.stream.Collectors

/**
* Service for fetching business partner records from the database
Expand All @@ -45,6 +44,7 @@ import org.springframework.transaction.annotation.Transactional
class BusinessPartnerFetchService(
private val legalEntityRepository: LegalEntityRepository,
private val identifierTypeRepository: IdentifierTypeRepository,
private val bpnRequestIdentifierRepository: BpnRequestIdentifierRepository,
private val legalEntityIdentifierRepository: LegalEntityIdentifierRepository,
private val addressIdentifierRepository: AddressIdentifierRepository,
private val addressService: AddressService
Expand Down Expand Up @@ -121,6 +121,21 @@ class BusinessPartnerFetchService(
}
}

/**
* Find bpn based on request-identifier value
*/
@Transactional
fun findBpnByRequestedIdentifiers(request: Set<String>): Set<BpnRequestIdentifierMappingDto> {
logger.debug { "Executing findBpnByRequestedIdentifiers() with parameters $request" }
if (request.isEmpty()) {
return emptySet()
}
var bpnRequestIdentifierMapping = bpnRequestIdentifierRepository.findDistinctByRequestIdentifierIn(request)
return bpnRequestIdentifierMapping.stream()
.map { BpnRequestIdentifierMappingDto(it.requestIdentifier, it.bpn) }
.collect(Collectors.toSet())
}

fun fetchDependenciesWithLegalAddress(partners: Set<LegalEntityDb>): Set<LegalEntityDb> {
fetchLegalEntityDependencies(partners)
legalEntityRepository.joinLegalAddresses(partners)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,27 @@ import org.eclipse.tractusx.bpdm.pool.api.client.PoolClientImpl
import org.eclipse.tractusx.bpdm.pool.api.model.IdentifierBusinessPartnerType
import org.eclipse.tractusx.bpdm.pool.api.model.LegalEntityIdentifierDto
import org.eclipse.tractusx.bpdm.pool.api.model.request.IdentifiersSearchRequest

import org.eclipse.tractusx.bpdm.pool.entity.BpnRequestIdentifierMappingDb
import org.eclipse.tractusx.bpdm.pool.repository.BpnRequestIdentifierRepository
import org.eclipse.tractusx.bpdm.pool.util.TestHelpers
import org.eclipse.tractusx.bpdm.test.containers.PostgreSQLContextInitializer
import org.eclipse.tractusx.bpdm.test.testdata.pool.BusinessPartnerNonVerboseValues
import org.eclipse.tractusx.bpdm.test.testdata.pool.BusinessPartnerVerboseValues
import org.eclipse.tractusx.bpdm.test.testdata.pool.LegalEntityStructureRequest
import org.eclipse.tractusx.bpdm.test.util.DbTestHelpers
import org.eclipse.tractusx.bpdm.test.util.PoolDataHelpers
import org.junit.Assert
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertThrows
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.web.reactive.function.client.WebClientResponseException
import java.util.*

@SpringBootTest(
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = [Application::class, TestHelpers::class],
Expand All @@ -48,6 +56,7 @@ import org.springframework.test.context.ContextConfiguration
class BpnControllerIT @Autowired constructor(
val testHelpers: TestHelpers,
val poolClient: PoolClientImpl,
val bpnRequestIdentifierRepository: BpnRequestIdentifierRepository,
val dbTestHelpers: DbTestHelpers,
val poolDataHelpers: PoolDataHelpers,
) {
Expand Down Expand Up @@ -81,6 +90,23 @@ class BpnControllerIT @Autowired constructor(
LegalEntityStructureRequest(legalEntity = legalEntityCreate3),
)
)

bpnRequestIdentifierRepository.saveAll(
mutableListOf(
BpnRequestIdentifierMappingDb(
BusinessPartnerVerboseValues.bpnLRequestMapping.requestedIdentifier,
BusinessPartnerVerboseValues.bpnLRequestMapping.bpn
),
BpnRequestIdentifierMappingDb(
BusinessPartnerVerboseValues.bpnSRequestMapping.requestedIdentifier,
BusinessPartnerVerboseValues.bpnSRequestMapping.bpn
),
BpnRequestIdentifierMappingDb(
BusinessPartnerVerboseValues.bpnARequestMapping.requestedIdentifier,
BusinessPartnerVerboseValues.bpnARequestMapping.bpn
)
)
)
}

/**
Expand Down Expand Up @@ -138,4 +164,46 @@ class BpnControllerIT @Autowired constructor(

testHelpers.`find bpns by nonexistent identifier type`(identifiersSearchRequest)
}

/**
* Fetch the BPNL/S/A based on the provided request identifier
*/
@Test
fun `find bpn by requested identifier`() {
val requestedIdentifiers = setOf(
BusinessPartnerVerboseValues.bpnLRequestMapping.requestedIdentifier,
BusinessPartnerVerboseValues.bpnSRequestMapping.requestedIdentifier,
)
val response = poolClient.bpns.findBpnByRequestedIdentifiers(requestedIdentifiers)
response.body?.let { Assertions.assertEquals(requestedIdentifiers.size, it.size) }
}

/**
* Find BPN based on the requested identifiers but with the set more than the search limit.
*/
@Test
fun `find bpn by requested identifier with extended search limit`() {
val requestedIdentifiers = setOf(
BusinessPartnerVerboseValues.bpnLRequestMapping.requestedIdentifier,
BusinessPartnerVerboseValues.bpnSRequestMapping.requestedIdentifier,
BusinessPartnerVerboseValues.bpnARequestMapping.requestedIdentifier,
)
try {
val result = poolClient.bpns.findBpnByRequestedIdentifiers(requestedIdentifiers)
assertThrows<WebClientResponseException> { result }
} catch (e: WebClientResponseException) {
Assert.assertEquals(HttpStatus.BAD_REQUEST, e.statusCode)
}
}

/**
* Fetch the BPNL/S/A based on the invalid request identifier
*/
@Test
fun `find bpn by invalid requested identifier`() {
val requestedIdentifiers = setOf(UUID.randomUUID().toString())
val response = poolClient.bpns.findBpnByRequestedIdentifiers(requestedIdentifiers)
response.body?.let { Assertions.assertNotEquals(requestedIdentifiers.size, it.size) }
response.body?.let { Assertions.assertTrue(it.isEmpty()) }
}
}
58 changes: 58 additions & 0 deletions docs/api/pool.json
Original file line number Diff line number Diff line change
Expand Up @@ -1528,6 +1528,46 @@
}
}
},
"/v6/bpn/request-ids": {
"post": {
"tags": [
"Bpn Controller"
],
"summary": "Return BPNL/S/A based on the requested identifiers",
"description": "Find business partner numbers by requested-identifiers.",
"operationId": "findBpnByRequestedIdentifiers",
"requestBody": {
"content": {
"application/json": {
"schema": {
"uniqueItems": true,
"type": "array",
"items": {
"type": "string"
}
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Found bpn to based on the requested identifiers",
"content": {
"application/json": {
"schema": {
"uniqueItems": true,
"type": "array",
"items": {
"$ref": "#/components/schemas/BpnRequestIdentifierMappingDto"
}
}
}
}
}
}
}
},
"/v6/addresses/search": {
"post": {
"tags": [
Expand Down Expand Up @@ -2817,6 +2857,24 @@
},
"description": "Mapping of Business Partner Number to identifier value"
},
"BpnRequestIdentifierMappingDto": {
"required": [
"bpn",
"requestedIdentifier"
],
"type": "object",
"properties": {
"requestedIdentifier": {
"type": "string",
"description": "Value of the requested-identifier"
},
"bpn": {
"type": "string",
"description": "Business Partner Number"
}
},
"description": "Mapping of Business Partner Number to requested-identifier value"
},
"ChangelogEntryVerboseDto": {
"required": [
"bpn",
Expand Down
Loading
Loading