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): Request indentifier mapping for Upserted Business Partners #549

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,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