FINERACT-2181: Fix integration test / unify getLoanRepaymentScheduleDetail()

This commit is contained in:
Adam Saghy
2025-06-06 15:08:40 +02:00
parent caf42f733c
commit 19b2a77127
12 changed files with 24 additions and 28 deletions
@@ -667,10 +667,6 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
return this.loanProduct; return this.loanProduct;
} }
public LoanProductRelatedDetail repaymentScheduleDetail() {
return this.loanRepaymentScheduleDetail;
}
public void updateClient(final Client client) { public void updateClient(final Client client) {
this.client = client; this.client = client;
} }
@@ -1347,7 +1343,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
} }
public Money getTotalOverpaidAsMoney() { public Money getTotalOverpaidAsMoney() {
return Money.of(this.repaymentScheduleDetail().getCurrency(), this.totalOverpaid); return Money.of(this.getLoanProductRelatedDetail().getCurrency(), this.totalOverpaid);
} }
public void updateIsInterestRecalculationEnabled() { public void updateIsInterestRecalculationEnabled() {
@@ -1512,7 +1508,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
public boolean isFeeCompoundingEnabledForInterestRecalculation() { public boolean isFeeCompoundingEnabledForInterestRecalculation() {
boolean isEnabled = false; boolean isEnabled = false;
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) { if (this.getLoanProductRelatedDetail().isInterestRecalculationEnabled()) {
isEnabled = this.loanInterestRecalculationDetails.getInterestRecalculationCompoundingMethod().isFeeCompoundingEnabled(); isEnabled = this.loanInterestRecalculationDetails.getInterestRecalculationCompoundingMethod().isFeeCompoundingEnabled();
} }
return isEnabled; return isEnabled;
@@ -1602,7 +1598,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
} }
return numberOfInstallments; return numberOfInstallments;
} }
return this.repaymentScheduleDetail().getNumberOfRepayments() + adjustNumberOfRepayments(); return this.getLoanProductRelatedDetail().getNumberOfRepayments() + adjustNumberOfRepayments();
} }
/* /*
@@ -86,7 +86,7 @@ public class LoanTermVariationsMapper {
CalendarHistoryDataWrapper calendarHistoryDataWrapper; CalendarHistoryDataWrapper calendarHistoryDataWrapper;
RepaymentStartDateType repaymentStartDateType = loan.getLoanProduct().getRepaymentStartDateType(); RepaymentStartDateType repaymentStartDateType = loan.getLoanProduct().getRepaymentStartDateType();
boolean allowCompoundingOnEod = false; boolean allowCompoundingOnEod = false;
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) { if (loan.getLoanProductRelatedDetail().isInterestRecalculationEnabled()) {
restCalendarInstance = scheduleGeneratorDTO.getCalendarInstanceForInterestRecalculation(); restCalendarInstance = scheduleGeneratorDTO.getCalendarInstanceForInterestRecalculation();
compoundingCalendarInstance = scheduleGeneratorDTO.getCompoundingCalendarInstance(); compoundingCalendarInstance = scheduleGeneratorDTO.getCompoundingCalendarInstance();
recalculationFrequencyType = loan.getLoanInterestRecalculationDetails().getRestFrequencyType(); recalculationFrequencyType = loan.getLoanInterestRecalculationDetails().getRestFrequencyType();
@@ -179,7 +179,7 @@ public class LoanDownPaymentHandlerServiceImpl implements LoanDownPaymentHandler
.reduce(BigDecimal.ZERO, BigDecimal::add); .reduce(BigDecimal.ZERO, BigDecimal::add);
final BigDecimal totalPrincipalCredited = totalDisbursed.add(totalPrincipalAdjusted).add(totalCapitalizedIncome); final BigDecimal totalPrincipalCredited = totalDisbursed.add(totalPrincipalAdjusted).add(totalCapitalizedIncome);
if (totalPrincipalCredited.compareTo(loan.getSummary().getTotalPrincipalRepaid()) < 0 if (totalPrincipalCredited.compareTo(loan.getSummary().getTotalPrincipalRepaid()) < 0
&& loan.repaymentScheduleDetail().getPrincipal().minus(totalDisbursed).isGreaterThanZero()) { && loan.getLoanProductRelatedDetail().getPrincipal().minus(totalDisbursed).isGreaterThanZero()) {
final String errorMessage = "The transaction amount cannot exceed threshold."; final String errorMessage = "The transaction amount cannot exceed threshold.";
throw new InvalidLoanStateTransitionException("transaction", "amount.exceeds.threshold", errorMessage); throw new InvalidLoanStateTransitionException("transaction", "amount.exceeds.threshold", errorMessage);
} }
@@ -1226,7 +1226,7 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
final MathContext mc = MoneyHelper.getMathContext(); final MathContext mc = MoneyHelper.getMathContext();
Loan loan = disbursementTransaction.getLoan(); Loan loan = disbursementTransaction.getLoan();
LoanProductRelatedDetail loanProductRelatedDetail = loan.getLoanRepaymentScheduleDetail(); LoanProductRelatedDetail loanProductRelatedDetail = loan.getLoanRepaymentScheduleDetail();
Integer installmentAmountInMultiplesOf = loan.getLoanProductRelatedDetail().getInstallmentAmountInMultiplesOf(); Integer installmentAmountInMultiplesOf = loanProductRelatedDetail.getInstallmentAmountInMultiplesOf();
List<LoanRepaymentScheduleInstallment> installments = transactionCtx.getInstallments(); List<LoanRepaymentScheduleInstallment> installments = transactionCtx.getInstallments();
LocalDate transactionDate = disbursementTransaction.getTransactionDate(); LocalDate transactionDate = disbursementTransaction.getTransactionDate();
MonetaryCurrency currency = transactionCtx.getCurrency(); MonetaryCurrency currency = transactionCtx.getCurrency();
@@ -529,12 +529,11 @@ class AdvancedPaymentScheduleTransactionProcessorTest {
LoanProductRelatedDetail loanProductRelatedDetail = mock(LoanProductRelatedDetail.class); LoanProductRelatedDetail loanProductRelatedDetail = mock(LoanProductRelatedDetail.class);
org.apache.fineract.portfolio.loanproduct.domain.LoanProduct loanProduct = mock( org.apache.fineract.portfolio.loanproduct.domain.LoanProduct loanProduct = mock(
org.apache.fineract.portfolio.loanproduct.domain.LoanProduct.class); org.apache.fineract.portfolio.loanproduct.domain.LoanProduct.class);
when(loanProduct.getInstallmentAmountInMultiplesOf()).thenReturn(null); when(loanProductRelatedDetail.getInstallmentAmountInMultiplesOf()).thenReturn(null);
when(loanProductRelatedDetail.isEnableDownPayment()).thenReturn(false); when(loanProductRelatedDetail.isEnableDownPayment()).thenReturn(false);
Loan loan = mock(Loan.class); Loan loan = mock(Loan.class);
when(loan.getLoanRepaymentScheduleDetail()).thenReturn(loanProductRelatedDetail); when(loan.getLoanRepaymentScheduleDetail()).thenReturn(loanProductRelatedDetail);
when(loan.getLoanProduct()).thenReturn(loanProduct);
when(loan.isInterestBearing()).thenReturn(true); when(loan.isInterestBearing()).thenReturn(true);
LoanRepaymentScheduleInstallment installment1 = spy( LoanRepaymentScheduleInstallment installment1 = spy(
@@ -215,8 +215,8 @@ public final class LoanApplicationValidator {
} }
validateLoanTermAndRepaidEveryValues(loan.getTermFrequency(), loan.getTermPeriodFrequencyType().getValue(), validateLoanTermAndRepaidEveryValues(loan.getTermFrequency(), loan.getTermPeriodFrequencyType().getValue(),
loan.repaymentScheduleDetail().getNumberOfRepayments(), loan.repaymentScheduleDetail().getRepayEvery(), loan.getLoanProductRelatedDetail().getNumberOfRepayments(), loan.getLoanProductRelatedDetail().getRepayEvery(),
loan.repaymentScheduleDetail().getRepaymentPeriodFrequencyType().getValue(), loan); loan.getLoanProductRelatedDetail().getRepaymentPeriodFrequencyType().getValue(), loan);
} }
public void validateForModify(final Loan loan) { public void validateForModify(final Loan loan) {
@@ -229,8 +229,8 @@ public final class LoanApplicationValidator {
} }
validateLoanTermAndRepaidEveryValues(loan.getTermFrequency(), loan.getTermPeriodFrequencyType().getValue(), validateLoanTermAndRepaidEveryValues(loan.getTermFrequency(), loan.getTermPeriodFrequencyType().getValue(),
loan.repaymentScheduleDetail().getNumberOfRepayments(), loan.repaymentScheduleDetail().getRepayEvery(), loan.getLoanProductRelatedDetail().getNumberOfRepayments(), loan.getLoanProductRelatedDetail().getRepayEvery(),
loan.repaymentScheduleDetail().getRepaymentPeriodFrequencyType().getValue(), loan); loan.getLoanProductRelatedDetail().getRepaymentPeriodFrequencyType().getValue(), loan);
} }
public void validateForCreate(JsonCommand command) { public void validateForCreate(JsonCommand command) {
@@ -233,12 +233,13 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
case DAILY -> CalendarFrequencyType.DAILY; case DAILY -> CalendarFrequencyType.DAILY;
case WEEKLY -> CalendarFrequencyType.WEEKLY; case WEEKLY -> CalendarFrequencyType.WEEKLY;
case MONTHLY -> CalendarFrequencyType.MONTHLY; case MONTHLY -> CalendarFrequencyType.MONTHLY;
case SAME_AS_REPAYMENT_PERIOD -> CalendarFrequencyType.from(loan.repaymentScheduleDetail().getRepaymentPeriodFrequencyType()); case SAME_AS_REPAYMENT_PERIOD ->
CalendarFrequencyType.from(loan.getLoanProductRelatedDetail().getRepaymentPeriodFrequencyType());
case INVALID -> CalendarFrequencyType.INVALID; case INVALID -> CalendarFrequencyType.INVALID;
}; };
if (recalculationFrequencyType == SAME_AS_REPAYMENT_PERIOD) { if (recalculationFrequencyType == SAME_AS_REPAYMENT_PERIOD) {
frequency = loan.repaymentScheduleDetail().getRepayEvery(); frequency = loan.getLoanProductRelatedDetail().getRepayEvery();
calendarStartDate = loan.getExpectedDisbursedOnLocalDate(); calendarStartDate = loan.getExpectedDisbursedOnLocalDate();
if (updatedRepeatsOnDay == null) { if (updatedRepeatsOnDay == null) {
updatedRepeatsOnDay = calendarStartDate.get(ChronoField.DAY_OF_WEEK); updatedRepeatsOnDay = calendarStartDate.get(ChronoField.DAY_OF_WEEK);
@@ -400,12 +401,12 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
} }
} }
} else { } else {
PeriodFrequencyType repaymentFrequencyType = loan.repaymentScheduleDetail().getRepaymentPeriodFrequencyType(); PeriodFrequencyType repaymentFrequencyType = loan.getLoanProductRelatedDetail().getRepaymentPeriodFrequencyType();
if (repaymentFrequencyType == PeriodFrequencyType.MONTHS) { if (repaymentFrequencyType == PeriodFrequencyType.MONTHS) {
final String title = "loan_schedule_" + loan.getId(); final String title = "loan_schedule_" + loan.getId();
final Integer typeId = CalendarType.COLLECTION.getValue(); final Integer typeId = CalendarType.COLLECTION.getValue();
final CalendarFrequencyType calendarFrequencyType = CalendarFrequencyType.MONTHLY; final CalendarFrequencyType calendarFrequencyType = CalendarFrequencyType.MONTHLY;
final Integer interval = loan.repaymentScheduleDetail().getRepayEvery(); final Integer interval = loan.getLoanProductRelatedDetail().getRepayEvery();
LocalDate startDate = loan.getExpectedFirstRepaymentOnDate(); LocalDate startDate = loan.getExpectedFirstRepaymentOnDate();
if (startDate == null) { if (startDate == null) {
startDate = loan.getExpectedDisbursedOnLocalDate(); startDate = loan.getExpectedDisbursedOnLocalDate();
@@ -775,7 +775,7 @@ public class LoanAssemblerImpl implements LoanAssembler {
changes.put(LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName, loan.getFixedPrincipalPercentagePerInstallment()); changes.put(LoanApiConstants.fixedPrincipalPercentagePerInstallmentParamName, loan.getFixedPrincipalPercentagePerInstallment());
} }
final LoanProductRelatedDetail productRelatedDetail = loan.repaymentScheduleDetail(); final LoanProductRelatedDetail productRelatedDetail = loan.getLoanProductRelatedDetail();
if (loan.loanProduct().getLoanConfigurableAttributes() != null) { if (loan.loanProduct().getLoanConfigurableAttributes() != null) {
loanScheduleAssembler.updateProductRelatedDetails(productRelatedDetail, loan); loanScheduleAssembler.updateProductRelatedDetails(productRelatedDetail, loan);
} }
@@ -249,7 +249,7 @@ public class LoanUtilService {
// immediately after disbursement date, // immediately after disbursement date,
// need to have minimum number of days gap between disbursement // need to have minimum number of days gap between disbursement
// and first repayment date. // and first repayment date.
final LoanProductRelatedDetail repaymentScheduleDetails = loan.repaymentScheduleDetail(); final LoanProductRelatedDetail repaymentScheduleDetails = loan.getLoanProductRelatedDetail();
// Not expecting to be null // Not expecting to be null
if (repaymentScheduleDetails != null) { if (repaymentScheduleDetails != null) {
final Integer repayEvery = repaymentScheduleDetails.getRepayEvery(); final Integer repayEvery = repaymentScheduleDetails.getRepayEvery();
@@ -273,7 +273,7 @@ public class LoanUtilService {
private LocalDate generateCalculatedRepaymentStartDate(final CalendarHistoryDataWrapper calendarHistoryDataWrapper, private LocalDate generateCalculatedRepaymentStartDate(final CalendarHistoryDataWrapper calendarHistoryDataWrapper,
LocalDate actualDisbursementDate, Loan loan) { LocalDate actualDisbursementDate, Loan loan) {
final LoanProductRelatedDetail repaymentScheduleDetails = loan.repaymentScheduleDetail(); final LoanProductRelatedDetail repaymentScheduleDetails = loan.getLoanProductRelatedDetail();
final WorkingDays workingDays = this.workingDaysRepository.findOne(); final WorkingDays workingDays = this.workingDaysRepository.findOne();
LocalDate calculatedRepaymentsStartingFromDate = null; LocalDate calculatedRepaymentsStartingFromDate = null;
@@ -415,7 +415,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
regenerateScheduleOnDisbursement(command, loan, recalculateSchedule, scheduleGeneratorDTO, nextPossibleRepaymentDate, regenerateScheduleOnDisbursement(command, loan, recalculateSchedule, scheduleGeneratorDTO, nextPossibleRepaymentDate,
rescheduledRepaymentDate); rescheduledRepaymentDate);
boolean downPaymentEnabled = loan.repaymentScheduleDetail().isEnableDownPayment(); boolean downPaymentEnabled = loan.getLoanProductRelatedDetail().isEnableDownPayment();
if (loan.isInterestBearingAndInterestRecalculationEnabled() || downPaymentEnabled) { if (loan.isInterestBearingAndInterestRecalculationEnabled() || downPaymentEnabled) {
createAndSaveLoanScheduleArchive(loan, scheduleGeneratorDTO); createAndSaveLoanScheduleArchive(loan, scheduleGeneratorDTO);
} }
@@ -786,7 +786,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom); final ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom);
regenerateScheduleOnDisbursement(command, loan, recalculateSchedule, scheduleGeneratorDTO, nextPossibleRepaymentDate, regenerateScheduleOnDisbursement(command, loan, recalculateSchedule, scheduleGeneratorDTO, nextPossibleRepaymentDate,
rescheduledRepaymentDate); rescheduledRepaymentDate);
boolean downPaymentEnabled = loan.repaymentScheduleDetail().isEnableDownPayment(); boolean downPaymentEnabled = loan.getLoanProductRelatedDetail().isEnableDownPayment();
if (loan.isInterestBearingAndInterestRecalculationEnabled() || downPaymentEnabled) { if (loan.isInterestBearingAndInterestRecalculationEnabled() || downPaymentEnabled) {
createAndSaveLoanScheduleArchive(loan, scheduleGeneratorDTO); createAndSaveLoanScheduleArchive(loan, scheduleGeneratorDTO);
} }
@@ -2340,7 +2340,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
loanDownPaymentTransactionValidator.validateAccountStatus(loan, LoanEvent.LOAN_EDIT_MULTI_DISBURSE_DATE); loanDownPaymentTransactionValidator.validateAccountStatus(loan, LoanEvent.LOAN_EDIT_MULTI_DISBURSE_DATE);
updateDisbursementDateAndAmountForTranche(loan, loanDisbursementDetails, command, changes, scheduleGeneratorDTO); updateDisbursementDateAndAmountForTranche(loan, loanDisbursementDetails, command, changes, scheduleGeneratorDTO);
} else { } else {
loan.repaymentScheduleDetail().setPrincipal(loan.getPrincipalAmountForRepaymentSchedule()); loan.getLoanProductRelatedDetail().setPrincipal(loan.getPrincipalAmountForRepaymentSchedule());
if (loan.isCumulativeSchedule() && loan.isInterestBearingAndInterestRecalculationEnabled()) { if (loan.isCumulativeSchedule() && loan.isInterestBearingAndInterestRecalculationEnabled()) {
loanScheduleService.regenerateRepaymentScheduleWithInterestRecalculation(loan, scheduleGeneratorDTO); loanScheduleService.regenerateRepaymentScheduleWithInterestRecalculation(loan, scheduleGeneratorDTO);
@@ -177,7 +177,7 @@ class LoanChargeWritePlatformServiceImplTest {
when(chargeDefinition.getChargeTimeType()).thenReturn(SPECIFIED_DUE_DATE); when(chargeDefinition.getChargeTimeType()).thenReturn(SPECIFIED_DUE_DATE);
when(chargeDefinition.getCurrencyCode()).thenReturn(CURRENCY_CODE); when(chargeDefinition.getCurrencyCode()).thenReturn(CURRENCY_CODE);
when(loanChargeAssembler.createNewFromJson(loan, chargeDefinition, jsonCommand)).thenReturn(loanCharge); when(loanChargeAssembler.createNewFromJson(loan, chargeDefinition, jsonCommand)).thenReturn(loanCharge);
when(loan.repaymentScheduleDetail()).thenReturn(loanRepaymentScheduleDetail); when(loan.getLoanProductRelatedDetail()).thenReturn(loanRepaymentScheduleDetail);
when(loanRepaymentScheduleDetail.getLoanScheduleType()).thenReturn(LoanScheduleType.CUMULATIVE); when(loanRepaymentScheduleDetail.getLoanScheduleType()).thenReturn(LoanScheduleType.CUMULATIVE);
when(loan.getLoanRepaymentScheduleDetail()).thenReturn(loanRepaymentScheduleDetail); when(loan.getLoanRepaymentScheduleDetail()).thenReturn(loanRepaymentScheduleDetail);
when(loan.hasCurrencyCodeOf(CURRENCY_CODE)).thenReturn(true); when(loan.hasCurrencyCodeOf(CURRENCY_CODE)).thenReturn(true);
@@ -162,7 +162,7 @@ public class LoanDownPaymentHandlerServiceImplTest {
when(loanRepaymentRelatedDetail.getInstallmentAmountInMultiplesOf()).thenReturn(10); when(loanRepaymentRelatedDetail.getInstallmentAmountInMultiplesOf()).thenReturn(10);
when(loanForProcessing.getLoanRepaymentScheduleDetail()).thenReturn(loanRepaymentRelatedDetail); when(loanForProcessing.getLoanRepaymentScheduleDetail()).thenReturn(loanRepaymentRelatedDetail);
when(loanForProcessing.repaymentScheduleDetail()).thenReturn(loanRepaymentRelatedDetail); when(loanForProcessing.getLoanProductRelatedDetail()).thenReturn(loanRepaymentRelatedDetail);
when(loanRepaymentRelatedDetail.isInterestRecalculationEnabled()).thenReturn(true); when(loanRepaymentRelatedDetail.isInterestRecalculationEnabled()).thenReturn(true);
when(loanForProcessing.isInterestBearingAndInterestRecalculationEnabled()).thenReturn(true); when(loanForProcessing.isInterestBearingAndInterestRecalculationEnabled()).thenReturn(true);
when(loanRepaymentRelatedDetail.getDisbursedAmountPercentageForDownPayment()).thenReturn(BigDecimal.valueOf(10)); when(loanRepaymentRelatedDetail.getDisbursedAmountPercentageForDownPayment()).thenReturn(BigDecimal.valueOf(10));