FINERACT-2405: totalUnpaidPayableNotDueInterest resets to 0 on Charge-Off

This commit is contained in:
Jose Alberto Hernandez
2025-11-19 19:58:33 +01:00
committed by Adam Saghy
parent 2681ee3518
commit 47e8674fa0
7 changed files with 177 additions and 4 deletions
@@ -177,6 +177,7 @@ public enum DefaultLoanProduct implements LoanProduct {
LP2_ADV_CUSTOM_PMT_ALLOC_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_INTEREST_RECALC_ZERO_CHARGE_OFF_ACCRUAL, //
LP1_INTEREST_FLAT_DAILY_RECALCULATION_SAR_MULTIDISB_EXPECT_TRANCHES, //
LP1_INTEREST_FLAT_DAILY_ACTUAL_ACTUAL_MULTIDISB_EXPECT_TRANCHES, //
LP2_ADV_PYMNT_360_30_ZERO_INTEREST_CHARGE_OFF_ACCRUAL_ACTIVITY, //
;
@Override
@@ -403,6 +403,14 @@ public final class ErrorMessageHelper {
actualToStr, expectedToStr);
}
public static String wrongAmountInTotalUnpaidPayableNotDueInterest(Double actual, Double expected) {
String actualToStr = actual.toString();
String expectedToStr = expected.toString();
return String.format(
"Wrong amount in Loan total unpaid payable not due interest. Actual amount is: %s - But expected amount is: %s",
actualToStr, expectedToStr);
}
public static String wrongAmountInTotalOverdue(Double actual, Double expected) {
String actualToStr = actual.toString();
String expectedToStr = expected.toString();
@@ -4172,10 +4172,9 @@ public class LoanProductGlobalInitializerStep implements FineractGlobalInitializ
// LP2 advanced + progressive loan schedule + horizontal + interest recalculation
// Frequency for recalculate Outstanding Principal: Daily, Frequency Interval for recalculation: 1
String name150 = DefaultLoanProduct.LP2_ADV_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_INTEREST_RECALC_ZERO_CHARGE_OF_ACCRUAL.getName();
PostLoanProductsRequest loanProductsResponseAdvCustomPaymentAllocationProgressiveLoanInterestDailyEmiActualInterestRecalcZeroChargeOffChargebackAccruals = loanProductsRequestFactory
.defaultLoanProductsRequestLP2Emi()//
.name(name150)//
.name(DefaultLoanProduct.LP2_ADV_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_INTEREST_RECALC_ZERO_CHARGE_OF_ACCRUAL.getName())//
.supportedInterestRefundTypes(supportedInterestRefundTypes).installmentAmountInMultiplesOf(null) //
.daysInYearType(DaysInYearType.ACTUAL.value)//
.daysInMonthType(DaysInMonthType.ACTUAL.value)//
@@ -4218,6 +4217,23 @@ public class LoanProductGlobalInitializerStep implements FineractGlobalInitializ
TestContext.INSTANCE.set(TestContextKey.LP1_INTEREST_FLAT_DAILY_RECALCULATION_SAR_MULTIDISB_EXPECT_TRANCHES,
responseLoanProductsRequestInterestFlatSaRRecalculationSameAsRepaymentMultiDisbursementExpectsTranches);
// LP2 + zero-interest chargeOff behaviour + progressive loan schedule + horizontal
// (LP2_ADV_PYMNT_360_30_ZERO_INTEREST_CHARGE_OFF_ACCRUAL_ACTIVITY)
final PostLoanProductsRequest loanProductsRequestAdvZeroInterestChargeOffBehaviourAccrualActivity = loanProductsRequestFactory
.defaultLoanProductsRequestLP2Emi()//
.name(DefaultLoanProduct.LP2_ADV_PYMNT_360_30_ZERO_INTEREST_CHARGE_OFF_ACCRUAL_ACTIVITY.getName())//
.daysInYearType(DaysInYearType.DAYS360.value)//
.daysInMonthType(DaysInMonthType.DAYS30.value)//
.paymentAllocation(List.of(//
createPaymentAllocation("DEFAULT", "NEXT_INSTALLMENT")))
.enableAccrualActivityPosting(true)//
.chargeOffBehaviour("ZERO_INTEREST");//
final Response<PostLoanProductsResponse> responseLoanProductsRequestAdvZeroInterestChargeOffBehaviourAccrualActivity = loanProductsApi
.createLoanProduct(loanProductsRequestAdvZeroInterestChargeOffBehaviourAccrualActivity).execute();
TestContext.INSTANCE.set(
TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_360_30_ZERO_INTEREST_CHARGE_OFF_ACCRUAL_ACTIVITY,
responseLoanProductsRequestAdvZeroInterestChargeOffBehaviourAccrualActivity);
// LP1 with 12% Flat interest, interest period: Daily, Interest recalculation- Actual
// Multi-disbursement that expects tranches
PostLoanProductsRequest loanProductsRequestInterestFlatActualActualMultiDisbursementExpectsTranches = loanProductsRequestFactory
@@ -6060,6 +6060,23 @@ public class LoanStepDef extends AbstractStepDef {
checkLoanAmortizationAllocationMappingData(resourceId, loanAmortizationAllocationResponse.body(), table);
}
@Then("Loan has {double} total unpaid payable not due interest")
public void loanTotalUnpaidPayableNotDueInterest(double totalUnpaidPayableNotDueInterestExpected) throws IOException {
Response<PostLoansResponse> loanCreateResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
long loanId = loanCreateResponse.body().getLoanId();
Response<GetLoansLoanIdResponse> loanDetailsResponse = loansApi.retrieveLoan(loanId, false, "repaymentSchedule", "", "").execute();
ErrorHelper.checkSuccessfulApiCall(loanDetailsResponse);
testContext().set(TestContextKey.LOAN_RESPONSE, loanDetailsResponse);
Double totalUnpaidPayableNotDueInterestActual = loanDetailsResponse.body().getSummary().getTotalUnpaidPayableNotDueInterest()
.doubleValue();
assertThat(totalUnpaidPayableNotDueInterestActual)
.as(ErrorMessageHelper.wrongAmountInTotalUnpaidPayableNotDueInterest(totalUnpaidPayableNotDueInterestActual,
totalUnpaidPayableNotDueInterestExpected))
.isEqualTo(totalUnpaidPayableNotDueInterestExpected);
}
private void checkLoanAmortizationAllocationMappingData(final String resourceId,
final LoanAmortizationAllocationResponse amortizationAllocationResponse, final DataTable table) {
final List<List<String>> data = table.asLists();
@@ -284,4 +284,5 @@ public abstract class TestContextKey {
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_CUSTOM_PMT_ALLOC_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_INTEREST_RECALC_ZERO_CHARGE_OFF_ACCRUAL = "loanProductCreateResponseLP2AdvancedPaymentCustomAllocationInterestDailyEmiActualInterestRecalcChargeOffAccruals";
public static final String LP1_INTEREST_FLAT_DAILY_RECALCULATION_SAR_MULTIDISB_EXPECT_TRANCHES = "loanProductCreateResponseLP1InterestFlatDailyRecalculationSameAsRepaymentMultiDisbursementExpectTranches";
public static final String LP1_INTEREST_FLAT_DAILY_ACTUAL_ACTUAL_MULTIDISB_EXPECT_TRANCHES = "loanProductCreateResponseLP1InterestFlatDailyActualActualMultiDisbursementExpectTranches";
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_360_30_ZERO_INTEREST_CHARGE_OFF_ACCRUAL_ACTIVITY = "loanProductCreateResponseLP2AdvancedPaymentZeroInterestChargeOffBehaviourAccrualActivity";
}