FINERACT-1981: do not calculate interest for charge adjustment when the activities occur on the same day

This commit is contained in:
Oleksii Novikov
2024-10-25 09:55:59 +02:00
committed by Adam Saghy
parent 4198b0bcf9
commit 8a2560fe2e
11 changed files with 138 additions and 34 deletions
@@ -41,6 +41,7 @@ public enum DefaultLoanProduct implements LoanProduct {
LP2_DOWNPAYMENT_AUTO_ADVANCED_PAYMENT_ALLOCATION, //
LP2_DOWNPAYMENT_ADVANCED_PAYMENT_ALLOCATION, //
LP2_DOWNPAYMENT_INTEREST, LP2_DOWNPAYMENT_INTEREST_AUTO, //
LP2_ADV_CUST_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL, //
LP2_DOWNPAYMENT_ADV_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL, //
LP2_DOWNPAYMENT_ADV_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_VERTICAL, //
LP2_DOWNPAYMENT_ADV_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL_INSTALLMENT_LEVEL_DELINQUENCY, //
@@ -66,6 +66,7 @@ public class LoanProductsRequestFactory {
public static final String NAME_PREFIX_INTEREST_FLAT_LP2 = "LP2InterestFlat-";
public static final String NAME_PREFIX_INTEREST_DECLINING = "LP1InterestDeclining-";
public static final String NAME_PREFIX_INTEREST_DECLINING_RECALCULATION = "LP1InterestDecliningRecalculation-";
public static final String NAME_PREFIX_INTEREST_RECALCULATION_WITH_DOWN_PAYMENT_LP3 = "LP3InterestRecalculationWithDownPayment-";
public static final String NAME_PREFIX_LP2_EMI = "LP2Emi-";
public static final String SHORT_NAME_PREFIX = "p";
public static final String SHORT_NAME_PREFIX_INTEREST = "i";
@@ -94,8 +95,11 @@ public class LoanProductsRequestFactory {
public static final String TRANSACTION_PROCESSING_STRATEGY_CODE = TransactionProcessingStrategyCode.PENALTIES_FEES_INTEREST_PRINCIPAL_ORDER.value;
public static final String TRANSACTION_PROCESSING_STRATEGY_CODE_ADVANCED = TransactionProcessingStrategyCode.ADVANCED_PAYMENT_ALLOCATION.value;
public static final Integer DAYS_IN_YEAR_TYPE = DaysInYearType.ACTUAL.value;
public static final Integer DAYS_IN_YEAR_TYPE_360 = DaysInYearType.DAYS360.value;
public static final Integer DAYS_IN_MONTH_TYPE = DaysInMonthType.ACTUAL.value;
public static final Integer DAYS_IN_MONTH_TYPE_30 = DaysInMonthType.DAYS30.value;
public static final Integer LOAN_ACCOUNTING_RULE = AccountingRule.ACCRUAL_PERIODIC.value;
public static final Integer LOAN_ACCOUNTING_RULE_NONE = AccountingRule.NONE.value;
public static final String OVER_APPLIED_CALCULATION_TYPE = "percentage";
public static final Integer OVER_APPLIED_NUMBER = 50;
public static final Integer DELINQUENCY_BUCKET_ID = DelinquencyBucket.BASIC_DELINQUENCY_BUCKET.value;
@@ -657,6 +661,38 @@ public class LoanProductsRequestFactory {
.recalculationRestFrequencyInterval(1);//
}
public PostLoanProductsRequest defaultLoanProductsRequestLP2InterestDailyRecalculationWithDownPayment() {
final String name = Utils.randomNameGenerator(NAME_PREFIX_INTEREST_RECALCULATION_WITH_DOWN_PAYMENT_LP3, 4);
final String shortName = Utils.randomNameGenerator(SHORT_NAME_PREFIX_INTEREST, 3);
return new PostLoanProductsRequest().name(name).shortName(shortName)
.description(DESCRIPTION_INTEREST_DECLINING_BALANCE_DAILY_RECALCULATION_COMPOUNDING_NONE).startDate(null).closeDate(null)
.accountMovesOutOfNPAOnlyOnArrearsCompletion(false).accountingRule(LOAN_ACCOUNTING_RULE_NONE)
.allowApprovedDisbursedAmountsOverApplied(true)
.allowAttributeOverrides(new AllowAttributeOverrides().amortizationType(true).interestType(true)
.transactionProcessingStrategyCode(true).interestCalculationPeriodType(true).inArrearsTolerance(true)
.repaymentEvery(true).graceOnPrincipalAndInterestPayment(true).graceOnArrearsAgeing(true))
.allowPartialPeriodInterestCalcualtion(false).allowVariableInstallments(false).amortizationType(AMORTIZATION_TYPE)
.canDefineInstallmentAmount(true).canUseForTopup(false).charges(new ArrayList<>()).creditAllocation(new ArrayList<>())
.currencyCode(CURRENCY_CODE).dateFormat(DATE_FORMAT).daysInMonthType(DAYS_IN_MONTH_TYPE_30)
.daysInYearType(DAYS_IN_YEAR_TYPE_360).delinquencyBucketId(DELINQUENCY_BUCKET_ID.longValue()).digitsAfterDecimal(2)
.disallowExpectedDisbursements(true).dueDaysForRepaymentEvent(1).enableDownPayment(false)
.enableInstallmentLevelDelinquency(true).fixedLength(null).holdGuaranteeFunds(false).inMultiplesOf(0)
.includeInBorrowerCycle(false).interestCalculationPeriodType(0).interestRateFrequencyType(3).interestRatePerPeriod(9.99)
.interestRateVariationsForBorrowerCycle(new ArrayList<>()).interestRecalculationCompoundingMethod(0).interestType(0)
.isArrearsBasedOnOriginalSchedule(false).isEqualAmortization(false).isInterestRecalculationEnabled(true)
.isLinkedToFloatingInterestRates(false).loanScheduleProcessingType("HORIZONTAL").loanScheduleType("PROGRESSIVE")
.locale(LOCALE_EN).maxInterestRatePerPeriod((double) 50).maxNumberOfRepayments(48).maxPrincipal((double) 10000)
.maxTrancheCount(10).minInterestRatePerPeriod((double) 0).minNumberOfRepayments(1).minPrincipal((double) 1)
.multiDisburseLoan(true).numberOfRepaymentVariationsForBorrowerCycle(new ArrayList<>()).numberOfRepayments(3)
.outstandingLoanBalance((double) 10000).overAppliedCalculationType("flat").overAppliedNumber(10000)
.overDueDaysForRepaymentEvent(2).preClosureInterestCalculationStrategy(1).principal((double) 40)
.principalThresholdForLastInstallment(50).principalVariationsForBorrowerCycle(new ArrayList<>())
.recalculationRestFrequencyInterval(1).recalculationRestFrequencyType(2).repaymentEvery(1).repaymentFrequencyType(2L)
.repaymentStartDateType(2).rescheduleStrategyMethod(4).supportedInterestRefundTypes(new ArrayList<>())
.transactionProcessingStrategyCode(TRANSACTION_PROCESSING_STRATEGY_CODE_ADVANCED).useBorrowerCycle(false);
}
public PostLoanProductsRequest defaultLoanProductsRequestLP2() {
String name = Utils.randomNameGenerator(NAME_PREFIX_LP2, 4);
String shortName = Utils.randomNameGenerator(SHORT_NAME_PREFIX, 3);
@@ -548,6 +548,36 @@ public class LoanProductGlobalInitializerStep implements FineractGlobalInitializ
.createLoanProduct(loanProductsRequestLP2AdvPmtAllocProgressiveLoanScheduleHorizontal).execute();
TestContext.INSTANCE.set(TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL,
responseLP2AdvPmtAllocProgressiveLoanScheduleHorizontal);
// LP2 with Down-payment + advanced custom payment allocation + progressive loan schedule + horizontal
// (LP2_DOWNPAYMENT_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL)
String name44 = DefaultLoanProduct.LP2_ADV_CUST_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL.getName();
PostLoanProductsRequest loanProductsRequestAdvCustomPaymentAllocationProgressiveLoanSchedule = loanProductsRequestFactory
.defaultLoanProductsRequestLP2InterestDailyRecalculationWithDownPayment()//
.name(name44)//
.paymentAllocation(List.of(//
createPaymentAllocation("DEFAULT", "NEXT_INSTALLMENT",
LoanProductPaymentAllocationRule.AllocationTypesEnum.PAST_DUE_INTEREST, //
LoanProductPaymentAllocationRule.AllocationTypesEnum.PAST_DUE_PRINCIPAL, //
LoanProductPaymentAllocationRule.AllocationTypesEnum.PAST_DUE_PENALTY, //
LoanProductPaymentAllocationRule.AllocationTypesEnum.PAST_DUE_FEE, //
LoanProductPaymentAllocationRule.AllocationTypesEnum.DUE_INTEREST, //
LoanProductPaymentAllocationRule.AllocationTypesEnum.DUE_PRINCIPAL, //
LoanProductPaymentAllocationRule.AllocationTypesEnum.DUE_PENALTY, //
LoanProductPaymentAllocationRule.AllocationTypesEnum.DUE_FEE, //
LoanProductPaymentAllocationRule.AllocationTypesEnum.IN_ADVANCE_INTEREST, //
LoanProductPaymentAllocationRule.AllocationTypesEnum.IN_ADVANCE_PRINCIPAL, //
LoanProductPaymentAllocationRule.AllocationTypesEnum.IN_ADVANCE_PENALTY, //
LoanProductPaymentAllocationRule.AllocationTypesEnum.IN_ADVANCE_FEE), //
createPaymentAllocation("GOODWILL_CREDIT", "LAST_INSTALLMENT"), //
createPaymentAllocation("MERCHANT_ISSUED_REFUND", "REAMORTIZATION"), //
createPaymentAllocation("PAYOUT_REFUND", "NEXT_INSTALLMENT")));//
Response<PostLoanProductsResponse> responseLoanProductsRequestAdvCustomPaymentAllocationProgressiveLoanSchedule = loanProductsApi
.createLoanProduct(loanProductsRequestAdvCustomPaymentAllocationProgressiveLoanSchedule).execute();
TestContext.INSTANCE.set(
TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADVANCED_CUSTOM_PAYMENT_ALLOCATION_PROGRESSIVE_LOAN_SCHEDULE,
responseLoanProductsRequestAdvCustomPaymentAllocationProgressiveLoanSchedule);
}
public static AdvancedPaymentData createPaymentAllocation(String transactionType, String futureInstallmentAllocationRule,
@@ -1141,13 +1141,10 @@ public class LoanStepDef extends AbstractStepDef {
List<List<String>> data = table.asLists();
for (int i = 1; i < data.size(); i++) {
List<String> expectedValues = data.get(i);
String transactionDateExpected = expectedValues.get(0);
List<List<String>> actualValuesList = transactions.stream()//
.filter(t -> transactionDateExpected.equals(FORMATTER.format(t.getDate())))//
.map(t -> fetchValuesOfTransaction(table.row(0), t))//
.collect(Collectors.toList());//
boolean containsExpectedValues = actualValuesList.stream()//
.anyMatch(actualValues -> actualValues.equals(expectedValues));//
boolean containsExpectedValues = actualValuesList.get(i - 1).equals(expectedValues);//
assertThat(containsExpectedValues).as(ErrorMessageHelper.wrongValueInLineInTransactionsTab(i, actualValuesList, expectedValues))
.isTrue();
}
@@ -61,6 +61,7 @@ public abstract class TestContextKey {
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_INTEREST_DECLINING_PERIOD_SAME_AS_PAYMENT = "loanProductCreateResponseLP1InterestDecliningPeriodSameAsPayment";
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_1MONTH_INTEREST_DECLINING_BALANCE_DAILY_RECALCULATION_COMPOUNDING_MONTHLY = "loanProductCreateResponseLP1InterestDecliningPeriodSameAsPaymentRecalculation";
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_INTEREST_DECLINING_BALANCE_DAILY_RECALCULATION_COMPOUNDING_NONE = "loanProductCreateResponseLP1InterestDecliningBalanceDailyRecalculationCompoundingNone";
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADVANCED_CUSTOM_PAYMENT_ALLOCATION_PROGRESSIVE_LOAN_SCHEDULE = "loanProductCreateResponseLP2ProgressiveLoanScheduleCustomPaymentAllocation";
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_INTEREST_DECLINING_BALANCE_DAILY_RECALCULATION_SAME_AS_REPAYMENT_COMPOUNDING_NONE = "loanProductCreateResponseLP1InterestDecliningBalanceDailyRecalculationSameAsRepaymentCompoundingNone";
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_INTEREST_DECLINING_BALANCE_SAR_RECALCULATION_SAME_AS_REPAYMENT_COMPOUNDING_NONE_MULTI_DISBURSEMENT = "loanProductCreateResponseLP1InterestDecliningBalanceDailyRecalculationSameAsRepaymentCompoundingNoneMultiDisbursement";
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_INTEREST_DECLINING_BALANCE_DAILY_RECALCULATION_COMPOUNDING_NONE_RESCHEDULE_REDUCE_NR_INSTALLMENTS = "loanProductCreateResponseLP1InterestDecliningBalanceDailyRecalculationCompoundingNoneRescheduleReduceNrInstallments";