Skip to content

Commit

Permalink
Merge pull request #192 from catenax-ng/persistence_query_input_sites
Browse files Browse the repository at this point in the history
Feat - Fetch of input data from the persistence layer (Logistic Address + Legal Entities + Sites)
  • Loading branch information
nicoprow authored May 30, 2023
2 parents 3864433 + c643d3d commit bc791a8
Show file tree
Hide file tree
Showing 8 changed files with 280 additions and 520 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import org.eclipse.tractusx.bpdm.gate.api.model.AddressGateInputResponse
import org.eclipse.tractusx.bpdm.gate.api.model.LegalEntityGateInputResponse
import org.eclipse.tractusx.bpdm.gate.api.model.SharingStateDto
import org.eclipse.tractusx.bpdm.gate.api.model.SiteGateInputResponse
import org.eclipse.tractusx.bpdm.gate.api.model.request.PaginationStartAfterRequest
import org.eclipse.tractusx.bpdm.gate.api.model.response.ChangelogResponse
import org.eclipse.tractusx.bpdm.gate.api.model.response.LsaType
import org.springframework.stereotype.Service
Expand Down Expand Up @@ -176,11 +175,11 @@ class GateQueryService(
do {
val pageResponse = gateClient.sites().getSitesByExternalIds(
externalIds = externalIds,
paginationRequest = PaginationStartAfterRequest(pageStartAfter, bridgeConfigProperties.queryPageSize)
paginationRequest = PaginationRequest(0, bridgeConfigProperties.queryPageSize)
)
pageStartAfter = pageResponse.nextStartAfter
validContent.addAll(pageResponse.content)
invalidEntries += pageResponse.invalidEntries
//pageStartAfter = pageResponse.nextStartAfter
validContent.addAll(pageResponse.content) //TODO Needs to be changed according to the removal of SaaS
invalidEntries += 0//pageResponse.invalidEntries
} while (pageStartAfter != null)

logger.info { "Gate returned ${validContent.size} valid sites, $invalidEntries were invalid" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@ import io.swagger.v3.oas.annotations.media.Content
import io.swagger.v3.oas.annotations.responses.ApiResponse
import io.swagger.v3.oas.annotations.responses.ApiResponses
import jakarta.validation.Valid
import org.eclipse.tractusx.bpdm.common.dto.request.PaginationRequest
import org.eclipse.tractusx.bpdm.common.dto.response.PageResponse
import org.eclipse.tractusx.bpdm.gate.api.model.SiteGateInputRequest
import org.eclipse.tractusx.bpdm.gate.api.model.SiteGateInputResponse
import org.eclipse.tractusx.bpdm.gate.api.model.SiteGateOutput
import org.eclipse.tractusx.bpdm.gate.api.model.request.PaginationStartAfterRequest
import org.eclipse.tractusx.bpdm.gate.api.model.response.PageOutputResponse
import org.eclipse.tractusx.bpdm.gate.api.model.response.PageStartAfterResponse
import org.eclipse.tractusx.bpdm.gate.api.model.response.ValidationResponse
import org.springdoc.core.annotations.ParameterObject
import org.springframework.http.MediaType
Expand Down Expand Up @@ -89,9 +90,9 @@ interface GateSiteApi {
@PostMapping("/input/sites/search")
@PostExchange("/input/sites/search")
fun getSitesByExternalIds(
@ParameterObject @Valid paginationRequest: PaginationStartAfterRequest,
@ParameterObject @Valid paginationRequest: PaginationRequest,
@RequestBody externalIds: Collection<String>
): PageStartAfterResponse<SiteGateInputResponse>
): PageResponse<SiteGateInputResponse>

@Operation(
summary = "Get page of sites",
Expand All @@ -105,7 +106,7 @@ interface GateSiteApi {
)
@GetMapping("/input/sites")
@GetExchange("/input/sites")
fun getSites(@ParameterObject @Valid paginationRequest: PaginationStartAfterRequest): PageStartAfterResponse<SiteGateInputResponse>
fun getSites(@ParameterObject @Valid paginationRequest: PaginationRequest): PageResponse<SiteGateInputResponse>

@Operation(
summary = "Get page of sites",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@

package org.eclipse.tractusx.bpdm.gate.controller

import org.eclipse.tractusx.bpdm.common.dto.request.PaginationRequest
import org.eclipse.tractusx.bpdm.common.dto.response.PageResponse
import org.eclipse.tractusx.bpdm.gate.api.GateSiteApi
import org.eclipse.tractusx.bpdm.gate.api.model.SiteGateInputRequest
import org.eclipse.tractusx.bpdm.gate.api.model.SiteGateInputResponse
import org.eclipse.tractusx.bpdm.gate.api.model.SiteGateOutput
import org.eclipse.tractusx.bpdm.gate.api.model.request.PaginationStartAfterRequest
import org.eclipse.tractusx.bpdm.gate.api.model.response.PageOutputResponse
import org.eclipse.tractusx.bpdm.gate.api.model.response.PageStartAfterResponse
import org.eclipse.tractusx.bpdm.gate.api.model.response.ValidationResponse
import org.eclipse.tractusx.bpdm.gate.config.ApiConfigProperties
import org.eclipse.tractusx.bpdm.gate.containsDuplicates
Expand Down Expand Up @@ -55,14 +56,14 @@ class SiteController(
}

override fun getSitesByExternalIds(
paginationRequest: PaginationStartAfterRequest,
paginationRequest: PaginationRequest,
externalIds: Collection<String>
): PageStartAfterResponse<SiteGateInputResponse> {
return siteService.getSites(paginationRequest.limit, paginationRequest.startAfter, externalIds)
): PageResponse<SiteGateInputResponse> {
return siteService.getSites(page = paginationRequest.page, size = paginationRequest.size, externalIds = externalIds)
}

override fun getSites(paginationRequest: PaginationStartAfterRequest): PageStartAfterResponse<SiteGateInputResponse> {
return siteService.getSites(paginationRequest.limit, paginationRequest.startAfter)
override fun getSites(paginationRequest: PaginationRequest): PageResponse<SiteGateInputResponse> {
return siteService.getSites(page = paginationRequest.page, size = paginationRequest.size)
}

override fun getSitesOutput(paginationRequest: PaginationStartAfterRequest, externalIds: Collection<String>?): PageOutputResponse<SiteGateOutput> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
package org.eclipse.tractusx.bpdm.gate.repository

import org.eclipse.tractusx.bpdm.gate.entity.Site
import org.springframework.data.domain.Page
import org.springframework.data.domain.Pageable
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.data.repository.CrudRepository

Expand All @@ -29,4 +31,6 @@ interface SiteRepository : JpaRepository<Site, Long>, CrudRepository<Site, Long>

fun findByExternalId(externalId: String): Site?

fun findByExternalIdIn(externalId: Collection<String>?, pageable: Pageable): Page<Site>

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,17 @@
package org.eclipse.tractusx.bpdm.gate.service

import org.eclipse.tractusx.bpdm.common.dto.*
import org.eclipse.tractusx.bpdm.common.dto.SiteStateDto
import org.eclipse.tractusx.bpdm.common.dto.response.PageResponse
import org.eclipse.tractusx.bpdm.gate.api.model.AddressGateInputRequest
import org.eclipse.tractusx.bpdm.gate.api.model.AddressGateInputResponse
import org.eclipse.tractusx.bpdm.gate.api.model.LegalEntityGateInputRequest
import org.eclipse.tractusx.bpdm.gate.api.model.LegalEntityGateInputResponse
import org.eclipse.tractusx.bpdm.gate.api.model.SiteGateInputRequest
import org.eclipse.tractusx.bpdm.gate.api.model.*
import org.eclipse.tractusx.bpdm.gate.api.model.response.ChangelogResponse
import org.eclipse.tractusx.bpdm.gate.entity.*
import org.springframework.data.domain.Page
import java.time.Instant
import java.time.temporal.ChronoUnit
import org.eclipse.tractusx.bpdm.gate.entity.ChangelogEntry
import org.eclipse.tractusx.bpdm.gate.entity.Site
import org.eclipse.tractusx.bpdm.gate.entity.SiteState

fun AddressGateInputRequest.toAddressGate(legalEntity: LegalEntity?, site: Site?): LogisticAddress {

Expand Down Expand Up @@ -153,14 +153,13 @@ fun LegalEntityGateInputRequest.toLegalEntity(): LegalEntity {
legalEntityExternalId = externalId
)

val legalEntity = LegalEntity(
val legalEntity= LegalEntity(
bpn = bpn,
externalId = externalId,
currentness = createCurrentnessTimestamp(),
legalForm = legalEntity.legalForm,
legalName = legalEntity.legalName.toName()
)

legalEntity.identifiers.addAll( this.legalEntity.identifiers.map {toEntityIdentifier(it,legalEntity)})
legalEntity.states.addAll(this.legalEntity.states.map { toEntityState(it,legalEntity) })
legalEntity.classifications.addAll(this.legalEntity.classifications.map { toEntityClassification(it,legalEntity) })
Expand Down Expand Up @@ -328,11 +327,40 @@ fun Name.toNameDto(): NameDto {
return NameDto(value, shortName)
}

//LegalEntity mapping to LegalEntityGateInputResponse
fun LegalEntity.LegalEntityGateInputResponse(legalEntity: LegalEntity): LegalEntityGateInputResponse {

return LegalEntityGateInputResponse(
legalEntity = legalEntity.toLegalEntityDto(),
externalId = legalEntity.externalId,
bpn = legalEntity.bpn,
processStartedAt = null
)
}

//Site mapping to SiteDto
fun Site.toSiteDto(): SiteDto {

return SiteDto(
name = name,
states = mapToDtoSitesStates(states),
mainAddress = mainAddress.toLogisticAddressDto()
)
}

fun mapToDtoSitesStates(states: MutableSet<SiteState>): Collection<SiteStateDto> {
return states.map { SiteStateDto(it.description, it.validFrom, it.validTo, it.type) }
}

//LegalEntity mapping to LegalEntityGateInputResponse
fun Site.toSiteGateInputResponse(sitePage: Site): SiteGateInputResponse {

return SiteGateInputResponse(
site = sitePage.toSiteDto(),
externalId = externalId,
legalEntityExternalId = legalEntity.externalId,
bpn = bpn,
processStartedAt = null //TODO Remove this?
)

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,56 +21,65 @@ package org.eclipse.tractusx.bpdm.gate.service

import mu.KotlinLogging
import org.eclipse.tractusx.bpdm.common.dto.response.LogisticAddressResponse
import org.eclipse.tractusx.bpdm.common.dto.response.PageResponse
import org.eclipse.tractusx.bpdm.common.dto.response.SiteResponse
import org.eclipse.tractusx.bpdm.common.dto.saas.BusinessPartnerSaas
import org.eclipse.tractusx.bpdm.common.dto.saas.FetchResponse
import org.eclipse.tractusx.bpdm.common.exception.BpdmNotFoundException
import org.eclipse.tractusx.bpdm.gate.api.model.SiteGateInputRequest
import org.eclipse.tractusx.bpdm.gate.api.model.SiteGateInputResponse
import org.eclipse.tractusx.bpdm.gate.api.model.SiteGateOutput
import org.eclipse.tractusx.bpdm.gate.api.model.response.LsaType
import org.eclipse.tractusx.bpdm.gate.api.model.response.PageOutputResponse
import org.eclipse.tractusx.bpdm.gate.api.model.response.PageStartAfterResponse
import org.eclipse.tractusx.bpdm.gate.config.BpnConfigProperties
import org.eclipse.tractusx.bpdm.gate.entity.ChangelogEntry
import org.eclipse.tractusx.bpdm.gate.exception.SaasInvalidRecordException
import org.eclipse.tractusx.bpdm.gate.entity.Site
import org.eclipse.tractusx.bpdm.gate.exception.SaasNonexistentParentException
import org.eclipse.tractusx.bpdm.gate.repository.ChangelogRepository
import org.eclipse.tractusx.bpdm.gate.repository.SiteRepository
import org.springframework.data.domain.Page
import org.springframework.data.domain.PageRequest
import org.springframework.stereotype.Service

@Service
class SiteService(
private val saasRequestMappingService: SaasRequestMappingService,
private val inputSaasMappingService: InputSaasMappingService,
private val outputSaasMappingService: OutputSaasMappingService,
private val saasClient: SaasClient,
private val poolClient: PoolClient,
private val bpnConfigProperties: BpnConfigProperties,
private val changelogRepository: ChangelogRepository,
private val sitePersistenceService: SitePersistenceService
private val sitePersistenceService: SitePersistenceService,
private val siteRepository: SiteRepository
) {
private val logger = KotlinLogging.logger { }

fun getSites(limit: Int, startAfter: String?, externalIds: Collection<String>? = null): PageStartAfterResponse<SiteGateInputResponse> {
val sitesPage = saasClient.getSites(limit, startAfter, externalIds)
fun getSites(page: Int, size: Int, externalIds: Collection<String>? = null): PageResponse<SiteGateInputResponse> {

val validEntries = toValidSites(sitesPage.values)
val sitesPage = if (externalIds != null) {
siteRepository.findByExternalIdIn(externalIds, PageRequest.of(page, size))
} else {
siteRepository.findAll(PageRequest.of(page, size))
}

return PageStartAfterResponse(
total = sitesPage.total,
nextStartAfter = sitesPage.nextStartAfter,
content = validEntries,
invalidEntries = sitesPage.values.size - validEntries.size
return PageResponse(
page = page,
totalElements = sitesPage.totalElements,
totalPages = sitesPage.totalPages,
contentSize = sitesPage.content.size,
content = toValidSite(sitesPage)
)
}

private fun toValidSite(sitePage: Page<Site>): List<SiteGateInputResponse> {
return sitePage.content.map { site ->
site.toSiteGateInputResponse(site)
}
}

fun getSiteByExternalId(externalId: String): SiteGateInputResponse {
val fetchResponse = saasClient.getBusinessPartner(externalId)
val siteRecord = siteRepository.findByExternalId(externalId) ?: throw BpdmNotFoundException("Site", externalId)

when (fetchResponse.status) {
FetchResponse.Status.OK -> return toValidSiteInput(fetchResponse.businessPartner!!)
FetchResponse.Status.NOT_FOUND -> throw BpdmNotFoundException("Site", externalId)
}
return siteRecord.toSiteGateInputResponse(siteRecord)
}

/**
Expand Down Expand Up @@ -137,19 +146,12 @@ class SiteService(
*/
fun upsertSites(sites: Collection<SiteGateInputRequest>) {

val sitesSaas = toSaasModels(sites)
saasClient.upsertSites(sitesSaas)

// create changelog entry if all goes well from saasClient
sites.forEach { site ->
changelogRepository.save(ChangelogEntry(site.externalId, LsaType.Site))
}

sitePersistenceService.persistSitesBP(sites)

deleteParentRelationsOfSites(sites)

upsertParentRelations(sites)
}

/**
Expand All @@ -160,84 +162,6 @@ class SiteService(
return sites.map { toSaasModel(it, parentLegalEntitiesByExternalId[it.legalEntityExternalId]) }
}

private fun upsertParentRelations(sites: Collection<SiteGateInputRequest>) {
val relations = sites.map {
SaasClient.SiteLegalEntityRelation(
siteExternalId = it.externalId,
legalEntityExternalId = it.legalEntityExternalId
)
}.toList()
saasClient.upsertSiteRelations(relations)
}

private fun deleteParentRelationsOfSites(sites: Collection<SiteGateInputRequest>) {
val sitesPage = saasClient.getSites(externalIds = sites.map { it.externalId })
saasClient.deleteParentRelations(sitesPage.values)
}

private fun toValidSites(partners: Collection<BusinessPartnerSaas>): Collection<SiteGateInputResponse> {
return partners.mapNotNull {
try {
toValidSiteInput(it)

} catch (e: RuntimeException) {
logger.warn { "${getLogDescription(it)} will be ignored: ${e.message}" }
null
}
}
}

private fun toValidSiteInput(partner: BusinessPartnerSaas): SiteGateInputResponse {
if (!validateSiteBusinessPartner(partner)) {
throw SaasInvalidRecordException(partner.id)
}
return inputSaasMappingService.toInputSite(partner)
}

private fun validateSiteBusinessPartner(partner: BusinessPartnerSaas): Boolean {
val logMessageStart = getLogDescription(partner)
return validateAddresses(partner, logMessageStart)
&& validateLegalEntityParents(partner, logMessageStart)
&& validateNames(partner, logMessageStart)
}

private fun getLogDescription(partner: BusinessPartnerSaas) =
"SaaS business partner for site with ${if (partner.id != null) "ID " + partner.id else "external id " + partner.externalId}"

private fun validateNames(partner: BusinessPartnerSaas, logMessageStart: String): Boolean {
if (partner.names.size > 1) {
logger.warn { "$logMessageStart has multiple names." }
}
if (partner.names.isEmpty()) {
logger.warn { "$logMessageStart does not have a name." }
return false
}
return true
}

private fun validateAddresses(partner: BusinessPartnerSaas, logMessageStart: String): Boolean {
if (partner.addresses.size > 1) {
logger.warn { "$logMessageStart has multiple main addresses" }
}
if (partner.addresses.isEmpty()) {
logger.warn { "$logMessageStart does not have a main address" }
return false
}
return true
}

private fun validateLegalEntityParents(partner: BusinessPartnerSaas, logMessageStart: String): Boolean {
val numLegalEntityParents = inputSaasMappingService.toParentLegalEntityExternalIds(partner).size
if (numLegalEntityParents > 1) {
logger.warn { "$logMessageStart has multiple parent legal entities." }
}
if (numLegalEntityParents == 0) {
logger.warn { "$logMessageStart does not have a parent legal entity." }
return false
}
return true
}

private fun getParentLegalEntities(sites: Collection<SiteGateInputRequest>): Map<String, BusinessPartnerSaas> {
val parentLegalEntityExternalIds = sites.map { it.legalEntityExternalId }.distinct().toList()
val parentLegalEntitiesPage = saasClient.getLegalEntities(externalIds = parentLegalEntityExternalIds)
Expand Down
Loading

0 comments on commit bc791a8

Please sign in to comment.