diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/config/GoldenRecordTaskConfiguration.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/config/GoldenRecordTaskConfiguration.kt index b52416f24..fc87cc055 100644 --- a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/config/GoldenRecordTaskConfiguration.kt +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/config/GoldenRecordTaskConfiguration.kt @@ -20,8 +20,9 @@ package org.eclipse.tractusx.bpdm.gate.config import jakarta.annotation.PostConstruct -import org.eclipse.tractusx.bpdm.gate.service.GoldenRecordTaskService import org.eclipse.tractusx.bpdm.gate.service.GoldenRecordUpdateService +import org.eclipse.tractusx.bpdm.gate.service.TaskCreationService +import org.eclipse.tractusx.bpdm.gate.service.TaskResolutionService import org.springframework.context.annotation.Configuration import org.springframework.scheduling.TaskScheduler import org.springframework.scheduling.support.CronTrigger @@ -30,14 +31,15 @@ import org.springframework.scheduling.support.CronTrigger class GoldenRecordTaskConfiguration( private val configProperties: GoldenRecordTaskConfigProperties, private val taskScheduler: TaskScheduler, - private val taskService: GoldenRecordTaskService, + private val taskCreationService: TaskCreationService, + private val taskResolutionService: TaskResolutionService, private val updateService: GoldenRecordUpdateService ) { @PostConstruct fun scheduleGoldenRecordTasks() { taskScheduler.scheduleIfEnabled( - { taskService.createTasksForReadyBusinessPartners() }, + { taskCreationService.createTasksForReadyBusinessPartners() }, configProperties.creation.fromSharingMember.cron ) @@ -47,7 +49,7 @@ class GoldenRecordTaskConfiguration( ) taskScheduler.scheduleIfEnabled( - { taskService.resolvePendingTasks() }, + { taskResolutionService.resolveTasks() }, configProperties.check.cron ) } diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/entity/ChangelogEntryDb.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/entity/ChangelogEntryDb.kt index 0d45dd3e7..bdc1eae5c 100644 --- a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/entity/ChangelogEntryDb.kt +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/entity/ChangelogEntryDb.kt @@ -31,8 +31,8 @@ class ChangelogEntryDb( @Column(name = "external_id", nullable = false, updatable = false) val externalId: String, - @Column(name = "associated_owner_bpnl", nullable = true) - var associatedOwnerBpnl: String? = null, + @Column(name = "tenant_bpnl", nullable = true) + var tenantBpnl: String? = null, @Enumerated(EnumType.STRING) @Column(name = "changelog_type", nullable = false, updatable = false) diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/entity/SharingStateDb.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/entity/SharingStateDb.kt index 506475a1f..a8d7a96a3 100644 --- a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/entity/SharingStateDb.kt +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/entity/SharingStateDb.kt @@ -33,8 +33,8 @@ class SharingStateDb( @Column(name = "external_id", nullable = false) var externalId: String, - @Column(name = "associated_owner_bpnl", nullable = true) - var associatedOwnerBpnl: String? = null, + @Column(name = "tenant_bpnl", nullable = true) + var tenantBpnl: String? = null, @Enumerated(EnumType.STRING) @Column(name = "sharing_state_type", nullable = false) diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/entity/generic/BusinessPartnerDb.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/entity/generic/BusinessPartnerDb.kt index 40b8595f7..fb2301349 100644 --- a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/entity/generic/BusinessPartnerDb.kt +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/entity/generic/BusinessPartnerDb.kt @@ -21,17 +21,18 @@ package org.eclipse.tractusx.bpdm.gate.entity.generic import jakarta.persistence.* import org.eclipse.tractusx.bpdm.common.dto.BusinessPartnerRole -import org.eclipse.tractusx.bpdm.common.dto.BusinessPartnerType import org.eclipse.tractusx.bpdm.common.model.BaseEntity import org.eclipse.tractusx.bpdm.common.model.StageType +import org.eclipse.tractusx.bpdm.gate.entity.SharingStateDb import java.util.* @Entity @Table(name = "business_partners") class BusinessPartnerDb( - @Column(name = "external_id") - var externalId: String, + @ManyToOne + @JoinColumn(name = "sharing_state_id", nullable = false) + var sharingState: SharingStateDb, @ElementCollection(fetch = FetchType.EAGER) @CollectionTable(name = "business_partners_name_parts", joinColumns = [JoinColumn(name = "business_partner_id")]) @@ -74,9 +75,6 @@ class BusinessPartnerDb( @Column(name = "is_own_company_data", nullable = false) var isOwnCompanyData: Boolean = false, - @Column(name = "associated_owner_bpnl", nullable = true) - var associatedOwnerBpnl: String? = null, - @Column(name = "bpnl") var bpnL: String? = null, @@ -94,13 +92,6 @@ class BusinessPartnerDb( @Enumerated(EnumType.STRING) var stage: StageType, - @Column(name = "parent_id") - var parentId: String? = null, - - @Column(name = "parent_type") - @Enumerated(EnumType.STRING) - var parentType: BusinessPartnerType? = null, - @OneToOne(cascade = [CascadeType.ALL], orphanRemoval = true) @JoinColumn(name = "legal_entity_confidence_id", unique = true) var legalEntityConfidence: ConfidenceCriteriaDb?, @@ -113,5 +104,18 @@ class BusinessPartnerDb( @JoinColumn(name = "address_confidence_id", unique = true) var addressConfidence: ConfidenceCriteriaDb?, - ) : BaseEntity() + ) : BaseEntity() { + + companion object { + fun createEmpty(sharingState: SharingStateDb, stage: StageType) = + BusinessPartnerDb( + sharingState = sharingState, + stage = stage, + postalAddress = PostalAddressDb(), + legalEntityConfidence = null, + siteConfidence = null, + addressConfidence = null + ) + } +} diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/exception/BpdmMissingSharingStateException.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/exception/BpdmMissingSharingStateException.kt new file mode 100644 index 000000000..e2367e5cb --- /dev/null +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/exception/BpdmMissingSharingStateException.kt @@ -0,0 +1,25 @@ +/******************************************************************************* + * 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.gate.exception + +class BpdmMissingSharingStateException( + externalId: String, + tenantBpnl: String? +) : RuntimeException("Sharing state with external-id '$externalId' in tenant '$tenantBpnl' is missing.") \ No newline at end of file diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/model/upsert/output/AlternativeAddress.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/model/upsert/output/AlternativeAddress.kt new file mode 100644 index 000000000..879b59919 --- /dev/null +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/model/upsert/output/AlternativeAddress.kt @@ -0,0 +1,34 @@ +/******************************************************************************* + * 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.gate.model.upsert.output + +import com.neovisionaries.i18n.CountryCode +import org.eclipse.tractusx.bpdm.common.model.DeliveryServiceType + +data class AlternativeAddress( + val geographicCoordinates: GeoCoordinate?, + val country: CountryCode, + val administrativeAreaLevel1: String?, + val postalCode: String?, + val city: String, + val deliveryServiceType: DeliveryServiceType, + val deliveryServiceQualifier: String?, + val deliveryServiceNumber: String +) \ No newline at end of file diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/model/SharingStatusEvaluationResult.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/model/upsert/output/ConfidenceCriteria.kt similarity index 69% rename from bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/model/SharingStatusEvaluationResult.kt rename to bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/model/upsert/output/ConfidenceCriteria.kt index d66c458bd..3c5c4ebd2 100644 --- a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/model/SharingStatusEvaluationResult.kt +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/model/upsert/output/ConfidenceCriteria.kt @@ -17,13 +17,15 @@ * SPDX-License-Identifier: Apache-2.0 ******************************************************************************/ -package org.eclipse.tractusx.bpdm.gate.model +package org.eclipse.tractusx.bpdm.gate.model.upsert.output -import org.eclipse.tractusx.bpdm.gate.api.exception.BusinessPartnerSharingError -import org.eclipse.tractusx.bpdm.gate.api.model.response.ErrorInfo +import java.time.LocalDateTime -data class SharingStatusEvaluationResult( - val validExternalIds: Collection, - val pendingExternalIds: Collection, - val errors: Collection> -) +data class ConfidenceCriteria( + val sharedByOwner: Boolean, + val checkedByExternalDataSource: Boolean, + val numberOfSharingMembers: Int, + val lastConfidenceCheckAt: LocalDateTime, + val nextConfidenceCheckAt: LocalDateTime, + val confidenceLevel: Int +) \ No newline at end of file diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/model/upsert/output/GeoCoordinate.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/model/upsert/output/GeoCoordinate.kt new file mode 100644 index 000000000..4e2cba988 --- /dev/null +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/model/upsert/output/GeoCoordinate.kt @@ -0,0 +1,26 @@ +/******************************************************************************* + * 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.gate.model.upsert.output + +data class GeoCoordinate( + val longitude: Float, + val latitude: Float, + val altitude: Float? +) \ No newline at end of file diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/model/upsert/output/Identifier.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/model/upsert/output/Identifier.kt new file mode 100644 index 000000000..dc069a5a2 --- /dev/null +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/model/upsert/output/Identifier.kt @@ -0,0 +1,29 @@ +/******************************************************************************* + * 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.gate.model.upsert.output + +import org.eclipse.tractusx.bpdm.common.dto.BusinessPartnerType + +data class Identifier( + val type: String, + val value: String, + val issuingBody: String?, + val businessPartnerType: BusinessPartnerType +) \ No newline at end of file diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/model/upsert/output/OutputUpsertData.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/model/upsert/output/OutputUpsertData.kt new file mode 100644 index 000000000..bc8bbfa9b --- /dev/null +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/model/upsert/output/OutputUpsertData.kt @@ -0,0 +1,45 @@ +/******************************************************************************* + * 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.gate.model.upsert.output + +import org.eclipse.tractusx.bpdm.common.dto.AddressType +import org.eclipse.tractusx.bpdm.common.dto.BusinessPartnerRole + +data class OutputUpsertData( + val nameParts: List, + val identifiers: Collection, + val states: Collection, + val roles: Collection, + val isOwnCompanyData: Boolean, + val legalEntityBpn: String, + val legalName: String, + val shortName: String?, + val legalForm: String?, + val siteBpn: String?, + val siteName: String?, + val addressBpn: String, + val addressName: String?, + val addressType: AddressType, + val physicalPostalAddress: PhysicalPostalAddress, + val alternativePostalAddress: AlternativeAddress?, + val legalEntityConfidence: ConfidenceCriteria, + val siteConfidence: ConfidenceCriteria?, + val addressConfidence: ConfidenceCriteria, +) \ No newline at end of file diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/model/upsert/output/PhysicalPostalAddress.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/model/upsert/output/PhysicalPostalAddress.kt new file mode 100644 index 000000000..624f1bef9 --- /dev/null +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/model/upsert/output/PhysicalPostalAddress.kt @@ -0,0 +1,39 @@ +/******************************************************************************* + * 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.gate.model.upsert.output + +import com.neovisionaries.i18n.CountryCode + +data class PhysicalPostalAddress( + val geographicCoordinates: GeoCoordinate?, + val country: CountryCode, + val administrativeAreaLevel1: String?, + val administrativeAreaLevel2: String?, + val administrativeAreaLevel3: String?, + val postalCode: String?, + val city: String, + val district: String?, + val street: Street?, + val companyPostalCode: String?, + val industrialZone: String?, + val building: String?, + val floor: String?, + val door: String? +) \ No newline at end of file diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/model/upsert/output/State.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/model/upsert/output/State.kt new file mode 100644 index 000000000..f7656e39b --- /dev/null +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/model/upsert/output/State.kt @@ -0,0 +1,31 @@ +/******************************************************************************* + * 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.gate.model.upsert.output + +import org.eclipse.tractusx.bpdm.common.dto.BusinessPartnerType +import org.eclipse.tractusx.bpdm.common.model.BusinessStateType +import java.time.LocalDateTime + +data class State( + val validFrom: LocalDateTime?, + val validTo: LocalDateTime?, + val type: BusinessStateType, + val businessPartnerType: BusinessPartnerType +) \ No newline at end of file diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/model/upsert/output/Street.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/model/upsert/output/Street.kt new file mode 100644 index 000000000..a3ad9b385 --- /dev/null +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/model/upsert/output/Street.kt @@ -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.gate.model.upsert.output + +data class Street( + val namePrefix: String?, + val additionalNamePrefix: String?, + val name: String?, + val nameSuffix: String?, + val additionalNameSuffix: String?, + val houseNumber: String?, + val houseNumberSupplement: String?, + val milestone: String?, + val direction: String?, +) \ No newline at end of file diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/repository/ChangelogRepository.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/repository/ChangelogRepository.kt index b1ddeb73f..800e8fe06 100644 --- a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/repository/ChangelogRepository.kt +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/repository/ChangelogRepository.kt @@ -21,11 +21,9 @@ package org.eclipse.tractusx.bpdm.gate.repository import org.eclipse.tractusx.bpdm.common.model.StageType import org.eclipse.tractusx.bpdm.gate.entity.ChangelogEntryDb -import org.eclipse.tractusx.bpdm.gate.entity.SharingStateDb import org.springframework.data.jpa.domain.Specification import org.springframework.data.jpa.repository.JpaRepository import org.springframework.data.jpa.repository.JpaSpecificationExecutor -import org.springframework.data.jpa.repository.Query import java.time.Instant @@ -63,17 +61,17 @@ interface ChangelogRepository : JpaRepository, JpaSpecif } } - fun byAssociatedOwnerBpnl(associatedOwnerBpnl: String?) = + fun byTenantBpnl(tenantBpnl: String?) = Specification { root, _, builder -> - associatedOwnerBpnl?.let { - builder.equal(root.get(ChangelogEntryDb::associatedOwnerBpnl.name), associatedOwnerBpnl) - } ?: builder.isNull(root.get(ChangelogEntryDb::associatedOwnerBpnl.name)) + tenantBpnl?.let { + builder.equal(root.get(ChangelogEntryDb::tenantBpnl.name), tenantBpnl) + } ?: builder.isNull(root.get(ChangelogEntryDb::tenantBpnl.name)) } } - fun findDistinctByExternalIdInAndAssociatedOwnerBpnl(externalIdList: Collection, ownerBpnl: String?): Set + fun findDistinctByExternalIdInAndTenantBpnl(externalIdList: Collection, tenantBpnl: String?): Set } diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/repository/SharingStateRepository.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/repository/SharingStateRepository.kt index 3b4233340..03fd39574 100644 --- a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/repository/SharingStateRepository.kt +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/repository/SharingStateRepository.kt @@ -44,17 +44,17 @@ interface SharingStateRepository : PagingAndSortingRepository { root, _, builder -> associatedOwnerBpnl?.let { - builder.equal(root.get(SharingStateDb::associatedOwnerBpnl.name), associatedOwnerBpnl) - } ?: builder.isNull(root.get(SharingStateDb::associatedOwnerBpnl.name)) + builder.equal(root.get(SharingStateDb::tenantBpnl.name), associatedOwnerBpnl) + } ?: builder.isNull(root.get(SharingStateDb::tenantBpnl.name)) } } - fun findByExternalIdInAndAssociatedOwnerBpnl(externalId: Collection,associatedOwnerBpnl: String?): Collection + fun findByExternalIdInAndTenantBpnl(externalId: Collection, tenantBpnl: String?): Collection fun findBySharingStateType(sharingStateType: SharingStateType, pageable: Pageable): Page diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/repository/generic/BusinessPartnerRepository.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/repository/generic/BusinessPartnerRepository.kt index 14e317c31..82f972d4a 100644 --- a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/repository/generic/BusinessPartnerRepository.kt +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/repository/generic/BusinessPartnerRepository.kt @@ -20,33 +20,52 @@ package org.eclipse.tractusx.bpdm.gate.repository.generic import org.eclipse.tractusx.bpdm.common.model.StageType +import org.eclipse.tractusx.bpdm.gate.entity.SharingStateDb import org.eclipse.tractusx.bpdm.gate.entity.generic.BusinessPartnerDb -import org.springframework.data.domain.Page -import org.springframework.data.domain.Pageable -import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.domain.Specification +import org.springframework.data.jpa.repository.JpaSpecificationExecutor import org.springframework.data.jpa.repository.Query import org.springframework.data.repository.CrudRepository -import org.springframework.data.repository.query.Param +import org.springframework.data.repository.PagingAndSortingRepository import org.springframework.stereotype.Repository -import java.time.Instant @Repository -interface BusinessPartnerRepository : JpaRepository, CrudRepository { +interface BusinessPartnerRepository : PagingAndSortingRepository, CrudRepository, + JpaSpecificationExecutor { - fun findByStageAndExternalIdIn(stage: StageType, externalId: Collection): Set + object Specs { + /** + * Restrict to entries with any one of the given externalIds; ignore if null + */ + fun byExternalIdsIn(externalIds: Collection?) = + Specification { root, _, _ -> + externalIds?.takeIf { it.isNotEmpty() }?.let { + root + .get(BusinessPartnerDb::sharingState.name) + .get(SharingStateDb::externalId.name).`in`(externalIds) + } + } - fun findByStageAndAssociatedOwnerBpnlAndExternalIdIn(stage: StageType,associatedOwnerBpnl: String?, externalId: Collection, pageable: Pageable): Page - fun findByStageAndAssociatedOwnerBpnl(stage: StageType,associatedOwnerBpnl: String?, pageable: Pageable): Page + fun byTenantBpnl(tenantBpnl: String?) = + Specification { root, _, builder -> + val path = root.get(BusinessPartnerDb::sharingState.name).get(SharingStateDb::tenantBpnl.name) + tenantBpnl?.let { + builder.equal(path, tenantBpnl) + } ?: builder.isNull(path) - @Query("SELECT e FROM BusinessPartnerDb e WHERE e.stage = :stage AND (e.bpnL IN :bpnL OR e.bpnS IN :bpnS OR e.bpnA IN :bpnA)") - fun findByStageAndBpnLInOrBpnSInOrBpnAIn( - @Param("stage") stage: StageType?, - @Param("bpnL") bpnLList: List?, - @Param("bpnS") bpnSList: List?, - @Param("bpnA") bpnAList: List? - ): Set + } + + fun byStage(stage: StageType) = + Specification { root, _, builder -> + val path = root.get(BusinessPartnerDb::stage.name) + builder.equal(path, stage) + } + + } + + fun findBySharingStateInAndStage(sharingStates: Collection, stage: StageType): Set @Query("SELECT b.stage as stage, COUNT(b.stage) as count FROM BusinessPartnerDb AS b GROUP BY b.stage") fun countPerStages(): List 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 653b23dd9..1aae0e337 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 @@ -27,10 +27,7 @@ import org.eclipse.tractusx.bpdm.common.model.StageType import org.eclipse.tractusx.bpdm.gate.api.model.* import org.eclipse.tractusx.bpdm.gate.api.model.request.BusinessPartnerInputRequest import org.eclipse.tractusx.bpdm.gate.api.model.response.* -import org.eclipse.tractusx.bpdm.gate.entity.AlternativePostalAddressDb -import org.eclipse.tractusx.bpdm.gate.entity.GeographicCoordinateDb -import org.eclipse.tractusx.bpdm.gate.entity.PhysicalPostalAddressDb -import org.eclipse.tractusx.bpdm.gate.entity.StreetDb +import org.eclipse.tractusx.bpdm.gate.entity.* import org.eclipse.tractusx.bpdm.gate.entity.generic.* import org.eclipse.tractusx.bpdm.gate.exception.BpdmInvalidPartnerException import org.springframework.stereotype.Service @@ -40,7 +37,7 @@ class BusinessPartnerMappings { fun toBusinessPartnerInputDto(entity: BusinessPartnerDb): BusinessPartnerInputDto { return BusinessPartnerInputDto( - externalId = entity.externalId, + externalId = entity.sharingState.externalId, nameParts = entity.nameParts, identifiers = entity.identifiers.map(::toIdentifierDto), states = entity.states.map(::toStateDto), @@ -56,7 +53,7 @@ class BusinessPartnerMappings { fun toBusinessPartnerOutputDto(entity: BusinessPartnerDb): BusinessPartnerOutputDto { return BusinessPartnerOutputDto( - externalId = entity.externalId, + externalId = entity.sharingState.externalId, nameParts = entity.nameParts, identifiers = entity.identifiers.map(::toIdentifierDto), states = entity.states.map(::toStateDto), @@ -70,10 +67,9 @@ class BusinessPartnerMappings { ) } - fun toBusinessPartnerInput(dto: BusinessPartnerInputRequest, ownerBpnl: String?): BusinessPartnerDb { + fun toBusinessPartnerInput(dto: BusinessPartnerInputRequest, sharingState: SharingStateDb): BusinessPartnerDb { return BusinessPartnerDb( stage = StageType.Input, - externalId = dto.externalId, nameParts = dto.nameParts.toMutableList(), roles = dto.roles.toSortedSet(), identifiers = dto.identifiers.mapNotNull{toIdentifier(it, BusinessPartnerType.GENERIC)}.toSortedSet(), @@ -95,7 +91,7 @@ class BusinessPartnerMappings { legalEntityConfidence = null, siteConfidence = null, addressConfidence = null, - associatedOwnerBpnl = ownerBpnl + sharingState = sharingState ) } @@ -134,13 +130,13 @@ class BusinessPartnerMappings { BusinessPartnerDb::class, BusinessPartnerOutputDto::class, BusinessPartnerDb::bpnL, - entity.externalId + entity.sharingState.externalId ), legalName = entity.legalName, shortName = entity.shortName, legalForm = entity.legalForm, confidenceCriteria = entity.legalEntityConfidence?.let { toConfidenceDto(it) } ?: throw BpdmInvalidPartnerException( - entity.externalId, + entity.sharingState.externalId, "Missing address confidence criteria" ), states = toStateDtos(entity.states, BusinessPartnerType.LEGAL_ENTITY) @@ -155,7 +151,7 @@ class BusinessPartnerMappings { siteBpn = entity.bpnS!!, name = entity.siteName, confidenceCriteria = entity.siteConfidence?.let { toConfidenceDto(it) } ?: throw BpdmInvalidPartnerException( - entity.externalId, + entity.sharingState.externalId, "Missing site confidence criteria" ), states = toStateDtos(entity.states, BusinessPartnerType.SITE) @@ -169,14 +165,14 @@ class BusinessPartnerMappings { BusinessPartnerDb::class, BusinessPartnerOutputDto::class, BusinessPartnerDb::bpnA, - entity.externalId + entity.sharingState.externalId ), entity.addressName, addressType = entity.postalAddress.addressType, physicalPostalAddress = entity.postalAddress.physicalPostalAddress?.toPhysicalPostalAddress() ?: PhysicalPostalAddressDto(), alternativePostalAddress = entity.postalAddress.alternativePostalAddress?.toAlternativePostalAddressDto() ?: AlternativePostalAddressDto(), confidenceCriteria = entity.addressConfidence?.let { toConfidenceDto(it) } ?: throw BpdmInvalidPartnerException( - entity.externalId, + entity.sharingState.externalId, "Missing legal entity confidence criteria" ), states = toStateDtos(entity.states, BusinessPartnerType.ADDRESS) @@ -228,19 +224,6 @@ class BusinessPartnerMappings { door = dto.door ) - - private fun toAlternativePostalAddressDto(entity: AlternativePostalAddressDb) = - AlternativePostalAddressDto( - geographicCoordinates = entity.geographicCoordinates?.let(::toGeoCoordinateDto), - country = entity.country, - administrativeAreaLevel1 = entity.administrativeAreaLevel1, - postalCode = entity.postalCode, - city = entity.city, - deliveryServiceType = entity.deliveryServiceType, - deliveryServiceQualifier = entity.deliveryServiceQualifier, - deliveryServiceNumber = entity.deliveryServiceNumber - ) - private fun toAlternativePostalAddress(dto: AlternativePostalAddressDto) = AlternativePostalAddressDb( geographicCoordinates = dto.geographicCoordinates?.let(::toGeographicCoordinate), @@ -254,20 +237,6 @@ class BusinessPartnerMappings { ) - private fun toStreetDto(entity: StreetDb) = - StreetDto( - name = entity.name, - houseNumber = entity.houseNumber, - houseNumberSupplement = entity.houseNumberSupplement, - milestone = entity.milestone, - direction = entity.direction, - namePrefix = entity.namePrefix, - additionalNamePrefix = entity.additionalNamePrefix, - nameSuffix = entity.nameSuffix, - additionalNameSuffix = entity.additionalNameSuffix - ) - - private fun toStreet(dto: StreetDto) = StreetDb( name = dto.name, @@ -300,9 +269,6 @@ class BusinessPartnerMappings { private fun toState(dto: BusinessPartnerStateDto, businessPartnerType: BusinessPartnerType) = dto.type?.let { StateDb(type = it, validFrom = dto.validFrom, validTo = dto.validTo, businessPartnerTyp = businessPartnerType) } - private fun toGeoCoordinateDto(entity: GeographicCoordinateDb) = - GeoCoordinateDto(latitude = entity.latitude, longitude = entity.longitude, altitude = entity.altitude) - private fun toGeographicCoordinate(dto: GeoCoordinateDto) = GeographicCoordinateDb(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 214d9a769..5bbe159c0 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 @@ -23,28 +23,22 @@ import mu.KotlinLogging import org.eclipse.tractusx.bpdm.common.dto.PageDto import org.eclipse.tractusx.bpdm.common.model.StageType import org.eclipse.tractusx.bpdm.common.service.toPageDto -import org.eclipse.tractusx.bpdm.common.util.copyAndSync -import org.eclipse.tractusx.bpdm.common.util.replace import org.eclipse.tractusx.bpdm.gate.api.model.ChangelogType -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.BusinessPartnerOutputDto import org.eclipse.tractusx.bpdm.gate.entity.ChangelogEntryDb -import org.eclipse.tractusx.bpdm.gate.entity.generic.* -import org.eclipse.tractusx.bpdm.gate.exception.BpdmMissingStageException +import org.eclipse.tractusx.bpdm.gate.entity.SharingStateDb +import org.eclipse.tractusx.bpdm.gate.entity.generic.BusinessPartnerDb +import org.eclipse.tractusx.bpdm.gate.exception.BpdmInvalidPartnerException +import org.eclipse.tractusx.bpdm.gate.model.upsert.output.OutputUpsertData import org.eclipse.tractusx.bpdm.gate.repository.ChangelogRepository -import org.eclipse.tractusx.bpdm.gate.repository.SharingStateRepository import org.eclipse.tractusx.bpdm.gate.repository.generic.BusinessPartnerRepository import org.eclipse.tractusx.bpdm.gate.util.BusinessPartnerComparisonUtil import org.eclipse.tractusx.bpdm.gate.util.BusinessPartnerCopyUtil -import org.eclipse.tractusx.orchestrator.api.client.OrchestrationApiClient -import org.eclipse.tractusx.orchestrator.api.model.TaskCreateRequest -import org.eclipse.tractusx.orchestrator.api.model.TaskCreateResponse -import org.eclipse.tractusx.orchestrator.api.model.TaskMode import org.springframework.data.domain.Page import org.springframework.data.domain.PageRequest -import org.springframework.data.domain.Pageable +import org.springframework.data.jpa.domain.Specification import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional @@ -54,165 +48,116 @@ class BusinessPartnerService( private val businessPartnerMappings: BusinessPartnerMappings, private val sharingStateService: SharingStateService, private val changelogRepository: ChangelogRepository, - private val sharingStateRepository: SharingStateRepository, private val copyUtil: BusinessPartnerCopyUtil, - private val compareUtil: BusinessPartnerComparisonUtil + private val compareUtil: BusinessPartnerComparisonUtil, + private val outputUpsertMappings: OutputUpsertMappings ) { private val logger = KotlinLogging.logger { } - @Transactional - fun upsertBusinessPartnersInput(dtos: List, ownerBpnl: String?): List { - logger.debug { "Executing upsertBusinessPartnersInput() with parameters $dtos" } - return OwnerContext(ownerBpnl).upsertBusinessPartnersInput(dtos) - } - fun getBusinessPartnersInput(pageRequest: PageRequest, externalIds: Collection?, ownerBpnl: String?): PageDto { + fun getBusinessPartnersInput(pageRequest: PageRequest, externalIds: Collection?, tenantBpnl: String?): PageDto { logger.debug { "Executing getBusinessPartnersInput() with parameters $pageRequest and $externalIds" } - return OwnerContext(ownerBpnl).getBusinessPartnersInput(pageRequest, externalIds) + + return getBusinessPartners(pageRequest, externalIds, StageType.Input, tenantBpnl).toPageDto(businessPartnerMappings::toBusinessPartnerInputDto) } - fun getBusinessPartnersOutput(pageRequest: PageRequest, externalIds: Collection?, ownerBpnl: String?): PageDto { + fun getBusinessPartnersOutput(pageRequest: PageRequest, externalIds: Collection?, tenantBpnl: String?): PageDto { logger.debug { "Executing getBusinessPartnersOutput() with parameters $pageRequest and $externalIds" } - return OwnerContext(ownerBpnl).getBusinessPartnersOutput(pageRequest, externalIds) - } - fun upsertBusinessPartnersOutputFromCandidates(entityCandidates: List, ownerBpnl: String?): List { - logger.debug { "Upsert output from candidates $entityCandidates" } - val candidateSet = entityCandidates.groupBy { it.externalId }.map { group -> group.value.last() } - return OwnerContext(ownerBpnl).upsertBusinessPartnersOutputFromCandidates(candidateSet) + return getBusinessPartners(pageRequest, externalIds, StageType.Output, tenantBpnl).toPageDto(businessPartnerMappings::toBusinessPartnerOutputDto) } - inner class OwnerContext( - private val ownerBpnl: String? - ){ - @Transactional - fun upsertBusinessPartnersInput(dtos: List): List { - val entities = dtos.map { dto -> businessPartnerMappings.toBusinessPartnerInput(dto, ownerBpnl) } - //Validation method - val validatedEntities = filterUpdateCandidates(entities, StageType.Input) - return upsertBusinessPartnersInputFromCandidates(validatedEntities).map(businessPartnerMappings::toBusinessPartnerInputDto) - } - - fun getBusinessPartnersInput(pageRequest: PageRequest, externalIds: Collection?): PageDto { - val stage = StageType.Input - return getBusinessPartners(pageRequest, externalIds, stage) - .toPageDto(businessPartnerMappings::toBusinessPartnerInputDto) - } + @Transactional + fun upsertBusinessPartnersInput(requests: List, tenantBpnl: String?): List { + logger.debug { "Executing upsertBusinessPartnersInput() with parameters $requests" } - fun getBusinessPartnersOutput(pageRequest: PageRequest, externalIds: Collection?): PageDto { - val stage = StageType.Output - return getBusinessPartners(pageRequest, externalIds, stage) - .toPageDto(businessPartnerMappings::toBusinessPartnerOutputDto) - } + val sharingStates = sharingStateService.getOrCreateStates(requests.map { it.externalId }, tenantBpnl) + val sharingStatesByExternalId = sharingStates.associateBy { it.externalId } + val existingInputs = businessPartnerRepository.findBySharingStateInAndStage(sharingStates, StageType.Input) + val existingInputsByExternalId = existingInputs.associateBy { it.sharingState.externalId } - fun upsertBusinessPartnersOutputFromCandidates(entityCandidates: List): List { - val externalIds = entityCandidates.map { it.externalId } - assertInputStageExists(externalIds) + val updatedEntities = requests.mapNotNull { request -> + val sharingState = sharingStatesByExternalId[request.externalId]!! + val updatedData = businessPartnerMappings.toBusinessPartnerInput(request, sharingState) + val existingInput = existingInputsByExternalId[request.externalId] - val changedBusinessPartners = filterUpdateCandidates(entityCandidates, StageType.Output) + sharingStateService.setInitial(sharingState) + upsertFromEntity(existingInput, updatedData).takeIf { it.hadChanges }?.businessPartner + } - val resolutionResults = resolveCandidatesForStage(changedBusinessPartners, StageType.Output) + return updatedEntities.map(businessPartnerMappings::toBusinessPartnerInputDto) + } - saveChangelog(resolutionResults) + @Transactional + fun upsertBusinessPartnersOutput(requests: List): List { + logger.debug { "Executing upsertBusinessPartnersOutput() with parameters $requests" } - val changedPartners = resolutionResults.map { it.businessPartner } + val existingOutputs = businessPartnerRepository.findBySharingStateInAndStage(requests.map { it.sharingState }, StageType.Output) + val existingOutputsByExternalId = existingOutputs.associateBy { it.sharingState.externalId } - val successRequests = entityCandidates.map { - SharingStateService.SuccessRequest(it.externalId) - } - sharingStateService.setSuccess(successRequests, ownerBpnl) + val updatedEntities = requests.map { request -> + val existingOutput = existingOutputsByExternalId[request.sharingState.externalId] + val updatedData = outputUpsertMappings.toEntity(request.upsertData, request.sharingState) - return businessPartnerRepository.saveAll(changedPartners) + upsertFromEntity(existingOutput, updatedData) } - private fun upsertBusinessPartnersInputFromCandidates(entityCandidates: List): List { - val resolutionResults = resolveCandidatesForStage(entityCandidates, StageType.Input) - - saveChangelog(resolutionResults) + return updatedEntities + } - val partners = resolutionResults.map { it.businessPartner } - sharingStateService.setInitial(partners.map { it.externalId }, ownerBpnl) + @Transactional + fun updateBusinessPartnerOutput(businessPartner: BusinessPartnerDb, upsertData: OutputUpsertData): UpsertResult { + logger.debug { "Executing updateBusinessPartnerOutput() with parameters $businessPartner and $upsertData" } - partners.forEach { logger.info { "Business Partner ${it.externalId} was created or updated" } } + if (businessPartner.stage != StageType.Output) + throw BpdmInvalidPartnerException(businessPartner.id.toString(), "Needs to be in Output stage") - return businessPartnerRepository.saveAll(partners) - } + val updatedData = outputUpsertMappings.toEntity(upsertData, businessPartner.sharingState) + return upsertFromEntity(businessPartner, updatedData) + } - private fun getBusinessPartners(pageRequest: PageRequest, externalIds: Collection?, stage: StageType): Page { - return when { - externalIds.isNullOrEmpty() -> businessPartnerRepository.findByStageAndAssociatedOwnerBpnl(stage, associatedOwnerBpnl = ownerBpnl,pageRequest) - else -> businessPartnerRepository.findByStageAndAssociatedOwnerBpnlAndExternalIdIn(stage, associatedOwnerBpnl = ownerBpnl,externalIds, pageRequest) - } - } - private fun saveChangelog(resolutionResults: Collection) { - resolutionResults.forEach { result -> - if (result.wasResolved) - saveChangelog(result.businessPartner, ChangelogType.UPDATE) - else - saveChangelog(result.businessPartner, ChangelogType.CREATE) - } - } + private fun upsertFromEntity(existingPartner: BusinessPartnerDb?, upsertData: BusinessPartnerDb): UpsertResult { + val sharingState = upsertData.sharingState + val stage = upsertData.stage + val changeType = if (existingPartner == null) ChangelogType.CREATE else ChangelogType.UPDATE + val partnerToUpsert = existingPartner ?: BusinessPartnerDb.createEmpty(upsertData.sharingState, upsertData.stage) - private fun saveChangelog(partner: BusinessPartnerDb, changelogType: ChangelogType) { - changelogRepository.save(ChangelogEntryDb(externalId = partner.externalId,changelogType = changelogType, stage = partner.stage, associatedOwnerBpnl = ownerBpnl)) - } + val hasChanges = compareUtil.hasChanges(upsertData, partnerToUpsert) - private fun assertInputStageExists(externalIds: Collection) { - val existingExternalIds = businessPartnerRepository.findByStageAndAssociatedOwnerBpnlAndExternalIdIn(StageType.Input, ownerBpnl, externalIds, Pageable.unpaged()) - .map { it.externalId } - .toSet() + if (hasChanges) { + changelogRepository.save(ChangelogEntryDb(sharingState.externalId, sharingState.tenantBpnl, changeType, stage)) - externalIds.minus(existingExternalIds) - .takeIf { it.isNotEmpty() } - ?.let { throw BpdmMissingStageException(it, StageType.Input) } + copyUtil.copyValues(upsertData, partnerToUpsert) + businessPartnerRepository.save(partnerToUpsert) } - /** - * Filters all [entities] by looking for existing business partner data in the given [stage] - * - * Filters incoming Business Partner for changes against the same persisted record in the Database - * If the data is the same, the consequent Business Partner will not have a new changelog and the golden record - * process will not start. If Business Partner has the same data, but linked sharing state has an error state, - * Business Partner will start the process again. - */ - private fun filterUpdateCandidates(entities: List, stage: StageType): List { - val externalIds = entities.map { it.externalId } - val persistedBusinessPartnerMap = businessPartnerRepository.findByStageAndExternalIdIn(stage, externalIds).associateBy { it.externalId } - val sharingStatesMap = - sharingStateRepository.findByExternalIdInAndAssociatedOwnerBpnl(externalIds, ownerBpnl).associateBy { it.externalId } - - return entities.filter { entity -> - val matchingBusinessPartner = persistedBusinessPartnerMap[entity.externalId] - val hasErrorSharingState = sharingStatesMap[entity.externalId]?.sharingStateType == SharingStateType.Error - - matchingBusinessPartner?.let { compareUtil.hasChanges(entity, it) } ?: true || hasErrorSharingState //If there are difference return true, else returns false - } - } - - /** - * Resolve all [entityCandidates] by looking for existing business partner data in the given [stage] - * - * Resolving a candidate means to exchange the candidate entity with the existing entity and copy from the candidate to that existing entity. - * - */ - private fun resolveCandidatesForStage(entityCandidates: List, stage: StageType): List { - val existingPartnersByExternalId = businessPartnerRepository.findByStageAndAssociatedOwnerBpnlAndExternalIdIn(stage, ownerBpnl, entityCandidates.map { it.externalId }, Pageable.unpaged()) - .associateBy { it.externalId } - - return entityCandidates.map { candidate -> - val existingEntity = existingPartnersByExternalId[candidate.externalId] - if (existingEntity != null) - ResolutionResult(copyUtil.copyValues(candidate, existingEntity), true) - else - ResolutionResult(candidate, false) - } - } + return UpsertResult(hasChanges, changeType, partnerToUpsert) + } + private fun getBusinessPartners( + pageRequest: PageRequest, + externalIds: Collection?, + stage: StageType, + tenantBpnl: String? + ): Page { + val spec = Specification.allOf( + BusinessPartnerRepository.Specs.byExternalIdsIn(externalIds), + BusinessPartnerRepository.Specs.byTenantBpnl(tenantBpnl), + BusinessPartnerRepository.Specs.byStage(stage) + ) + + return businessPartnerRepository.findAll(spec, pageRequest) } - data class ResolutionResult( - val businessPartner: BusinessPartnerDb, - val wasResolved: Boolean + data class UpsertResult( + val hadChanges: Boolean, + val type: ChangelogType, + val businessPartner: BusinessPartnerDb + ) + + data class OutputUpsertRequest( + val sharingState: SharingStateDb, + val upsertData: OutputUpsertData ) } diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/ChangelogService.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/ChangelogService.kt index ebec7c765..d86e3f898 100644 --- a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/ChangelogService.kt +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/ChangelogService.kt @@ -20,18 +20,16 @@ package org.eclipse.tractusx.bpdm.gate.service import mu.KotlinLogging - import org.eclipse.tractusx.bpdm.common.model.StageType import org.eclipse.tractusx.bpdm.gate.api.exception.ChangeLogOutputError import org.eclipse.tractusx.bpdm.gate.api.model.response.ChangelogGateDto import org.eclipse.tractusx.bpdm.gate.api.model.response.ErrorInfo import org.eclipse.tractusx.bpdm.gate.api.model.response.PageChangeLogDto import org.eclipse.tractusx.bpdm.gate.repository.ChangelogRepository -import org.eclipse.tractusx.bpdm.gate.repository.ChangelogRepository.Specs.byAssociatedOwnerBpnl import org.eclipse.tractusx.bpdm.gate.repository.ChangelogRepository.Specs.byCreatedAtGreaterThan import org.eclipse.tractusx.bpdm.gate.repository.ChangelogRepository.Specs.byExternalIdsIn import org.eclipse.tractusx.bpdm.gate.repository.ChangelogRepository.Specs.byStage -import org.eclipse.tractusx.bpdm.gate.util.getCurrentUserBpn +import org.eclipse.tractusx.bpdm.gate.repository.ChangelogRepository.Specs.byTenantBpnl import org.springframework.data.domain.PageRequest import org.springframework.data.jpa.domain.Specification import org.springframework.stereotype.Service @@ -44,7 +42,7 @@ class ChangelogService(private val changelogRepository: ChangelogRepository) { fun getChangeLogEntries( externalIds: Set?, - ownerBpnl: String?, + tenantBpnl: String?, createdAt: Instant?, stage: StageType?, page: Int, @@ -59,12 +57,12 @@ class ChangelogService(private val changelogRepository: ChangelogRepository) { byExternalIdsIn(externalIds = nonNullExternalIds), byCreatedAtGreaterThan(createdAt = createdAt), byStage(stage), - byAssociatedOwnerBpnl(ownerBpnl) + byTenantBpnl(tenantBpnl) ) val pageable = PageRequest.of(page, pageSize) val pageResponse = changelogRepository.findAll(spec, pageable) - val setDistinctList = changelogRepository.findDistinctByExternalIdInAndAssociatedOwnerBpnl(nonNullExternalIds, ownerBpnl).map { it.externalId } + val setDistinctList = changelogRepository.findDistinctByExternalIdInAndTenantBpnl(nonNullExternalIds, tenantBpnl).map { it.externalId } val pageDto = pageResponse.map { diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/GoldenRecordTaskService.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/GoldenRecordTaskService.kt deleted file mode 100644 index 7e51a932f..000000000 --- a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/GoldenRecordTaskService.kt +++ /dev/null @@ -1,171 +0,0 @@ -/******************************************************************************* - * 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.gate.service - -import mu.KotlinLogging -import org.eclipse.tractusx.bpdm.common.dto.BusinessPartnerType -import org.eclipse.tractusx.bpdm.common.dto.PaginationRequest -import org.eclipse.tractusx.bpdm.common.model.StageType -import org.eclipse.tractusx.bpdm.gate.api.exception.BusinessPartnerSharingError -import org.eclipse.tractusx.bpdm.gate.api.model.SharingStateType -import org.eclipse.tractusx.bpdm.gate.config.GoldenRecordTaskConfigProperties -import org.eclipse.tractusx.bpdm.gate.entity.SharingStateDb -import org.eclipse.tractusx.bpdm.gate.entity.SyncTypeDb -import org.eclipse.tractusx.bpdm.gate.repository.SharingStateRepository -import org.eclipse.tractusx.bpdm.gate.repository.generic.BusinessPartnerRepository -import org.eclipse.tractusx.bpdm.pool.api.client.PoolApiClient -import org.eclipse.tractusx.bpdm.pool.api.model.ChangelogType -import org.eclipse.tractusx.bpdm.pool.api.model.request.ChangelogSearchRequest -import org.eclipse.tractusx.orchestrator.api.client.OrchestrationApiClient -import org.eclipse.tractusx.orchestrator.api.model.* -import org.eclipse.tractusx.orchestrator.api.model.BusinessPartner -import org.springframework.data.domain.Pageable -import org.springframework.stereotype.Service -import org.springframework.transaction.annotation.Transactional - -@Service -class GoldenRecordTaskService( - private val sharingStateRepository: SharingStateRepository, - private val sharingStateService: SharingStateService, - private val businessPartnerRepository: BusinessPartnerRepository, - private val businessPartnerService: BusinessPartnerService, - private val orchestratorMappings: OrchestratorMappings, - private val orchestrationApiClient: OrchestrationApiClient, - private val properties: GoldenRecordTaskConfigProperties -) { - private val logger = KotlinLogging.logger { } - - @Transactional - fun createTasksForReadyBusinessPartners() { - logger.info { "Started scheduled task to create golden record tasks from ready business partners" } - - val pageRequest = Pageable.ofSize(properties.creation.fromSharingMember.batchSize) - val foundStates = sharingStateRepository.findBySharingStateType(SharingStateType.Ready, pageRequest).content - - logger.debug { "Found ${foundStates.size} business partners in ready state" } - - foundStates.groupBy { it.associatedOwnerBpnl }.forEach{ (ownerBpnl, states) -> - - val partners = businessPartnerRepository.findByStageAndAssociatedOwnerBpnlAndExternalIdIn(StageType.Input, ownerBpnl, states.map { it.externalId }, Pageable.unpaged() ).content - - val orchestratorBusinessPartnersDto = partners.map { orchestratorMappings.toOrchestratorDto(it) } - - val createdTasks = createGoldenRecordTasks(TaskMode.UpdateFromSharingMember, orchestratorBusinessPartnersDto) - - val pendingRequests = partners.zip(createdTasks) - .map { (partner, task) -> - SharingStateService.PendingRequest( - partner.externalId, - task.taskId - ) - } - - sharingStateService.setPending(pendingRequests, ownerBpnl) - - logger.info { "Created ${createdTasks.size} new golden record tasks from ready business partners for owner $ownerBpnl" } - } - } - - @Transactional - fun resolvePendingTasks() { - logger.info { "Started scheduled task to resolve pending golden record tasks" } - - val pageRequest = Pageable.ofSize(properties.check.batchSize) - val sharingStates = sharingStateRepository.findBySharingStateTypeAndTaskIdNotNull(SharingStateType.Pending, pageRequest).content - - logger.debug { "Found ${sharingStates.size} business partners in pending state" } - - val tasks = orchestrationApiClient.goldenRecordTasks.searchTaskStates(TaskStateRequest(sharingStates.map { it.taskId!! })).tasks - - - sharingStates.groupBy { it.associatedOwnerBpnl }.forEach{ (ownerBpnl, states) -> - resolvePendingTasksForOwner(tasks, states, ownerBpnl) - } - } - - private fun createGoldenRecordTasks(mode: TaskMode, orchestratorBusinessPartnersDto: List): List { - if (orchestratorBusinessPartnersDto.isEmpty()) - return emptyList() - - return orchestrationApiClient.goldenRecordTasks.createTasks(TaskCreateRequest(mode, orchestratorBusinessPartnersDto)).createdTasks - } - - private fun resolvePendingTasksForOwner(allTasks: List, sharingStates: List, ownerBpnl: String?){ - - val allTasksById = allTasks.associateBy { it.taskId } - val inputsByExternalId = businessPartnerRepository.findByStageAndAssociatedOwnerBpnlAndExternalIdIn(StageType.Input, ownerBpnl, sharingStates.map { it.externalId }, Pageable.unpaged()) - .associateBy { it.externalId } - - val (statesWithTask, statesWithoutTask) = sharingStates.map { state -> Pair(state, allTasksById[state.taskId])}.partition { (_, task) -> task != null } - val (statesWithTaskAndInput, statesWithoutInput) = statesWithTask.map { (state, task) -> Triple(state, task!!, inputsByExternalId[state.externalId]) }.partition { (_, _, input) -> input != null } - val statesInSuccess = statesWithTaskAndInput.filter { (_,task,_) -> task.processingState.resultState == ResultState.Success } - val statesInError = statesWithTaskAndInput.filter { (_,task,_) -> task.processingState.resultState == ResultState.Error } - - val (statesWithOutput, statesWithoutOutput) = statesInSuccess.map { (state, task, input) -> - val roles = input!!.roles.toSortedSet() - val output = try{ - orchestratorMappings.toBusinessPartner(task.businessPartnerResult, state.externalId, state.associatedOwnerBpnl, roles) - }catch (_: Exception){ null } - Pair(state, output) - }.partition { (_, output) -> output != null } - - val upsertedPartners = businessPartnerService.upsertBusinessPartnersOutputFromCandidates(statesWithOutput.map { (_, output) -> output!! }, ownerBpnl) - - val statesWithoutTaskErrors = statesWithoutTask.map { (state, _) -> - SharingStateService.ErrorRequest( - state.externalId, - BusinessPartnerSharingError.MissingTaskID, - errorMessage = "Missing Task in Orchestrator" - ) - } - - val statesWithoutInputErrors = statesWithoutInput.map { (state, _, _) -> - SharingStateService.ErrorRequest( - state.externalId, - BusinessPartnerSharingError.SharingProcessError, - errorMessage = "No input data found for the references business partner" - ) - } - - val statesInErrorErrors = statesInError.map { (state, task, _) -> - SharingStateService.ErrorRequest( - state.externalId, - BusinessPartnerSharingError.SharingProcessError, - if (task.processingState.errors.isNotEmpty()) task.processingState.errors.joinToString(" // ") { it.description }.take(255) else null - ) - } - - val statesWithoutOutputError = statesWithoutOutput.map { (state, _) -> - SharingStateService.ErrorRequest( - state.externalId, - BusinessPartnerSharingError.SharingProcessError, - "Output could not be created from golden record result" - ) - } - - val allErrors = statesWithoutTaskErrors + statesWithoutInputErrors + statesInErrorErrors + statesWithoutOutputError - - sharingStateService.setError(allErrors, ownerBpnl) - - logger.info { "Resolved ${upsertedPartners.size} tasks as successful and ${allErrors.size} as errors for owner $ownerBpnl" } - } - - -} \ No newline at end of file diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/GoldenRecordUpdateService.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/GoldenRecordUpdateService.kt index 0404d62eb..af02ee462 100644 --- a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/GoldenRecordUpdateService.kt +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/GoldenRecordUpdateService.kt @@ -19,21 +19,17 @@ package org.eclipse.tractusx.bpdm.gate.service -import com.nimbusds.oauth2.sdk.id.Identifier -import jakarta.persistence.Column import mu.KotlinLogging import org.eclipse.tractusx.bpdm.common.dto.BusinessPartnerType import org.eclipse.tractusx.bpdm.common.dto.IBaseStateDto import org.eclipse.tractusx.bpdm.common.dto.PaginationRequest -import org.eclipse.tractusx.bpdm.common.model.BusinessStateType +import org.eclipse.tractusx.bpdm.common.exception.BpdmNullMappingException import org.eclipse.tractusx.bpdm.common.model.StageType -import org.eclipse.tractusx.bpdm.gate.api.model.ChangelogType import org.eclipse.tractusx.bpdm.gate.config.GoldenRecordTaskConfigProperties import org.eclipse.tractusx.bpdm.gate.entity.* import org.eclipse.tractusx.bpdm.gate.entity.generic.* -import org.eclipse.tractusx.bpdm.gate.repository.ChangelogRepository +import org.eclipse.tractusx.bpdm.gate.model.upsert.output.* import org.eclipse.tractusx.bpdm.gate.repository.generic.BusinessPartnerRepository -import org.eclipse.tractusx.bpdm.gate.util.BusinessPartnerComparisonUtil import org.eclipse.tractusx.bpdm.gate.util.BusinessPartnerCopyUtil import org.eclipse.tractusx.bpdm.pool.api.client.PoolApiClient import org.eclipse.tractusx.bpdm.pool.api.model.* @@ -43,7 +39,7 @@ import org.eclipse.tractusx.bpdm.pool.api.model.request.LegalEntitySearchRequest import org.eclipse.tractusx.bpdm.pool.api.model.request.SiteSearchRequest import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional -import java.time.LocalDateTime +import kotlin.reflect.KProperty @Service class GoldenRecordUpdateService( @@ -51,9 +47,8 @@ class GoldenRecordUpdateService( private val syncRecordService: SyncRecordService, private val taskConfigProperties: GoldenRecordTaskConfigProperties, private val businessPartnerRepository: BusinessPartnerRepository, - private val changelogRepository: ChangelogRepository, private val copyUtil: BusinessPartnerCopyUtil, - private val compareUtil: BusinessPartnerComparisonUtil + private val businessPartnerService: BusinessPartnerService ) { private val logger = KotlinLogging.logger { } @@ -75,79 +70,58 @@ class GoldenRecordUpdateService( logger.debug { "Found ${changedBpnLs.size} BPNL, ${changedBpnSs.size} BPNS and ${changedBpnAs.size} BPNA entries." } - updateLegalEntities(changedBpnLs) - updateSites(changedBpnSs) - updateAddresses(changedBpnAs) + val updatedLegalEntities = updateLegalEntities(changedBpnLs).size + val updatedSites = updateSites(changedBpnSs).size + val updatedAddresses = updateAddresses(changedBpnAs).size syncRecordService.setSynchronizationSuccess(SyncTypeDb.POOL_TO_GATE_OUTPUT) + + logger.debug { "Updated '$updatedLegalEntities' legal entities, '$updatedSites' sites and '$updatedAddresses' addresses." } } - private fun updateLegalEntities(changedBpnLs: Collection){ + private fun updateLegalEntities(changedBpnLs: Collection): List { val businessPartnersToUpdate = businessPartnerRepository.findByStageAndBpnLIn(StageType.Output, changedBpnLs) - logger.debug { "Found ${businessPartnersToUpdate.size} business partners with matching BPNL to update." } - val bpnLsToQuery = businessPartnersToUpdate.mapNotNull { it.bpnL } val searchRequest = LegalEntitySearchRequest(bpnLs = bpnLsToQuery) val legalEntities = if(searchRequest.bpnLs.isNotEmpty()) - poolClient.legalEntities.getLegalEntities(searchRequest, PaginationRequest(size = searchRequest.bpnLs.size)).content - else - emptyList() - + poolClient.legalEntities.getLegalEntities(searchRequest, PaginationRequest(size = searchRequest.bpnLs.size)).content.map { it.legalEntity } + else + emptyList() - val legalEntitiesByBpn = legalEntities.associateBy { it.legalEntity.bpnl } + val legalEntitiesByBpn = legalEntities.associateBy { it.bpnl } - val updatedPartners = businessPartnersToUpdate.mapNotNull { partner -> - legalEntitiesByBpn[partner.bpnL]?.legalEntity?.let { legalEntity -> partner.apply { update(partner, legalEntity) } } + return businessPartnersToUpdate.mapNotNull { output -> + val legalEntity = legalEntitiesByBpn[output.bpnL!!] ?: return@mapNotNull null + val upsertData = legalEntity.toUpsertData(output) + businessPartnerService.updateBusinessPartnerOutput(output, upsertData) } - - logger.debug { "Updating ${updatedPartners.size} business partners from legal entities" } - - val changedPartners = filterChanged(updatedPartners) - - businessPartnerRepository.saveAll(changedPartners) - - val changelogs = changedPartners.map { ChangelogEntryDb(it.externalId, it.associatedOwnerBpnl, ChangelogType.UPDATE, StageType.Output) } - changelogRepository.saveAll(changelogs) - - logger.debug { "Actual values changed of ${changedPartners.size} business partners from legal entities" } } - private fun updateSites(changedSiteBpns: Collection){ + private fun updateSites(changedSiteBpns: Collection): List { val businessPartnersToUpdate = businessPartnerRepository.findByStageAndBpnSIn(StageType.Output, changedSiteBpns) logger.debug { "Found ${businessPartnersToUpdate.size} business partners with matching BPNS to update." } val siteBpnsToQuery = businessPartnersToUpdate.mapNotNull { it.bpnS } - val searchRequest = SiteSearchRequest(siteBpns = siteBpnsToQuery) val sites = if(searchRequest.siteBpns.isNotEmpty()) - poolClient.sites.getSites(searchRequest, PaginationRequest(size = searchRequest.siteBpns.size)).content + poolClient.sites.getSites(searchRequest, PaginationRequest(size = searchRequest.siteBpns.size)).content.map { it.site } else emptyList() - val sitesByBpn = sites.associateBy { it.site.bpns } + val sitesByBpn = sites.associateBy { it.bpns } - val updatedPartners = businessPartnersToUpdate.mapNotNull { partner -> - sitesByBpn[partner.bpnS]?.site?.let { site -> partner.apply { update(partner, site) } } + return businessPartnersToUpdate.mapNotNull { output -> + val site = sitesByBpn[output.bpnS!!] ?: return@mapNotNull null + val upsertData = site.toUpsertData(output) + businessPartnerService.updateBusinessPartnerOutput(output, upsertData) } - - logger.debug { "Updating ${updatedPartners.size} business partners from sites" } - - - val changedPartners = filterChanged(updatedPartners) - - businessPartnerRepository.saveAll(changedPartners) - - val changelogs = changedPartners.map { ChangelogEntryDb(it.externalId, it.associatedOwnerBpnl, ChangelogType.UPDATE, StageType.Output) } - changelogRepository.saveAll(changelogs) - - logger.debug { "Actual values changed of ${changedPartners.size} business partners from sites" } } - private fun updateAddresses(changedAddressBpns: Collection){ + private fun updateAddresses(changedAddressBpns: Collection): List { val businessPartnersToUpdate = businessPartnerRepository.findByStageAndBpnAIn(StageType.Output, changedAddressBpns) logger.debug { "Found ${businessPartnersToUpdate.size} business partners with matching BPNA to update." } @@ -162,20 +136,132 @@ class GoldenRecordUpdateService( val addressesByBpn = addresses.associateBy { it.bpna } - val updatedPartners = businessPartnersToUpdate.mapNotNull { partner -> - addressesByBpn[partner.bpnA]?.let { address -> partner.apply { update(partner, address) } } + return businessPartnersToUpdate.mapNotNull { output -> + val address = addressesByBpn[output.bpnA!!] ?: return@mapNotNull null + val upsertData = address.toUpsertData(output) + businessPartnerService.updateBusinessPartnerOutput(output, upsertData) } + } + + private fun LegalEntityVerboseDto.toUpsertData(existingOutput: BusinessPartnerDb): OutputUpsertData { + val copy = BusinessPartnerDb.createEmpty(existingOutput.sharingState, existingOutput.stage) + copyUtil.copyValues(existingOutput, copy) + update(copy, this) + + return copy.toUpsertData() + } + + private fun SiteVerboseDto.toUpsertData(existingOutput: BusinessPartnerDb): OutputUpsertData { + val copy = BusinessPartnerDb.createEmpty(existingOutput.sharingState, existingOutput.stage) + copyUtil.copyValues(existingOutput, copy) + update(copy, this) - logger.debug { "Updating ${updatedPartners.size} business partners from logistic addresses" } + return copy.toUpsertData() + } + + private fun LogisticAddressVerboseDto.toUpsertData(existingOutput: BusinessPartnerDb): OutputUpsertData { + val copy = BusinessPartnerDb.createEmpty(existingOutput.sharingState, existingOutput.stage) + copyUtil.copyValues(existingOutput, copy) + update(copy, this) - val changedPartners = filterChanged(updatedPartners) + return copy.toUpsertData() + } - businessPartnerRepository.saveAll(changedPartners) - val changelogs = changedPartners.map { ChangelogEntryDb(it.externalId, it.associatedOwnerBpnl, ChangelogType.UPDATE, StageType.Output) } - changelogRepository.saveAll(changelogs) + private fun BusinessPartnerDb.toUpsertData(): OutputUpsertData { + return OutputUpsertData( + nameParts = nameParts, + identifiers = identifiers.map { it.toUpsertData() }, + states = states.map { it.toUpsertData() }, + roles = roles.toList(), + isOwnCompanyData = isOwnCompanyData, + legalEntityBpn = bpnL ?: throw createMappingException(BusinessPartnerDb::bpnL, id), + siteBpn = bpnS, + addressBpn = bpnA ?: throw createMappingException(BusinessPartnerDb::bpnA, id), + legalName = legalName ?: throw createMappingException(BusinessPartnerDb::legalName, id), + legalForm = legalForm, + shortName = shortName, + siteName = siteName, + addressName = addressName, + addressType = postalAddress.addressType ?: throw createMappingException(PostalAddressDb::addressType, id), + physicalPostalAddress = postalAddress.physicalPostalAddress?.toUpsertData() ?: throw createMappingException( + PostalAddressDb::physicalPostalAddress, + id + ), + alternativePostalAddress = postalAddress.alternativePostalAddress?.toUpsertData(), + legalEntityConfidence = legalEntityConfidence?.toUpsertData() ?: throw createMappingException(BusinessPartnerDb::legalEntityConfidence, id), + siteConfidence = siteConfidence?.toUpsertData(), + addressConfidence = addressConfidence?.toUpsertData() ?: throw createMappingException(BusinessPartnerDb::addressConfidence, id), + ) + } + + private fun IdentifierDb.toUpsertData(): Identifier { + return Identifier(type, value, issuingBody, businessPartnerType) + } - logger.debug { "Actual values changed of ${changedPartners.size} business partners from logistic addresses" } + private fun StateDb.toUpsertData(): State { + return State(validFrom = validFrom, validTo = validTo, type = type, businessPartnerType = businessPartnerTyp) + } + + private fun PhysicalPostalAddressDb.toUpsertData(): PhysicalPostalAddress { + return PhysicalPostalAddress( + geographicCoordinates = geographicCoordinates?.toUpsertData(), + country = country ?: throw createMappingException(PhysicalPostalAddress::country), + postalCode = postalCode, + city = city ?: throw createMappingException(PhysicalPostalAddress::city), + administrativeAreaLevel1 = administrativeAreaLevel1, + administrativeAreaLevel2 = administrativeAreaLevel2, + administrativeAreaLevel3 = administrativeAreaLevel3, + district = district, + companyPostalCode = companyPostalCode, + industrialZone = industrialZone, + building = building, + floor = floor, + door = door, + street = street?.toUpsertData() + ) + } + + private fun StreetDb.toUpsertData(): Street { + return Street( + name = name, + houseNumber = houseNumber, + houseNumberSupplement = houseNumberSupplement, + milestone = milestone, + direction = direction, + namePrefix = namePrefix, + additionalNamePrefix = additionalNamePrefix, + nameSuffix = nameSuffix, + additionalNameSuffix = additionalNameSuffix + ) + } + + private fun AlternativePostalAddressDb.toUpsertData(): AlternativeAddress { + return AlternativeAddress( + geographicCoordinates = geographicCoordinates?.toUpsertData(), + country = country ?: throw createMappingException(AlternativePostalAddressDb::country), + administrativeAreaLevel1 = administrativeAreaLevel1, + postalCode = postalCode, + city = city ?: throw createMappingException(AlternativePostalAddressDb::city), + deliveryServiceType = deliveryServiceType ?: throw createMappingException(AlternativePostalAddressDb::deliveryServiceType), + deliveryServiceQualifier = deliveryServiceQualifier, + deliveryServiceNumber = deliveryServiceNumber ?: throw createMappingException(AlternativePostalAddressDb::deliveryServiceNumber) + ) + } + + private fun ConfidenceCriteriaDb.toUpsertData(): ConfidenceCriteria { + return ConfidenceCriteria( + sharedByOwner = sharedByOwner, + checkedByExternalDataSource = checkedByExternalDataSource, + numberOfSharingMembers = numberOfBusinessPartners, + lastConfidenceCheckAt = lastConfidenceCheckAt, + nextConfidenceCheckAt = nextConfidenceCheckAt, + confidenceLevel = confidenceLevel + ) + } + + private fun GeographicCoordinateDb.toUpsertData(): GeoCoordinate { + return GeoCoordinate(longitude, latitude, altitude) } private fun update(businessPartner: BusinessPartnerDb, legalEntity: LegalEntityVerboseDto){ @@ -287,20 +373,8 @@ class GoldenRecordUpdateService( deliveryServiceNumber = deliveryServiceNumber ) - private fun emptyBusinessPartner(externalId: String) = - BusinessPartnerDb( - externalId = externalId, - stage = StageType.Output, - legalEntityConfidence = null, - siteConfidence = null, - addressConfidence = null, - postalAddress = PostalAddressDb() - ) - - private fun filterChanged(partners: Collection): Collection{ - return partners.associateWith { partner -> emptyBusinessPartner(partner.externalId).apply { copyUtil.copyValues( partner, this) } } - .filter { (partner, copy) -> compareUtil.hasChanges(partner, copy) } - .keys + private fun createMappingException(property: KProperty<*>, entityId: Long? = null): BpdmNullMappingException { + return BpdmNullMappingException(BusinessPartnerDb::class, OutputUpsertData::class, property, entityId.toString()) } } \ No newline at end of file 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 index 92715e098..b7d81003f 100644 --- 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 @@ -25,18 +25,17 @@ import org.eclipse.tractusx.bpdm.common.dto.AddressType import org.eclipse.tractusx.bpdm.common.dto.BusinessPartnerRole import org.eclipse.tractusx.bpdm.common.dto.BusinessPartnerType import org.eclipse.tractusx.bpdm.common.exception.BpdmNullMappingException -import org.eclipse.tractusx.bpdm.common.model.StageType import org.eclipse.tractusx.bpdm.gate.config.BpnConfigProperties -import org.eclipse.tractusx.bpdm.gate.entity.AlternativePostalAddressDb import org.eclipse.tractusx.bpdm.gate.entity.GeographicCoordinateDb -import org.eclipse.tractusx.bpdm.gate.entity.PhysicalPostalAddressDb -import org.eclipse.tractusx.bpdm.gate.entity.StreetDb -import org.eclipse.tractusx.bpdm.gate.entity.generic.* +import org.eclipse.tractusx.bpdm.gate.entity.generic.BusinessPartnerDb +import org.eclipse.tractusx.bpdm.gate.entity.generic.ConfidenceCriteriaDb +import org.eclipse.tractusx.bpdm.gate.entity.generic.StateDb +import org.eclipse.tractusx.bpdm.gate.model.upsert.output.OutputUpsertData +import org.eclipse.tractusx.bpdm.gate.model.upsert.output.PhysicalPostalAddress +import org.eclipse.tractusx.bpdm.gate.model.upsert.output.State import org.eclipse.tractusx.orchestrator.api.model.* -import org.eclipse.tractusx.orchestrator.api.model.BpnReferenceType import org.springframework.stereotype.Service import java.time.ZoneOffset -import java.util.SortedSet @Service class OrchestratorMappings( @@ -177,8 +176,8 @@ class OrchestratorMappings( } ?: BpnReference.empty private fun getOwnerBpnL(entity: BusinessPartnerDb): String? { - return if(entity.associatedOwnerBpnl != null){ - entity.associatedOwnerBpnl + return if (entity.sharingState.tenantBpnl != null) { + entity.sharingState.tenantBpnl }else if (entity.isOwnCompanyData) { bpnConfigProperties.ownerBpnL } @@ -189,8 +188,7 @@ class OrchestratorMappings( } - //Mapping from orchestrator model to entity - fun toBusinessPartner(dto: BusinessPartner, externalId: String, associatedOwnerBpnl: String?, roles: SortedSet): BusinessPartnerDb{ + fun toOutputUpsertData(dto: BusinessPartner, roles: List, tenantBpnl: String?): OutputUpsertData { val addressType = when(dto.type){ GoldenRecordType.LegalEntity -> AddressType.LegalAddress GoldenRecordType.Site -> if(dto.site!!.siteMainIsLegalAddress) AddressType.LegalAndSiteMainAddress else AddressType.SiteMainAddress @@ -206,37 +204,31 @@ class OrchestratorMappings( } return with(dto) { - BusinessPartnerDb( - externalId = externalId, + OutputUpsertData( nameParts = uncategorized.nameParts.toMutableList(), shortName = legalEntity.legalShortName, identifiers = uncategorized.identifiers.mapNotNull { toIdentifier(it, BusinessPartnerType.GENERIC) } .plus(legalEntity.identifiers.mapNotNull { toIdentifier(it, BusinessPartnerType.LEGAL_ENTITY) }) - .plus(postalAddress.identifiers.mapNotNull { toIdentifier(it, BusinessPartnerType.ADDRESS) }) - .toSortedSet(), - legalName = legalEntity.legalName, + .plus(postalAddress.identifiers.mapNotNull { toIdentifier(it, BusinessPartnerType.ADDRESS) }), + legalName = legalEntity.legalName ?: throw BpdmNullMappingException(BusinessPartner::class, OutputUpsertData::class, LegalEntity::legalName), siteName = site?.siteName, addressName = postalAddress.addressName, legalForm = legalEntity.legalForm, - states = uncategorized.states.asSequence().mapNotNull { toState(it, BusinessPartnerType.GENERIC) } + states = uncategorized.states.mapNotNull { toState(it, BusinessPartnerType.GENERIC) } .plus(legalEntity.states.mapNotNull{ toState(it, BusinessPartnerType.LEGAL_ENTITY) }) .plus(site?.states?.mapNotNull{ toState(it, BusinessPartnerType.SITE) } ?: emptyList()) - .plus(postalAddress.states.mapNotNull{ toState(it, BusinessPartnerType.ADDRESS)} ) - .toSortedSet(), - roles = roles, - postalAddress = PostalAddressDb( - addressType = addressType, - physicalPostalAddress = toPhysicalPostalAddress(postalAddress.physicalAddress), - alternativePostalAddress = postalAddress.alternativeAddress?.let(::toAlternativePostalAddress) - ), - bpnL = legalEntity.bpnReference.referenceValue!!, - bpnS = site?.bpnReference?.referenceValue, - bpnA = postalAddress.bpnReference.referenceValue!!, - stage = StageType.Output, + .plus(postalAddress.states.mapNotNull { toState(it, BusinessPartnerType.ADDRESS) }), + roles = roles.toSortedSet(), + addressType = addressType, + physicalPostalAddress = toPhysicalPostalAddress(postalAddress.physicalAddress), + alternativePostalAddress = postalAddress.alternativeAddress?.let(::toAlternativePostalAddress), + legalEntityBpn = legalEntity.bpnReference.referenceValue!!, + siteBpn = site?.bpnReference?.referenceValue, + addressBpn = postalAddress.bpnReference.referenceValue!!, legalEntityConfidence = toConfidenceCriteria(legalEntity.confidenceCriteria), siteConfidence = site?.let { toConfidenceCriteria(it.confidenceCriteria) }, addressConfidence = toConfidenceCriteria(postalAddress.confidenceCriteria), - associatedOwnerBpnl = associatedOwnerBpnl + isOwnCompanyData = if (tenantBpnl != null && owningCompany != null) tenantBpnl == owningCompany else false ) } } @@ -245,28 +237,35 @@ class OrchestratorMappings( private fun toIdentifier(dto: Identifier, businessPartnerType: BusinessPartnerType) = dto.type?.let { type -> dto.value?.let { value -> - IdentifierDb(type = type, value = value, issuingBody = dto.issuingBody, businessPartnerType = businessPartnerType) + org.eclipse.tractusx.bpdm.gate.model.upsert.output.Identifier( + type = type, + value = value, + issuingBody = dto.issuingBody, + businessPartnerType = businessPartnerType + ) } } private fun toState(dto: BusinessState, businessPartnerType: BusinessPartnerType) = - dto.type?.let { StateDb( + dto.type?.let { + State( type = it, validFrom = dto.validFrom?.atZone(ZoneOffset.UTC)?.toLocalDateTime(), validTo = dto.validTo?.atZone(ZoneOffset.UTC)?.toLocalDateTime(), - businessPartnerTyp = businessPartnerType) + businessPartnerType = businessPartnerType + ) } private fun toPhysicalPostalAddress(dto: PhysicalAddress) = - PhysicalPostalAddressDb( + PhysicalPostalAddress( geographicCoordinates = toGeographicCoordinate(dto.geographicCoordinates), country = CountryCode.getByAlpha2Code(dto.country), administrativeAreaLevel1 = dto.administrativeAreaLevel1, administrativeAreaLevel2 = dto.administrativeAreaLevel2, administrativeAreaLevel3 = dto.administrativeAreaLevel3, postalCode = dto.postalCode, - city = dto.city, + city = dto.city ?: throw BpdmNullMappingException(BusinessPartner::class, OutputUpsertData::class, PhysicalAddress::city), district = dto.district, street = toStreet(dto.street), companyPostalCode = dto.companyPostalCode, @@ -277,19 +276,27 @@ class OrchestratorMappings( ) private fun toAlternativePostalAddress(dto: AlternativeAddress) = - AlternativePostalAddressDb( + org.eclipse.tractusx.bpdm.gate.model.upsert.output.AlternativeAddress( geographicCoordinates = toGeographicCoordinate(dto.geographicCoordinates), country = CountryCode.getByAlpha2Code(dto.country), administrativeAreaLevel1 = dto.administrativeAreaLevel1, postalCode = dto.postalCode, - city = dto.city, - deliveryServiceType = dto.deliveryServiceType, + city = dto.city ?: throw BpdmNullMappingException(BusinessPartner::class, OutputUpsertData::class, AlternativeAddress::city), + deliveryServiceType = dto.deliveryServiceType ?: throw BpdmNullMappingException( + BusinessPartner::class, + OutputUpsertData::class, + AlternativeAddress::deliveryServiceType + ), deliveryServiceQualifier = dto.deliveryServiceQualifier, - deliveryServiceNumber = dto.deliveryServiceNumber + deliveryServiceNumber = dto.deliveryServiceNumber ?: throw BpdmNullMappingException( + BusinessPartner::class, + OutputUpsertData::class, + AlternativeAddress::deliveryServiceNumber + ) ) private fun toStreet(dto: Street) = - StreetDb( + org.eclipse.tractusx.bpdm.gate.model.upsert.output.Street( name = dto.name, houseNumber = dto.houseNumber, houseNumberSupplement = dto.houseNumberSupplement, @@ -304,15 +311,15 @@ class OrchestratorMappings( private fun toGeographicCoordinate(dto: GeoCoordinate) = dto.latitude?.let { lat -> dto.longitude?.let { lon -> - GeographicCoordinateDb(latitude = lat, longitude = lon, altitude = dto.altitude) + org.eclipse.tractusx.bpdm.gate.model.upsert.output.GeoCoordinate(latitude = lat, longitude = lon, altitude = dto.altitude) } } private fun toConfidenceCriteria(dto: ConfidenceCriteria) = - ConfidenceCriteriaDb( + org.eclipse.tractusx.bpdm.gate.model.upsert.output.ConfidenceCriteria( sharedByOwner = dto.sharedByOwner!!, checkedByExternalDataSource = dto.checkedByExternalDataSource!!, - numberOfBusinessPartners = dto.numberOfSharingMembers!!, + numberOfSharingMembers = dto.numberOfSharingMembers!!, lastConfidenceCheckAt = dto.lastConfidenceCheckAt!!.atZone(ZoneOffset.UTC).toLocalDateTime(), nextConfidenceCheckAt = dto.nextConfidenceCheckAt!!.atZone(ZoneOffset.UTC).toLocalDateTime(), confidenceLevel = dto.confidenceLevel!! diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/OutputUpsertMappings.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/OutputUpsertMappings.kt new file mode 100644 index 000000000..6bc676151 --- /dev/null +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/OutputUpsertMappings.kt @@ -0,0 +1,112 @@ +/******************************************************************************* + * 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.gate.service + +import org.eclipse.tractusx.bpdm.common.model.StageType +import org.eclipse.tractusx.bpdm.gate.entity.* +import org.eclipse.tractusx.bpdm.gate.entity.generic.* +import org.eclipse.tractusx.bpdm.gate.model.upsert.output.* +import org.springframework.stereotype.Service + +@Service +class OutputUpsertMappings { + + fun toEntity(upsertData: OutputUpsertData, sharingState: SharingStateDb): BusinessPartnerDb { + return with(upsertData) { + BusinessPartnerDb( + sharingState = sharingState, + stage = StageType.Output, + nameParts = nameParts.toMutableList(), + roles = roles.toSortedSet(), + identifiers = identifiers.map { it.toEntity() }.toSortedSet(), + states = states.map { it.toEntity() }.toSortedSet(), + shortName = shortName, + legalName = legalName, + siteName = siteName, + addressName = addressName, + legalForm = legalForm, + isOwnCompanyData = isOwnCompanyData, + bpnL = legalEntityBpn, + bpnS = siteBpn, + bpnA = addressBpn, + postalAddress = PostalAddressDb(addressType, physicalPostalAddress.toEntity(), alternativePostalAddress?.toEntity()), + legalEntityConfidence = legalEntityConfidence.toEntity(), + siteConfidence = siteConfidence?.toEntity(), + addressConfidence = addressConfidence.toEntity(), + ) + } + } + + private fun Identifier.toEntity() = + IdentifierDb(type = type, value = value, issuingBody = issuingBody, businessPartnerType = businessPartnerType) + + private fun State.toEntity() = + StateDb(type = type, validFrom = validFrom, validTo = validTo, businessPartnerTyp = businessPartnerType) + + private fun ConfidenceCriteria.toEntity() = + ConfidenceCriteriaDb(sharedByOwner, checkedByExternalDataSource, numberOfSharingMembers, lastConfidenceCheckAt, nextConfidenceCheckAt, confidenceLevel) + + + private fun PhysicalPostalAddress.toEntity() = + PhysicalPostalAddressDb( + geographicCoordinates = geographicCoordinates?.toEntity(), + country = country, + administrativeAreaLevel1 = administrativeAreaLevel1, + administrativeAreaLevel2 = administrativeAreaLevel2, + administrativeAreaLevel3 = administrativeAreaLevel3, + postalCode = postalCode, + city = city, + district = district, + street = street?.toEntity(), + companyPostalCode = companyPostalCode, + industrialZone = industrialZone, + building = building, + floor = floor, + door = door + ) + + private fun AlternativeAddress.toEntity() = + AlternativePostalAddressDb( + geographicCoordinates = geographicCoordinates?.toEntity(), + country = country, + administrativeAreaLevel1 = administrativeAreaLevel1, + postalCode = postalCode, + city = city, + deliveryServiceType = deliveryServiceType, + deliveryServiceQualifier = deliveryServiceQualifier, + deliveryServiceNumber = deliveryServiceNumber + ) + + private fun Street.toEntity() = + StreetDb( + name = name, + houseNumber = houseNumber, + houseNumberSupplement = houseNumberSupplement, + milestone = milestone, + direction = direction, + namePrefix = namePrefix, + additionalNamePrefix = additionalNamePrefix, + nameSuffix = nameSuffix, + additionalNameSuffix = additionalNameSuffix + ) + + private fun GeoCoordinate.toEntity() = GeographicCoordinateDb(latitude = latitude, longitude = longitude, altitude = altitude) + +} \ 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 6abc41619..1b34b7cf4 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 @@ -31,8 +31,8 @@ import org.eclipse.tractusx.bpdm.gate.entity.SharingStateDb import org.eclipse.tractusx.bpdm.gate.exception.BpdmInvalidStateException import org.eclipse.tractusx.bpdm.gate.exception.BpdmMissingPartnerException import org.eclipse.tractusx.bpdm.gate.repository.SharingStateRepository -import org.eclipse.tractusx.bpdm.gate.repository.SharingStateRepository.Specs.byAssociatedOwnerBpnl import org.eclipse.tractusx.bpdm.gate.repository.SharingStateRepository.Specs.byExternalIdsIn +import org.eclipse.tractusx.bpdm.gate.repository.SharingStateRepository.Specs.byTenantBpnl import org.springframework.data.domain.PageRequest import org.springframework.data.jpa.domain.Specification import org.springframework.stereotype.Service @@ -56,7 +56,7 @@ class SharingStateService( logger.info { "findSharingStates() called with $paginationRequest // $externalIds" } val pageRequest = PageRequest.of(paginationRequest.page, paginationRequest.size) - val spec = Specification.allOf(byExternalIdsIn(externalIds), byAssociatedOwnerBpnl(ownerBpnl)) + val spec = Specification.allOf(byExternalIdsIn(externalIds), byTenantBpnl(ownerBpnl)) val sharingStatePage = stateRepository.findAll(spec, pageRequest) return sharingStatePage.toPageDto { @@ -71,37 +71,12 @@ class SharingStateService( } } - fun setInitial(sharingStateIds: List, ownerBpnl: String?): List { - val sharingStates = getOrCreate(sharingStateIds, ownerBpnl) - return sharingStates.map { setInitial(it) } - } - - - - fun setSuccess(successRequests: List, ownerBpnl: String?): List { - val sharingStates = getOrCreate(successRequests.map { it.externalId }, ownerBpnl) - return sharingStates - .zip(successRequests) - .map { (sharingState, request) -> setSuccess(sharingState, request.startTimeOverwrite) } - } - - fun setPending(pendingRequests: List, ownerBpnl: String?): List { - val sharingStates = getOrCreate(pendingRequests.map { it.externalId }, ownerBpnl) - return sharingStates - .zip(pendingRequests) - .map { (sharingState, request) -> setPending(sharingState, request.taskId, request.startTimeOverwrite) } - } - - fun setError(errorRequests: List, ownerBpnl: String?): List { - val sharingStates = getOrCreate(errorRequests.map { it.externalId }, ownerBpnl) - - return sharingStates - .zip(errorRequests) - .map { (sharingState, request) -> setError(sharingState, request.errorCode, request.errorMessage, request.startTimeOverwrite) } + fun getOrCreateStates(sharingStateIds: List, ownerBpnl: String?): List { + return getOrCreate(sharingStateIds, ownerBpnl) } fun setReady(externalIds: List, ownerBpnl: String?): List { - val existingSharingStates = stateRepository.findByExternalIdInAndAssociatedOwnerBpnl(externalIds, ownerBpnl) + val existingSharingStates = stateRepository.findByExternalIdInAndTenantBpnl(externalIds, ownerBpnl) val existingIds = existingSharingStates.map { it.externalId }.toSet() val missingIds = externalIds.minus(existingIds) @@ -120,7 +95,7 @@ class SharingStateService( return correctStates.map { setReady(it) } } - private fun setInitial(sharingState: SharingStateDb): SharingStateDb { + fun setInitial(sharingState: SharingStateDb): SharingStateDb { sharingState.sharingStateType = //If new business partner data should be immediately ready to be shared our initial state is ready instead if (goldenRecordTaskConfigProperties.creation.fromSharingMember.startsAsReady) @@ -135,7 +110,7 @@ class SharingStateService( return stateRepository.save(sharingState) } - private fun setSuccess(sharingState: SharingStateDb, startTimeOverwrite: LocalDateTime? = null): SharingStateDb { + fun setSuccess(sharingState: SharingStateDb, startTimeOverwrite: LocalDateTime? = null): SharingStateDb { sharingState.sharingStateType = SharingStateType.Success sharingState.sharingErrorCode = null @@ -145,7 +120,7 @@ class SharingStateService( return stateRepository.save(sharingState) } - private fun setPending(sharingState: SharingStateDb, taskId: String, startTimeOverwrite: LocalDateTime? = null): SharingStateDb { + fun setPending(sharingState: SharingStateDb, taskId: String, startTimeOverwrite: LocalDateTime? = null): SharingStateDb { sharingState.sharingStateType = SharingStateType.Pending sharingState.sharingErrorCode = null sharingState.sharingErrorMessage = null @@ -155,7 +130,7 @@ class SharingStateService( return stateRepository.save(sharingState) } - private fun setError( + fun setError( sharingState: SharingStateDb, sharingErrorCode: BusinessPartnerSharingError, sharingErrorMessage: String? = null, @@ -183,18 +158,20 @@ class SharingStateService( private fun getOrCreate(externalIds: List, ownerBpnl: String?): List { - val sharingStates = stateRepository.findByExternalIdInAndAssociatedOwnerBpnl(externalIds, ownerBpnl) + val sharingStates = stateRepository.findByExternalIdInAndTenantBpnl(externalIds, ownerBpnl) val sharingStatesByExternalId = sharingStates.associateBy { it.externalId } return externalIds.map { externalId -> sharingStatesByExternalId[externalId] - ?: SharingStateDb( - externalId, - sharingStateType = SharingStateType.Ready, - sharingErrorCode = null, - sharingErrorMessage = null, - sharingProcessStarted = null, - associatedOwnerBpnl = ownerBpnl + ?: setInitial( + SharingStateDb( + externalId, + sharingStateType = SharingStateType.Ready, + sharingErrorCode = null, + sharingErrorMessage = null, + sharingProcessStarted = null, + tenantBpnl = ownerBpnl + ) ) } } diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/TaskCreationService.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/TaskCreationService.kt new file mode 100644 index 000000000..0317fdea0 --- /dev/null +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/TaskCreationService.kt @@ -0,0 +1,74 @@ +/******************************************************************************* + * 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.gate.service + +import mu.KotlinLogging +import org.eclipse.tractusx.bpdm.common.model.StageType +import org.eclipse.tractusx.bpdm.gate.api.model.SharingStateType +import org.eclipse.tractusx.bpdm.gate.config.GoldenRecordTaskConfigProperties +import org.eclipse.tractusx.bpdm.gate.repository.SharingStateRepository +import org.eclipse.tractusx.bpdm.gate.repository.generic.BusinessPartnerRepository +import org.eclipse.tractusx.orchestrator.api.client.OrchestrationApiClient +import org.eclipse.tractusx.orchestrator.api.model.BusinessPartner +import org.eclipse.tractusx.orchestrator.api.model.TaskClientStateDto +import org.eclipse.tractusx.orchestrator.api.model.TaskCreateRequest +import org.eclipse.tractusx.orchestrator.api.model.TaskMode +import org.springframework.data.domain.Pageable +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional + +@Service +class TaskCreationService( + private val sharingStateRepository: SharingStateRepository, + private val sharingStateService: SharingStateService, + private val businessPartnerRepository: BusinessPartnerRepository, + private val orchestratorMappings: OrchestratorMappings, + private val orchestrationApiClient: OrchestrationApiClient, + private val properties: GoldenRecordTaskConfigProperties +) { + private val logger = KotlinLogging.logger { } + + @Transactional + fun createTasksForReadyBusinessPartners() { + logger.info { "Started scheduled task to create golden record tasks from ready business partners" } + + val pageRequest = Pageable.ofSize(properties.creation.fromSharingMember.batchSize) + val foundStates = sharingStateRepository.findBySharingStateType(SharingStateType.Ready, pageRequest).content + + logger.debug { "Found ${foundStates.size} business partners in ready state" } + + val foundPartners = businessPartnerRepository.findBySharingStateInAndStage(foundStates, StageType.Input) + val orchestratorBusinessPartnersDto = foundPartners.map { orchestratorMappings.toOrchestratorDto(it) } + val createdTasks = createGoldenRecordTasks(TaskMode.UpdateFromSharingMember, orchestratorBusinessPartnersDto) + + foundStates.zip(createdTasks).forEach { (state, task) -> + sharingStateService.setPending(state, task.taskId) + } + + logger.info { "Created ${createdTasks.size} new golden record tasks from ready business partners" } + } + + private fun createGoldenRecordTasks(mode: TaskMode, orchestratorBusinessPartnersDto: List): List { + if (orchestratorBusinessPartnersDto.isEmpty()) + return emptyList() + + return orchestrationApiClient.goldenRecordTasks.createTasks(TaskCreateRequest(mode, orchestratorBusinessPartnersDto)).createdTasks + } +} \ No newline at end of file diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/TaskResolutionService.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/TaskResolutionService.kt new file mode 100644 index 000000000..15d1cd11d --- /dev/null +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/service/TaskResolutionService.kt @@ -0,0 +1,141 @@ +/******************************************************************************* + * 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.gate.service + +import mu.KotlinLogging +import org.eclipse.tractusx.bpdm.common.model.StageType +import org.eclipse.tractusx.bpdm.gate.api.exception.BusinessPartnerSharingError +import org.eclipse.tractusx.bpdm.gate.api.model.SharingStateType +import org.eclipse.tractusx.bpdm.gate.config.GoldenRecordTaskConfigProperties +import org.eclipse.tractusx.bpdm.gate.entity.SharingStateDb +import org.eclipse.tractusx.bpdm.gate.entity.generic.BusinessPartnerDb +import org.eclipse.tractusx.bpdm.gate.model.upsert.output.OutputUpsertData +import org.eclipse.tractusx.bpdm.gate.repository.SharingStateRepository +import org.eclipse.tractusx.bpdm.gate.repository.generic.BusinessPartnerRepository +import org.eclipse.tractusx.orchestrator.api.client.OrchestrationApiClient +import org.eclipse.tractusx.orchestrator.api.model.ResultState +import org.eclipse.tractusx.orchestrator.api.model.TaskClientStateDto +import org.eclipse.tractusx.orchestrator.api.model.TaskStateRequest +import org.springframework.data.domain.Pageable +import org.springframework.stereotype.Service + +@Service +class TaskResolutionService( + private val sharingStateRepository: SharingStateRepository, + private val sharingStateService: SharingStateService, + private val businessPartnerRepository: BusinessPartnerRepository, + private val taskProperties: GoldenRecordTaskConfigProperties, + private val orchestrationApiClient: OrchestrationApiClient, + private val businessPartnerService: BusinessPartnerService, + private val orchestratorMappings: OrchestratorMappings +) { + + private val logger = KotlinLogging.logger { } + + fun resolveTasks() { + val pageRequest = Pageable.ofSize(taskProperties.check.batchSize) + val sharingStates = sharingStateRepository.findBySharingStateTypeAndTaskIdNotNull(SharingStateType.Pending, pageRequest).content + + val tasks = orchestrationApiClient.goldenRecordTasks.searchTaskStates(TaskStateRequest(sharingStates.map { it.taskId!! })).tasks + val tasksById = tasks.associateBy { it.taskId } + + val inputs = businessPartnerRepository.findBySharingStateInAndStage(sharingStates, StageType.Input) + val inputsByExternalId = inputs.associateBy { it.sharingState.externalId } + + val mappingResults = sharingStates.map { sharingState -> + tryCreateUpsertRequest(sharingState, tasksById[sharingState.taskId], inputsByExternalId[sharingState.externalId]) + } + + val successes = mappingResults.filter { it.businessPartnerResult != null } + val errors = mappingResults.filter { it.errorType != null } + val unresolved = mappingResults.filter { it.businessPartnerResult == null && it.errorType == null } + + resolveAsUpserts(successes) + resolveAsErrors(errors) + + logger.info { "Resolved ${successes.size} tasks as successful, ${errors.size} as errors and ${unresolved.size} still unresolved" } + } + + private fun tryCreateUpsertRequest(sharingState: SharingStateDb, task: TaskClientStateDto?, input: BusinessPartnerDb?): RequestCreationResult { + if (task == null) { + return RequestCreationResult.error(sharingState, BusinessPartnerSharingError.MissingTaskID, "Missing Task in Orchestrator") + } + + return when (task.processingState.resultState) { + ResultState.Pending -> RequestCreationResult(sharingState, null, null, null) + ResultState.Success -> createUpsertRequestForSuccessfulTask(sharingState, task, input) + ResultState.Error -> RequestCreationResult.error( + sharingState, + BusinessPartnerSharingError.SharingProcessError, + if (task.processingState.errors.isNotEmpty()) task.processingState.errors.joinToString(" // ") { it.description }.take(255) else null + ) + } + } + + private fun createUpsertRequestForSuccessfulTask(sharingState: SharingStateDb, task: TaskClientStateDto, input: BusinessPartnerDb?): RequestCreationResult { + if (input == null) { + return RequestCreationResult.error( + sharingState, + BusinessPartnerSharingError.SharingProcessError, + "No input data found for the references business partner" + ) + } + + val upsertRequest = try { + orchestratorMappings.toOutputUpsertData(task.businessPartnerResult, input.roles.toList(), sharingState.tenantBpnl) + } catch (ex: Throwable) { + return RequestCreationResult.error(sharingState, BusinessPartnerSharingError.SharingProcessError, ex.message?.take(255)) + } + + return RequestCreationResult.success(sharingState, upsertRequest) + } + + private fun resolveAsUpserts(requests: List) { + requests.forEach { sharingStateService.setSuccess(it.sharingState) } + businessPartnerService.upsertBusinessPartnersOutput(requests.map { + BusinessPartnerService.OutputUpsertRequest( + it.sharingState, + it.businessPartnerResult!! + ) + }) + } + + private fun resolveAsErrors(errors: List) { + errors.forEach { + sharingStateService.setError(it.sharingState, it.errorType!!, it.errorMessage) + } + } + + private data class RequestCreationResult( + val sharingState: SharingStateDb, + val businessPartnerResult: OutputUpsertData?, + val errorType: BusinessPartnerSharingError?, + val errorMessage: String? + ) { + companion object { + fun error(sharingState: SharingStateDb, errorType: BusinessPartnerSharingError, errorMessage: String?) = + RequestCreationResult(sharingState, null, errorType, errorMessage) + + fun success(sharingState: SharingStateDb, request: OutputUpsertData) = + RequestCreationResult(sharingState, request, null, null) + } + } + +} \ No newline at end of file diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/util/BusinessPartnerComparisonUtil.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/util/BusinessPartnerComparisonUtil.kt index 699ef1fef..f6d17db62 100644 --- a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/util/BusinessPartnerComparisonUtil.kt +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/util/BusinessPartnerComparisonUtil.kt @@ -40,8 +40,6 @@ class BusinessPartnerComparisonUtil { entity.bpnS != persistedBP.bpnS || entity.bpnA != persistedBP.bpnA || entity.stage != persistedBP.stage || - entity.parentId != persistedBP.parentId || - entity.parentType != persistedBP.parentType || entity.identifiers != persistedBP.identifiers || entity.states != persistedBP.states || entity.classifications != persistedBP.classifications || diff --git a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/util/BusinessPartnerCopyUtil.kt b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/util/BusinessPartnerCopyUtil.kt index 542eb1d2b..0b55ba853 100644 --- a/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/util/BusinessPartnerCopyUtil.kt +++ b/bpdm-gate/src/main/kotlin/org/eclipse/tractusx/bpdm/gate/util/BusinessPartnerCopyUtil.kt @@ -39,8 +39,6 @@ class BusinessPartnerCopyUtil { bpnL = fromPartner.bpnL bpnS = fromPartner.bpnS bpnA = fromPartner.bpnA - parentId = fromPartner.parentId - parentType = fromPartner.parentType legalEntityConfidence = fromPartner.legalEntityConfidence siteConfidence = fromPartner.siteConfidence addressConfidence = fromPartner.addressConfidence diff --git a/bpdm-gate/src/main/resources/db/migration/V6_1_0_0__add_partners_sharing_state.sql b/bpdm-gate/src/main/resources/db/migration/V6_1_0_0__add_partners_sharing_state.sql new file mode 100644 index 000000000..8bc3afd97 --- /dev/null +++ b/bpdm-gate/src/main/resources/db/migration/V6_1_0_0__add_partners_sharing_state.sql @@ -0,0 +1,5 @@ +ALTER TABLE business_partners +ADD COLUMN sharing_state_id BIGINT DEFAULT NULL; + +ALTER TABLE business_partners +ADD CONSTRAINT fk_business_partners_sharing_state FOREIGN KEY (sharing_state_id) REFERENCES sharing_states (id) diff --git a/bpdm-gate/src/main/resources/db/migration/V6_1_0_1__attach_partners_to_sharing_states.sql b/bpdm-gate/src/main/resources/db/migration/V6_1_0_1__attach_partners_to_sharing_states.sql new file mode 100644 index 000000000..299eae6cf --- /dev/null +++ b/bpdm-gate/src/main/resources/db/migration/V6_1_0_1__attach_partners_to_sharing_states.sql @@ -0,0 +1,4 @@ +UPDATE business_partners bp +SET sharing_state_id = sh.id +FROM sharing_states sh +WHERE bp.external_id IS NOT DISTINCT FROM sh.external_id AND bp.associated_owner_bpnl IS NOT DISTINCT FROM sh.associated_owner_bpnl; \ No newline at end of file diff --git a/bpdm-gate/src/main/resources/db/migration/V6_1_0_2__drop_business_partners_owner.sql b/bpdm-gate/src/main/resources/db/migration/V6_1_0_2__drop_business_partners_owner.sql new file mode 100644 index 000000000..7c365020c --- /dev/null +++ b/bpdm-gate/src/main/resources/db/migration/V6_1_0_2__drop_business_partners_owner.sql @@ -0,0 +1,14 @@ +ALTER TABLE business_partners +DROP COLUMN associated_owner_bpnl; + +ALTER TABLE business_partners +DROP COLUMN external_id; + +ALTER TABLE sharing_states +RENAME COLUMN associated_owner_bpnl TO tenant_bpnl; + +ALTER TABLE changelog_entries +RENAME COLUMN associated_owner_bpnl TO tenant_bpnl; + +ALTER TABLE business_partners +ALTER COLUMN sharing_state_id SET NOT NULL; diff --git a/bpdm-gate/src/test/kotlin/org/eclipse/tractusx/bpdm/gate/controller/BusinessPartnerControllerAndSharingControllerIT.kt b/bpdm-gate/src/test/kotlin/org/eclipse/tractusx/bpdm/gate/controller/BusinessPartnerControllerAndSharingControllerIT.kt index 00b4db1dc..0d3f053f7 100644 --- a/bpdm-gate/src/test/kotlin/org/eclipse/tractusx/bpdm/gate/controller/BusinessPartnerControllerAndSharingControllerIT.kt +++ b/bpdm-gate/src/test/kotlin/org/eclipse/tractusx/bpdm/gate/controller/BusinessPartnerControllerAndSharingControllerIT.kt @@ -22,14 +22,14 @@ package org.eclipse.tractusx.bpdm.gate.controller import com.github.tomakehurst.wiremock.core.WireMockConfiguration import com.github.tomakehurst.wiremock.junit5.WireMockExtension -import org.eclipse.tractusx.bpdm.common.dto.BusinessPartnerType import org.eclipse.tractusx.bpdm.gate.api.client.GateClient import org.eclipse.tractusx.bpdm.gate.api.exception.BusinessPartnerSharingError 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.request.PostSharingStateReadyRequest import org.eclipse.tractusx.bpdm.gate.api.model.response.SharingStateDto -import org.eclipse.tractusx.bpdm.gate.service.GoldenRecordTaskService +import org.eclipse.tractusx.bpdm.gate.service.TaskCreationService +import org.eclipse.tractusx.bpdm.gate.service.TaskResolutionService import org.eclipse.tractusx.bpdm.gate.util.MockAndAssertUtils import org.eclipse.tractusx.bpdm.test.containers.PostgreSQLContextInitializer import org.eclipse.tractusx.bpdm.test.testdata.gate.BusinessPartnerNonVerboseValues @@ -57,7 +57,8 @@ class BusinessPartnerControllerAndSharingControllerIT @Autowired constructor( val testHelpers: DbTestHelpers, val assertHelpers: AssertHelpers, val gateClient: GateClient, - val goldenRecordTaskService: GoldenRecordTaskService, + val taskCreationService: TaskCreationService, + val taskResolutionService: TaskResolutionService, val mockAndAssertUtils: MockAndAssertUtils ) { @@ -182,7 +183,7 @@ class BusinessPartnerControllerAndSharingControllerIT @Autowired constructor( .isEqualTo(createdSharingState) // Call Finish Cleaning Method - goldenRecordTaskService.resolvePendingTasks() + taskResolutionService.resolveTasks() val cleanedSharingState = listOf( SharingStateDto( @@ -247,7 +248,7 @@ class BusinessPartnerControllerAndSharingControllerIT @Autowired constructor( .isEqualTo(createdSharingState) // Call Finish Cleaning Method - goldenRecordTaskService.resolvePendingTasks() + taskResolutionService.resolveTasks() val cleanedSharingState = listOf( SharingStateDto( @@ -271,7 +272,7 @@ class BusinessPartnerControllerAndSharingControllerIT @Autowired constructor( fun upsertBusinessPartnersAndShare(partners: List) { gateClient.businessParters.upsertBusinessPartnersInput(partners) gateClient.sharingState.postSharingStateReady(PostSharingStateReadyRequest(partners.map { it.externalId })) - goldenRecordTaskService.createTasksForReadyBusinessPartners() + taskCreationService.createTasksForReadyBusinessPartners() } 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 638f6a613..689e77e7a 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 @@ -21,14 +21,14 @@ package org.eclipse.tractusx.bpdm.gate.controller import com.github.tomakehurst.wiremock.core.WireMockConfiguration import com.github.tomakehurst.wiremock.junit5.WireMockExtension -import org.eclipse.tractusx.bpdm.common.dto.BusinessPartnerType import org.eclipse.tractusx.bpdm.common.dto.PaginationRequest import org.eclipse.tractusx.bpdm.gate.api.client.GateClient import org.eclipse.tractusx.bpdm.gate.api.exception.BusinessPartnerSharingError 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.SharingStateDto -import org.eclipse.tractusx.bpdm.gate.service.GoldenRecordTaskService +import org.eclipse.tractusx.bpdm.gate.service.TaskCreationService +import org.eclipse.tractusx.bpdm.gate.service.TaskResolutionService import org.eclipse.tractusx.bpdm.gate.util.MockAndAssertUtils import org.eclipse.tractusx.bpdm.test.containers.PostgreSQLContextInitializer import org.eclipse.tractusx.bpdm.test.testdata.gate.BusinessPartnerNonVerboseValues @@ -58,7 +58,8 @@ class BusinessPartnerControllerIT @Autowired constructor( val testHelpers: DbTestHelpers, val assertHelpers: AssertHelpers, val gateClient: GateClient, - val goldenRecordTaskService: GoldenRecordTaskService, + val taskCreationService: TaskCreationService, + val taskResolutionService: TaskResolutionService, val mockAndAssertUtils: MockAndAssertUtils ) { @@ -319,7 +320,7 @@ class BusinessPartnerControllerIT @Autowired constructor( .isEqualTo(createdSharingState) // Call Finish Cleaning Method - goldenRecordTaskService.resolvePendingTasks() + taskResolutionService.resolveTasks() val cleanedSharingState = listOf( SharingStateDto( @@ -384,7 +385,7 @@ class BusinessPartnerControllerIT @Autowired constructor( .isEqualTo(createdSharingState) // Call Finish Cleaning Method - goldenRecordTaskService.resolvePendingTasks() + taskResolutionService.resolveTasks() val cleanedSharingState = listOf( SharingStateDto( @@ -407,7 +408,7 @@ class BusinessPartnerControllerIT @Autowired constructor( private fun upsertBusinessPartnersAndShare(partners: List) { gateClient.businessParters.upsertBusinessPartnersInput(partners) - goldenRecordTaskService.createTasksForReadyBusinessPartners() + taskCreationService.createTasksForReadyBusinessPartners() } private fun BusinessPartnerInputRequest.fastCopy(externalId: String, shortName: String) = copy(externalId = externalId, legalEntity = legalEntity.copy(shortName = shortName)) diff --git a/bpdm-gate/src/test/kotlin/org/eclipse/tractusx/bpdm/gate/controller/ChangeLogControllerIT.kt b/bpdm-gate/src/test/kotlin/org/eclipse/tractusx/bpdm/gate/controller/ChangeLogControllerIT.kt index 08aefb722..48d2b1b35 100644 --- a/bpdm-gate/src/test/kotlin/org/eclipse/tractusx/bpdm/gate/controller/ChangeLogControllerIT.kt +++ b/bpdm-gate/src/test/kotlin/org/eclipse/tractusx/bpdm/gate/controller/ChangeLogControllerIT.kt @@ -38,8 +38,6 @@ package org.eclipse.tractusx.bpdm.gate.controller -import com.github.tomakehurst.wiremock.core.WireMockConfiguration -import com.github.tomakehurst.wiremock.junit5.WireMockExtension import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.RecursiveComparisonAssert import org.eclipse.tractusx.bpdm.common.dto.PaginationRequest @@ -50,13 +48,12 @@ import org.eclipse.tractusx.bpdm.gate.api.model.request.ChangelogSearchRequest import org.eclipse.tractusx.bpdm.gate.api.model.response.ChangelogGateDto import org.eclipse.tractusx.bpdm.gate.api.model.response.ErrorInfo import org.eclipse.tractusx.bpdm.gate.entity.ChangelogEntryDb -import org.eclipse.tractusx.bpdm.gate.util.PostgreSQLContextInitializer +import org.eclipse.tractusx.bpdm.test.containers.PostgreSQLContextInitializer import org.eclipse.tractusx.bpdm.test.testdata.gate.BusinessPartnerNonVerboseValues import org.eclipse.tractusx.bpdm.test.testdata.gate.BusinessPartnerVerboseValues import org.eclipse.tractusx.bpdm.test.util.DbTestHelpers 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.test.context.ActiveProfiles @@ -70,21 +67,12 @@ internal class ChangeLogControllerIT @Autowired constructor( val gateClient: GateClient, private val testHelpers: DbTestHelpers, ) { - companion object { - @RegisterExtension - private val wireMockServer: WireMockExtension = WireMockExtension.newInstance() - .options(WireMockConfiguration.wireMockConfig().dynamicPort()) - .build() - - } - val instant = Instant.now() @BeforeEach fun beforeEach() { testHelpers.truncateDbTables() - wireMockServer.resetAll() createChangeLogs() } 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 97b1af165..64528782d 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 @@ -25,17 +25,17 @@ 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.SharingStateDto -import org.eclipse.tractusx.bpdm.gate.service.GoldenRecordTaskService +import org.eclipse.tractusx.bpdm.gate.service.TaskCreationService import org.eclipse.tractusx.bpdm.gate.util.MockAndAssertUtils import org.eclipse.tractusx.bpdm.test.containers.PostgreSQLContextInitializer import org.eclipse.tractusx.bpdm.test.testdata.gate.BusinessPartnerNonVerboseValues import org.eclipse.tractusx.bpdm.test.testdata.gate.BusinessPartnerVerboseValues import org.eclipse.tractusx.bpdm.test.util.AssertHelpers import org.eclipse.tractusx.bpdm.test.util.DbTestHelpers +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.Assertions.assertEquals import org.junit.jupiter.api.extension.RegisterExtension import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest @@ -58,7 +58,7 @@ class PartnerUploadControllerIT @Autowired constructor( val testHelpers: DbTestHelpers, val assertHelpers: AssertHelpers, val gateClient: GateClient, - val goldenRecordTaskService: GoldenRecordTaskService, + val taskCreationService: TaskCreationService, val mockAndAssertUtils: MockAndAssertUtils ){ @@ -183,7 +183,7 @@ class PartnerUploadControllerIT @Autowired constructor( private fun uploadBusinessPartnerRecordAndShare(file: MockMultipartFile) { gateClient.partnerUpload.uploadPartnerCsvFile(file) - goldenRecordTaskService.createTasksForReadyBusinessPartners() + taskCreationService.createTasksForReadyBusinessPartners() } private fun BusinessPartnerInputRequest.fastCopy(externalId: String, shortName: String) = diff --git a/bpdm-gate/src/test/kotlin/org/eclipse/tractusx/bpdm/gate/entity/generic/BusinessPartnerIT.kt b/bpdm-gate/src/test/kotlin/org/eclipse/tractusx/bpdm/gate/entity/generic/BusinessPartnerIT.kt index 29fae19a7..4c04d322a 100644 --- a/bpdm-gate/src/test/kotlin/org/eclipse/tractusx/bpdm/gate/entity/generic/BusinessPartnerIT.kt +++ b/bpdm-gate/src/test/kotlin/org/eclipse/tractusx/bpdm/gate/entity/generic/BusinessPartnerIT.kt @@ -48,10 +48,9 @@ import org.eclipse.tractusx.bpdm.common.model.BusinessStateType import org.eclipse.tractusx.bpdm.common.model.ClassificationType import org.eclipse.tractusx.bpdm.common.model.DeliveryServiceType import org.eclipse.tractusx.bpdm.common.model.StageType -import org.eclipse.tractusx.bpdm.gate.entity.AlternativePostalAddressDb -import org.eclipse.tractusx.bpdm.gate.entity.GeographicCoordinateDb -import org.eclipse.tractusx.bpdm.gate.entity.PhysicalPostalAddressDb -import org.eclipse.tractusx.bpdm.gate.entity.StreetDb +import org.eclipse.tractusx.bpdm.gate.api.model.SharingStateType +import org.eclipse.tractusx.bpdm.gate.entity.* +import org.eclipse.tractusx.bpdm.gate.repository.SharingStateRepository import org.eclipse.tractusx.bpdm.gate.repository.generic.BusinessPartnerRepository import org.eclipse.tractusx.bpdm.gate.repository.generic.PostalAddressRepository import org.eclipse.tractusx.bpdm.test.containers.PostgreSQLContextInitializer @@ -76,6 +75,9 @@ internal class BusinessPartnerIT @Autowired constructor( val assertHelpers: AssertHelpers, ) { + @Autowired + lateinit var sharingStateRepository: SharingStateRepository + @Autowired lateinit var businessPartnerRepository: BusinessPartnerRepository @@ -98,7 +100,10 @@ internal class BusinessPartnerIT @Autowired constructor( @Test fun `test save BusinessPartner`() { - val businessPartner = createBusinessPartner() + val sharingState = createSharingState() + sharingStateRepository.save(sharingState) + + val businessPartner = createBusinessPartner(sharingState) val savedEntity = businessPartnerRepository.save(businessPartner) val foundEntity = businessPartnerRepository.findById(savedEntity.id).get() @@ -152,12 +157,20 @@ internal class BusinessPartnerIT @Autowired constructor( assertEquals("Berlin", foundAlternativePostalAddress?.city) } + private fun createSharingState(): SharingStateDb { + return SharingStateDb( + externalId = "testExternalId", + sharingErrorCode = null, + sharingStateType = SharingStateType.Initial + ) + } + - private fun createBusinessPartner(): BusinessPartnerDb { + private fun createBusinessPartner(sharingState: SharingStateDb): BusinessPartnerDb { val postalAddress = createPostalAddress() return BusinessPartnerDb( - externalId = "testExternalId", + sharingState = sharingState, nameParts = mutableListOf("testNameParts", "testNameParts2", "testNameParts3", "testNameParts4", "testNameParts5"), shortName = "testShortName", legalName = "testLegalName", @@ -174,8 +187,6 @@ internal class BusinessPartnerIT @Autowired constructor( states = sortedSetOf(createState()), classifications = sortedSetOf(createClassification()), stage = StageType.Input, - parentId = null, - parentType = null, legalEntityConfidence = null, addressConfidence = null, siteConfidence = null diff --git a/bpdm-gate/src/test/kotlin/org/eclipse/tractusx/bpdm/gate/util/PostgreSQLContextInitializer.kt b/bpdm-gate/src/test/kotlin/org/eclipse/tractusx/bpdm/gate/util/PostgreSQLContextInitializer.kt deleted file mode 100644 index b6ef51a94..000000000 --- a/bpdm-gate/src/test/kotlin/org/eclipse/tractusx/bpdm/gate/util/PostgreSQLContextInitializer.kt +++ /dev/null @@ -1,43 +0,0 @@ -/******************************************************************************* - * 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.gate.util - -import org.springframework.boot.test.util.TestPropertyValues -import org.springframework.context.ApplicationContextInitializer -import org.springframework.context.ConfigurableApplicationContext -import org.testcontainers.containers.PostgreSQLContainer - -/** - * When used on a spring boot test, starts a singleton postgres db container that is shared between all integration tests. - */ -class PostgreSQLContextInitializer : ApplicationContextInitializer { - companion object { - val postgreSQLContainer = PostgreSQLContainer("postgres:13.2") - } - - override fun initialize(applicationContext: ConfigurableApplicationContext) { - postgreSQLContainer.start() - TestPropertyValues.of( - "spring.datasource.url=${postgreSQLContainer.jdbcUrl}", - "spring.datasource.username=${postgreSQLContainer.username}", - "spring.datasource.password=${postgreSQLContainer.password}" - ).applyTo(applicationContext.environment) - } -} \ No newline at end of file