Skip to content

Commit 8408a4c

Browse files
authored
Merge pull request #5739
FINERACT-2579: Batch entity lookups in generateLoanProvisioningEntry to eliminate per-row DB calls
2 parents 3b6b672 + 4bae9dc commit 8408a4c

2 files changed

Lines changed: 47 additions & 10 deletions

File tree

fineract-provider/src/main/java/org/apache/fineract/accounting/provisioning/service/ProvisioningEntriesWritePlatformServiceJpaRepositoryImpl.java

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,15 @@
2323
import java.util.Collection;
2424
import java.util.HashMap;
2525
import java.util.Map;
26+
import java.util.Set;
27+
import java.util.function.Function;
28+
import java.util.stream.Collectors;
29+
import java.util.stream.Stream;
2630
import lombok.RequiredArgsConstructor;
2731
import lombok.extern.slf4j.Slf4j;
2832
import org.apache.fineract.accounting.glaccount.domain.GLAccount;
2933
import org.apache.fineract.accounting.glaccount.domain.GLAccountRepository;
34+
import org.apache.fineract.accounting.glaccount.exception.GLAccountNotFoundException;
3035
import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService;
3136
import org.apache.fineract.accounting.provisioning.data.LoanProductProvisioningEntryData;
3237
import org.apache.fineract.accounting.provisioning.data.ProvisioningEntryData;
@@ -48,14 +53,16 @@
4853
import org.apache.fineract.organisation.monetary.domain.Money;
4954
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
5055
import org.apache.fineract.organisation.office.domain.Office;
51-
import org.apache.fineract.organisation.office.domain.OfficeRepositoryWrapper;
56+
import org.apache.fineract.organisation.office.domain.OfficeRepository;
57+
import org.apache.fineract.organisation.office.exception.OfficeNotFoundException;
5258
import org.apache.fineract.organisation.provisioning.data.ProvisioningCriteriaData;
5359
import org.apache.fineract.organisation.provisioning.domain.ProvisioningCategory;
5460
import org.apache.fineract.organisation.provisioning.domain.ProvisioningCategoryRepository;
5561
import org.apache.fineract.organisation.provisioning.service.ProvisioningCriteriaReadPlatformService;
5662
import org.apache.fineract.portfolio.PortfolioProductType;
5763
import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
5864
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository;
65+
import org.apache.fineract.portfolio.loanproduct.exception.LoanProductNotFoundException;
5966
import org.apache.fineract.useradministration.domain.AppUser;
6067
import org.springframework.dao.DataIntegrityViolationException;
6168
import org.springframework.orm.jpa.JpaSystemException;
@@ -68,7 +75,7 @@ public class ProvisioningEntriesWritePlatformServiceJpaRepositoryImpl implements
6875
private final ProvisioningCriteriaReadPlatformService provisioningCriteriaReadPlatformService;
6976
private final LoanProductRepository loanProductRepository;
7077
private final GLAccountRepository glAccountRepository;
71-
private final OfficeRepositoryWrapper officeRepositoryWrapper;
78+
private final OfficeRepository officeRepository;
7279
private final ProvisioningCategoryRepository provisioningCategoryRepository;
7380
private final PlatformSecurityContext platformSecurityContext;
7481
private final ProvisioningEntryRepository provisioningEntryRepository;
@@ -186,13 +193,43 @@ public CommandProcessingResult reCreateProvisioningEntries(Long provisioningEntr
186193
private Collection<LoanProductProvisioningEntry> generateLoanProvisioningEntry(ProvisioningEntry parent, LocalDate date) {
187194
Collection<LoanProductProvisioningEntryData> entries = this.provisioningEntriesReadPlatformService
188195
.retrieveLoanProductsProvisioningData(date);
196+
// Collect all referenced IDs upfront and bulk-fetch via findAllById,
197+
// replacing the previous pattern of N x 5 individual repository calls per
198+
// loop iteration (consistent with the optimisation in FINERACT-2561).
199+
Set<Long> productIds = entries.stream().map(LoanProductProvisioningEntryData::getProductId).collect(Collectors.toSet());
200+
Set<Long> officeIds = entries.stream().map(LoanProductProvisioningEntryData::getOfficeId).collect(Collectors.toSet());
201+
Set<Long> categoryIds = entries.stream().map(LoanProductProvisioningEntryData::getCategoryId).collect(Collectors.toSet());
202+
Set<Long> glAccountIds = entries.stream().flatMap(d -> Stream.of(d.getLiablityAccount(), d.getExpenseAccount()))
203+
.collect(Collectors.toSet());
204+
205+
Map<Long, LoanProduct> loanProductMap = loanProductRepository.findAllById(productIds).stream()
206+
.collect(Collectors.toMap(LoanProduct::getId, Function.identity()));
207+
Map<Long, Office> officeMap = officeRepository.findAllById(officeIds).stream()
208+
.collect(Collectors.toMap(Office::getId, Function.identity()));
209+
Map<Long, ProvisioningCategory> categoryMap = provisioningCategoryRepository.findAllById(categoryIds).stream()
210+
.collect(Collectors.toMap(ProvisioningCategory::getId, Function.identity()));
211+
Map<Long, GLAccount> glAccountMap = glAccountRepository.findAllById(glAccountIds).stream()
212+
.collect(Collectors.toMap(GLAccount::getId, Function.identity()));
213+
189214
Map<Integer, LoanProductProvisioningEntry> provisioningEntries = new HashMap<>();
190215
for (LoanProductProvisioningEntryData data : entries) {
191-
LoanProduct loanProduct = this.loanProductRepository.findById(data.getProductId()).orElseThrow();
192-
Office office = this.officeRepositoryWrapper.findOneWithNotFoundDetection(data.getOfficeId());
193-
ProvisioningCategory provisioningCategory = provisioningCategoryRepository.findById(data.getCategoryId()).orElse(null);
194-
GLAccount liabilityAccount = glAccountRepository.findById(data.getLiablityAccount()).orElseThrow();
195-
GLAccount expenseAccount = glAccountRepository.findById(data.getExpenseAccount()).orElseThrow();
216+
LoanProduct loanProduct = loanProductMap.get(data.getProductId());
217+
if (loanProduct == null) {
218+
throw new LoanProductNotFoundException(data.getProductId());
219+
}
220+
Office office = officeMap.get(data.getOfficeId());
221+
if (office == null) {
222+
throw new OfficeNotFoundException(data.getOfficeId());
223+
}
224+
GLAccount liabilityAccount = glAccountMap.get(data.getLiablityAccount());
225+
if (liabilityAccount == null) {
226+
throw new GLAccountNotFoundException(data.getLiablityAccount());
227+
}
228+
GLAccount expenseAccount = glAccountMap.get(data.getExpenseAccount());
229+
if (expenseAccount == null) {
230+
throw new GLAccountNotFoundException(data.getExpenseAccount());
231+
}
232+
ProvisioningCategory provisioningCategory = categoryMap.get(data.getCategoryId());
196233
MonetaryCurrency currency = loanProduct.getPrincipalAmount().getCurrency();
197234
Money money = Money.of(currency, data.getBalance());
198235
Money amountToReserve = money.percentageOf(data.getPercentage(), MoneyHelper.getMathContext());

fineract-provider/src/main/java/org/apache/fineract/accounting/provisioning/starter/AccountingProvisioningConfiguration.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
import org.apache.fineract.infrastructure.core.service.PaginationHelper;
3131
import org.apache.fineract.infrastructure.core.service.database.DatabaseSpecificSQLGenerator;
3232
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
33-
import org.apache.fineract.organisation.office.domain.OfficeRepositoryWrapper;
33+
import org.apache.fineract.organisation.office.domain.OfficeRepository;
3434
import org.apache.fineract.organisation.provisioning.domain.ProvisioningCategoryRepository;
3535
import org.apache.fineract.organisation.provisioning.service.ProvisioningCriteriaReadPlatformService;
3636
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository;
@@ -56,12 +56,12 @@ public ProvisioningEntriesReadPlatformService provisioningEntriesReadPlatformSer
5656
public ProvisioningEntriesWritePlatformService provisioningEntriesWritePlatformService(
5757
ProvisioningEntriesReadPlatformService provisioningEntriesReadPlatformService,
5858
ProvisioningCriteriaReadPlatformService provisioningCriteriaReadPlatformService, LoanProductRepository loanProductRepository,
59-
GLAccountRepository glAccountRepository, OfficeRepositoryWrapper officeRepositoryWrapper,
59+
GLAccountRepository glAccountRepository, OfficeRepository officeRepository,
6060
ProvisioningCategoryRepository provisioningCategoryRepository, PlatformSecurityContext platformSecurityContext,
6161
ProvisioningEntryRepository provisioningEntryRepository, JournalEntryWritePlatformService journalEntryWritePlatformService,
6262
ProvisioningEntriesDefinitionJsonDeserializer fromApiJsonDeserializer, FromJsonHelper fromApiJsonHelper) {
6363
return new ProvisioningEntriesWritePlatformServiceJpaRepositoryImpl(provisioningEntriesReadPlatformService,
64-
provisioningCriteriaReadPlatformService, loanProductRepository, glAccountRepository, officeRepositoryWrapper,
64+
provisioningCriteriaReadPlatformService, loanProductRepository, glAccountRepository, officeRepository,
6565
provisioningCategoryRepository, platformSecurityContext, provisioningEntryRepository, journalEntryWritePlatformService,
6666
fromApiJsonDeserializer, fromApiJsonHelper) {};
6767
}

0 commit comments

Comments
 (0)