FINERACT-2311: Add Buy Down Fees transaction support
This commit is contained in:
committed by
Adam Saghy
parent
b8d6dfa794
commit
53108227ae
+1
-3
@@ -70,10 +70,8 @@ public enum LoanTransactionType {
|
|||||||
CAPITALIZED_INCOME(35, "loanTransactionType.capitalizedIncome"), //
|
CAPITALIZED_INCOME(35, "loanTransactionType.capitalizedIncome"), //
|
||||||
CAPITALIZED_INCOME_AMORTIZATION(36, "loanTransactionType.capitalizedIncomeAmortization"), //
|
CAPITALIZED_INCOME_AMORTIZATION(36, "loanTransactionType.capitalizedIncomeAmortization"), //
|
||||||
CAPITALIZED_INCOME_ADJUSTMENT(37, "loanTransactionType.capitalizedIncomeAdjustment"), //
|
CAPITALIZED_INCOME_ADJUSTMENT(37, "loanTransactionType.capitalizedIncomeAdjustment"), //
|
||||||
CAPITALIZED_INCOME_AMORTIZATION_ADJUSTMENT(39, "loanTransactionType.capitalizedIncomeAmortizationAdjustment"), //
|
|
||||||
// Kind of Final Transactions
|
|
||||||
CONTRACT_TERMINATION(38, "loanTransactionType.contractTermination"), //
|
CONTRACT_TERMINATION(38, "loanTransactionType.contractTermination"), //
|
||||||
|
CAPITALIZED_INCOME_AMORTIZATION_ADJUSTMENT(39, "loanTransactionType.capitalizedIncomeAmortizationAdjustment"), //
|
||||||
BUY_DOWN_FEE(40, "loanTransactionType.buyDownFee"), //
|
BUY_DOWN_FEE(40, "loanTransactionType.buyDownFee"), //
|
||||||
BUY_DOWN_FEE_ADJUSTMENT(41, "loanTransactionType.buyDownFeeAdjustment"), //
|
BUY_DOWN_FEE_ADJUSTMENT(41, "loanTransactionType.buyDownFeeAdjustment"), //
|
||||||
BUY_DOWN_FEE_AMORTIZATION(42, "loanTransactionType.buyDownFeeAmortization"), //
|
BUY_DOWN_FEE_AMORTIZATION(42, "loanTransactionType.buyDownFeeAmortization"), //
|
||||||
|
|||||||
+1
@@ -61,4 +61,5 @@ public class LoanBuyDownFeeBalance extends AbstractAuditableWithUTCDateTimeCusto
|
|||||||
|
|
||||||
@Column(name = "amount_adjustment", scale = 6, precision = 19)
|
@Column(name = "amount_adjustment", scale = 6, precision = 19)
|
||||||
private BigDecimal amountAdjustment;
|
private BigDecimal amountAdjustment;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -689,7 +689,8 @@ public class LoanTransactionsApiResource {
|
|||||||
transactionData = this.loanReadPlatformService.retrieveLoanTransactionTemplate(resolvedLoanId,
|
transactionData = this.loanReadPlatformService.retrieveLoanTransactionTemplate(resolvedLoanId,
|
||||||
LoanTransactionType.CAPITALIZED_INCOME_ADJUSTMENT, transactionId);
|
LoanTransactionType.CAPITALIZED_INCOME_ADJUSTMENT, transactionId);
|
||||||
} else if (CommandParameterUtil.is(commandParam, LoanApiConstants.BUY_DOWN_FEE_COMMAND)) {
|
} else if (CommandParameterUtil.is(commandParam, LoanApiConstants.BUY_DOWN_FEE_COMMAND)) {
|
||||||
transactionData = this.loanReadPlatformService.retrieveLoanTransactionTemplate(resolvedLoanId);
|
transactionData = this.loanReadPlatformService.retrieveLoanTransactionTemplate(resolvedLoanId, LoanTransactionType.BUY_DOWN_FEE,
|
||||||
|
transactionId);
|
||||||
} else if (CommandParameterUtil.is(commandParam, LoanApiConstants.BUY_DOWN_FEE_ADJUSTMENT_COMMAND)) {
|
} else if (CommandParameterUtil.is(commandParam, LoanApiConstants.BUY_DOWN_FEE_ADJUSTMENT_COMMAND)) {
|
||||||
transactionData = this.loanReadPlatformService.retrieveLoanTransactionTemplate(resolvedLoanId,
|
transactionData = this.loanReadPlatformService.retrieveLoanTransactionTemplate(resolvedLoanId,
|
||||||
LoanTransactionType.BUY_DOWN_FEE_ADJUSTMENT, transactionId);
|
LoanTransactionType.BUY_DOWN_FEE_ADJUSTMENT, transactionId);
|
||||||
|
|||||||
+4
-4
@@ -33,7 +33,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
|||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanBuyDownFeeBalance;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanBuyDownFeeBalance;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
||||||
import org.apache.fineract.portfolio.loanaccount.repository.LoanBuyDownFeesBalanceRepository;
|
import org.apache.fineract.portfolio.loanaccount.repository.LoanBuyDownFeeBalanceRepository;
|
||||||
import org.apache.fineract.portfolio.loanaccount.util.BuyDownFeeAmortizationUtil;
|
import org.apache.fineract.portfolio.loanaccount.util.BuyDownFeeAmortizationUtil;
|
||||||
import org.springframework.lang.NonNull;
|
import org.springframework.lang.NonNull;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@@ -44,7 +44,7 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
public class LoanBuyDownFeeAmortizationProcessingServiceImpl implements LoanBuyDownFeeAmortizationProcessingService {
|
public class LoanBuyDownFeeAmortizationProcessingServiceImpl implements LoanBuyDownFeeAmortizationProcessingService {
|
||||||
|
|
||||||
private final LoanTransactionRepository loanTransactionRepository;
|
private final LoanTransactionRepository loanTransactionRepository;
|
||||||
private final LoanBuyDownFeesBalanceRepository loanBuyDownFeesBalanceRepository;
|
private final LoanBuyDownFeeBalanceRepository loanBuyDownFeeBalanceRepository;
|
||||||
private final BusinessEventNotifierService businessEventNotifierService;
|
private final BusinessEventNotifierService businessEventNotifierService;
|
||||||
private final LoanJournalEntryPoster journalEntryPoster;
|
private final LoanJournalEntryPoster journalEntryPoster;
|
||||||
private final ExternalIdFactory externalIdFactory;
|
private final ExternalIdFactory externalIdFactory;
|
||||||
@@ -55,7 +55,7 @@ public class LoanBuyDownFeeAmortizationProcessingServiceImpl implements LoanBuyD
|
|||||||
final List<Long> existingTransactionIds = loanTransactionRepository.findTransactionIdsByLoan(loan);
|
final List<Long> existingTransactionIds = loanTransactionRepository.findTransactionIdsByLoan(loan);
|
||||||
final List<Long> existingReversedTransactionIds = loanTransactionRepository.findReversedTransactionIdsByLoan(loan);
|
final List<Long> existingReversedTransactionIds = loanTransactionRepository.findReversedTransactionIdsByLoan(loan);
|
||||||
|
|
||||||
List<LoanBuyDownFeeBalance> balances = loanBuyDownFeesBalanceRepository.findAllByLoanId(loan.getId());
|
List<LoanBuyDownFeeBalance> balances = loanBuyDownFeeBalanceRepository.findAllByLoanId(loan.getId());
|
||||||
|
|
||||||
LocalDate maturityDate = loan.getMaturityDate() != null ? loan.getMaturityDate()
|
LocalDate maturityDate = loan.getMaturityDate() != null ? loan.getMaturityDate()
|
||||||
: getFinalBuyDownFeeAmortizationTransactionDate(loan);
|
: getFinalBuyDownFeeAmortizationTransactionDate(loan);
|
||||||
@@ -75,7 +75,7 @@ public class LoanBuyDownFeeAmortizationProcessingServiceImpl implements LoanBuyD
|
|||||||
.subtract(amortizationTillDate.getAmount()));
|
.subtract(amortizationTillDate.getAmount()));
|
||||||
}
|
}
|
||||||
|
|
||||||
loanBuyDownFeesBalanceRepository.saveAll(balances);
|
loanBuyDownFeeBalanceRepository.saveAll(balances);
|
||||||
|
|
||||||
BigDecimal totalAmortized = loanTransactionRepository.getAmortizedAmountBuyDownFee(loan);
|
BigDecimal totalAmortized = loanTransactionRepository.getAmortizedAmountBuyDownFee(loan);
|
||||||
BigDecimal totalAmortizationAmount = totalAmortization.getAmount().subtract(totalAmortized);
|
BigDecimal totalAmortizationAmount = totalAmortization.getAmount().subtract(totalAmortized);
|
||||||
|
|||||||
+27
-2
@@ -484,16 +484,41 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
|
|||||||
switch (transactionType) {
|
switch (transactionType) {
|
||||||
case CAPITALIZED_INCOME:
|
case CAPITALIZED_INCOME:
|
||||||
final Loan loan = loanRepositoryWrapper.findOneWithNotFoundDetection(loanId);
|
final Loan loan = loanRepositoryWrapper.findOneWithNotFoundDetection(loanId);
|
||||||
|
BigDecimal capitalizedIncomeBalance = BigDecimal.ZERO;
|
||||||
|
BigDecimal buyDownFeeBalance = BigDecimal.ZERO;
|
||||||
if (loan.getLoanProduct().getLoanProductRelatedDetail().isEnableIncomeCapitalization()) {
|
if (loan.getLoanProduct().getLoanProductRelatedDetail().isEnableIncomeCapitalization()) {
|
||||||
final BigDecimal capitalizedIncomeBalance = loanCapitalizedIncomeBalanceRepository.findAllByLoanId(loanId).stream()
|
capitalizedIncomeBalance = loanCapitalizedIncomeBalanceRepository.findAllByLoanId(loanId).stream()
|
||||||
.map(LoanCapitalizedIncomeBalance::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
|
.map(LoanCapitalizedIncomeBalance::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||||
transactionAmount = loan.getApprovedPrincipal().subtract(loan.getDisbursedAmount()).subtract(capitalizedIncomeBalance);
|
|
||||||
}
|
}
|
||||||
|
// Calculate Buy Down Fee balance to subtract from Capitalized Income formula
|
||||||
|
buyDownFeeBalance = loanBuyDownFeeBalanceRepository.findAllByLoanId(loanId).stream().map(LoanBuyDownFeeBalance::getAmount)
|
||||||
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||||
|
transactionAmount = loan.getApprovedPrincipal().subtract(loan.getDisbursedAmount()).subtract(capitalizedIncomeBalance)
|
||||||
|
.subtract(buyDownFeeBalance);
|
||||||
paymentOptions = this.paymentTypeReadPlatformService.retrieveAllPaymentTypes();
|
paymentOptions = this.paymentTypeReadPlatformService.retrieveAllPaymentTypes();
|
||||||
loanTransactionData = LoanTransactionData.loanTransactionDataForCreditTemplate(
|
loanTransactionData = LoanTransactionData.loanTransactionDataForCreditTemplate(
|
||||||
LoanEnumerations.transactionType(transactionType), DateUtils.getBusinessLocalDate(), transactionAmount,
|
LoanEnumerations.transactionType(transactionType), DateUtils.getBusinessLocalDate(), transactionAmount,
|
||||||
paymentOptions, retriveLoanCurrencyData(loanId));
|
paymentOptions, retriveLoanCurrencyData(loanId));
|
||||||
|
break;
|
||||||
|
case BUY_DOWN_FEE:
|
||||||
|
final Loan buyDownLoan = loanRepositoryWrapper.findOneWithNotFoundDetection(loanId);
|
||||||
|
BigDecimal buyDownFeeBalanceForCalc = BigDecimal.ZERO;
|
||||||
|
BigDecimal capitalizedIncomeBalanceForCalc = BigDecimal.ZERO;
|
||||||
|
|
||||||
|
// Calculate existing Buy Down Fee balance
|
||||||
|
buyDownFeeBalanceForCalc = loanBuyDownFeeBalanceRepository.findAllByLoanId(loanId).stream()
|
||||||
|
.map(LoanBuyDownFeeBalance::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||||
|
// Calculate Capitalized Income balance to subtract from Buy Down Fee formula
|
||||||
|
if (buyDownLoan.getLoanProduct().getLoanProductRelatedDetail().isEnableIncomeCapitalization()) {
|
||||||
|
capitalizedIncomeBalanceForCalc = loanCapitalizedIncomeBalanceRepository.findAllByLoanId(loanId).stream()
|
||||||
|
.map(LoanCapitalizedIncomeBalance::getAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||||
|
}
|
||||||
|
transactionAmount = buyDownLoan.getApprovedPrincipal().subtract(buyDownLoan.getDisbursedAmount())
|
||||||
|
.subtract(buyDownFeeBalanceForCalc).subtract(capitalizedIncomeBalanceForCalc);
|
||||||
|
paymentOptions = this.paymentTypeReadPlatformService.retrieveAllPaymentTypes();
|
||||||
|
loanTransactionData = LoanTransactionData.loanTransactionDataForCreditTemplate(
|
||||||
|
LoanEnumerations.transactionType(transactionType), DateUtils.getBusinessLocalDate(), transactionAmount,
|
||||||
|
paymentOptions, retriveLoanCurrencyData(loanId));
|
||||||
break;
|
break;
|
||||||
case CAPITALIZED_INCOME_ADJUSTMENT:
|
case CAPITALIZED_INCOME_ADJUSTMENT:
|
||||||
final LoanCapitalizedIncomeBalance loanCapitalizedIncomeBalance = loanCapitalizedIncomeBalanceRepository
|
final LoanCapitalizedIncomeBalance loanCapitalizedIncomeBalance = loanCapitalizedIncomeBalanceRepository
|
||||||
|
|||||||
+2
-2
@@ -567,10 +567,10 @@ public class LoanAccountConfiguration {
|
|||||||
@ConditionalOnMissingBean(LoanBuyDownFeeAmortizationProcessingService.class)
|
@ConditionalOnMissingBean(LoanBuyDownFeeAmortizationProcessingService.class)
|
||||||
public LoanBuyDownFeeAmortizationProcessingService loanBuyDownFeeAmortizationProcessingService(
|
public LoanBuyDownFeeAmortizationProcessingService loanBuyDownFeeAmortizationProcessingService(
|
||||||
final LoanTransactionRepository loanTransactionRepository,
|
final LoanTransactionRepository loanTransactionRepository,
|
||||||
final LoanBuyDownFeesBalanceRepository loanBuyDownFeesBalanceRepository,
|
final LoanBuyDownFeeBalanceRepository loanBuyDownFeeBalanceRepository,
|
||||||
final BusinessEventNotifierService businessEventNotifierService, final LoanJournalEntryPoster journalEntryPoster,
|
final BusinessEventNotifierService businessEventNotifierService, final LoanJournalEntryPoster journalEntryPoster,
|
||||||
final ExternalIdFactory externalIdFactory) {
|
final ExternalIdFactory externalIdFactory) {
|
||||||
return new LoanBuyDownFeeAmortizationProcessingServiceImpl(loanTransactionRepository, loanBuyDownFeesBalanceRepository,
|
return new LoanBuyDownFeeAmortizationProcessingServiceImpl(loanTransactionRepository, loanBuyDownFeeBalanceRepository,
|
||||||
businessEventNotifierService, journalEntryPoster, externalIdFactory);
|
businessEventNotifierService, journalEntryPoster, externalIdFactory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+29
@@ -208,4 +208,33 @@ public class LoanTransactionTest extends BaseLoanIntegrationTest {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetLoanTransactionTemplateForBuyDownFee() {
|
||||||
|
final PostClientsResponse client = clientHelper.createClient(ClientHelper.defaultClientCreationRequest());
|
||||||
|
|
||||||
|
final PostLoanProductsResponse loanProductsResponse = loanProductHelper
|
||||||
|
.createLoanProduct(create4IProgressive().enableIncomeCapitalization(true)
|
||||||
|
.capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT)
|
||||||
|
.capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION)
|
||||||
|
.deferredIncomeLiabilityAccountId(deferredIncomeLiabilityAccount.getAccountID().longValue())
|
||||||
|
.incomeFromCapitalizationAccountId(feeIncomeAccount.getAccountID().longValue())
|
||||||
|
.capitalizedIncomeType(PostLoanProductsRequest.CapitalizedIncomeTypeEnum.FEE));
|
||||||
|
|
||||||
|
final String loanExternalIdStr = UUID.randomUUID().toString();
|
||||||
|
|
||||||
|
runAt("20 December 2024", () -> {
|
||||||
|
Long loanId = applyAndApproveProgressiveLoan(client.getClientId(), loanProductsResponse.getResourceId(), "20 December 2024",
|
||||||
|
430.0, 7.0, 6, (request) -> request.externalId(loanExternalIdStr));
|
||||||
|
|
||||||
|
disburseLoan(loanId, BigDecimal.valueOf(230), "20 December 2024");
|
||||||
|
|
||||||
|
final GetLoansLoanIdTransactionsTemplateResponse transactionTemplate = loanTransactionHelper.retrieveTransactionTemplate(loanId,
|
||||||
|
buyDownFeeCommand, null, null, null);
|
||||||
|
|
||||||
|
assertNotNull(transactionTemplate);
|
||||||
|
assertEquals("loanTransactionType." + buyDownFeeCommand, transactionTemplate.getType().getCode());
|
||||||
|
assertEquals(transactionTemplate.getAmount(), 200);
|
||||||
|
assertThat(transactionTemplate.getPaymentTypeOptions().size() > 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-8
@@ -636,15 +636,15 @@ public class ExternalEventConfigurationHelper {
|
|||||||
loanTransactionUndoContractTerminationBusinessEvent.put("enabled", false);
|
loanTransactionUndoContractTerminationBusinessEvent.put("enabled", false);
|
||||||
defaults.add(loanTransactionUndoContractTerminationBusinessEvent);
|
defaults.add(loanTransactionUndoContractTerminationBusinessEvent);
|
||||||
|
|
||||||
Map<String, Object> loanBuyDownFeeTransactionCreatedBusinessEvent = new HashMap<>();
|
Map<String, Object> loanTransactionBuyDownFeePostBusinessEvent = new HashMap<>();
|
||||||
loanBuyDownFeeTransactionCreatedBusinessEvent.put("type", "LoanBuyDownFeeTransactionCreatedBusinessEvent");
|
loanTransactionBuyDownFeePostBusinessEvent.put("type", "LoanBuyDownFeeTransactionCreatedBusinessEvent");
|
||||||
loanBuyDownFeeTransactionCreatedBusinessEvent.put("enabled", false);
|
loanTransactionBuyDownFeePostBusinessEvent.put("enabled", false);
|
||||||
defaults.add(loanBuyDownFeeTransactionCreatedBusinessEvent);
|
defaults.add(loanTransactionBuyDownFeePostBusinessEvent);
|
||||||
|
|
||||||
Map<String, Object> loanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent = new HashMap<>();
|
Map<String, Object> loanTransactionBuyDownFeeAdjustmentPostBusinessEvent = new HashMap<>();
|
||||||
loanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent.put("type", "LoanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent");
|
loanTransactionBuyDownFeeAdjustmentPostBusinessEvent.put("type", "LoanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent");
|
||||||
loanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent.put("enabled", false);
|
loanTransactionBuyDownFeeAdjustmentPostBusinessEvent.put("enabled", false);
|
||||||
defaults.add(loanBuyDownFeeAdjustmentTransactionCreatedBusinessEvent);
|
defaults.add(loanTransactionBuyDownFeeAdjustmentPostBusinessEvent);
|
||||||
|
|
||||||
Map<String, Object> loanBuyDownFeeAmortizationTransactionCreatedBusinessEvent = new HashMap<>();
|
Map<String, Object> loanBuyDownFeeAmortizationTransactionCreatedBusinessEvent = new HashMap<>();
|
||||||
loanBuyDownFeeAmortizationTransactionCreatedBusinessEvent.put("type", "LoanBuyDownFeeAmortizationTransactionCreatedBusinessEvent");
|
loanBuyDownFeeAmortizationTransactionCreatedBusinessEvent.put("type", "LoanBuyDownFeeAmortizationTransactionCreatedBusinessEvent");
|
||||||
|
|||||||
Reference in New Issue
Block a user