Skip to content

Commit 0e7791f

Browse files
Jose Alberto Hernandezadamsaghy
authored andcommitted
FINERACT-2311: Add Buy Down Fees transaction support
1 parent b8d6dfa commit 0e7791f

File tree

8 files changed

+76
-22
lines changed

8 files changed

+76
-22
lines changed

fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanTransactionType.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,8 @@ public enum LoanTransactionType {
7070
CAPITALIZED_INCOME(35, "loanTransactionType.capitalizedIncome"), //
7171
CAPITALIZED_INCOME_AMORTIZATION(36, "loanTransactionType.capitalizedIncomeAmortization"), //
7272
CAPITALIZED_INCOME_ADJUSTMENT(37, "loanTransactionType.capitalizedIncomeAdjustment"), //
73-
CAPITALIZED_INCOME_AMORTIZATION_ADJUSTMENT(39, "loanTransactionType.capitalizedIncomeAmortizationAdjustment"), //
74-
// Kind of Final Transactions
7573
CONTRACT_TERMINATION(38, "loanTransactionType.contractTermination"), //
76-
74+
CAPITALIZED_INCOME_AMORTIZATION_ADJUSTMENT(39, "loanTransactionType.capitalizedIncomeAmortizationAdjustment"), //
7775
BUY_DOWN_FEE(40, "loanTransactionType.buyDownFee"), //
7876
BUY_DOWN_FEE_ADJUSTMENT(41, "loanTransactionType.buyDownFeeAdjustment"), //
7977
BUY_DOWN_FEE_AMORTIZATION(42, "loanTransactionType.buyDownFeeAmortization"), //

fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanBuyDownFeeBalance.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,5 @@ public class LoanBuyDownFeeBalance extends AbstractAuditableWithUTCDateTimeCusto
6161

6262
@Column(name = "amount_adjustment", scale = 6, precision = 19)
6363
private BigDecimal amountAdjustment;
64+
6465
}

fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanTransactionsApiResource.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -689,7 +689,8 @@ private String retrieveTransactionTemplate(Long loanId, String loanExternalIdStr
689689
transactionData = this.loanReadPlatformService.retrieveLoanTransactionTemplate(resolvedLoanId,
690690
LoanTransactionType.CAPITALIZED_INCOME_ADJUSTMENT, transactionId);
691691
} else if (CommandParameterUtil.is(commandParam, LoanApiConstants.BUY_DOWN_FEE_COMMAND)) {
692-
transactionData = this.loanReadPlatformService.retrieveLoanTransactionTemplate(resolvedLoanId);
692+
transactionData = this.loanReadPlatformService.retrieveLoanTransactionTemplate(resolvedLoanId, LoanTransactionType.BUY_DOWN_FEE,
693+
transactionId);
693694
} else if (CommandParameterUtil.is(commandParam, LoanApiConstants.BUY_DOWN_FEE_ADJUSTMENT_COMMAND)) {
694695
transactionData = this.loanReadPlatformService.retrieveLoanTransactionTemplate(resolvedLoanId,
695696
LoanTransactionType.BUY_DOWN_FEE_ADJUSTMENT, transactionId);

fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanBuyDownFeeAmortizationProcessingServiceImpl.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
import org.apache.fineract.portfolio.loanaccount.domain.LoanBuyDownFeeBalance;
3434
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
3535
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
36-
import org.apache.fineract.portfolio.loanaccount.repository.LoanBuyDownFeesBalanceRepository;
36+
import org.apache.fineract.portfolio.loanaccount.repository.LoanBuyDownFeeBalanceRepository;
3737
import org.apache.fineract.portfolio.loanaccount.util.BuyDownFeeAmortizationUtil;
3838
import org.springframework.lang.NonNull;
3939
import org.springframework.stereotype.Component;
@@ -44,7 +44,7 @@
4444
public class LoanBuyDownFeeAmortizationProcessingServiceImpl implements LoanBuyDownFeeAmortizationProcessingService {
4545

4646
private final LoanTransactionRepository loanTransactionRepository;
47-
private final LoanBuyDownFeesBalanceRepository loanBuyDownFeesBalanceRepository;
47+
private final LoanBuyDownFeeBalanceRepository loanBuyDownFeeBalanceRepository;
4848
private final BusinessEventNotifierService businessEventNotifierService;
4949
private final LoanJournalEntryPoster journalEntryPoster;
5050
private final ExternalIdFactory externalIdFactory;
@@ -55,7 +55,7 @@ public void processBuyDownFeeAmortizationTillDate(@NonNull Loan loan, @NonNull L
5555
final List<Long> existingTransactionIds = loanTransactionRepository.findTransactionIdsByLoan(loan);
5656
final List<Long> existingReversedTransactionIds = loanTransactionRepository.findReversedTransactionIdsByLoan(loan);
5757

58-
List<LoanBuyDownFeeBalance> balances = loanBuyDownFeesBalanceRepository.findAllByLoanId(loan.getId());
58+
List<LoanBuyDownFeeBalance> balances = loanBuyDownFeeBalanceRepository.findAllByLoanId(loan.getId());
5959

6060
LocalDate maturityDate = loan.getMaturityDate() != null ? loan.getMaturityDate()
6161
: getFinalBuyDownFeeAmortizationTransactionDate(loan);
@@ -75,7 +75,7 @@ public void processBuyDownFeeAmortizationTillDate(@NonNull Loan loan, @NonNull L
7575
.subtract(amortizationTillDate.getAmount()));
7676
}
7777

78-
loanBuyDownFeesBalanceRepository.saveAll(balances);
78+
loanBuyDownFeeBalanceRepository.saveAll(balances);
7979

8080
BigDecimal totalAmortized = loanTransactionRepository.getAmortizedAmountBuyDownFee(loan);
8181
BigDecimal totalAmortizationAmount = totalAmortization.getAmount().subtract(totalAmortized);

fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -484,16 +484,41 @@ public LoanTransactionData retrieveLoanTransactionTemplate(final Long loanId, fi
484484
switch (transactionType) {
485485
case CAPITALIZED_INCOME:
486486
final Loan loan = loanRepositoryWrapper.findOneWithNotFoundDetection(loanId);
487+
BigDecimal capitalizedIncomeBalance = BigDecimal.ZERO;
488+
BigDecimal buyDownFeeBalance = BigDecimal.ZERO;
487489
if (loan.getLoanProduct().getLoanProductRelatedDetail().isEnableIncomeCapitalization()) {
488-
final BigDecimal capitalizedIncomeBalance = loanCapitalizedIncomeBalanceRepository.findAllByLoanId(loanId).stream()
490+
capitalizedIncomeBalance = loanCapitalizedIncomeBalanceRepository.findAllByLoanId(loanId).stream()
489491
.map(LoanCapitalizedIncomeBalance::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
490-
transactionAmount = loan.getApprovedPrincipal().subtract(loan.getDisbursedAmount()).subtract(capitalizedIncomeBalance);
491492
}
493+
// Calculate Buy Down Fee balance to subtract from Capitalized Income formula
494+
buyDownFeeBalance = loanBuyDownFeeBalanceRepository.findAllByLoanId(loanId).stream().map(LoanBuyDownFeeBalance::getAmount)
495+
.reduce(BigDecimal.ZERO, BigDecimal::add);
496+
transactionAmount = loan.getApprovedPrincipal().subtract(loan.getDisbursedAmount()).subtract(capitalizedIncomeBalance)
497+
.subtract(buyDownFeeBalance);
498+
paymentOptions = this.paymentTypeReadPlatformService.retrieveAllPaymentTypes();
499+
loanTransactionData = LoanTransactionData.loanTransactionDataForCreditTemplate(
500+
LoanEnumerations.transactionType(transactionType), DateUtils.getBusinessLocalDate(), transactionAmount,
501+
paymentOptions, retriveLoanCurrencyData(loanId));
502+
break;
503+
case BUY_DOWN_FEE:
504+
final Loan buyDownLoan = loanRepositoryWrapper.findOneWithNotFoundDetection(loanId);
505+
BigDecimal buyDownFeeBalanceForCalc = BigDecimal.ZERO;
506+
BigDecimal capitalizedIncomeBalanceForCalc = BigDecimal.ZERO;
507+
508+
// Calculate existing Buy Down Fee balance
509+
buyDownFeeBalanceForCalc = loanBuyDownFeeBalanceRepository.findAllByLoanId(loanId).stream()
510+
.map(LoanBuyDownFeeBalance::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
511+
// Calculate Capitalized Income balance to subtract from Buy Down Fee formula
512+
if (buyDownLoan.getLoanProduct().getLoanProductRelatedDetail().isEnableIncomeCapitalization()) {
513+
capitalizedIncomeBalanceForCalc = loanCapitalizedIncomeBalanceRepository.findAllByLoanId(loanId).stream()
514+
.map(LoanCapitalizedIncomeBalance::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
515+
}
516+
transactionAmount = buyDownLoan.getApprovedPrincipal().subtract(buyDownLoan.getDisbursedAmount())
517+
.subtract(buyDownFeeBalanceForCalc).subtract(capitalizedIncomeBalanceForCalc);
492518
paymentOptions = this.paymentTypeReadPlatformService.retrieveAllPaymentTypes();
493519
loanTransactionData = LoanTransactionData.loanTransactionDataForCreditTemplate(
494520
LoanEnumerations.transactionType(transactionType), DateUtils.getBusinessLocalDate(), transactionAmount,
495521
paymentOptions, retriveLoanCurrencyData(loanId));
496-
497522
break;
498523
case CAPITALIZED_INCOME_ADJUSTMENT:
499524
final LoanCapitalizedIncomeBalance loanCapitalizedIncomeBalance = loanCapitalizedIncomeBalanceRepository

fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountConfiguration.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -567,10 +567,10 @@ public LoanCapitalizedIncomeAmortizationProcessingService loanCapitalizedIncomeA
567567
@ConditionalOnMissingBean(LoanBuyDownFeeAmortizationProcessingService.class)
568568
public LoanBuyDownFeeAmortizationProcessingService loanBuyDownFeeAmortizationProcessingService(
569569
final LoanTransactionRepository loanTransactionRepository,
570-
final LoanBuyDownFeesBalanceRepository loanBuyDownFeesBalanceRepository,
570+
final LoanBuyDownFeeBalanceRepository loanBuyDownFeeBalanceRepository,
571571
final BusinessEventNotifierService businessEventNotifierService, final LoanJournalEntryPoster journalEntryPoster,
572572
final ExternalIdFactory externalIdFactory) {
573-
return new LoanBuyDownFeeAmortizationProcessingServiceImpl(loanTransactionRepository, loanBuyDownFeesBalanceRepository,
573+
return new LoanBuyDownFeeAmortizationProcessingServiceImpl(loanTransactionRepository, loanBuyDownFeeBalanceRepository,
574574
businessEventNotifierService, journalEntryPoster, externalIdFactory);
575575
}
576576
}

integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanTransactionTest.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,4 +208,33 @@ public void testGetLoanTransactionTemplateForBuyDownFeeAdjustment() {
208208
});
209209
}
210210

211+
@Test
212+
public void testGetLoanTransactionTemplateForBuyDownFee() {
213+
final PostClientsResponse client = clientHelper.createClient(ClientHelper.defaultClientCreationRequest());
214+
215+
final PostLoanProductsResponse loanProductsResponse = loanProductHelper
216+
.createLoanProduct(create4IProgressive().enableIncomeCapitalization(true)
217+
.capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT)
218+
.capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION)
219+
.deferredIncomeLiabilityAccountId(deferredIncomeLiabilityAccount.getAccountID().longValue())
220+
.incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue())
221+
.capitalizedIncomeType(PostLoanProductsRequest.CapitalizedIncomeTypeEnum.FEE));
222+
223+
final String loanExternalIdStr = UUID.randomUUID().toString();
224+
225+
runAt("20 December 2024", () -> {
226+
Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProductsResponse.getResourceId(), "20 December 2024",
227+
430.0, 7.0, 6, (request) -> request.externalId(loanExternalIdStr));
228+
229+
disburseLoan(loanId, BigDecimal.valueOf(230), "20 December 2024");
230+
231+
final GetLoansLoanIdTransactionsTemplateResponse transactionTemplate = loanTransactionHelper.retrieveTransactionTemplate(loanId,
232+
buyDownFeeCommand, null, null, null);
233+
234+
assertNotNull(transactionTemplate);
235+
assertEquals("loanTransactionType." + buyDownFeeCommand, transactionTemplate.getType().getCode());
236+
assertEquals(transactionTemplate.getAmount(), 200);
237+
assertThat(transactionTemplate.getPaymentTypeOptions().size() > 0);
238+
});
239+
}
211240
}

integration-tests/src/test/java/org/apache/fineract/integrationtests/common/ExternalEventConfigurationHelper.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -636,15 +636,15 @@ public static ArrayList<Map<String, Object>> getDefaultExternalEventConfiguratio
636636
loanTransactionUndoContractTerminationBusinessEvent.put("enabled", false);
637637
defaults.add(loanTransactionUndoContractTerminationBusinessEvent);
638638

639-
Map<String, Object> loanBuyDownFeeTransactionCreatedBusinessEvent = new HashMap<>();
640-
loanBuyDownFeeTransactionCreatedBusinessEvent.put("type", "LoanBuyDownFeeTransactionCreatedBusinessEvent");
641-
loanBuyDownFeeTransactionCreatedBusinessEvent.put("enabled", false);
642-
defaults.add(loanBuyDownFeeTransactionCreatedBusinessEvent);
643-
644-
Map<String, Object> loanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent = new HashMap<>();
645-
loanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent.put("type", "LoanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent");
646-
loanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent.put("enabled", false);
647-
defaults.add(loanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent);
639+
Map<String, Object> loanTransactionBuyDownFeePostBusinessEvent = new HashMap<>();
640+
loanTransactionBuyDownFeePostBusinessEvent.put("type", "LoanBuyDownFeeTransactionCreatedBusinessEvent");
641+
loanTransactionBuyDownFeePostBusinessEvent.put("enabled", false);
642+
defaults.add(loanTransactionBuyDownFeePostBusinessEvent);
643+
644+
Map<String, Object> loanTransactionBuyDownFeeAdjustmentPostBusinessEvent = new HashMap<>();
645+
loanTransactionBuyDownFeeAdjustmentPostBusinessEvent.put("type", "LoanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent");
646+
loanTransactionBuyDownFeeAdjustmentPostBusinessEvent.put("enabled", false);
647+
defaults.add(loanTransactionBuyDownFeeAdjustmentPostBusinessEvent);
648648

649649
Map<String, Object> loanBuyDownFeeAmortizationTransactionCreatedBusinessEvent = new HashMap<>();
650650
loanBuyDownFeeAmortizationTransactionCreatedBusinessEvent.put("type", "LoanBuyDownFeeAmortizationTransactionCreatedBusinessEvent");

0 commit comments

Comments
 (0)