Skip to content

Commit

Permalink
feat(pool): #432 Upsert Business Partners from Cleaning Result
Browse files Browse the repository at this point in the history
- add BpnRequestIdentifierMapping entity
- map RequestIdentifier to bpn

feat(pool): #432 Upsert Business Partners from Cleaning Result
- map RequestIdentifier to bpn
  • Loading branch information
rainer-exxcellent committed Oct 20, 2023
1 parent 01774fe commit 1210c60
Show file tree
Hide file tree
Showing 7 changed files with 279 additions and 42 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*******************************************************************************
* 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.entity

import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.Index
import jakarta.persistence.Table
import org.eclipse.tractusx.bpdm.common.model.BaseEntity

@Entity
@Table(
name = "bpn_requestidentifier_mapping",
indexes = [
Index(columnList = "request_identifier"),
]
)
class BpnRequestIdentifierMapping(

@Column(name = "request_identifier", unique = true, nullable = false)
var requestIdentifier: String,
@Column(name = "bpn", nullable = false)
var bpn: String
) : BaseEntity()
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*******************************************************************************
* 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.repository

import org.eclipse.tractusx.bpdm.pool.entity.BpnRequestIdentifierMapping
import org.springframework.data.repository.CrudRepository
import org.springframework.data.repository.PagingAndSortingRepository

interface BpnRequestIdentifierRepository : PagingAndSortingRepository<BpnRequestIdentifierMapping, Long>, CrudRepository<BpnRequestIdentifierMapping, Long> {

fun findDistinctByRequestIdentifierIn(requestIdentifiers: Collection<String>): Set<BpnRequestIdentifierMapping>

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*******************************************************************************
* 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.BpnRequestIdentifierMapping
import org.eclipse.tractusx.bpdm.pool.repository.BpnRequestIdentifierRepository
import org.eclipse.tractusx.orchestrator.api.model.BpnReferenceDto
import org.eclipse.tractusx.orchestrator.api.model.BpnReferenceType
import org.eclipse.tractusx.orchestrator.api.model.TaskStepReservationEntryDto

class TaskEntryBpnMapping(taskEntries: List<TaskStepReservationEntryDto>, bpnRequestIdentifierRepository: BpnRequestIdentifierRepository) {

private val bpnByRequestIdentifier: MutableMap<String, String>
private val createdBpnByRequestIdentifier: MutableMap<String, String> = mutableMapOf()
init{
this.bpnByRequestIdentifier = readRequestMappings(taskEntries, bpnRequestIdentifierRepository)

}

private fun readRequestMappings(taskEntries: List<TaskStepReservationEntryDto>, bpnRequestIdentifierRepository: BpnRequestIdentifierRepository ): MutableMap<String, String> {

val references = taskEntries.mapNotNull { it.businessPartner.legalEntity?.bpnLReference } +
taskEntries.mapNotNull { it.businessPartner.site?.bpnSReference } +
taskEntries.mapNotNull { it.businessPartner.address?.bpnAReference }

val usedRequestIdentifiers: Collection<String> = references.map { it.referenceValue }

val mappings = bpnRequestIdentifierRepository.findDistinctByRequestIdentifierIn(usedRequestIdentifiers)
val bpnByRequestIdentifier = mappings
.map { it.requestIdentifier to it.bpn }
.toMap()
return bpnByRequestIdentifier.toMutableMap()
}

fun getBpn(bpnLReference: BpnReferenceDto): String? {

return if (bpnLReference.referenceType == BpnReferenceType.BpnRequestIdentifier) {
bpnByRequestIdentifier.get(bpnLReference.referenceValue)
} else {
bpnLReference.referenceValue
}
}

fun addMapping(bpnLReference: BpnReferenceDto, bpn: String) {

createdBpnByRequestIdentifier[bpnLReference.referenceValue] = bpn
bpnByRequestIdentifier[bpnLReference.referenceValue] = bpn
}

fun writeCreatedMappingsToDb(bpnRequestIdentifierRepository: BpnRequestIdentifierRepository) {

val mappingsToCreate = createdBpnByRequestIdentifier.map{
BpnRequestIdentifierMapping(requestIdentifier=it.key, bpn =it.value)
}
bpnRequestIdentifierRepository.saveAll(mappingsToCreate)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -65,32 +65,40 @@ class TaskStepBuildService(
}

@Transactional
fun upsertBusinessPartner(taskEntry: TaskStepReservationEntryDto): TaskStepResultEntryDto {
fun upsertBusinessPartner(taskEntry: TaskStepReservationEntryDto, taskEntryBpnMapping: TaskEntryBpnMapping): TaskStepResultEntryDto {

// TODO associate generated BPN with BPN request identifier
val businessPartnerDto = taskEntry.businessPartner
var siteResult: SiteDto? = null
var addressResult: LogisticAddressDto? = null

val legalEntity = upsertLegalEntity(businessPartnerDto.legalEntity)
val legalEntity = upsertLegalEntity(businessPartnerDto.legalEntity, taskEntryBpnMapping)
var genericBpnA= legalEntity.legalAddress.bpn

var siteEntity: Site? = null
if (businessPartnerDto.site != null) {
siteEntity = upsertSite(businessPartnerDto.site, legalEntity)
siteEntity = upsertSite(businessPartnerDto.site, legalEntity, taskEntryBpnMapping)
siteResult = businessPartnerDto.site!!.copy(
bpnSReference = BpnReferenceDto(referenceValue = siteEntity.bpn, referenceType = BpnReferenceType.Bpn)
)
genericBpnA = siteEntity.mainAddress.bpn
}
var addressEntity: LogisticAddress? = null
if (businessPartnerDto.address != null) {
val addressEntity = upsertLogisticAddress(businessPartnerDto.address, legalEntity, siteEntity)
addressEntity = upsertLogisticAddress(businessPartnerDto.address, legalEntity, siteEntity, taskEntryBpnMapping)
addressResult = businessPartnerDto.address!!.copy(
bpnAReference = BpnReferenceDto(referenceValue = addressEntity.bpn, referenceType = BpnReferenceType.Bpn)
)
genericBpnA = addressEntity.bpn
}

return TaskStepResultEntryDto(
taskId = taskEntry.taskId,
businessPartner = BusinessPartnerFullDto(
generic = businessPartnerDto.generic,
generic = businessPartnerDto.generic.copy(
bpnL = legalEntity.bpn,
bpnS = siteEntity?.bpn,
bpnA = genericBpnA
),
legalEntity = businessPartnerDto.legalEntity!!.copy(
bpnLReference = BpnReferenceDto(referenceValue = legalEntity.bpn, referenceType = BpnReferenceType.Bpn)
),
Expand All @@ -103,21 +111,20 @@ class TaskStepBuildService(
private fun upsertLogisticAddress(
addressDto: LogisticAddressDto?,
legalEntity: LegalEntity,
siteEntity: Site?
siteEntity: Site?,
taskEntryBpnMapping: TaskEntryBpnMapping
): LogisticAddress {

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

val isCreate = bpnAReference.referenceType == BpnReferenceType.BpnRequestIdentifier
val changelogType =
if (isCreate) ChangelogType.CREATE else ChangelogType.UPDATE
val bpn = taskEntryBpnMapping.getBpn(bpnAReference)

val upsertAddress = if (isCreate) {
val bpnLA = bpnIssuingService.issueAddressBpns(1).single()
createLogisticAddressInternal(addressDto, bpnLA)
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(bpnAReference.referenceValue)
if (updateAddress != null) {
updateLogisticAddress(updateAddress, addressDto, addressMetadataMap)
Expand All @@ -132,6 +139,9 @@ class TaskStepBuildService(
upsertAddress.legalEntity = legalEntity
}
logisticAddressRepository.save(upsertAddress)

val changelogType =
if (bpn == null) ChangelogType.CREATE else ChangelogType.UPDATE
changelogService.createChangelogEntries(
listOf(
ChangelogEntryCreateRequest(upsertAddress.bpn, changelogType, BusinessPartnerType.ADDRESS)
Expand All @@ -141,12 +151,15 @@ class TaskStepBuildService(
return upsertAddress
}

private fun createLogisticAddress(
addressDto: LogisticAddressDto?
): LogisticAddress {
private fun createLogisticAddress(addressDto: LogisticAddressDto?, taskEntryBpnMapping: TaskEntryBpnMapping): LogisticAddress {

val bpnAReference = addressDto?.bpnAReference
val bpnL = bpnIssuingService.issueAddressBpns(1).single()

val bpnLA = bpnIssuingService.issueAddressBpns(1)
val newAddress = createLogisticAddressInternal(addressDto, bpnLA[0])
if (bpnAReference != null && bpnAReference.referenceType == BpnReferenceType.BpnRequestIdentifier) {
taskEntryBpnMapping.addMapping(bpnAReference, bpnL)
}
val newAddress = createLogisticAddressInternal(addressDto, bpnL)
changelogService.createChangelogEntries(
listOf(
ChangelogEntryCreateRequest(newAddress.bpn, ChangelogType.CREATE, BusinessPartnerType.ADDRESS)
Expand Down Expand Up @@ -323,28 +336,26 @@ class TaskStepBuildService(


fun upsertLegalEntity(
legalEntityDto: LegalEntityDto?
legalEntityDto: LegalEntityDto?, taskEntryBpnMapping: TaskEntryBpnMapping
): LegalEntity {

val bpnLReference = legalEntityDto?.bpnLReference ?: throw BpdmValidationException(CleaningError.LEGAL_ENTITY_IS_NULL.message)
val legalAddress = legalEntityDto.legalAddress ?: throw BpdmValidationException(CleaningError.LEGAL_ADDRESS_IS_NULL.message)

val isCreate = bpnLReference.referenceType == BpnReferenceType.BpnRequestIdentifier
val changelogType =
if (isCreate) ChangelogType.CREATE else ChangelogType.UPDATE

val legalEntityMetadataMap = metadataService.getMetadata(listOf(legalEntityDto)).toMapping()

val upsertLe = if (isCreate) {
val bpn = taskEntryBpnMapping.getBpn(bpnLReference)

val upsertLe = if (bpn == null) {
val bpnL = bpnIssuingService.issueLegalEntityBpns(1).single()
val createdLe = createLegalEntity(legalEntityDto, bpnL, legalEntityMetadataMap)
val address = createLogisticAddress(legalAddress)
taskEntryBpnMapping.addMapping(bpnLReference, bpnL)
val createdLe = createLegalEntity(legalEntityDto, bpnL, legalEntityMetadataMap)
val address = createLogisticAddress(legalAddress, taskEntryBpnMapping)
createdLe.legalAddress = address
address.legalEntity = createdLe
createdLe
} else {

val updateLe = legalEntityRepository.findByBpn(bpnLReference.referenceValue)
val updateLe = legalEntityRepository.findByBpn(bpn)
if (updateLe != null) {
if (legalEntityDto.hasChanged == false) {
updateLegalEntity(updateLe, legalEntityDto,
Expand All @@ -358,6 +369,8 @@ 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)
Expand All @@ -367,20 +380,19 @@ class TaskStepBuildService(
return upsertLe
}

private fun upsertSite(
siteDto: SiteDto?,
legalEntity: LegalEntity
): Site {
private fun upsertSite(siteDto: SiteDto?, legalEntity: LegalEntity, taskEntryBpnMapping: TaskEntryBpnMapping): Site {

val bpnSReference = siteDto?.bpnSReference ?: throw BpdmValidationException(CleaningError.BPNS_IS_NULL.message)
val mainAddress = siteDto.mainAddress ?: throw BpdmValidationException(CleaningError.MAINE_ADDRESS_IS_NULL.message)

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

val upsertSite = if (isCreate) {
val upsertSite = if (bpn == null) {
val bpnS = bpnIssuingService.issueSiteBpns(1).single()
val createSite = createSite(siteDto, bpnS, legalEntity)
val address = createLogisticAddress(mainAddress)
taskEntryBpnMapping.addMapping(bpnSReference, bpnS)
val address = createLogisticAddress(mainAddress, taskEntryBpnMapping)
createSite.mainAddress = address
address.site = createSite
createSite
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import org.eclipse.tractusx.bpdm.common.dto.IBaseLogisticAddressDto
import org.eclipse.tractusx.bpdm.pool.api.model.response.ErrorInfo
import org.eclipse.tractusx.bpdm.pool.api.model.response.LegalEntityCreateError
import org.eclipse.tractusx.bpdm.pool.exception.BpdmValidationException
import org.eclipse.tractusx.bpdm.pool.repository.BpnRequestIdentifierRepository
import org.eclipse.tractusx.orchestrator.api.client.OrchestrationApiClient
import org.eclipse.tractusx.orchestrator.api.model.*
import org.springframework.scheduling.annotation.Scheduled
Expand All @@ -35,6 +36,7 @@ class TaskStepFetchAndReserveService(
private val orchestrationClient: OrchestrationApiClient,
private val taskStepBuildService: TaskStepBuildService,
private val requestValidationService: RequestValidationService,
private val bpnRequestIdentifierRepository: BpnRequestIdentifierRepository
) {
private val logger = KotlinLogging.logger { }

Expand All @@ -60,20 +62,23 @@ class TaskStepFetchAndReserveService(

fun upsertGoldenRecordIntoPool(taskEntries: List<TaskStepReservationEntryDto>): List<TaskStepResultEntryDto> {

val taskEntryBpnMapping = TaskEntryBpnMapping(taskEntries, bpnRequestIdentifierRepository)
//TODO Implement validation for sites, ...
val validationStepErrorsByEntry = validateLegalEntityCreateTasks(taskEntries)

return taskEntries.map {
val taksResults = taskEntries.map {

val existingEntryError = validationStepErrorsByEntry.get(it)
existingEntryError ?: businessPartnerTaskResult(it)
existingEntryError ?: businessPartnerTaskResult(it, taskEntryBpnMapping)
}
taskEntryBpnMapping.writeCreatedMappingsToDb(bpnRequestIdentifierRepository)
return taksResults
}

fun businessPartnerTaskResult(taskStep: TaskStepReservationEntryDto): TaskStepResultEntryDto {
private fun businessPartnerTaskResult(taskStep: TaskStepReservationEntryDto, taskEntryBpnMapping: TaskEntryBpnMapping): TaskStepResultEntryDto {

return try {
taskStepBuildService.upsertBusinessPartner(taskStep)
taskStepBuildService.upsertBusinessPartner(taskStep, taskEntryBpnMapping)
} catch (ex: BpdmValidationException) {
TaskStepResultEntryDto(
taskId = taskStep.taskId,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-- field Rules
create table bpn_requestidentifier_mapping
(
id bigint not null,
uuid UUID not null,
created_at timestamp without time zone not null,
updated_at timestamp without time zone not null,
request_identifier varchar(255) not null,
bpn varchar(255) not null,
primary key (id)
);

alter table bpn_requestidentifier_mapping
add constraint uc_field_request_identifier unique (uuid);

create index idx_request_identifier_on_bpn_requestidentifier_mapping
on bpn_requestidentifier_mapping (request_identifier);

commit;

Loading

0 comments on commit 1210c60

Please sign in to comment.