diff --git a/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/AddressIdentifierDto.kt b/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/AddressIdentifierDto.kt index f6a99b762..2cbde3579 100644 --- a/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/AddressIdentifierDto.kt +++ b/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/AddressIdentifierDto.kt @@ -26,8 +26,8 @@ import org.eclipse.tractusx.bpdm.common.dto.openapidescription.AddressIdentifier data class AddressIdentifierDto( @get:Schema(description = AddressIdentifierDescription.value) - val value: String, + override val value: String, @get:Schema(description = AddressIdentifierDescription.type) - val type: String, -) + override val type: String, +) : IBaseAddressIdentifierDto diff --git a/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/AddressStateDto.kt b/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/AddressStateDto.kt index 35a0af2f4..33ea8c684 100644 --- a/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/AddressStateDto.kt +++ b/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/AddressStateDto.kt @@ -28,14 +28,14 @@ import java.time.LocalDateTime data class AddressStateDto( @get:Schema(description = AddressStateDescription.description) - val description: String?, + override val description: String?, @get:Schema(description = AddressStateDescription.validFrom) - val validFrom: LocalDateTime?, + override val validFrom: LocalDateTime?, @get:Schema(description = AddressStateDescription.validTo) - val validTo: LocalDateTime?, + override val validTo: LocalDateTime?, @get:Schema(description = AddressStateDescription.type) - val type: BusinessStateType -) + override val type: BusinessStateType +): IBaseAddressStateDto diff --git a/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/ClassificationDto.kt b/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/ClassificationDto.kt index 047afddfc..54414abc8 100644 --- a/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/ClassificationDto.kt +++ b/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/ClassificationDto.kt @@ -27,11 +27,11 @@ import org.eclipse.tractusx.bpdm.common.model.ClassificationType data class ClassificationDto( @get:Schema(description = ClassificationDescription.type) - val type: ClassificationType, + override val type: ClassificationType, @get:Schema(description = ClassificationDescription.code) - val code: String?, + override val code: String?, @get:Schema(description = ClassificationDescription.value) - val value: String? -) + override val value: String? +) : IBaseClassificationDto diff --git a/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/IBaseLegalEntityDto.kt b/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/IBaseLegalEntityDto.kt index 9a9548b54..672638b7a 100644 --- a/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/IBaseLegalEntityDto.kt +++ b/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/IBaseLegalEntityDto.kt @@ -40,7 +40,4 @@ interface IBaseLegalEntityDto { @get:ArraySchema(arraySchema = Schema(description = LegalEntityDescription.classifications, required = false)) val classifications: Collection - // TODO OpenAPI description for complex field does not work!! - @get:Schema(description = LegalEntityDescription.legalAddress) - val legalAddress: IBaseLogisticAddressDto? } \ No newline at end of file diff --git a/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/LegalEntityDto.kt b/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/LegalEntityDto.kt index 3b604fb7f..79af635ed 100644 --- a/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/LegalEntityDto.kt +++ b/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/LegalEntityDto.kt @@ -26,17 +26,17 @@ import org.eclipse.tractusx.bpdm.common.dto.openapidescription.LegalEntityDescri @Schema(description = LegalEntityDescription.header) data class LegalEntityDto( @get:ArraySchema(arraySchema = Schema(description = LegalEntityDescription.identifiers, required = false)) - val identifiers: Collection = emptyList(), + override val identifiers: Collection = emptyList(), @get:Schema(description = LegalEntityDescription.legalShortName) - val legalShortName: String?, + override val legalShortName: String?, @get:Schema(description = LegalEntityDescription.legalForm) - val legalForm: String? = null, + override val legalForm: String? = null, @get:ArraySchema(arraySchema = Schema(description = LegalEntityDescription.states)) - val states: Collection = emptyList(), + override val states: Collection = emptyList(), @get:ArraySchema(arraySchema = Schema(description = LegalEntityDescription.classifications, required = false)) - val classifications: Collection = emptyList(), -) + override val classifications: Collection = emptyList(), +) : IBaseLegalEntityDto diff --git a/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/LegalEntityIdentifierDto.kt b/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/LegalEntityIdentifierDto.kt index 2545a5146..a646af8ae 100644 --- a/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/LegalEntityIdentifierDto.kt +++ b/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/LegalEntityIdentifierDto.kt @@ -22,15 +22,10 @@ package org.eclipse.tractusx.bpdm.common.dto import io.swagger.v3.oas.annotations.media.Schema import org.eclipse.tractusx.bpdm.common.dto.openapidescription.LegalEntityIdentifierDescription -@Schema(description = LegalEntityIdentifierDescription.header) -data class LegalEntityIdentifierDto( - - @get:Schema(description = LegalEntityIdentifierDescription.value) - val value: String, - @get:Schema(description = LegalEntityIdentifierDescription.type) - val type: String, +data class LegalEntityIdentifierDto( - @get:Schema(description = LegalEntityIdentifierDescription.issuingBody) - val issuingBody: String? -) + override val value: String, + override val type: String, + override val issuingBody: String? +) : IBaseLegalEntityIdentifierDto diff --git a/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/LegalEntityStateDto.kt b/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/LegalEntityStateDto.kt index d46916089..e68a1768b 100644 --- a/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/LegalEntityStateDto.kt +++ b/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/LegalEntityStateDto.kt @@ -28,14 +28,14 @@ import java.time.LocalDateTime data class LegalEntityStateDto( @get:Schema(description = LegalEntityStateDescription.description) - val description: String?, + override val description: String?, @get:Schema(description = LegalEntityStateDescription.validFrom) - val validFrom: LocalDateTime?, + override val validFrom: LocalDateTime?, @get:Schema(description = LegalEntityStateDescription.validTo) - val validTo: LocalDateTime?, + override val validTo: LocalDateTime?, @get:Schema(description = LegalEntityStateDescription.type) - val type: BusinessStateType -) + override val type: BusinessStateType +) : IBaseLegalEntityStateDto diff --git a/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/LogisticAddressDto.kt b/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/LogisticAddressDto.kt index b7ae27f8a..c6502e8d7 100644 --- a/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/LogisticAddressDto.kt +++ b/bpdm-common/src/main/kotlin/org/eclipse/tractusx/bpdm/common/dto/LogisticAddressDto.kt @@ -30,16 +30,12 @@ data class LogisticAddressDto( val name: String? = null, @get:ArraySchema(arraySchema = Schema(description = LogisticAddressDescription.states)) - val states: Collection = emptyList(), + override val states: Collection = emptyList(), @get:ArraySchema(arraySchema = Schema(description = LogisticAddressDescription.identifiers)) - val identifiers: Collection = emptyList(), + override val identifiers: Collection = emptyList(), - // TODO OpenAPI description for complex field does not work!! - @get:Schema(description = LogisticAddressDescription.physicalPostalAddress) - val physicalPostalAddress: PhysicalPostalAddressDto, + override val physicalPostalAddress: PhysicalPostalAddressDto, - // TODO OpenAPI description for complex field does not work!! - @get:Schema(description = LogisticAddressDescription.alternativePostalAddress) - val alternativePostalAddress: AlternativePostalAddressDto? = null -) \ No newline at end of file + override val alternativePostalAddress: AlternativePostalAddressDto? = null +) : IBaseLogisticAddressDto \ No newline at end of file diff --git a/bpdm-orchestrator-api/src/main/kotlin/org/eclipse/tractusx/orchestrator/api/model/LegalEntityDto.kt b/bpdm-orchestrator-api/src/main/kotlin/org/eclipse/tractusx/orchestrator/api/model/LegalEntityDto.kt index 2f844959f..8a625ca95 100644 --- a/bpdm-orchestrator-api/src/main/kotlin/org/eclipse/tractusx/orchestrator/api/model/LegalEntityDto.kt +++ b/bpdm-orchestrator-api/src/main/kotlin/org/eclipse/tractusx/orchestrator/api/model/LegalEntityDto.kt @@ -44,6 +44,6 @@ data class LegalEntityDto( override val classifications: Collection = emptyList(), - override val legalAddress: LogisticAddressDto? = null + val legalAddress: LogisticAddressDto? = null ) : IBaseLegalEntityDto diff --git a/bpdm-pool/pom.xml b/bpdm-pool/pom.xml index 459e1dee8..cb5dc92af 100644 --- a/bpdm-pool/pom.xml +++ b/bpdm-pool/pom.xml @@ -43,6 +43,10 @@ ${project.groupId} bpdm-pool-api + + ${project.groupId} + bpdm-orchestrator-api + org.jetbrains.kotlin kotlin-stdlib diff --git a/bpdm-pool/src/main/kotlin/org/eclipse/tractusx/bpdm/pool/service/BusinessPartnerBuildService.kt b/bpdm-pool/src/main/kotlin/org/eclipse/tractusx/bpdm/pool/service/BusinessPartnerBuildService.kt index 10138dbef..2f4b9103b 100644 --- a/bpdm-pool/src/main/kotlin/org/eclipse/tractusx/bpdm/pool/service/BusinessPartnerBuildService.kt +++ b/bpdm-pool/src/main/kotlin/org/eclipse/tractusx/bpdm/pool/service/BusinessPartnerBuildService.kt @@ -61,9 +61,12 @@ class BusinessPartnerBuildService( fun createLegalEntities(requests: Collection): LegalEntityPartnerCreateResponseWrapper { logger.info { "Create ${requests.size} new legal entities" } - val errorsByRequest = requestValidationService.validateLegalEntityCreates(requests) - val errors = errorsByRequest.flatMap { it.value } - val validRequests = requests.filterNot { errorsByRequest.containsKey(it) } + + val errorsByRequest = requestValidationService.validateLegalEntityCreatesPool(requests.associateWith { it.legalEntity }) + val errorsByRequestAddress = requestValidationService.validateLegalEntityCreatesAddressesPool(requests.associateWith { it.legalAddress }) + + val errors = errorsByRequest.flatMap { it.value } + errorsByRequestAddress.flatMap { it.value } + val validRequests = requests.filterNot { errorsByRequest.containsKey(it) || errorsByRequestAddress.containsKey(it) } val legalEntityMetadataMap = metadataService.getMetadata(requests.map { it.legalEntity }).toMapping() val addressMetadataMap = metadataService.getMetadata(requests.map { it.legalAddress }).toMapping() @@ -410,8 +413,8 @@ class BusinessPartnerBuildService( bpn = bpn, legalEntity = null, site = null, - physicalPostalAddress = createPhysicalAddress(dto.physicalPostalAddress, metadataMap), - alternativePostalAddress = dto.alternativePostalAddress?.let { createAlternativeAddress(it, metadataMap) }, + physicalPostalAddress = createPhysicalAddress(dto.physicalPostalAddress, metadataMap.regions), + alternativePostalAddress = dto.alternativePostalAddress?.let { createAlternativeAddress(it, metadataMap.regions) }, name = dto.name ) @@ -422,12 +425,12 @@ class BusinessPartnerBuildService( private fun updateLogisticAddress(address: LogisticAddress, dto: LogisticAddressDto, metadataMap: AddressMetadataMapping) { address.name = dto.name - address.physicalPostalAddress = createPhysicalAddress(dto.physicalPostalAddress, metadataMap) - address.alternativePostalAddress = dto.alternativePostalAddress?.let { createAlternativeAddress(it, metadataMap) } + address.physicalPostalAddress = createPhysicalAddress(dto.physicalPostalAddress, metadataMap.regions) + address.alternativePostalAddress = dto.alternativePostalAddress?.let { createAlternativeAddress(it, metadataMap.regions) } address.identifiers.apply { clear() - addAll(dto.identifiers.map { toEntity(it, metadataMap, address) }) + addAll(dto.identifiers.map { toEntity(it, metadataMap.idTypes, address) }) } address.states.apply { clear() @@ -435,11 +438,11 @@ class BusinessPartnerBuildService( } } - private fun createPhysicalAddress(physicalAddress: PhysicalPostalAddressDto, metadataMap: AddressMetadataMapping): PhysicalPostalAddress { + private fun createPhysicalAddress(physicalAddress: PhysicalPostalAddressDto, regions: Map): PhysicalPostalAddress { return PhysicalPostalAddress( geographicCoordinates = physicalAddress.geographicCoordinates?.let { toEntity(it) }, country = physicalAddress.country, - administrativeAreaLevel1 = metadataMap.regions[physicalAddress.administrativeAreaLevel1], + administrativeAreaLevel1 = regions[physicalAddress.administrativeAreaLevel1], administrativeAreaLevel2 = physicalAddress.administrativeAreaLevel2, administrativeAreaLevel3 = physicalAddress.administrativeAreaLevel3, postCode = physicalAddress.postalCode, @@ -454,11 +457,11 @@ class BusinessPartnerBuildService( ) } - private fun createAlternativeAddress(alternativeAddress: AlternativePostalAddressDto, metadataMap: AddressMetadataMapping): AlternativePostalAddress { + private fun createAlternativeAddress(alternativeAddress: AlternativePostalAddressDto, regions: Map): AlternativePostalAddress { return AlternativePostalAddress( geographicCoordinates = alternativeAddress.geographicCoordinates?.let { toEntity(it) }, country = alternativeAddress.country, - administrativeAreaLevel1 = metadataMap.regions[alternativeAddress.administrativeAreaLevel1], + administrativeAreaLevel1 = regions[alternativeAddress.administrativeAreaLevel1], postCode = alternativeAddress.postalCode, city = alternativeAddress.city, deliveryServiceType = alternativeAddress.deliveryServiceType, @@ -530,12 +533,12 @@ class BusinessPartnerBuildService( private fun toEntity( dto: AddressIdentifierDto, - metadataMap: AddressMetadataMapping, + idTypes: Map, partner: LogisticAddress ): AddressIdentifier { return AddressIdentifier( value = dto.value, - type = metadataMap.idTypes[dto.type]!!, + type = idTypes[dto.type]!!, address = partner ) } @@ -561,13 +564,14 @@ class BusinessPartnerBuildService( ) - private data class LegalEntityMetadataMapping( + data class LegalEntityMetadataMapping( val idTypes: Map, val legalForms: Map ) - private data class AddressMetadataMapping( + data class AddressMetadataMapping( val idTypes: Map, val regions: Map ) + } \ No newline at end of file diff --git a/bpdm-pool/src/main/kotlin/org/eclipse/tractusx/bpdm/pool/service/FetchAndReserveCleaningStepService.kt b/bpdm-pool/src/main/kotlin/org/eclipse/tractusx/bpdm/pool/service/FetchAndReserveCleaningStepService.kt new file mode 100644 index 000000000..fe1abda26 --- /dev/null +++ b/bpdm-pool/src/main/kotlin/org/eclipse/tractusx/bpdm/pool/service/FetchAndReserveCleaningStepService.kt @@ -0,0 +1,204 @@ +/******************************************************************************* + * 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.pool.service + +import mu.KotlinLogging +import org.eclipse.tractusx.bpdm.common.dto.IBaseLegalEntityDto +import org.eclipse.tractusx.bpdm.pool.api.model.response.ErrorInfo +import org.eclipse.tractusx.bpdm.pool.api.model.response.LegalEntityCreateError +import org.eclipse.tractusx.bpdm.pool.dto.LegalEntityMetadataDto +import org.eclipse.tractusx.bpdm.pool.entity.* +import org.eclipse.tractusx.bpdm.pool.entity.LegalEntityState +import org.eclipse.tractusx.orchestrator.api.client.OrchestrationApiClient +import org.eclipse.tractusx.orchestrator.api.model.* +import org.springframework.scheduling.annotation.Scheduled +import java.time.Instant +import java.time.temporal.ChronoUnit + +class FetchAndReserveCleaningStepService( + private val orchestrationClient: OrchestrationApiClient, + private val metadataService: MetadataService, + private val requestValidationService: RequestValidationService, + private val bpnIssuingService: BpnIssuingService, +) { + private val logger = KotlinLogging.logger { } + + @Scheduled(cron = "\${bpdm.opensearch.export-scheduler-cron-expr:-}", zone = "UTC") + fun fetchAndReserve() { + + val reservationRequest = TaskStepReservationRequest(step = TaskStep.PoolSync, amount = 10) + val taskStepReservation = orchestrationClient.goldenRecordTasks.reserveTasksForStep(reservationRequest = reservationRequest) + + val taskResults = upsertGoldenRecordIntoPool(taskStepReservation.reservedTasks) + orchestrationClient.goldenRecordTasks.resolveStepResults(TaskStepResultRequest(step=TaskStep.PoolSync,results = taskResults)) + } + + private fun upsertGoldenRecordIntoPool(tasks: List): List { + + val isTaskCreateLegalEntity = + { task: TaskStepReservationEntryDto -> task.businessPartner.legalEntity?.bpnLReference?.referenceType == BpnReferenceType.BpnRequestIdentifier } + + val legalEntitiesToCreateSteps: List = tasks + .filter { isTaskCreateLegalEntity(it) } + + val legalEntityByTask = legalEntitiesToCreateSteps + .associateWith { it.businessPartner.legalEntity as IBaseLegalEntityDto } + + val addressByTask = legalEntitiesToCreateSteps + .associateWith { it.businessPartner.legalEntity?.legalAddress as LogisticAddressDto } + + + val errorsByRequest = requestValidationService.validateLegalEntityCreatesOrchestrator(legalEntityByTask) + val errorsByRequestAddress = requestValidationService.validateLegalEntityCreatesAddressesOrchestrator(addressByTask) + + val legalEntityCreateTaskResults = legalEntitiesToCreateSteps + .map { taskStep -> + if (errorsByRequest.containsKey(taskStep) || errorsByRequestAddress.containsKey(taskStep)) { + taskResultsForErrors( + taskStep.taskId, + errorsByRequest.getOrDefault(taskStep, emptyList()) + errorsByRequestAddress.getOrDefault(taskStep, emptyList()) + ) + } else { + legalEntityCreateTaskResult(taskStep) + } + } + return legalEntityCreateTaskResults + } + + private fun taskResultsForErrors(errorTaskId: String, errors: Collection>): TaskStepResultEntryDto { + + return TaskStepResultEntryDto(taskId = errorTaskId, errors = errors.map { TaskErrorDto(type = TaskErrorType.Unspecified, description = it.message) }) + } + + private fun legalEntityCreateTaskResult(task: TaskStepReservationEntryDto): TaskStepResultEntryDto { + + val legalEntity = task.businessPartner.legalEntity + val legalName = legalEntity?.legalName + val legalAddress = legalEntity?.legalAddress + + return if (legalEntity != null && legalName != null && legalAddress != null) { + val bpnLs = bpnIssuingService.issueLegalEntityBpns(1) + val legalEntityMetadataMap = metadataService.getMetadata(listOf(legalEntity)).toMapping() + val newLegalEntity = createLegalEntity(legalEntity, bpnLs[0], legalName, legalEntityMetadataMap) + // todo create address, changelogService and write to db + TaskStepResultEntryDto( + taskId = task.taskId, + businessPartner = BusinessPartnerFullDto(generic = task.businessPartner.generic) + ) + } else { + TaskStepResultEntryDto( + taskId = task.taskId, + errors = listOf( + TaskErrorDto( + type = TaskErrorType.Unspecified, + description = "Legal name or legal address is empty" + ) + ) + ) + } + } + + + private fun createLegalEntity( + legalEntityDto: LegalEntityDto, + bpnL: String, + legalNameValue: String, + metadataMap: BusinessPartnerBuildService.LegalEntityMetadataMapping + ): LegalEntity { + + // it has to be validated that the legalForm exits + val legalForm = legalEntityDto.legalForm?.let { metadataMap.legalForms[it]!! } + val legalName = Name( + value = legalNameValue, + shortName = legalEntityDto.legalShortName + ) + val newLegalEntity = LegalEntity( + bpn = bpnL, + legalName = legalName, + legalForm = legalForm, + currentness = Instant.now().truncatedTo(ChronoUnit.MICROS), + ) + updateLegalEntity(newLegalEntity, legalEntityDto, legalName, legalEntityDto.identifiers.map { toEntity(it, metadataMap.idTypes, newLegalEntity) }) + + return newLegalEntity + } + + private fun updateLegalEntity( + legalEntity: LegalEntity, + request: LegalEntityDto, + legalName: Name, + identifiers: List + ) { + + legalEntity.currentness = createCurrentnessTimestamp() + + legalEntity.legalName = legalName + + legalEntity.identifiers.clear() + legalEntity.states.clear() + legalEntity.classifications.clear() + + legalEntity.states.addAll(request.states.map { toEntity(it, legalEntity) }) + legalEntity.identifiers.addAll(identifiers) + legalEntity.classifications.addAll(request.classifications.map { toEntity(it, legalEntity) }.toSet()) + } + + private fun createCurrentnessTimestamp(): Instant { + return Instant.now().truncatedTo(ChronoUnit.MICROS) + } + + private fun toEntity(dto: org.eclipse.tractusx.orchestrator.api.model.LegalEntityState, legalEntity: LegalEntity): LegalEntityState { + return LegalEntityState( + description = dto.description, + validFrom = dto.validFrom, + validTo = dto.validTo, + type = dto.type, + legalEntity = legalEntity + ) + } + + private fun toEntity( + dto: LegalEntityIdentifierDto, + idTypes: Map, + partner: LegalEntity + ): LegalEntityIdentifier { + return LegalEntityIdentifier( + value = dto.value, + type = idTypes[dto.type]!!, + issuingBody = dto.issuingBody, + legalEntity = partner + ) + } + + private fun toEntity(dto: BusinessPartnerClassificationDto, partner: LegalEntity): LegalEntityClassification { + return LegalEntityClassification( + value = dto.value, + code = dto.code, + type = dto.type, + legalEntity = partner + ) + } + + private fun LegalEntityMetadataDto.toMapping() = + BusinessPartnerBuildService.LegalEntityMetadataMapping( + idTypes = idTypes.associateBy { it.technicalKey }, + legalForms = legalForms.associateBy { it.technicalKey } + ) +} \ No newline at end of file diff --git a/bpdm-pool/src/main/kotlin/org/eclipse/tractusx/bpdm/pool/service/MetadataService.kt b/bpdm-pool/src/main/kotlin/org/eclipse/tractusx/bpdm/pool/service/MetadataService.kt index bbd625808..f5791e7c9 100644 --- a/bpdm-pool/src/main/kotlin/org/eclipse/tractusx/bpdm/pool/service/MetadataService.kt +++ b/bpdm-pool/src/main/kotlin/org/eclipse/tractusx/bpdm/pool/service/MetadataService.kt @@ -37,6 +37,7 @@ import org.eclipse.tractusx.bpdm.pool.repository.FieldQualityRuleRepository import org.eclipse.tractusx.bpdm.pool.repository.IdentifierTypeRepository import org.eclipse.tractusx.bpdm.pool.repository.LegalFormRepository import org.eclipse.tractusx.bpdm.pool.repository.RegionRepository +import org.eclipse.tractusx.orchestrator.api.model.LogisticAddressDto import org.springframework.data.domain.Pageable import org.springframework.data.jpa.domain.Specification import org.springframework.stereotype.Service @@ -142,7 +143,7 @@ class MetadataService( return resultList } - fun getMetadata(requests: Collection): LegalEntityMetadataDto { + fun getMetadata(requests: Collection): LegalEntityMetadataDto { val idTypeKeys = requests.flatMap { it.identifiers }.map { it.type }.toSet() val idTypes = identifierTypeRepository.findByBusinessPartnerTypeAndTechnicalKeyIn(IdentifierBusinessPartnerType.LEGAL_ENTITY, idTypeKeys) @@ -152,7 +153,19 @@ class MetadataService( return LegalEntityMetadataDto(idTypes, legalForms) } - fun getMetadata(requests: Collection): AddressMetadataDto { + fun getMetadataOrchestrator(requests: Collection): AddressMetadataDto { + val idTypeKeys = requests.flatMap { it.identifiers }.map { it.type }.toSet() + val idTypes = identifierTypeRepository.findByBusinessPartnerTypeAndTechnicalKeyIn(IdentifierBusinessPartnerType.ADDRESS, idTypeKeys) + + val regionKeys = requests.mapNotNull { it.physicalPostalAddress?.administrativeAreaLevel1 } + .plus(requests.mapNotNull { it.alternativePostalAddress?.administrativeAreaLevel1 }) + .toSet() + val regions = regionRepository.findByRegionCodeIn(regionKeys) + + return AddressMetadataDto(idTypes, regions) + } + + fun getMetadata(requests: Collection): AddressMetadataDto { val idTypeKeys = requests.flatMap { it.identifiers }.map { it.type }.toSet() val idTypes = identifierTypeRepository.findByBusinessPartnerTypeAndTechnicalKeyIn(IdentifierBusinessPartnerType.ADDRESS, idTypeKeys) diff --git a/bpdm-pool/src/main/kotlin/org/eclipse/tractusx/bpdm/pool/service/RequestValidationService.kt b/bpdm-pool/src/main/kotlin/org/eclipse/tractusx/bpdm/pool/service/RequestValidationService.kt index 47ab80c00..ac046b9b5 100644 --- a/bpdm-pool/src/main/kotlin/org/eclipse/tractusx/bpdm/pool/service/RequestValidationService.kt +++ b/bpdm-pool/src/main/kotlin/org/eclipse/tractusx/bpdm/pool/service/RequestValidationService.kt @@ -19,15 +19,15 @@ package org.eclipse.tractusx.bpdm.pool.service -import org.eclipse.tractusx.bpdm.common.dto.BusinessPartnerType -import org.eclipse.tractusx.bpdm.common.dto.LegalEntityDto -import org.eclipse.tractusx.bpdm.common.dto.LogisticAddressDto +import org.eclipse.tractusx.bpdm.common.dto.* import org.eclipse.tractusx.bpdm.common.util.findDuplicates import org.eclipse.tractusx.bpdm.pool.api.model.request.* import org.eclipse.tractusx.bpdm.pool.api.model.response.* import org.eclipse.tractusx.bpdm.pool.dto.AddressMetadataDto import org.eclipse.tractusx.bpdm.pool.dto.LegalEntityMetadataDto import org.eclipse.tractusx.bpdm.pool.repository.* +import org.eclipse.tractusx.orchestrator.api.model.LogisticAddressDto +import org.eclipse.tractusx.orchestrator.api.model.TaskStepReservationEntryDto import org.springframework.stereotype.Service @Service @@ -40,56 +40,151 @@ class RequestValidationService( private val addressRepository: LogisticAddressRepository, private val metadataService: MetadataService ) { - fun validateLegalEntityCreates( - requests: Collection - ): Map>> { - val legalEntityRequests = requests.map { it.legalEntity } - val legalAddressRequests = requests.map { it.legalAddress } + fun validateLegalEntityCreatesOrchestrator( + legalEntitiesByRequest: Map + ): Map>> { + val entityKeyFunc = { task: TaskStepReservationEntryDto -> task.businessPartner.legalEntity?.bpnLReference?.referenceValue } + val legalEntityRequests = legalEntitiesByRequest.values val legalEntityMetadata = metadataService.getMetadata(legalEntityRequests).toKeys() - val addressMetadata = metadataService.getMetadata(legalAddressRequests).toKeys() + val legalEntityDuplicateIdentifierCandidates = getLegalEntityDuplicateIdentifierCandidates(legalEntityRequests) + + return legalEntitiesByRequest.map { + val legalEntity = it.value + val request = it.key + + val validationErrors = + validateLegalFormExists(legalEntity + , legalEntityMetadata.legalForms + , LegalEntityCreateError.LegalFormNotFound + , entityKeyFunc(request) + ) + + validateIdentifierTypesExists( + legalEntity, + legalEntityMetadata.idTypes, + LegalEntityCreateError.LegalEntityIdentifierNotFound, + entityKeyFunc(request) + ) + + validateLegalEntityIdentifiersDuplicated( + legalEntity = legalEntity, + existingIdentifiers = legalEntityDuplicateIdentifierCandidates, + bpn = null, + error = LegalEntityCreateError.LegalEntityDuplicateIdentifier, + entityKey = entityKeyFunc(request) + ) + request to validationErrors + }.toMap() + .filterValues { it.isNotEmpty() } + } + + fun validateLegalEntityCreatesPool( + legalEntitiesByRequest: Map + ): Map>> { + + val entityKeyFunc = { theRequest: LegalEntityPartnerCreateRequest -> theRequest.index } + val legalEntityRequests = legalEntitiesByRequest.values + val legalEntityMetadata = metadataService.getMetadata(legalEntityRequests).toKeys() val legalEntityDuplicateIdentifierCandidates = getLegalEntityDuplicateIdentifierCandidates(legalEntityRequests) - val addressDuplicateIdentifierCandidates = getAddressDuplicateIdentifierCandidates(legalAddressRequests) - return requests.flatMap { request -> - val legalEntity = request.legalEntity - val legalAddress = request.legalAddress + return legalEntitiesByRequest.map { + val legalEntity = it.value + val request = it.key val validationErrors = - validateLegalFormExists(legalEntity, legalEntityMetadata.legalForms, LegalEntityCreateError.LegalFormNotFound, request.index) + + validateLegalFormExists(legalEntity + , legalEntityMetadata.legalForms + , LegalEntityCreateError.LegalFormNotFound + , entityKeyFunc(request) + ) + validateIdentifierTypesExists( legalEntity, legalEntityMetadata.idTypes, LegalEntityCreateError.LegalEntityIdentifierNotFound, - request.index - ) + - validateRegionExists(legalAddress, addressMetadata.regions, LegalEntityCreateError.LegalAddressRegionNotFound, request.index) + - validateIdentifierTypesExists( - legalAddress, - addressMetadata.idTypes, - LegalEntityCreateError.LegalAddressIdentifierNotFound, - request.index + entityKeyFunc(request) ) + validateLegalEntityIdentifiersDuplicated( legalEntity = legalEntity, existingIdentifiers = legalEntityDuplicateIdentifierCandidates, bpn = null, error = LegalEntityCreateError.LegalEntityDuplicateIdentifier, - entityKey = request.index + entityKey = entityKeyFunc(request) + ) + request to validationErrors + }.toMap() + .filterValues { it.isNotEmpty() } + } + + + fun validateLegalEntityCreatesAddressesOrchestrator( + addressByRequest: Map + ): Map>> { + + val entityKeyFunc = { task: TaskStepReservationEntryDto -> task.businessPartner.legalEntity?.bpnLReference?.referenceValue } + val legalAddressRequests = addressByRequest.values + val addressDuplicateIdentifierCandidates = getAddressDuplicateIdentifierCandidates(legalAddressRequests) + val addressMetadata = metadataService.getMetadataOrchestrator(legalAddressRequests).toKeys() + + return addressByRequest.map{ + val legalAddress = it.value + val request = it.key + val validationErrors = + validateRegionExists(legalAddress, + addressMetadata.regions, + LegalEntityCreateError.LegalAddressRegionNotFound, + entityKeyFunc(request)) + + validateIdentifierTypesExists( + legalAddress, + addressMetadata.idTypes, + LegalEntityCreateError.LegalAddressIdentifierNotFound, + entityKeyFunc(request) ) + validateAddressIdentifiersDuplicated( address = legalAddress, existingIdentifiers = addressDuplicateIdentifierCandidates, bpn = null, error = LegalEntityCreateError.LegalAddressDuplicateIdentifier, - entityKey = request.index + entityKey = entityKeyFunc(request) ) + request to validationErrors + }.toMap() + .filterValues { it.isNotEmpty() } + } - validationErrors.map { Pair(request, it) } + fun validateLegalEntityCreatesAddressesPool( + addressByRequest: Map + ): Map>> { - }.groupBy({ it.first }, { it.second }) + val entityKeyFunc = { theRequest: LegalEntityPartnerCreateRequest -> theRequest.index } + val legalAddressRequests = addressByRequest.values + val addressDuplicateIdentifierCandidates = getAddressDuplicateIdentifierCandidates(legalAddressRequests) + val addressMetadata = metadataService.getMetadata(legalAddressRequests).toKeys() + + return addressByRequest.map{ + val legalAddress = it.value + val request = it.key + val validationErrors = + validateRegionExists(legalAddress, + addressMetadata.regions, + LegalEntityCreateError.LegalAddressRegionNotFound, + entityKeyFunc(request)) + + validateIdentifierTypesExists( + legalAddress, + addressMetadata.idTypes, + LegalEntityCreateError.LegalAddressIdentifierNotFound, + entityKeyFunc(request) + ) + + validateAddressIdentifiersDuplicated( + address = legalAddress, + existingIdentifiers = addressDuplicateIdentifierCandidates, + bpn = null, + error = LegalEntityCreateError.LegalAddressDuplicateIdentifier, + entityKey = entityKeyFunc(request) + ) + request to validationErrors + }.toMap() + .filterValues { it.isNotEmpty() } } fun validateLegalEntityUpdates( @@ -278,7 +373,7 @@ class RequestValidationService( } - private fun validateIdentifierTypesExists(request: LegalEntityDto, existingTypes: Set, error: ERROR, entityKey: String?) + private fun validateIdentifierTypesExists(request: IBaseLegalEntityDto, existingTypes: Set, error: ERROR, entityKey: String?) : Collection> { val requestedTypes = request.identifiers.map { it.type } val missingTypes = requestedTypes - existingTypes @@ -292,7 +387,7 @@ class RequestValidationService( } } - private fun validateLegalFormExists(request: LegalEntityDto, existingLegalForms: Set, error: ERROR, entityKey: String?) + private fun validateLegalFormExists(request: IBaseLegalEntityDto, existingLegalForms: Set, error: ERROR, entityKey: String?) : Collection> { if (request.legalForm != null) { @@ -304,7 +399,7 @@ class RequestValidationService( return emptyList() } - private fun validateIdentifierTypesExists(request: LogisticAddressDto, existingTypes: Set, error: ERROR, entityKey: String?) + private fun validateIdentifierTypesExists(request: IBaseLogisticAddressDto, existingTypes: Set, error: ERROR, entityKey: String?) : Collection> { val requestedTypes = request.identifiers.map { it.type } val missingTypes = requestedTypes - existingTypes @@ -318,10 +413,10 @@ class RequestValidationService( } } - private fun validateRegionExists(request: LogisticAddressDto, existingRegions: Set, error: ERROR, entityKey: String?) + private fun validateRegionExists(request: IBaseLogisticAddressDto, existingRegions: Set, error: ERROR, entityKey: String?) : Collection> { val requestedTypes = listOfNotNull( - request.physicalPostalAddress.administrativeAreaLevel1, + request.physicalPostalAddress?.administrativeAreaLevel1, request.alternativePostalAddress?.administrativeAreaLevel1 ) @@ -352,7 +447,7 @@ class RequestValidationService( emptyList() } - private fun getLegalEntityDuplicateIdentifierCandidates(requests: Collection) + private fun getLegalEntityDuplicateIdentifierCandidates(requests: Collection) : Map { val identifiers = requests.flatMap { it.identifiers } val idValues = identifiers.map { it.value } @@ -366,7 +461,7 @@ class RequestValidationService( return duplicatesFromRequest.plus(duplicatesFromDb) } - private fun getAddressDuplicateIdentifierCandidates(requests: Collection) + private fun getAddressDuplicateIdentifierCandidates(requests: Collection) : Map { val identifiers = requests.flatMap { it.identifiers } val idValues = identifiers.map { it.value } @@ -381,7 +476,7 @@ class RequestValidationService( } private fun validateLegalEntityIdentifiersDuplicated( - legalEntity: LegalEntityDto, + legalEntity: IBaseLegalEntityDto, existingIdentifiers: Map, bpn: String?, error: ERROR, @@ -399,7 +494,7 @@ class RequestValidationService( } private fun validateAddressIdentifiersDuplicated( - address: LogisticAddressDto, + address: IBaseLogisticAddressDto, existingIdentifiers: Map, bpn: String?, error: ERROR,