This is an automated email from the ASF dual-hosted git repository.

adamsaghy pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git


The following commit(s) were added to refs/heads/develop by this push:
     new 5c2a5c7cfe FINERACT-2455: Retry loan originator creation in case of 
unique constraint violation
5c2a5c7cfe is described below

commit 5c2a5c7cfe7c95e82d67c0b7a7176fc97048a5fa
Author: Oleksii Novikov <[email protected]>
AuthorDate: Tue Mar 10 01:28:10 2026 +0200

    FINERACT-2455: Retry loan originator creation in case of unique constraint 
violation
---
 .../service/LoanOriginatorHelper.java              | 104 ++++++++++++++++++++
 .../service/LoanOriginatorLinkingServiceImpl.java  | 107 ++++++++-------------
 .../client/feign/helpers/FeignLoanHelper.java      |  12 ++-
 .../FeignLoanOriginatorDuringApplicationTest.java  |  76 +++++++++++++++
 4 files changed, 229 insertions(+), 70 deletions(-)

diff --git 
a/fineract-loan-origination/src/main/java/org/apache/fineract/portfolio/loanorigination/service/LoanOriginatorHelper.java
 
b/fineract-loan-origination/src/main/java/org/apache/fineract/portfolio/loanorigination/service/LoanOriginatorHelper.java
new file mode 100644
index 0000000000..161c2aadcf
--- /dev/null
+++ 
b/fineract-loan-origination/src/main/java/org/apache/fineract/portfolio/loanorigination/service/LoanOriginatorHelper.java
@@ -0,0 +1,104 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://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.
+ */
+package org.apache.fineract.portfolio.loanorigination.service;
+
+import static 
org.apache.fineract.infrastructure.configuration.api.GlobalConfigurationConstants.ENABLE_ORIGINATOR_CREATION_DURING_LOAN_APPLICATION;
+import static 
org.apache.fineract.portfolio.loanorigination.api.LoanOriginatorApiConstants.CHANNEL_TYPE_CODE_NAME;
+import static 
org.apache.fineract.portfolio.loanorigination.api.LoanOriginatorApiConstants.ORIGINATOR_TYPE_CODE_NAME;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.fineract.infrastructure.codes.domain.CodeValue;
+import 
org.apache.fineract.infrastructure.codes.domain.CodeValueRepositoryWrapper;
+import 
org.apache.fineract.infrastructure.configuration.domain.GlobalConfigurationProperty;
+import 
org.apache.fineract.infrastructure.configuration.domain.GlobalConfigurationRepositoryWrapper;
+import 
org.apache.fineract.infrastructure.configuration.exception.GlobalConfigurationPropertyNotFoundException;
+import org.apache.fineract.infrastructure.core.domain.ExternalId;
+import 
org.apache.fineract.portfolio.loanorigination.data.LoanApplicationOriginatorData;
+import org.apache.fineract.portfolio.loanorigination.domain.LoanOriginator;
+import 
org.apache.fineract.portfolio.loanorigination.domain.LoanOriginatorRepository;
+import 
org.apache.fineract.portfolio.loanorigination.domain.LoanOriginatorStatus;
+import 
org.apache.fineract.portfolio.loanorigination.exception.LoanOriginatorCreationNotAllowedException;
+import 
org.apache.fineract.portfolio.loanorigination.exception.LoanOriginatorNotActiveException;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+
+@Slf4j
+@Service
+@RequiredArgsConstructor
+public class LoanOriginatorHelper {
+
+    private final LoanOriginatorRepository loanOriginatorRepository;
+    private final GlobalConfigurationRepositoryWrapper 
globalConfigurationRepository;
+    private final CodeValueRepositoryWrapper codeValueRepositoryWrapper;
+
+    // REQUIRES_NEW isolates the INSERT into a separate transaction and 
persistence context,
+    // so a constraint violation does not corrupt the caller's session or mark 
the
+    // outer transaction as rollback-only, allowing a safe retry.
+    @Transactional(propagation = Propagation.REQUIRES_NEW)
+    public Long findOrCreateOriginatorId(final LoanApplicationOriginatorData 
data) {
+        final ExternalId externalId = new ExternalId(data.getExternalId());
+        return 
loanOriginatorRepository.findByExternalId(externalId).map(existing -> {
+            validateActive(existing);
+            return existing.getId();
+        }).orElseGet(() -> {
+            if (!isOriginatorCreationDuringLoanApplicationEnabled()) {
+                throw new 
LoanOriginatorCreationNotAllowedException(data.getExternalId());
+            }
+            return createNewOriginator(data, externalId).getId();
+        });
+    }
+
+    private void validateActive(final LoanOriginator originator) {
+        if (originator.getStatus() != LoanOriginatorStatus.ACTIVE) {
+            throw new LoanOriginatorNotActiveException(originator.getId(), 
originator.getStatus().getValue());
+        }
+    }
+
+    private boolean isOriginatorCreationDuringLoanApplicationEnabled() {
+        try {
+            final GlobalConfigurationProperty config = 
globalConfigurationRepository
+                    
.findOneByNameWithNotFoundDetection(ENABLE_ORIGINATOR_CREATION_DURING_LOAN_APPLICATION);
+            return config.isEnabled();
+        } catch (final GlobalConfigurationPropertyNotFoundException e) {
+            log.warn("Global configuration '{}' not found, defaulting to 
disabled", ENABLE_ORIGINATOR_CREATION_DURING_LOAN_APPLICATION);
+            return false;
+        }
+    }
+
+    private LoanOriginator createNewOriginator(final 
LoanApplicationOriginatorData data, final ExternalId externalId) {
+        log.info("Creating new originator with externalId: {} during loan 
application", data.getExternalId());
+
+        final CodeValue originatorType = resolveCodeValue(data.getTypeId(), 
ORIGINATOR_TYPE_CODE_NAME);
+        final CodeValue channelType = 
resolveCodeValue(data.getChannelTypeId(), CHANNEL_TYPE_CODE_NAME);
+
+        final LoanOriginator originator = LoanOriginator.create(externalId, 
data.getName(), LoanOriginatorStatus.ACTIVE, originatorType,
+                channelType);
+
+        return loanOriginatorRepository.saveAndFlush(originator);
+    }
+
+    private CodeValue resolveCodeValue(final Long codeValueId, final String 
codeName) {
+        if (codeValueId == null) {
+            return null;
+        }
+        return 
codeValueRepositoryWrapper.findOneByCodeNameAndIdWithNotFoundDetection(codeName,
 codeValueId);
+    }
+}
diff --git 
a/fineract-loan-origination/src/main/java/org/apache/fineract/portfolio/loanorigination/service/LoanOriginatorLinkingServiceImpl.java
 
b/fineract-loan-origination/src/main/java/org/apache/fineract/portfolio/loanorigination/service/LoanOriginatorLinkingServiceImpl.java
index bc4115a6ed..edfc273f9c 100644
--- 
a/fineract-loan-origination/src/main/java/org/apache/fineract/portfolio/loanorigination/service/LoanOriginatorLinkingServiceImpl.java
+++ 
b/fineract-loan-origination/src/main/java/org/apache/fineract/portfolio/loanorigination/service/LoanOriginatorLinkingServiceImpl.java
@@ -18,24 +18,14 @@
  */
 package org.apache.fineract.portfolio.loanorigination.service;
 
-import static 
org.apache.fineract.infrastructure.configuration.api.GlobalConfigurationConstants.ENABLE_ORIGINATOR_CREATION_DURING_LOAN_APPLICATION;
-import static 
org.apache.fineract.portfolio.loanorigination.api.LoanOriginatorApiConstants.CHANNEL_TYPE_CODE_NAME;
-import static 
org.apache.fineract.portfolio.loanorigination.api.LoanOriginatorApiConstants.ORIGINATOR_TYPE_CODE_NAME;
-
 import com.google.gson.JsonArray;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonObject;
+import java.sql.SQLException;
 import java.util.HashSet;
-import java.util.Optional;
 import java.util.Set;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.fineract.infrastructure.codes.domain.CodeValue;
-import 
org.apache.fineract.infrastructure.codes.domain.CodeValueRepositoryWrapper;
-import 
org.apache.fineract.infrastructure.configuration.domain.GlobalConfigurationProperty;
-import 
org.apache.fineract.infrastructure.configuration.domain.GlobalConfigurationRepositoryWrapper;
-import 
org.apache.fineract.infrastructure.configuration.exception.GlobalConfigurationPropertyNotFoundException;
-import org.apache.fineract.infrastructure.core.domain.ExternalId;
 import 
org.apache.fineract.portfolio.loanaccount.service.LoanOriginatorLinkingService;
 import 
org.apache.fineract.portfolio.loanorigination.data.LoanApplicationOriginatorData;
 import org.apache.fineract.portfolio.loanorigination.domain.LoanOriginator;
@@ -43,11 +33,13 @@ import 
org.apache.fineract.portfolio.loanorigination.domain.LoanOriginatorMappin
 import 
org.apache.fineract.portfolio.loanorigination.domain.LoanOriginatorMappingRepository;
 import 
org.apache.fineract.portfolio.loanorigination.domain.LoanOriginatorRepository;
 import 
org.apache.fineract.portfolio.loanorigination.domain.LoanOriginatorStatus;
-import 
org.apache.fineract.portfolio.loanorigination.exception.LoanOriginatorCreationNotAllowedException;
 import 
org.apache.fineract.portfolio.loanorigination.exception.LoanOriginatorNotActiveException;
 import 
org.apache.fineract.portfolio.loanorigination.exception.LoanOriginatorNotFoundException;
 import 
org.apache.fineract.portfolio.loanorigination.serialization.LoanApplicationOriginatorDataValidator;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.dao.DataAccessException;
+import org.springframework.dao.DataIntegrityViolationException;
+import org.springframework.orm.jpa.JpaSystemException;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -61,98 +53,75 @@ import 
org.springframework.transaction.annotation.Transactional;
 @ConditionalOnProperty(value = "fineract.module.loan-origination.enabled", 
havingValue = "true")
 public class LoanOriginatorLinkingServiceImpl implements 
LoanOriginatorLinkingService {
 
+    private static final String SQL_STATE_INTEGRITY_CONSTRAINT_VIOLATION = 
"23";
+
     private final LoanOriginatorRepository loanOriginatorRepository;
     private final LoanOriginatorMappingRepository 
loanOriginatorMappingRepository;
     private final LoanApplicationOriginatorDataValidator validator;
-    private final GlobalConfigurationRepositoryWrapper 
globalConfigurationRepository;
-    private final CodeValueRepositoryWrapper codeValueRepositoryWrapper;
+    private final LoanOriginatorHelper loanOriginatorHelper;
 
     @Transactional
     @Override
-    public void processOriginatorsForLoanApplication(Long loanId, JsonArray 
originatorsArray) {
+    public void processOriginatorsForLoanApplication(final Long loanId, final 
JsonArray originatorsArray) {
         if (originatorsArray == null || originatorsArray.isEmpty()) {
             return;
         }
 
         log.debug("Processing {} originators for loan application {}", 
originatorsArray.size(), loanId);
 
-        Set<Long> attachedOriginatorIds = new HashSet<>();
+        final Set<Long> attachedOriginatorIds = new HashSet<>();
 
-        for (JsonElement element : originatorsArray) {
+        for (final JsonElement element : originatorsArray) {
             if (!element.isJsonObject()) {
                 continue;
             }
 
-            JsonObject jsonObject = element.getAsJsonObject();
-            LoanApplicationOriginatorData originatorData = 
validator.validateAndExtract(jsonObject);
-            LoanOriginator originator = 
resolveOrCreateOriginator(originatorData);
+            final JsonObject jsonObject = element.getAsJsonObject();
+            final LoanApplicationOriginatorData originatorData = 
validator.validateAndExtract(jsonObject);
+            final Long originatorId = 
resolveOrCreateOriginatorId(originatorData);
 
-            if (attachedOriginatorIds.contains(originator.getId())) {
-                log.debug("Originator {} already attached to loan {}, skipping 
duplicate", originator.getId(), loanId);
+            if (attachedOriginatorIds.contains(originatorId)) {
+                log.debug("Originator {} already attached to loan {}, skipping 
duplicate", originatorId, loanId);
                 continue;
             }
 
-            if (originator.getStatus() != LoanOriginatorStatus.ACTIVE) {
-                throw new LoanOriginatorNotActiveException(originator.getId(), 
originator.getStatus().getValue());
-            }
-
-            if 
(!loanOriginatorMappingRepository.existsByLoanIdAndOriginatorId(loanId, 
originator.getId())) {
-                LoanOriginatorMapping mapping = 
LoanOriginatorMapping.create(loanId, originator);
+            if 
(!loanOriginatorMappingRepository.existsByLoanIdAndOriginatorId(loanId, 
originatorId)) {
+                final LoanOriginator originatorRef = 
loanOriginatorRepository.getReferenceById(originatorId);
+                final LoanOriginatorMapping mapping = 
LoanOriginatorMapping.create(loanId, originatorRef);
                 loanOriginatorMappingRepository.save(mapping);
-                log.debug("Attached originator {} to loan {}", 
originator.getId(), loanId);
+                log.debug("Attached originator {} to loan {}", originatorId, 
loanId);
             }
 
-            attachedOriginatorIds.add(originator.getId());
+            attachedOriginatorIds.add(originatorId);
         }
     }
 
-    private LoanOriginator 
resolveOrCreateOriginator(LoanApplicationOriginatorData originatorData) {
+    private Long resolveOrCreateOriginatorId(final 
LoanApplicationOriginatorData originatorData) {
         if (originatorData.getId() != null) {
-            return loanOriginatorRepository.findById(originatorData.getId())
+            final LoanOriginator originator = 
loanOriginatorRepository.findById(originatorData.getId())
                     .orElseThrow(() -> new 
LoanOriginatorNotFoundException(originatorData.getId()));
+            if (originator.getStatus() != LoanOriginatorStatus.ACTIVE) {
+                throw new LoanOriginatorNotActiveException(originator.getId(), 
originator.getStatus().getValue());
+            }
+            return originator.getId();
         }
-
-        String externalId = originatorData.getExternalId();
-        Optional<LoanOriginator> existingOriginator = 
loanOriginatorRepository.findByExternalId(new ExternalId(externalId));
-
-        if (existingOriginator.isPresent()) {
-            return existingOriginator.get();
-        }
-
-        if (!isOriginatorCreationDuringLoanApplicationEnabled()) {
-            throw new LoanOriginatorCreationNotAllowedException(externalId);
-        }
-
-        return createNewOriginator(originatorData);
+        return findOrCreateOriginatorIdByExternalId(originatorData);
     }
 
-    private boolean isOriginatorCreationDuringLoanApplicationEnabled() {
+    private Long findOrCreateOriginatorIdByExternalId(final 
LoanApplicationOriginatorData originatorData) {
         try {
-            GlobalConfigurationProperty config = globalConfigurationRepository
-                    
.findOneByNameWithNotFoundDetection(ENABLE_ORIGINATOR_CREATION_DURING_LOAN_APPLICATION);
-            return config.isEnabled();
-        } catch (GlobalConfigurationPropertyNotFoundException e) {
-            log.warn("Global configuration '{}' not found, defaulting to 
disabled", ENABLE_ORIGINATOR_CREATION_DURING_LOAN_APPLICATION);
-            return false;
+            return 
loanOriginatorHelper.findOrCreateOriginatorId(originatorData);
+        } catch (final JpaSystemException | DataIntegrityViolationException e) 
{
+            if (!isConstraintViolation(e)) {
+                throw e;
+            }
+            // Another thread created the originator concurrently - retry
+            return 
loanOriginatorHelper.findOrCreateOriginatorId(originatorData);
         }
     }
 
-    private LoanOriginator createNewOriginator(LoanApplicationOriginatorData 
data) {
-        log.info("Creating new originator with externalId: {} during loan 
application", data.getExternalId());
-
-        CodeValue originatorType = resolveCodeValue(data.getTypeId(), 
ORIGINATOR_TYPE_CODE_NAME);
-        CodeValue channelType = resolveCodeValue(data.getChannelTypeId(), 
CHANNEL_TYPE_CODE_NAME);
-
-        LoanOriginator originator = LoanOriginator.create(new 
ExternalId(data.getExternalId()), data.getName(), LoanOriginatorStatus.ACTIVE,
-                originatorType, channelType);
-
-        return loanOriginatorRepository.saveAndFlush(originator);
-    }
-
-    private CodeValue resolveCodeValue(Long codeValueId, String codeName) {
-        if (codeValueId == null) {
-            return null;
-        }
-        return 
codeValueRepositoryWrapper.findOneByCodeNameAndIdWithNotFoundDetection(codeName,
 codeValueId);
+    private boolean isConstraintViolation(final DataAccessException e) {
+        return e.getMostSpecificCause() instanceof SQLException sqlEx && 
sqlEx.getSQLState() != null
+                && 
sqlEx.getSQLState().startsWith(SQL_STATE_INTEGRITY_CONSTRAINT_VIOLATION);
     }
 }
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignLoanHelper.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignLoanHelper.java
index 5cf0c3bced..93496f0f74 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignLoanHelper.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignLoanHelper.java
@@ -182,6 +182,13 @@ public class FeignLoanHelper {
         return response.getLoanId();
     }
 
+    public Long createSubmittedLoanWithOriginators(Long clientId, Long 
productId, List<PostLoansOriginatorData> originators) {
+        PostLoansRequest request = buildSubmittedLoanRequest(clientId, 
productId);
+        request.setOriginators(originators);
+        PostLoansResponse response = ok(() -> 
fineractClient.loans().calculateLoanScheduleOrSubmitLoanApplication(request, 
(String) null));
+        return response.getLoanId();
+    }
+
     public CallFailedRuntimeException 
createSubmittedLoanWithOriginatorsExpectingError(Long clientId,
             List<PostLoansOriginatorData> originators) {
         PostLoansRequest request = buildSubmittedLoanRequest(clientId);
@@ -190,7 +197,10 @@ public class FeignLoanHelper {
     }
 
     private PostLoansRequest buildSubmittedLoanRequest(Long clientId) {
-        Long productId = createSimpleLoanProduct();
+        return buildSubmittedLoanRequest(clientId, createSimpleLoanProduct());
+    }
+
+    private PostLoansRequest buildSubmittedLoanRequest(Long clientId, Long 
productId) {
         String todayDate = 
org.apache.fineract.integrationtests.common.Utils.dateFormatter
                 
.format(org.apache.fineract.integrationtests.common.Utils.getLocalDateOfTenant());
         return new PostLoansRequest()//
diff --git 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/tests/FeignLoanOriginatorDuringApplicationTest.java
 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/tests/FeignLoanOriginatorDuringApplicationTest.java
index 8fb841e3b1..4f71c7d149 100644
--- 
a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/tests/FeignLoanOriginatorDuringApplicationTest.java
+++ 
b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/tests/FeignLoanOriginatorDuringApplicationTest.java
@@ -18,7 +18,17 @@
  */
 package org.apache.fineract.integrationtests.client.feign.tests;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
 import org.apache.fineract.client.feign.FineractFeignClient;
 import org.apache.fineract.client.feign.util.CallFailedRuntimeException;
 import org.apache.fineract.client.models.PostLoansOriginatorData;
@@ -215,4 +225,70 @@ public class FeignLoanOriginatorDuringApplicationTest 
extends FeignIntegrationTe
         originatorHelper.detachOriginatorFromLoan(loanId, originatorId);
         originatorHelper.deleteOriginator(originatorId);
     }
+
+    @Test
+    public void 
testCreateLoanWithSameOriginatorExternalIdInParallelShouldNotFail() throws 
InterruptedException {
+        configHelper.enableOriginatorCreationDuringLoanApplication();
+
+        try {
+            final int threadCount = 10;
+            final String sharedOriginatorExternalId = 
FeignLoanOriginatorHelper.generateUniqueExternalId();
+            final Long productId = loanHelper.createSimpleLoanProduct();
+
+            final List<Long> clientIds = new ArrayList<>();
+            for (int i = 0; i < threadCount; i++) {
+                clientIds.add(clientHelper.createClient());
+            }
+
+            final ExecutorService executorService = 
Executors.newFixedThreadPool(threadCount);
+            final CountDownLatch startLatch = new CountDownLatch(1);
+            final CountDownLatch doneLatch = new CountDownLatch(threadCount);
+            final List<Long> results = Collections.synchronizedList(new 
ArrayList<>());
+            final List<Exception> exceptions = 
Collections.synchronizedList(new ArrayList<>());
+
+            for (int i = 0; i < threadCount; i++) {
+                final Long clientId = clientIds.get(i);
+                executorService.execute(() -> {
+                    try {
+                        startLatch.await();
+                        final List<PostLoansOriginatorData> originators = 
List.of(
+                                new 
PostLoansOriginatorData().externalId(sharedOriginatorExternalId).name("Parallel 
Created Originator"));
+                        final Long loanId = 
loanHelper.createSubmittedLoanWithOriginators(clientId, productId, originators);
+                        results.add(loanId);
+                    } catch (final Exception e) {
+                        exceptions.add(e);
+                    } finally {
+                        doneLatch.countDown();
+                    }
+                });
+            }
+
+            startLatch.countDown();
+            assertTrue(doneLatch.await(30, TimeUnit.SECONDS), "All threads 
should complete within timeout");
+            executorService.shutdown();
+            assertTrue(executorService.awaitTermination(10, TimeUnit.SECONDS), 
"ExecutorService should terminate");
+
+            assertTrue(exceptions.isEmpty(),
+                    "Expected no exceptions but got " + exceptions.size() + ": 
" + exceptions.stream().map(Throwable::getMessage).toList());
+            assertEquals(threadCount, results.size(), "All loan applications 
should succeed");
+
+            // Verify all loans have the same originator attached
+            for (final Long loanId : results) {
+                final var loanDetails = 
loanHelper.getLoanDetailsWithAssociations(loanId, "originators");
+                assertNotNull(loanDetails.getOriginators());
+                assertEquals(1, loanDetails.getOriginators().size());
+                assertEquals(sharedOriginatorExternalId, 
loanDetails.getOriginators().get(0).getExternalId(),
+                        "All loans should reference the same originator");
+            }
+
+            // Cleanup
+            final var createdOriginator = 
originatorHelper.getOriginatorByExternalId(sharedOriginatorExternalId);
+            for (final Long loanId : results) {
+                originatorHelper.detachOriginatorFromLoan(loanId, 
createdOriginator.getId());
+            }
+            originatorHelper.deleteOriginator(createdOriginator.getId());
+        } finally {
+            configHelper.disableOriginatorCreationDuringLoanApplication();
+        }
+    }
 }

Reply via email to