Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

feat(pool): Update only changed Business Partners #650

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
/*******************************************************************************
* Copyright (c) 2021,2023 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* SPDX-License-Identifier: Apache-2.0
******************************************************************************/

package org.eclipse.tractusx.bpdm.pool.service

import org.eclipse.tractusx.bpdm.pool.entity.*
import org.springframework.stereotype.Service

@Service
class BusinessPartnerEquivalenceService {
fun isEquivalent(original: LegalEntity, updated: LegalEntity): Boolean =
original.bpn != updated.bpn ||
isEquivalent(original.legalForm, updated.legalForm) ||
isEquivalentLegalEntityIdentifier(original.identifiers, updated.identifiers) ||
isEquivalentLegalEntityState(original.states, updated.states) ||
isEquivalentLogisticAddress(original.addresses, updated.addresses) ||
isEquivalent(original.sites, updated.sites) ||
isEquivalentLegalEntityClassification(original.classifications, updated.classifications) ||
isEquivalent(original.legalName, updated.legalName) ||
isEquivalent(original.legalAddress, updated.legalAddress)


private fun isEquivalentLegalEntityIdentifier(
originalSet: MutableSet<LegalEntityIdentifier>,
updatedSet: MutableSet<LegalEntityIdentifier>
): Boolean {
return isEquivalent(originalSet, updatedSet) { entity1, entity2 ->
isEquivalent(entity1, entity2)
}
}

private fun isEquivalent(original: LegalEntityIdentifier, updated: LegalEntityIdentifier): Boolean =
original.value != updated.value ||
isEquivalent(original.type, updated.type) ||
original.issuingBody != updated.issuingBody

private fun isEquivalent(original: IdentifierType, updated: IdentifierType): Boolean =
original.technicalKey != updated.technicalKey ||
original.name != updated.name ||
original.businessPartnerType.name != updated.businessPartnerType.name


private fun isEquivalentLegalEntityState(
originalSet: MutableSet<LegalEntityState>,
updatedSet: MutableSet<LegalEntityState>
): Boolean {
return isEquivalent(originalSet, updatedSet) { entity1, entity2 ->
isEquivalent(entity1, entity2)
}
}

private fun isEquivalent(original: LegalEntityState, updated: LegalEntityState): Boolean =
original.description != updated.description ||
original.validFrom != updated.validFrom ||
original.validTo != updated.validTo ||
original.type != updated.type


private fun isEquivalentLegalEntityClassification(
originalSet: MutableSet<LegalEntityClassification>,
updatedSet: MutableSet<LegalEntityClassification>
): Boolean {
return isEquivalent(originalSet, updatedSet) { entity1, entity2 ->
isEquivalent(entity1, entity2)
}
}


private fun isEquivalent(original: LegalEntityClassification, updated: LegalEntityClassification): Boolean {
return (
original.value != updated.value ||
original.code != updated.code ||
original.type != updated.type
)
}

private fun isEquivalent(original: Name, updated: Name): Boolean =
original.value != updated.value ||
original.shortName != updated.shortName

private fun isEquivalent(original: LegalForm?, updated: LegalForm?): Boolean =
original?.name != updated?.name ||
original?.technicalKey != updated?.technicalKey ||
original?.abbreviation != updated?.abbreviation


private fun isEquivalentLogisticAddress(
originalSet: MutableSet<LogisticAddress>,
updatedSet: MutableSet<LogisticAddress>
): Boolean {
return isEquivalent(originalSet, updatedSet) { entity1, entity2 ->
isEquivalent(entity1, entity2)
}
}


fun isEquivalent(original: LogisticAddress, updated: LogisticAddress): Boolean =
original.bpn != updated.bpn ||
original.name != updated.name ||
isEquivalent(original.physicalPostalAddress, updated.physicalPostalAddress) ||
isEquivalent(original.alternativePostalAddress, updated.alternativePostalAddress)


fun isEquivalentLogisticAddressSite(original: LogisticAddress, updated: LogisticAddress): Boolean =
original.name != updated.name ||
isEquivalent(original.physicalPostalAddress, updated.physicalPostalAddress) ||
isEquivalent(original.alternativePostalAddress, updated.alternativePostalAddress)


private fun isEquivalent(
originalSet: MutableSet<Site>,
updatedSet: MutableSet<Site>
): Boolean {
return isEquivalent(originalSet, updatedSet) { entity1, entity2 ->
isEquivalent(entity1, entity2)
}
}

fun isEquivalent(original: Site, updated: Site): Boolean =
original.bpn != updated.bpn ||
original.name != updated.name ||
isEquivalentLogisticAddressSite(original.mainAddress, updated.mainAddress)

private fun isEquivalent(
original: AlternativePostalAddress?,
updated: AlternativePostalAddress?
): Boolean =
isEquivalent(original?.geographicCoordinates, updated?.geographicCoordinates) ||
original?.country != updated?.country ||
isEquivalent(original?.administrativeAreaLevel1, updated?.administrativeAreaLevel1) ||
original?.postCode != updated?.postCode ||
original?.city != updated?.city ||
original?.deliveryServiceType != updated?.deliveryServiceType ||
original?.deliveryServiceNumber != updated?.deliveryServiceNumber ||
original?.deliveryServiceQualifier != updated?.deliveryServiceQualifier


private fun isEquivalent(original: GeographicCoordinate?, updated: GeographicCoordinate?): Boolean =
original?.latitude != updated?.latitude ||
original?.longitude != updated?.longitude ||
original?.altitude != updated?.altitude

private fun isEquivalent(original: Region?, updated: Region?): Boolean =
original?.countryCode != updated?.countryCode ||
original?.regionCode != updated?.regionCode ||
original?.regionName != updated?.regionName


private fun isEquivalent(
original: PhysicalPostalAddress,
updated: PhysicalPostalAddress
): Boolean =
original.country.name != updated.country.name ||
original.administrativeAreaLevel1 != updated.administrativeAreaLevel1 ||
original.administrativeAreaLevel2 != updated.administrativeAreaLevel2 ||
original.administrativeAreaLevel3 != updated.administrativeAreaLevel3 ||
original.administrativeAreaLevel4 != updated.administrativeAreaLevel4 ||
original.postCode != updated.postCode ||
original.city != updated.city ||
original.districtLevel1 != updated.districtLevel1 ||
original.districtLevel2 != updated.districtLevel2 ||
original.companyPostCode != updated.companyPostCode ||
original.industrialZone != updated.industrialZone ||
original.building != updated.building ||
original.floor != updated.floor ||
original.door != updated.door ||
isEquivalent(original.geographicCoordinates, updated.geographicCoordinates) ||
isEquivalent(original.street, updated.street)

private fun isEquivalent(original: Street?, updated: Street?): Boolean =
original?.name != updated?.name ||
original?.houseNumber != updated?.houseNumber ||
original?.milestone != updated?.milestone ||
original?.direction != updated?.direction

private fun <T> isEquivalent(
originalSet: MutableSet<T>,
updatedSet: MutableSet<T>,
comparator: (T, T) -> Boolean
): Boolean {
if (originalSet.size != updatedSet.size) {
return true
}

for (originalEntity in originalSet) {
val updatedEntity = updatedSet.find { comparator(it, originalEntity) }

if (updatedEntity == null || comparator(originalEntity, updatedEntity)) {
return true
}
}

return false
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class TaskStepBuildService(
private val legalEntityRepository: LegalEntityRepository,
private val logisticAddressRepository: LogisticAddressRepository,
private val siteRepository: SiteRepository,
private val businessPartnerEquivalenceService: BusinessPartnerEquivalenceService,
) {

enum class CleaningError(val message: String) {
Expand Down Expand Up @@ -98,7 +99,7 @@ class TaskStepBuildService(
addressBpn = genericBpnA
),
legalEntity = businessPartnerDto.legalEntity!!.copy(
bpnLReference = BpnReferenceDto(referenceValue = legalEntity.bpn, referenceType = BpnReferenceType.Bpn) ,
bpnLReference = BpnReferenceDto(referenceValue = legalEntity.bpn, referenceType = BpnReferenceType.Bpn),
legalAddress = businessPartnerDto.legalEntity!!.legalAddress!!.copy(
bpnAReference = BpnReferenceDto(referenceValue = legalEntity.legalAddress.bpn, referenceType = BpnReferenceType.Bpn)
)
Expand All @@ -115,19 +116,22 @@ class TaskStepBuildService(
siteEntity: Site?,
taskEntryBpnMapping: TaskEntryBpnMapping
): LogisticAddress {

val bpnAReference = addressDto?.bpnAReference ?: throw BpdmValidationException(CleaningError.BPNA_IS_NULL.message)

val bpn = taskEntryBpnMapping.getBpn(bpnAReference)

var hasChanges = false
val upsertAddress = if (bpn == null) {
val bpnA = bpnIssuingService.issueAddressBpns(1).single()
taskEntryBpnMapping.addMapping(bpnAReference, bpnA)
createLogisticAddressInternal(addressDto, bpnA)
} else {
val addressMetadataMap = metadataService.getMetadata(listOf(addressDto)).toMapping()
val updateAddress = logisticAddressRepository.findByBpn(bpn)

if (updateAddress != null) {
val newAddress = createLogisticAddressInternal(addressDto, updateAddress.bpn)
updateLogisticAddress(newAddress, addressDto, addressMetadataMap)
hasChanges = businessPartnerEquivalenceService.isEquivalent(updateAddress, newAddress)
updateLogisticAddress(updateAddress, addressDto, addressMetadataMap)
} else {
throw BpdmValidationException(CleaningError.INVALID_LOGISTIC_ADDRESS_BPN.message)
Expand All @@ -139,15 +143,22 @@ class TaskStepBuildService(
} else {
upsertAddress.legalEntity = legalEntity
}
logisticAddressRepository.save(upsertAddress)

if (hasChanges || bpn == null) {
logisticAddressRepository.save(upsertAddress)
}


val changelogType =
if (bpn == null) ChangelogType.CREATE else ChangelogType.UPDATE
changelogService.createChangelogEntries(
listOf(
ChangelogEntryCreateRequest(upsertAddress.bpn, changelogType, BusinessPartnerType.ADDRESS)
if (hasChanges || bpn == null) {
changelogService.createChangelogEntries(
listOf(
ChangelogEntryCreateRequest(upsertAddress.bpn, changelogType, BusinessPartnerType.ADDRESS)
)
)
)
}


return upsertAddress
}
Expand Down Expand Up @@ -250,7 +261,7 @@ class TaskStepBuildService(
val legalEntityMetadataMap = metadataService.getMetadata(listOf(legalEntityDto)).toMapping()

val bpn = taskEntryBpnMapping.getBpn(bpnLReference)

var hasChanges = false
val upsertLe = if (bpn == null) {
val bpnL = bpnIssuingService.issueLegalEntityBpns(1).single()
taskEntryBpnMapping.addMapping(bpnLReference, bpnL)
Expand All @@ -264,6 +275,14 @@ class TaskStepBuildService(
val updateLe = legalEntityRepository.findByBpn(bpn)
if (updateLe != null) {
if (legalEntityDto.hasChanged == true) {

val createdLe =
BusinessPartnerBuildService.createLegalEntity(legalEntityDto, updateLe.bpn, legalEntityDto.legalName, legalEntityMetadataMap)
val address = createLogisticAddress(legalAddress, taskEntryBpnMapping)
createdLe.legalAddress = address
address.legalEntity = createdLe
hasChanges = businessPartnerEquivalenceService.isEquivalent(updateLe, createdLe)

BusinessPartnerBuildService.updateLegalEntity(updateLe, legalEntityDto, legalEntityDto.legalName, legalEntityMetadataMap)
val addressMetadataMap = metadataService.getMetadata(listOf(legalAddress)).toMapping()
updateLogisticAddress(updateLe.legalAddress, legalAddress, addressMetadataMap)
Expand All @@ -273,15 +292,17 @@ class TaskStepBuildService(
}
updateLe
}
legalEntityRepository.save(upsertLe)
val changelogType =
if (bpn == null) ChangelogType.CREATE else ChangelogType.UPDATE
changelogService.createChangelogEntries(
listOf(
ChangelogEntryCreateRequest(upsertLe.bpn, changelogType, BusinessPartnerType.LEGAL_ENTITY)
)
)

if (hasChanges || bpn == null) {
legalEntityRepository.save(upsertLe)
changelogService.createChangelogEntries(
listOf(
ChangelogEntryCreateRequest(upsertLe.bpn, changelogType, BusinessPartnerType.LEGAL_ENTITY)
)
)
}
return upsertLe
}

Expand All @@ -297,7 +318,7 @@ class TaskStepBuildService(

val bpn = taskEntryBpnMapping.getBpn(bpnSReference)
val changelogType = if (bpn == null) ChangelogType.CREATE else ChangelogType.UPDATE

var hasChanges = false
val upsertSite = if (bpn == null) {
val bpnS = bpnIssuingService.issueSiteBpns(1).single()
val createSite = BusinessPartnerBuildService.createSite(siteDto, bpnS, legalEntity)
Expand All @@ -318,6 +339,16 @@ class TaskStepBuildService(
val updateSite = siteRepository.findByBpn(bpn)
if (updateSite != null) {
if (siteDto.hasChanged == true) {
val createSite = BusinessPartnerBuildService.createSite(siteDto, updateSite.bpn, legalEntity)
val siteMainAddress =
if (genericBusinessPartner.generic.postalAddress.addressType == AddressType.LegalAndSiteMainAddress)
legalEntity.legalAddress
else
createLogisticAddress(mainAddress, taskEntryBpnMapping)
createSite.mainAddress = siteMainAddress
siteMainAddress.site = createSite
hasChanges = businessPartnerEquivalenceService.isEquivalent(updateSite, createSite)

BusinessPartnerBuildService.updateSite(updateSite, siteDto)
val addressMetadataMap = metadataService.getMetadata(listOf(mainAddress)).toMapping()
updateLogisticAddress(updateSite.mainAddress, mainAddress, addressMetadataMap)
Expand All @@ -327,12 +358,15 @@ class TaskStepBuildService(
}
updateSite
}
siteRepository.save(upsertSite)
changelogService.createChangelogEntries(
listOf(
ChangelogEntryCreateRequest(upsertSite.bpn, changelogType, BusinessPartnerType.SITE)

if (hasChanges || bpn == null) {
siteRepository.save(upsertSite)
changelogService.createChangelogEntries(
listOf(
ChangelogEntryCreateRequest(upsertSite.bpn, changelogType, BusinessPartnerType.SITE)
)
)
)
}

return upsertSite
}
Expand Down
Loading
Loading