FINERACT-2433/fix-interest-accrual-calculation - E2E test

This commit is contained in:
Peter Kovacs
2026-01-08 12:22:48 +01:00
committed by Adam Saghy
parent 8b3c8280de
commit 9003034b34
5 changed files with 289 additions and 0 deletions
@@ -180,6 +180,7 @@ public enum DefaultLoanProduct implements LoanProduct {
LP1_INTEREST_FLAT_DAILY_ACTUAL_ACTUAL_MULTIDISB_EXPECT_TRANCHES, // LP1_INTEREST_FLAT_DAILY_ACTUAL_ACTUAL_MULTIDISB_EXPECT_TRANCHES, //
LP2_ADV_PYMNT_360_30_ZERO_INTEREST_CHARGE_OFF_ACCRUAL_ACTIVITY, // LP2_ADV_PYMNT_360_30_ZERO_INTEREST_CHARGE_OFF_ACCRUAL_ACTIVITY, //
LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL_PRINCIPAL_FIRST, // LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL_PRINCIPAL_FIRST, //
LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL_360_30_USD, //
; ;
@Override @Override
@@ -22,6 +22,7 @@ import static org.apache.fineract.test.data.TransactionProcessingStrategyCode.AD
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@@ -94,6 +95,7 @@ public class LoanProductsRequestFactory {
public static final String DESCRIPTION_INTEREST_DECLINING_BALANCE_DAILY_RECALCULATION_COMPOUNDING_NONE = "LP1 with 12% DECLINING BALANCE interest, interest period: Daily, Interest recalculation-Daily, Compounding:none"; public static final String DESCRIPTION_INTEREST_DECLINING_BALANCE_DAILY_RECALCULATION_COMPOUNDING_NONE = "LP1 with 12% DECLINING BALANCE interest, interest period: Daily, Interest recalculation-Daily, Compounding:none";
public static final Long FUND_ID = FundId.LENDER_A.value; public static final Long FUND_ID = FundId.LENDER_A.value;
public static final String CURRENCY_CODE = "EUR"; public static final String CURRENCY_CODE = "EUR";
public static final String CURRENCY_CODE_USD = "USD";
public static final Integer INTEREST_RATE_FREQUENCY_TYPE_MONTH = InterestRateFrequencyType.MONTH.value; public static final Integer INTEREST_RATE_FREQUENCY_TYPE_MONTH = InterestRateFrequencyType.MONTH.value;
public static final Integer INTEREST_RATE_FREQUENCY_TYPE_YEAR = InterestRateFrequencyType.YEAR.value; public static final Integer INTEREST_RATE_FREQUENCY_TYPE_YEAR = InterestRateFrequencyType.YEAR.value;
public static final Integer INTEREST_RATE_FREQUENCY_TYPE_WHOLE_TERM = InterestRateFrequencyType.WHOLE_TERM.value; public static final Integer INTEREST_RATE_FREQUENCY_TYPE_WHOLE_TERM = InterestRateFrequencyType.WHOLE_TERM.value;
@@ -1779,6 +1781,110 @@ public class LoanProductsRequestFactory {
.chargeOffReasonToExpenseAccountMappings(chargeOffReasonToExpenseAccountMappings);// .chargeOffReasonToExpenseAccountMappings(chargeOffReasonToExpenseAccountMappings);//
} }
public PostLoanProductsRequest defaultLoanProductsRequestLP2EmiUSD() {
String name = Utils.randomNameGenerator(NAME_PREFIX_LP2_EMI, 10);
String shortName = generateShortNameSafely();
List<Integer> principalVariationsForBorrowerCycle = new ArrayList<>();
List<Integer> numberOfRepaymentVariationsForBorrowerCycle = new ArrayList<>();
List<Integer> interestRateVariationsForBorrowerCycle = new ArrayList<>();
return new PostLoanProductsRequest()//
.name(name)//
.shortName(shortName)//
.description(DESCRIPTION_LP2_EMI)//
.includeInBorrowerCycle(false)//
.useBorrowerCycle(false)//
.currencyCode(CURRENCY_CODE_USD)//
.digitsAfterDecimal(2)//
.inMultiplesOf(0)//
.principal(1500.0)//
.minPrincipal(1.0)//
.maxPrincipal(10000.0)//
.numberOfRepayments(3)//
.minNumberOfRepayments(3)//
.maxNumberOfRepayments(48)//
.repaymentEvery(1)//
.repaymentFrequencyType(REPAYMENT_FREQUENCY_TYPE_MONTHS)//
.interestRatePerPeriod(9.99)//
.minInterestRatePerPeriod((double) 0)//
.maxInterestRatePerPeriod((double) 50)//
.interestRateFrequencyType(INTEREST_RATE_FREQUENCY_TYPE_YEAR)//
.isLinkedToFloatingInterestRates(false)//
.allowVariableInstallments(false)//
.amortizationType(AmortizationType.EQUAL_INSTALLMENTS.value)//
.interestType(INTEREST_TYPE_DECLINING_BALANCE)//
.interestCalculationPeriodType(INTEREST_CALCULATION_PERIOD_TYPE_DAILY)//
.allowPartialPeriodInterestCalculation(false)//
.transactionProcessingStrategyCode(ADVANCED_PAYMENT_ALLOCATION.getValue())//
.daysInMonthType(DAYS_IN_MONTH_TYPE_30)//
.daysInYearType(DAYS_IN_YEAR_TYPE_360)//
.isInterestRecalculationEnabled(true)//
.interestRecalculationCompoundingMethod(INTEREST_RECALCULATION_COMPOUND_METHOD_NONE)//
.rescheduleStrategyMethod(AdvancePaymentsAdjustmentType.ADJUST_LAST_UNPAID_PERIOD.value)//
.recalculationRestFrequencyType(FREQUENCY_FOR_RECALCULATE_OUTSTANDING_DAILY)//
.recalculationRestFrequencyInterval(1)//
.isArrearsBasedOnOriginalSchedule(false)//
.preClosureInterestCalculationStrategy(PRE_CLOSURE_INTEREST_CALCULATION_RULE_TILL_PRE_CLOSE_DATE)//
.canDefineInstallmentAmount(true)//
.repaymentStartDateType(1)//
.supportedInterestRefundTypes(Arrays.asList("MERCHANT_ISSUED_REFUND", "PAYOUT_REFUND"))//
.chargeOffBehaviour(ChargeOffBehaviour.ZERO_INTEREST.value)
.principalVariationsForBorrowerCycle(principalVariationsForBorrowerCycle)//
.interestRateVariationsForBorrowerCycle(interestRateVariationsForBorrowerCycle)//
.numberOfRepaymentVariationsForBorrowerCycle(numberOfRepaymentVariationsForBorrowerCycle)//
.accountingRule(AccountingRule.ACCRUAL_PERIODIC.value)//
.canUseForTopup(false)//
.enableAccrualActivityPosting(true)//
.multiDisburseLoan(true)//
.maxTrancheCount(500)//
.outstandingLoanBalance(10000.0)//
.disallowExpectedDisbursements(true)//
.allowApprovedDisbursedAmountsOverApplied(true)//
.overAppliedCalculationType(OverAppliedCalculationType.FIXED_SIZE.value)//
.overAppliedNumber(10000)//
.principalThresholdForLastInstallment(50)//
.holdGuaranteeFunds(false)//
.accountMovesOutOfNPAOnlyOnArrearsCompletion(false)//
.allowAttributeOverrides(new AllowAttributeOverrides()//
.amortizationType(true)//
.interestType(true)//
.transactionProcessingStrategyCode(true)//
.interestCalculationPeriodType(true)//
.inArrearsTolerance(true)//
.repaymentEvery(true)//
.graceOnPrincipalAndInterestPayment(true)//
.graceOnArrearsAgeing(true))//
.isEqualAmortization(false)//
.delinquencyBucketId(DELINQUENCY_BUCKET_ID.longValue())//
.enableDownPayment(false)//
.enableInstallmentLevelDelinquency(true)//
.loanScheduleType("PROGRESSIVE") //
.loanScheduleProcessingType("HORIZONTAL")//
.enableIncomeCapitalization(false)//
.capitalizedIncomeCalculationType(PostLoanProductsRequest.CapitalizedIncomeCalculationTypeEnum.FLAT)//
.capitalizedIncomeStrategy(PostLoanProductsRequest.CapitalizedIncomeStrategyEnum.EQUAL_AMORTIZATION)//
.capitalizedIncomeType(PostLoanProductsRequest.CapitalizedIncomeTypeEnum.INTEREST).enableBuyDownFee(true)//
.merchantBuyDownFee(true)//
.buyDownFeeCalculationType(PostLoanProductsRequest.BuyDownFeeCalculationTypeEnum.FLAT)//
.buyDownFeeStrategy(PostLoanProductsRequest.BuyDownFeeStrategyEnum.EQUAL_AMORTIZATION)//
.buyDownFeeIncomeType(PostLoanProductsRequest.BuyDownFeeIncomeTypeEnum.INTEREST)//
.fundSourceAccountId(accountTypeResolver.resolve(DefaultAccountType.SUSPENSE_CLEARING_ACCOUNT))//
.loanPortfolioAccountId(accountTypeResolver.resolve(DefaultAccountType.LOANS_RECEIVABLE))//
.transfersInSuspenseAccountId(accountTypeResolver.resolve(DefaultAccountType.TRANSFER_IN_SUSPENSE_ACCOUNT))//
.interestOnLoanAccountId(accountTypeResolver.resolve(DefaultAccountType.INTEREST_INCOME))//
.incomeFromFeeAccountId(accountTypeResolver.resolve(DefaultAccountType.FEE_INCOME))//
.incomeFromPenaltyAccountId(accountTypeResolver.resolve(DefaultAccountType.FEE_INCOME))//
.incomeFromRecoveryAccountId(accountTypeResolver.resolve(DefaultAccountType.RECOVERIES))//
.writeOffAccountId(accountTypeResolver.resolve(DefaultAccountType.WRITTEN_OFF))//
.overpaymentLiabilityAccountId(accountTypeResolver.resolve(DefaultAccountType.OVERPAYMENT_ACCOUNT))//
.receivableInterestAccountId(accountTypeResolver.resolve(DefaultAccountType.INTEREST_FEE_RECEIVABLE))//
.receivableFeeAccountId(accountTypeResolver.resolve(DefaultAccountType.INTEREST_FEE_RECEIVABLE))//
.receivablePenaltyAccountId(accountTypeResolver.resolve(DefaultAccountType.INTEREST_FEE_RECEIVABLE))//
.buyDownExpenseAccountId(accountTypeResolver.resolve(DefaultAccountType.BUY_DOWN_EXPENSE))//
.incomeFromBuyDownAccountId(accountTypeResolver.resolve(DefaultAccountType.INCOME_FROM_BUY_DOWN)).dateFormat(DATE_FORMAT)//
.locale(LOCALE_EN);//
}
public String generateShortNameSafely() { public String generateShortNameSafely() {
String generatedShortName; String generatedShortName;
int counter = 0; int counter = 0;
@@ -4263,6 +4263,40 @@ public class LoanProductGlobalInitializerStep implements FineractGlobalInitializ
TestContext.INSTANCE.set( TestContext.INSTANCE.set(
TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADVANCED_CUSTOM_PAYMENT_ALLOCATION_PROGRESSIVE_LOAN_SCHEDULE_PRINCIPAL_FIRST, TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADVANCED_CUSTOM_PAYMENT_ALLOCATION_PROGRESSIVE_LOAN_SCHEDULE_PRINCIPAL_FIRST,
responseLoanProductsRequestAdvCustomPaymentAllocationProgressiveLoanSchedulePrincipalFirst); responseLoanProductsRequestAdvCustomPaymentAllocationProgressiveLoanSchedulePrincipalFirst);
// LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL_360_30_USD
// Similar to LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL but with 360/30 days and USD
// currency
String name169 = DefaultLoanProduct.LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL_360_30_USD.getName();
PostLoanProductsRequest loanProductsRequestAdvCustomPaymentAllocationProgressiveLoanScheduleHorizontalUSD = loanProductsRequestFactory
.defaultLoanProductsRequestLP2EmiUSD()//
.name(name169)//
.paymentAllocation(List.of(//
createPaymentAllocation("DEFAULT", "NEXT_INSTALLMENT", //
LoanProductPaymentAllocationRule.AllocationTypesEnum.PAST_DUE_PENALTY, //
LoanProductPaymentAllocationRule.AllocationTypesEnum.PAST_DUE_FEE, //
LoanProductPaymentAllocationRule.AllocationTypesEnum.PAST_DUE_PRINCIPAL, //
LoanProductPaymentAllocationRule.AllocationTypesEnum.PAST_DUE_INTEREST, //
LoanProductPaymentAllocationRule.AllocationTypesEnum.DUE_PENALTY, //
LoanProductPaymentAllocationRule.AllocationTypesEnum.DUE_FEE, //
LoanProductPaymentAllocationRule.AllocationTypesEnum.DUE_PRINCIPAL, //
LoanProductPaymentAllocationRule.AllocationTypesEnum.DUE_INTEREST, //
LoanProductPaymentAllocationRule.AllocationTypesEnum.IN_ADVANCE_PENALTY, //
LoanProductPaymentAllocationRule.AllocationTypesEnum.IN_ADVANCE_FEE, //
LoanProductPaymentAllocationRule.AllocationTypesEnum.IN_ADVANCE_PRINCIPAL, //
LoanProductPaymentAllocationRule.AllocationTypesEnum.IN_ADVANCE_INTEREST), //
createPaymentAllocation("GOODWILL_CREDIT", "NEXT_INSTALLMENT"), //
createPaymentAllocation("MERCHANT_ISSUED_REFUND", "LAST_INSTALLMENT"), //
createPaymentAllocation("PAYOUT_REFUND", "NEXT_INSTALLMENT")))
.creditAllocation(List.of(//
createCreditAllocation("CHARGEBACK", List.of("PENALTY", "FEE", "PRINCIPAL", "INTEREST"))//
));//
PostLoanProductsResponse responseLoanProductsResponseAdvCustomPaymentAllocationProgressiveLoanScheduleHorizontalUSD = createLoanProductIdempotent(
loanProductsRequestAdvCustomPaymentAllocationProgressiveLoanScheduleHorizontalUSD);
TestContext.INSTANCE.set(
TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL_360_30_USD,
responseLoanProductsResponseAdvCustomPaymentAllocationProgressiveLoanScheduleHorizontalUSD);
} }
public static AdvancedPaymentData createPaymentAllocation(String transactionType, String futureInstallmentAllocationRule, public static AdvancedPaymentData createPaymentAllocation(String transactionType, String futureInstallmentAllocationRule,
@@ -292,4 +292,5 @@ public abstract class TestContextKey {
public static final String LP1_INTEREST_FLAT_DAILY_ACTUAL_ACTUAL_MULTIDISB_EXPECT_TRANCHES = "loanProductCreateResponseLP1InterestFlatDailyActualActualMultiDisbursementExpectTranches"; 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"; public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_360_30_ZERO_INTEREST_CHARGE_OFF_ACCRUAL_ACTIVITY = "loanProductCreateResponseLP2AdvancedPaymentZeroInterestChargeOffBehaviourAccrualActivity";
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADVANCED_CUSTOM_PAYMENT_ALLOCATION_PROGRESSIVE_LOAN_SCHEDULE_PRINCIPAL_FIRST = "loanProductCreateResponseLP2AdvancedPaymentHorizontalPrincipalFirst"; public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADVANCED_CUSTOM_PAYMENT_ALLOCATION_PROGRESSIVE_LOAN_SCHEDULE_PRINCIPAL_FIRST = "loanProductCreateResponseLP2AdvancedPaymentHorizontalPrincipalFirst";
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL_360_30_USD = "loanProductCreateResponseLP2AdvancedPaymentHorizontal36030Usd";
} }
@@ -9399,3 +9399,150 @@ Feature: LoanAccrualActivity
When Admin makes Credit Balance Refund transaction on "06 October 2025" with 36.34 EUR transaction amount When Admin makes Credit Balance Refund transaction on "06 October 2025" with 36.34 EUR transaction amount
Then Loan is closed with zero outstanding balance and it's all installments have obligations met Then Loan is closed with zero outstanding balance and it's all installments have obligations met
@TestRailId:C4517
Scenario: Verify that accrual and accrual activity amounts are correct in case of early paid last installment, overdue last-1 installment on each days around due date
When Admin sets the business date to "21 April 2025"
And Admin creates a client with random data
And Admin creates a fully customized loan with the following data:
| LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy |
| LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL_360_30_USD | 21 April 2025 | 218.54 | 9.99 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION |
And Admin successfully approves the loan on "21 April 2025" with "218.54" amount and expected disbursement date on "21 April 2025"
And Admin successfully disburse the loan on "21 April 2025" with "218.54" EUR transaction amount
When Admin sets the business date to "02 May 2025"
And Customer makes "MERCHANT_ISSUED_REFUND" transaction with "AUTOPAY" payment type on "02 May 2025" with 37.49 EUR transaction amount and system-generated Idempotency key
When Admin sets the business date to "21 May 2025"
And Customer makes "AUTOPAY" repayment on "21 May 2025" with 37.49 EUR transaction amount
When Admin sets the business date to "21 June 2025"
And Customer makes "AUTOPAY" repayment on "21 June 2025" with 37.49 EUR transaction amount
When Admin sets the business date to "21 July 2025"
And Customer makes "AUTOPAY" repayment on "21 July 2025" with 37.49 EUR transaction amount
When Admin sets the business date to "21 August 2025"
And Customer makes "AUTOPAY" repayment on "21 August 2025" with 37.49 EUR transaction amount
# --- Check on maturity date - 1 ---
When Admin sets the business date to "20 October 2025"
And Admin runs inline COB job for Loan
Then Loan Repayment schedule has 6 periods, with the following data for periods:
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
| | | 21 April 2025 | | 218.54 | | | 0.0 | | 0.0 | 0.0 | | | |
| 1 | 30 | 21 May 2025 | 21 May 2025 | 182.67 | 35.87 | 1.62 | 0.0 | 0.0 | 37.49 | 37.49 | 0.12 | 0.0 | 0.0 |
| 2 | 31 | 21 June 2025 | 21 June 2025 | 146.39 | 36.28 | 1.21 | 0.0 | 0.0 | 37.49 | 37.49 | 0.12 | 0.0 | 0.0 |
| 3 | 30 | 21 July 2025 | 21 July 2025 | 109.81 | 36.58 | 0.91 | 0.0 | 0.0 | 37.49 | 37.49 | 0.12 | 0.0 | 0.0 |
| 4 | 31 | 21 August 2025 | 21 August 2025 | 72.92 | 36.89 | 0.6 | 0.0 | 0.0 | 37.49 | 37.49 | 0.12 | 0.0 | 0.0 |
| 5 | 31 | 21 September 2025 | | 37.49 | 35.43 | 0.57 | 0.0 | 0.0 | 36.0 | 0.12 | 0.12 | 0.0 | 35.88 |
| 6 | 30 | 21 October 2025 | 02 May 2025 | 0.0 | 37.49 | 0.0 | 0.0 | 0.0 | 37.49 | 37.49 | 37.49 | 0.0 | 0.0 |
And Loan Repayment schedule has the following data in Total row:
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
| 218.54 | 4.91 | 0.0 | 0.0 | 223.45 | 187.57 | 38.09 | 0.0 | 35.88 |
And Loan Transactions tab has the following data:
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed |
| 21 April 2025 | Disbursement | 218.54 | 0.0 | 0.0 | 0.0 | 0.0 | 218.54 | false | false |
| 02 May 2025 | Merchant Issued Refund | 37.49 | 37.49 | 0.0 | 0.0 | 0.0 | 181.05 | false | false |
| 02 May 2025 | Interest Refund | 0.12 | 0.12 | 0.0 | 0.0 | 0.0 | 180.93 | false | false |
| 21 May 2025 | Repayment | 37.49 | 35.87 | 1.62 | 0.0 | 0.0 | 145.06 | false | false |
| 21 May 2025 | Accrual Activity | 1.62 | 0.0 | 1.62 | 0.0 | 0.0 | 0.0 | false | false |
| 21 June 2025 | Repayment | 37.49 | 36.28 | 1.21 | 0.0 | 0.0 | 108.78 | false | false |
| 21 June 2025 | Accrual Activity | 1.21 | 0.0 | 1.21 | 0.0 | 0.0 | 0.0 | false | false |
| 21 July 2025 | Repayment | 37.49 | 36.58 | 0.91 | 0.0 | 0.0 | 72.2 | false | false |
| 21 July 2025 | Accrual Activity | 0.91 | 0.0 | 0.91 | 0.0 | 0.0 | 0.0 | false | false |
| 21 August 2025 | Repayment | 37.49 | 36.89 | 0.6 | 0.0 | 0.0 | 35.31 | false | false |
| 21 August 2025 | Accrual Activity | 0.6 | 0.0 | 0.6 | 0.0 | 0.0 | 0.0 | false | false |
| 21 September 2025 | Accrual Activity | 0.56 | 0.0 | 0.56 | 0.0 | 0.0 | 0.0 | false | false |
| 19 October 2025 | Accrual | 4.63 | 0.0 | 4.63 | 0.0 | 0.0 | 0.0 | false | false |
# --- Check on maturity date ---
When Admin sets the business date to "21 October 2025"
And Admin runs inline COB job for Loan
Then Loan Repayment schedule has 6 periods, with the following data for periods:
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
| | | 21 April 2025 | | 218.54 | | | 0.0 | | 0.0 | 0.0 | | | |
| 1 | 30 | 21 May 2025 | 21 May 2025 | 182.67 | 35.87 | 1.62 | 0.0 | 0.0 | 37.49 | 37.49 | 0.12 | 0.0 | 0.0 |
| 2 | 31 | 21 June 2025 | 21 June 2025 | 146.39 | 36.28 | 1.21 | 0.0 | 0.0 | 37.49 | 37.49 | 0.12 | 0.0 | 0.0 |
| 3 | 30 | 21 July 2025 | 21 July 2025 | 109.81 | 36.58 | 0.91 | 0.0 | 0.0 | 37.49 | 37.49 | 0.12 | 0.0 | 0.0 |
| 4 | 31 | 21 August 2025 | 21 August 2025 | 72.92 | 36.89 | 0.6 | 0.0 | 0.0 | 37.49 | 37.49 | 0.12 | 0.0 | 0.0 |
| 5 | 31 | 21 September 2025 | | 37.49 | 35.43 | 0.58 | 0.0 | 0.0 | 36.01 | 0.12 | 0.12 | 0.0 | 35.89 |
| 6 | 30 | 21 October 2025 | 02 May 2025 | 0.0 | 37.49 | 0.0 | 0.0 | 0.0 | 37.49 | 37.49 | 37.49 | 0.0 | 0.0 |
And Loan Repayment schedule has the following data in Total row:
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
| 218.54 | 4.92 | 0.0 | 0.0 | 223.46 | 187.57 | 38.09 | 0.0 | 35.89 |
And Loan Transactions tab has the following data:
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed |
| 21 April 2025 | Disbursement | 218.54 | 0.0 | 0.0 | 0.0 | 0.0 | 218.54 | false | false |
| 02 May 2025 | Merchant Issued Refund | 37.49 | 37.49 | 0.0 | 0.0 | 0.0 | 181.05 | false | false |
| 02 May 2025 | Interest Refund | 0.12 | 0.12 | 0.0 | 0.0 | 0.0 | 180.93 | false | false |
| 21 May 2025 | Repayment | 37.49 | 35.87 | 1.62 | 0.0 | 0.0 | 145.06 | false | false |
| 21 May 2025 | Accrual Activity | 1.62 | 0.0 | 1.62 | 0.0 | 0.0 | 0.0 | false | false |
| 21 June 2025 | Repayment | 37.49 | 36.28 | 1.21 | 0.0 | 0.0 | 108.78 | false | false |
| 21 June 2025 | Accrual Activity | 1.21 | 0.0 | 1.21 | 0.0 | 0.0 | 0.0 | false | false |
| 21 July 2025 | Repayment | 37.49 | 36.58 | 0.91 | 0.0 | 0.0 | 72.2 | false | false |
| 21 July 2025 | Accrual Activity | 0.91 | 0.0 | 0.91 | 0.0 | 0.0 | 0.0 | false | false |
| 21 August 2025 | Repayment | 37.49 | 36.89 | 0.6 | 0.0 | 0.0 | 35.31 | false | false |
| 21 August 2025 | Accrual Activity | 0.6 | 0.0 | 0.6 | 0.0 | 0.0 | 0.0 | false | false |
| 21 September 2025 | Accrual Activity | 0.57 | 0.0 | 0.57 | 0.0 | 0.0 | 0.0 | false | true |
| 19 October 2025 | Accrual | 4.63 | 0.0 | 4.63 | 0.0 | 0.0 | 0.0 | false | false |
| 20 October 2025 | Accrual | 0.28 | 0.0 | 0.28 | 0.0 | 0.0 | 0.0 | false | false |
# --- Check on maturity date + 1 ---
When Admin sets the business date to "22 October 2025"
And Admin runs inline COB job for Loan
Then Loan Repayment schedule has 6 periods, with the following data for periods:
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
| | | 21 April 2025 | | 218.54 | | | 0.0 | | 0.0 | 0.0 | | | |
| 1 | 30 | 21 May 2025 | 21 May 2025 | 182.67 | 35.87 | 1.62 | 0.0 | 0.0 | 37.49 | 37.49 | 0.12 | 0.0 | 0.0 |
| 2 | 31 | 21 June 2025 | 21 June 2025 | 146.39 | 36.28 | 1.21 | 0.0 | 0.0 | 37.49 | 37.49 | 0.12 | 0.0 | 0.0 |
| 3 | 30 | 21 July 2025 | 21 July 2025 | 109.81 | 36.58 | 0.91 | 0.0 | 0.0 | 37.49 | 37.49 | 0.12 | 0.0 | 0.0 |
| 4 | 31 | 21 August 2025 | 21 August 2025 | 72.92 | 36.89 | 0.6 | 0.0 | 0.0 | 37.49 | 37.49 | 0.12 | 0.0 | 0.0 |
| 5 | 31 | 21 September 2025 | | 37.49 | 35.43 | 0.58 | 0.0 | 0.0 | 36.01 | 0.12 | 0.12 | 0.0 | 35.89 |
| 6 | 30 | 21 October 2025 | 02 May 2025 | 0.0 | 37.49 | 0.0 | 0.0 | 0.0 | 37.49 | 37.49 | 37.49 | 0.0 | 0.0 |
And Loan Repayment schedule has the following data in Total row:
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
| 218.54 | 4.92 | 0.0 | 0.0 | 223.46 | 187.57 | 38.09 | 0.0 | 35.89 |
And Loan Transactions tab has the following data:
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed |
| 21 April 2025 | Disbursement | 218.54 | 0.0 | 0.0 | 0.0 | 0.0 | 218.54 | false | false |
| 02 May 2025 | Merchant Issued Refund | 37.49 | 37.49 | 0.0 | 0.0 | 0.0 | 181.05 | false | false |
| 02 May 2025 | Interest Refund | 0.12 | 0.12 | 0.0 | 0.0 | 0.0 | 180.93 | false | false |
| 21 May 2025 | Repayment | 37.49 | 35.87 | 1.62 | 0.0 | 0.0 | 145.06 | false | false |
| 21 May 2025 | Accrual Activity | 1.62 | 0.0 | 1.62 | 0.0 | 0.0 | 0.0 | false | false |
| 21 June 2025 | Repayment | 37.49 | 36.28 | 1.21 | 0.0 | 0.0 | 108.78 | false | false |
| 21 June 2025 | Accrual Activity | 1.21 | 0.0 | 1.21 | 0.0 | 0.0 | 0.0 | false | false |
| 21 July 2025 | Repayment | 37.49 | 36.58 | 0.91 | 0.0 | 0.0 | 72.2 | false | false |
| 21 July 2025 | Accrual Activity | 0.91 | 0.0 | 0.91 | 0.0 | 0.0 | 0.0 | false | false |
| 21 August 2025 | Repayment | 37.49 | 36.89 | 0.6 | 0.0 | 0.0 | 35.31 | false | false |
| 21 August 2025 | Accrual Activity | 0.6 | 0.0 | 0.6 | 0.0 | 0.0 | 0.0 | false | false |
| 21 September 2025 | Accrual Activity | 0.58 | 0.0 | 0.58 | 0.0 | 0.0 | 0.0 | false | true |
| 19 October 2025 | Accrual | 4.63 | 0.0 | 4.63 | 0.0 | 0.0 | 0.0 | false | false |
| 20 October 2025 | Accrual | 0.28 | 0.0 | 0.28 | 0.0 | 0.0 | 0.0 | false | false |
| 21 October 2025 | Accrual | 0.01 | 0.0 | 0.01 | 0.0 | 0.0 | 0.0 | false | false |
# --- Check on maturity date + 2 ---
When Admin sets the business date to "23 October 2025"
And Admin runs inline COB job for Loan
Then Loan Repayment schedule has 6 periods, with the following data for periods:
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
| | | 21 April 2025 | | 218.54 | | | 0.0 | | 0.0 | 0.0 | | | |
| 1 | 30 | 21 May 2025 | 21 May 2025 | 182.67 | 35.87 | 1.62 | 0.0 | 0.0 | 37.49 | 37.49 | 0.12 | 0.0 | 0.0 |
| 2 | 31 | 21 June 2025 | 21 June 2025 | 146.39 | 36.28 | 1.21 | 0.0 | 0.0 | 37.49 | 37.49 | 0.12 | 0.0 | 0.0 |
| 3 | 30 | 21 July 2025 | 21 July 2025 | 109.81 | 36.58 | 0.91 | 0.0 | 0.0 | 37.49 | 37.49 | 0.12 | 0.0 | 0.0 |
| 4 | 31 | 21 August 2025 | 21 August 2025 | 72.92 | 36.89 | 0.6 | 0.0 | 0.0 | 37.49 | 37.49 | 0.12 | 0.0 | 0.0 |
| 5 | 31 | 21 September 2025 | | 37.49 | 35.43 | 0.58 | 0.0 | 0.0 | 36.01 | 0.12 | 0.12 | 0.0 | 35.89 |
| 6 | 30 | 21 October 2025 | 02 May 2025 | 0.0 | 37.49 | 0.0 | 0.0 | 0.0 | 37.49 | 37.49 | 37.49 | 0.0 | 0.0 |
And Loan Repayment schedule has the following data in Total row:
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
| 218.54 | 4.92 | 0.0 | 0.0 | 223.46 | 187.57 | 38.09 | 0.0 | 35.89 |
And Loan Transactions tab has the following data:
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed |
| 21 April 2025 | Disbursement | 218.54 | 0.0 | 0.0 | 0.0 | 0.0 | 218.54 | false | false |
| 02 May 2025 | Merchant Issued Refund | 37.49 | 37.49 | 0.0 | 0.0 | 0.0 | 181.05 | false | false |
| 02 May 2025 | Interest Refund | 0.12 | 0.12 | 0.0 | 0.0 | 0.0 | 180.93 | false | false |
| 21 May 2025 | Repayment | 37.49 | 35.87 | 1.62 | 0.0 | 0.0 | 145.06 | false | false |
| 21 May 2025 | Accrual Activity | 1.62 | 0.0 | 1.62 | 0.0 | 0.0 | 0.0 | false | false |
| 21 June 2025 | Repayment | 37.49 | 36.28 | 1.21 | 0.0 | 0.0 | 108.78 | false | false |
| 21 June 2025 | Accrual Activity | 1.21 | 0.0 | 1.21 | 0.0 | 0.0 | 0.0 | false | false |
| 21 July 2025 | Repayment | 37.49 | 36.58 | 0.91 | 0.0 | 0.0 | 72.2 | false | false |
| 21 July 2025 | Accrual Activity | 0.91 | 0.0 | 0.91 | 0.0 | 0.0 | 0.0 | false | false |
| 21 August 2025 | Repayment | 37.49 | 36.89 | 0.6 | 0.0 | 0.0 | 35.31 | false | false |
| 21 August 2025 | Accrual Activity | 0.6 | 0.0 | 0.6 | 0.0 | 0.0 | 0.0 | false | false |
| 21 September 2025 | Accrual Activity | 0.58 | 0.0 | 0.58 | 0.0 | 0.0 | 0.0 | false | true |
| 19 October 2025 | Accrual | 4.63 | 0.0 | 4.63 | 0.0 | 0.0 | 0.0 | false | false |
| 20 October 2025 | Accrual | 0.28 | 0.0 | 0.28 | 0.0 | 0.0 | 0.0 | false | false |
| 21 October 2025 | Accrual | 0.01 | 0.0 | 0.01 | 0.0 | 0.0 | 0.0 | false | false |
# --- Close loan ---
When Loan Pay-off is made on "23 October 2025"
Then Loan is closed with zero outstanding balance and it's all installments have obligations met