Skip to content

Commit 4bae9dc

Browse files
FINERACT-2579: Batch entity lookups in generateLoanProvisioningEntry to eliminate per-row DB calls
1 parent c3434d6 commit 4bae9dc

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;
@@ -177,13 +184,43 @@ public CommandProcessingResult reCreateProvisioningEntries(Long provisioningEntr
177184
private Collection<LoanProductProvisioningEntry> generateLoanProvisioningEntry(ProvisioningEntry parent, LocalDate date) {
178185
Collection<LoanProductProvisioningEntryData> entries = this.provisioningEntriesReadPlatformService
179186
.retrieveLoanProductsProvisioningData(date);
187+
// Collect all referenced IDs upfront and bulk-fetch via findAllById,
188+
// replacing the previous pattern of N x 5 individual repository calls per
189+
// loop iteration (consistent with the optimisation in FINERACT-2561).
190+
Set<Long> productIds = entries.stream().map(LoanProductProvisioningEntryData::getProductId).collect(Collectors.toSet());
191+
Set<Long> officeIds = entries.stream().map(LoanProductProvisioningEntryData::getOfficeId).collect(Collectors.toSet());
192+
Set<Long> categoryIds = entries.stream().map(LoanProductProvisioningEntryData::getCategoryId).collect(Collectors.toSet());
193+
Set<Long> glAccountIds = entries.stream().flatMap(d -> Stream.of(d.getLiablityAccount(), d.getExpenseAccount()))
194+
.collect(Collectors.toSet());
195+
196+
Map<Long, LoanProduct> loanProductMap = loanProductRepository.findAllById(productIds).stream()
197+
.collect(Collectors.toMap(LoanProduct::getId, Function.identity()));
198+
Map<Long, Office> officeMap = officeRepository.findAllById(officeIds).stream()
199+
.collect(Collectors.toMap(Office::getId, Function.identity()));
200+
Map<Long, ProvisioningCategory> categoryMap = provisioningCategoryRepository.findAllById(categoryIds).stream()
201+
.collect(Collectors.toMap(ProvisioningCategory::getId, Function.identity()));
202+
Map<Long, GLAccount> glAccountMap = glAccountRepository.findAllById(glAccountIds).stream()
203+
.collect(Collectors.toMap(GLAccount::getId, Function.identity()));
204+
180205
Map<Integer, LoanProductProvisioningEntry> provisioningEntries = new HashMap<>();
181206
for (LoanProductProvisioningEntryData data : entries) {
182-
LoanProduct loanProduct = this.loanProductRepository.findById(data.getProductId()).orElseThrow();
183-
Office office = this.officeRepositoryWrapper.findOneWithNotFoundDetection(data.getOfficeId());
184-
ProvisioningCategory provisioningCategory = provisioningCategoryRepository.findById(data.getCategoryId()).orElse(null);
185-
GLAccount liabilityAccount = glAccountRepository.findById(data.getLiablityAccount()).orElseThrow();
186-
GLAccount expenseAccount = glAccountRepository.findById(data.getExpenseAccount()).orElseThrow();
207+
LoanProduct loanProduct = loanProductMap.get(data.getProductId());
208+
if (loanProduct == null) {
209+
throw new LoanProductNotFoundException(data.getProductId());
210+
}
211+
Office office = officeMap.get(data.getOfficeId());
212+
if (office == null) {
213+
throw new OfficeNotFoundException(data.getOfficeId());
214+
}
215+
GLAccount liabilityAccount = glAccountMap.get(data.getLiablityAccount());
216+
if (liabilityAccount == null) {
217+
throw new GLAccountNotFoundException(data.getLiablityAccount());
218+
}
219+
GLAccount expenseAccount = glAccountMap.get(data.getExpenseAccount());
220+
if (expenseAccount == null) {
221+
throw new GLAccountNotFoundException(data.getExpenseAccount());
222+
}
223+
ProvisioningCategory provisioningCategory = categoryMap.get(data.getCategoryId());
187224
MonetaryCurrency currency = loanProduct.getPrincipalAmount().getCurrency();
188225
Money money = Money.of(currency, data.getBalance());
189226
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)