diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/DateUtils.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/DateUtils.java index 3f5eadf16..47b081478 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/DateUtils.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/core/service/DateUtils.java @@ -461,4 +461,17 @@ public final class DateUtils { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", errors, e); } } + + /** + * Returns the earlier date. If date1 is before date2 it return date1 otherwise date2. + * + * @param date1 + * non null date1 + * @param date2 + * non null date2 + * @return earlier date + */ + public static LocalDate min(@NonNull LocalDate date1, @NonNull LocalDate date2) { + return date1.isBefore(date2) ? date1 : date2; + } } diff --git a/fineract-e2e-tests-runner/src/test/resources/features/LoanReAging.feature b/fineract-e2e-tests-runner/src/test/resources/features/LoanReAging.feature index 8d056db1e..1a22f4658 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/LoanReAging.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanReAging.feature @@ -3119,16 +3119,17 @@ Feature: LoanReAging When Admin creates a Loan re-aging transaction by Loan external ID with the following data: | frequencyNumber | frequencyType | startDate | numberOfInstallments | | 1 | MONTHS | 16 January 2025 | 4 | - Then Loan Repayment schedule has 4 periods, with the following data for periods: + Then Loan Repayment schedule has 5 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 | | | | 01 January 2025 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | | | 1 | 15 | 16 January 2025 | | 791.66 | 208.34 | 0.0 | 0.0 | 0.0 | 208.34 | 0.0 | 0.0 | 0.0 | 208.34 | | 2 | 31 | 16 February 2025 | | 583.32 | 208.34 | 0.0 | 0.0 | 0.0 | 208.34 | 0.0 | 0.0 | 0.0 | 208.34 | | 3 | 28 | 16 March 2025 | | 374.98 | 208.34 | 0.0 | 0.0 | 0.0 | 208.34 | 0.0 | 0.0 | 0.0 | 208.34 | | 4 | 31 | 16 April 2025 | | 166.65 | 208.33 | 0.0 | 0.0 | 0.0 | 208.33 | 0.0 | 0.0 | 0.0 | 208.33 | + | 5 | 30 | 01 July 2025 | 15 January 2025 | 0.0 | 166.65 | 0.0 | 0.0 | 0.0 | 166.65 | 166.65 | 166.65 | 0.0 | 0.0 | Then Loan Repayment schedule has the following data in Total row: - | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | - | 833.35 | 0.0 | 0.0 | 0.0 | 833.35 | 0.0 | 0.0 | 0.0 | 833.35 | + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 1000.0 | 0.0 | 0.0 | 0.0 | 1000.0 | 166.65 | 166.65 | 0.0 | 833.35 | Then Loan Transactions tab has the following data: | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | | 01 January 2025 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | @@ -5966,3 +5967,1675 @@ Feature: LoanReAging | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | | 01 February 2024 | Re-age | 83.57 | 83.57 | 0.0 | 0.0 | 0.0 | 0.0 | false | true | | 01 March 2024 | Repayment | 17.01 | 16.7 | 0.31 | 0.0 | 0.0 | 66.87 | false | true | + + @TestRailId:C_PS-2778 @TestRailId:C_PS-2778_1 @AdvancedPaymentAllocation + Scenario: Verify Loan re-aging transaction with repayment - interest bearing loan with equal amortization; outstanding payable interest + outstanding principal - UC1 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When 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_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" + When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + + When Admin sets the business date to "01 February 2024" + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 17.01 EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 17.01 | 0.0 | 0.0 | 85.04 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + + When Admin sets the business date to "15 March 2024" + When Admin creates a Loan re-aging transaction by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | reAgeInterestHandling | + | 1 | MONTHS | 01 April 2024 | 6 | EQUAL_AMORTIZATION_PAYABLE_INTEREST | + + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 15 March 2024 | Re-age | 84.28 | 83.57 | 0.71 | 0.0 | 0.0 | 0.0 | false | false | + + @TestRailId:C_PS-2778 @TestRailId:C_PS-2778_2 @AdvancedPaymentAllocation + Scenario: Verify Loan re-aging transaction with repayment and charge - interest bearing loan with equal amortization; outstanding payable interest + outstanding principal - UC2 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When 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_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" + When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + + When Admin sets the business date to "01 February 2024" + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 17.01 EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 17.01 | 0.0 | 0.0 | 85.04 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + + When Admin sets the business date to "15 February 2024" + And Admin adds "LOAN_SNOOZE_FEE" due date charge with "15 February 2024" due date and 10 EUR transaction amount + Then Loan Charges tab has the following data: + | Name | isPenalty | Payment due at | Due as of | Calculation type | Due | Paid | Waived | Outstanding | + | Snooze fee | false | Specified due date | 15 February 2024 | Flat | 10.0 | 0.0 | 0.0 | 10.0 | + + When Admin sets the business date to "15 March 2024" + When Admin creates a Loan re-aging transaction by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | reAgeInterestHandling | + | 1 | MONTHS | 01 April 2024 | 6 | EQUAL_AMORTIZATION_PAYABLE_INTEREST | + Then Loan Repayment schedule has 8 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | 15 March 2024 | 83.57 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 3 | 31 | 01 April 2024 | | 69.65 | 13.92 | 0.12 | 1.67 | 0.0 | 15.71 | 0.0 | 0.0 | 0.0 | 15.71 | + | 4 | 30 | 01 May 2024 | | 55.73 | 13.92 | 0.12 | 1.67 | 0.0 | 15.71 | 0.0 | 0.0 | 0.0 | 15.71 | + | 5 | 31 | 01 June 2024 | | 41.81 | 13.92 | 0.12 | 1.67 | 0.0 | 15.71 | 0.0 | 0.0 | 0.0 | 15.71 | + | 6 | 30 | 01 July 2024 | | 27.89 | 13.92 | 0.12 | 1.67 | 0.0 | 15.71 | 0.0 | 0.0 | 0.0 | 15.71 | + | 7 | 31 | 01 August 2024 | | 13.97 | 13.92 | 0.12 | 1.67 | 0.0 | 15.71 | 0.0 | 0.0 | 0.0 | 15.71 | + | 8 | 31 | 01 September 2024 | | 0.0 | 13.97 | 0.11 | 1.65 | 0.0 | 15.73 | 0.0 | 0.0 | 0.0 | 15.73 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 1.29 | 10.0 | 0.0 | 111.29 | 17.01 | 0.0 | 0.0 | 94.28 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 15 March 2024 | Re-age | 94.28 | 83.57 | 0.71 | 10.0 | 0.0 | 0.0 | false | false | + + And Loan Pay-off is made on "15 March 2024" + Then Loan status will be "CLOSED_OBLIGATIONS_MET" + + @TestRailId:C_PS-2778 @TestRailId:C_PS-2778_3 @AdvancedPaymentAllocation + Scenario: Verify Loan re-aging transaction with repayment and chargeback - interest bearing loan with equal amortization; outstanding payable interest + outstanding principal - UC3 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When 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_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" + When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + + When Admin sets the business date to "01 February 2024" + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 17.01 EUR transaction amount + When Admin makes "REPAYMENT_ADJUSTMENT_CHARGEBACK" chargeback with 17.01 EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.15 | 33.43 | 0.59 | 0.0 | 0.0 | 34.02 | 0.0 | 0.0 | 0.0 | 34.02 | + | 3 | 31 | 01 April 2024 | | 50.53 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.81 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 17.0 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 17.0 | 0.1 | 0.0 | 0.0 | 17.1 | 0.0 | 0.0 | 0.0 | 17.1 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 117.01 | 2.15 | 0.0 | 0.0 | 119.16 | 17.01 | 0.0 | 0.0 | 102.15 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 01 February 2024 | Chargeback | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | 100.58 | false | false | + + When Admin sets the business date to "15 March 2024" + When Admin creates a Loan re-aging transaction by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | reAgeInterestHandling | + | 1 | MONTHS | 01 April 2024 | 6 | EQUAL_AMORTIZATION_PAYABLE_INTEREST | + + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 01 February 2024 | Chargeback | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | 100.58 | false | false | + | 15 March 2024 | Re-age | 101.43 | 100.58 | 0.85 | 0.0 | 0.0 | 0.0 | false | false | + + When Loan Pay-off is made on "15 March 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + + @TestRailId:C_PS-2778 @TestRailId:C_PS-2778_3.1 @AdvancedPaymentAllocation + Scenario: Verify Loan re-aging transaction with repayment and full chargeback(with pymnt alloc W/OUT interest recalc) - interest bearing loan with equal amortization; outstanding payable interest + outstanding principal - UC3.1 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When 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_PYMNT_INTEREST_DAILY_EMI_360_30_CHARGEBACK_INTEREST_FEE_PRINCIPAL | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" + When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + + When Admin sets the business date to "01 February 2024" + # When Admin runs inline COB job for Loan + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 17.01 EUR transaction amount + When Admin makes "REPAYMENT_ADJUSTMENT_CHARGEBACK" chargeback with 17.01 EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.05 | 32.95 | 1.07 | 0.0 | 0.0 | 34.02 | 0.0 | 0.0 | 0.0 | 34.02 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 116.43 | 2.63 | 0.0 | 0.0 | 119.06 | 17.01 | 0.0 | 0.0 | 102.05 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 01 February 2024 | Chargeback | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 100.0 | false | false | + + When Admin sets the business date to "15 March 2024" + # When Admin runs inline COB job for Loan + When Admin creates a Loan re-aging transaction by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | reAgeInterestHandling | + | 1 | MONTHS | 01 April 2024 | 6 | EQUAL_AMORTIZATION_PAYABLE_INTEREST | + Then Loan Repayment schedule has 8 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | 15 March 2024 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 3 | 31 | 01 April 2024 | | 83.33 | 16.67 | 0.21 | 0.0 | 0.0 | 16.88 | 0.0 | 0.0 | 0.0 | 16.88 | + | 4 | 30 | 01 May 2024 | | 66.66 | 16.67 | 0.21 | 0.0 | 0.0 | 16.88 | 0.0 | 0.0 | 0.0 | 16.88 | + | 5 | 31 | 01 June 2024 | | 49.99 | 16.67 | 0.21 | 0.0 | 0.0 | 16.88 | 0.0 | 0.0 | 0.0 | 16.88 | + | 6 | 30 | 01 July 2024 | | 33.32 | 16.67 | 0.21 | 0.0 | 0.0 | 16.88 | 0.0 | 0.0 | 0.0 | 16.88 | + | 7 | 31 | 01 August 2024 | | 16.65 | 16.67 | 0.21 | 0.0 | 0.0 | 16.88 | 0.0 | 0.0 | 0.0 | 16.88 | + | 8 | 31 | 01 September 2024 | | 0.0 | 16.65 | 0.2 | 0.0 | 0.0 | 16.85 | 0.0 | 0.0 | 0.0 | 16.85 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 116.43 | 1.83 | 0.0 | 0.0 | 118.26 | 17.01 | 0.0 | 0.0 | 101.25 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 01 February 2024 | Chargeback | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 100.0 | false | false | + | 15 March 2024 | Re-age | 101.25 | 100.0 | 1.25 | 0.0 | 0.0 | 0.0 | false | false | + + When Loan Pay-off is made on "15 March 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + + @TestRailId:C_PS-2778 @TestRailId:C_PS-2778_3.2 @AdvancedPaymentAllocation + Scenario: Verify Loan re-aging transaction with repayment and partial chargeback(with pymnt alloc WITH interest recalc) - interest bearing loan with equal amortization; outstanding payable interest + outstanding principal - UC3.2 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When 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_PYMNT_INTEREST_DAILY_INTEREST_RECALC_EMI_360_30_CHARGEBACK_INTEREST_PENALTY_FEE_PRINCIPAL | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" + When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + + When Admin sets the business date to "01 February 2024" + # When Admin runs inline COB job for Loan + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 17.01 EUR transaction amount + When Admin makes "REPAYMENT_ADJUSTMENT_CHARGEBACK" chargeback with 10 EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.1 | 25.89 | 1.12 | 0.0 | 0.0 | 27.01 | 0.0 | 0.0 | 0.0 | 27.01 | + | 3 | 31 | 01 April 2024 | | 50.48 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.76 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.95 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.95 | 0.1 | 0.0 | 0.0 | 17.05 | 0.0 | 0.0 | 0.0 | 17.05 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 109.42 | 2.68 | 0.0 | 0.0 | 112.1 | 17.01 | 0.0 | 0.0 | 95.09 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 01 February 2024 | Chargeback | 10.0 | 9.42 | 0.58 | 0.0 | 0.0 | 92.99 | false | false | + + When Admin sets the business date to "15 March 2024" + # When Admin runs inline COB job for Loan + When Admin creates a Loan re-aging transaction by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | reAgeInterestHandling | + | 1 | MONTHS | 01 April 2024 | 6 | EQUAL_AMORTIZATION_PAYABLE_INTEREST | + Then Loan Repayment schedule has 8 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | 15 March 2024 | 92.99 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 3 | 31 | 01 April 2024 | | 77.5 | 15.49 | 0.23 | 0.0 | 0.0 | 15.72 | 0.0 | 0.0 | 0.0 | 15.72 | + | 4 | 30 | 01 May 2024 | | 62.01 | 15.49 | 0.23 | 0.0 | 0.0 | 15.72 | 0.0 | 0.0 | 0.0 | 15.72 | + | 5 | 31 | 01 June 2024 | | 46.52 | 15.49 | 0.23 | 0.0 | 0.0 | 15.72 | 0.0 | 0.0 | 0.0 | 15.72 | + | 6 | 30 | 01 July 2024 | | 31.03 | 15.49 | 0.23 | 0.0 | 0.0 | 15.72 | 0.0 | 0.0 | 0.0 | 15.72 | + | 7 | 31 | 01 August 2024 | | 15.54 | 15.49 | 0.23 | 0.0 | 0.0 | 15.72 | 0.0 | 0.0 | 0.0 | 15.72 | + | 8 | 31 | 01 September 2024 | | 0.0 | 15.54 | 0.21 | 0.0 | 0.0 | 15.75 | 0.0 | 0.0 | 0.0 | 15.75 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 109.42 | 1.94 | 0.0 | 0.0 | 111.36 | 17.01 | 0.0 | 0.0 | 94.35 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 01 February 2024 | Chargeback | 10.0 | 9.42 | 0.58 | 0.0 | 0.0 | 92.99 | false | false | + | 15 March 2024 | Re-age | 94.35 | 92.99 | 1.36 | 0.0 | 0.0 | 0.0 | false | false | + + When Loan Pay-off is made on "15 March 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + + @TestRailId:C_PS-2778 @TestRailId:C_PS-2778_3.3 @AdvancedPaymentAllocation + Scenario: Verify Loan re-aging transaction with repayment, charge and partial chargeback(with pymnt alloc WITH interest recalc) - interest bearing loan with equal amortization; outstanding payable interest + outstanding principal - UC3.3 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When 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_PYMNT_INTEREST_DAILY_INTEREST_RECALC_EMI_360_30_CHARGEBACK_INTEREST_FEE_PRINCIPAL | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" + When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + + When Admin sets the business date to "01 February 2024" + When Admin runs inline COB job for Loan + And Admin adds "LOAN_SNOOZE_FEE" due date charge with "01 February 2024" due date and 8 EUR transaction amount + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 17.01 EUR transaction amount + When Admin makes "REPAYMENT_ADJUSTMENT_CHARGEBACK" chargeback with 10 EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 8.0 | 0.0 | 25.01 | 17.01 | 0.0 | 0.0 | 8.0 | + | 2 | 29 | 01 March 2024 | | 67.06 | 18.51 | 0.5 | 8.0 | 0.0 | 27.01 | 0.0 | 0.0 | 0.0 | 27.01 | + | 3 | 31 | 01 April 2024 | | 50.44 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.72 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.91 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.91 | 0.1 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 102.0 | 2.06 | 16.0 | 0.0 | 120.06 | 17.01 | 0.0 | 0.0 | 103.05 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 31 January 2024 | Accrual | 0.56 | 0.0 | 0.56 | 0.0 | 0.0 | 0.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 9.01 | 0.0 | 8.0 | 0.0 | 90.99 | false | false | + | 01 February 2024 | Chargeback | 10.0 | 2.0 | 0.0 | 8.0 | 0.0 | 92.99 | false | false | + + When Admin sets the business date to "15 March 2024" + # When Admin runs inline COB job for Loan + When Admin creates a Loan re-aging transaction by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | reAgeInterestHandling | + | 1 | MONTHS | 01 April 2024 | 6 | EQUAL_AMORTIZATION_PAYABLE_INTEREST | + Then Loan Repayment schedule has 8 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 15 March 2024 | 90.99 | 9.01 | 0.0 | 8.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | 15 March 2024 | 92.99 | 0.0 | 0.0 | 1.33 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 3 | 31 | 01 April 2024 | | 77.5 | 15.49 | 0.23 | 1.33 | 0.0 | 15.72 | 0.0 | 0.0 | 0.0 | 15.72 | + | 4 | 30 | 01 May 2024 | | 62.01 | 15.49 | 0.23 | 1.33 | 0.0 | 15.72 | 0.0 | 0.0 | 0.0 | 15.72 | + | 5 | 31 | 01 June 2024 | | 46.52 | 15.49 | 0.23 | 0.0 | 0.0 | 15.72 | 0.0 | 0.0 | 0.0 | 15.72 | + | 6 | 30 | 01 July 2024 | | 31.03 | 15.49 | 0.23 | 0.0 | 0.0 | 15.72 | 0.0 | 0.0 | 0.0 | 15.72 | + | 7 | 31 | 01 August 2024 | | 15.54 | 15.49 | 0.23 | 0.0 | 0.0 | 15.72 | 0.0 | 0.0 | 0.0 | 15.72 | + | 8 | 31 | 01 September 2024 | | 0.0 | 15.54 | 0.21 | 0.0 | 0.0 | 15.75 | 0.0 | 0.0 | 0.0 | 15.75 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 102.0 | 1.36 | 8.0 | 0.0 | 111.36 | 17.01 | 0.0 | 0.0 | 94.35 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 31 January 2024 | Accrual | 0.56 | 0.0 | 0.56 | 0.0 | 0.0 | 0.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 9.01 | 0.0 | 8.0 | 0.0 | 90.99 | false | false | + | 01 February 2024 | Chargeback | 10.0 | 2.0 | 0.0 | 8.0 | 0.0 | 92.99 | false | false | + | 15 March 2024 | Re-age | 94.35 | 92.99 | 1.36 | 0.0 | 0.0 | 0.0 | false | false | + + When Loan Pay-off is made on "15 March 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + + @TestRailId:C_PS-2778 @TestRailId:C_PS-2778_3.4 @AdvancedPaymentAllocation + Scenario: Verify Loan re-aging transaction with repayment, charges(penalty and fee) and partial chargeback(with pymnt alloc WITH interest recalc) - interest bearing loan with equal amortization; outstanding payable interest + outstanding principal - UC3.4 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When 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_PYMNT_INTEREST_DAILY_EMI_360_30_CHARGEBACK_PRINCIPAL_INTEREST_FEE | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" + When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + + When Admin sets the business date to "01 February 2024" + When Admin runs inline COB job for Loan + And Admin adds "LOAN_SNOOZE_FEE" due date charge with "01 February 2024" due date and 8 EUR transaction amount + When Admin adds "LOAN_NSF_FEE" due date charge with "01 February 2024" due date and 10 EUR transaction amount + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 34.02 EUR transaction amount + When Admin makes "REPAYMENT_ADJUSTMENT_CHARGEBACK" chargeback with 17.01 EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 8.0 | 10.0 | 35.01 | 34.02 | 0.0 | 0.0 | 0.99 | + | 2 | 29 | 01 March 2024 | | 67.05 | 32.54 | 0.49 | 0.99 | 0.0 | 34.02 | 0.0 | 0.0 | 0.0 | 34.02 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 116.02 | 2.05 | 8.99 | 10.0 | 137.06| 34.02 | 0.0 | 0.0 | 103.04 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 31 January 2024 | Accrual | 0.56 | 0.0 | 0.56 | 0.0 | 0.0 | 0.0 | false | false | + | 01 February 2024 | Repayment | 34.02 | 16.02 | 0.0 | 8.0 | 10.0 | 83.98 | false | false | + | 01 February 2024 | Chargeback | 17.01 | 16.02 | 0.0 | 0.99 | 0.0 | 100.0 | false | false | + + When Admin sets the business date to "15 March 2024" + # When Admin runs inline COB job for Loan + When Admin creates a Loan re-aging transaction by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | reAgeInterestHandling | + | 1 | MONTHS | 01 April 2024 | 6 | EQUAL_AMORTIZATION_PAYABLE_INTEREST | + Then Loan Repayment schedule has 8 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 15 March 2024 | 83.98 | 16.02 | 0.0 | 8.0 | 10.0 | 34.02 | 34.02 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | 15 March 2024 | 100.0 | 0.0 | 0.0 | 0.0 | 1.67 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 3 | 31 | 01 April 2024 | | 83.33 | 16.67 | 0.21 | 0.0 | 1.67 | 16.88 | 0.0 | 0.0 | 0.0 | 16.88 | + | 4 | 30 | 01 May 2024 | | 66.66 | 16.67 | 0.21 | 0.0 | 1.67 | 16.88 | 0.0 | 0.0 | 0.0 | 16.88 | + | 5 | 31 | 01 June 2024 | | 49.99 | 16.67 | 0.21 | 0.0 | 0.0 | 16.88 | 0.0 | 0.0 | 0.0 | 16.88 | + | 6 | 30 | 01 July 2024 | | 33.32 | 16.67 | 0.21 | 0.0 | 0.0 | 16.88 | 0.0 | 0.0 | 0.0 | 16.88 | + | 7 | 31 | 01 August 2024 | | 16.65 | 16.67 | 0.21 | 0.0 | 0.0 | 16.88 | 0.0 | 0.0 | 0.0 | 16.88 | + | 8 | 31 | 01 September 2024 | | 0.0 | 16.65 | 0.2 | 0.0 | 0.0 | 16.85 | 0.0 | 0.0 | 0.0 | 16.85 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 116.02 | 1.25 | 8.0 | 10.0 | 135.27 | 34.02 | 0.0 | 0.0 | 101.25 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 31 January 2024 | Accrual | 0.56 | 0.0 | 0.56 | 0.0 | 0.0 | 0.0 | false | false | + | 01 February 2024 | Repayment | 34.02 | 16.02 | 0.0 | 8.0 | 10.0 | 83.98 | false | false | + | 01 February 2024 | Chargeback | 17.01 | 16.02 | 0.0 | 0.99 | 0.0 | 100.0 | false | false | + | 15 March 2024 | Re-age | 101.25 | 100.0 | 1.25 | 0.0 | 0.0 | 0.0 | false | false | + + When Loan Pay-off is made on "15 March 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + + @TestRailId:C_PS-2778 @TestRailId:C_PS-2778_3.5 @AdvancedPaymentAllocation + Scenario: Verify Loan re-aging transaction with repayment and charges(fee and penalty) with due date after re-age - interest bearing loan with equal amortization; outstanding payable interest + outstanding principal - UC3.5 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When 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_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" + When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + + When Admin sets the business date to "01 February 2024" + When Admin runs inline COB job for Loan + And Admin adds "LOAN_SNOOZE_FEE" due date charge with "01 April 2024" due date and 8 EUR transaction amount + When Admin adds "LOAN_NSF_FEE" due date charge with "01 April 2024" due date and 10 EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 8.0 | 10.0 | 35.01 | 0.0 | 0.0 | 0.0 | 35.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 8.0 | 10.0 | 120.05 | 0.0 | 0.0 | 0.0 | 120.05 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 31 January 2024 | Accrual | 0.56 | 0.0 | 0.56 | 0.0 | 0.0 | 0.0 | false | false | + + When Admin sets the business date to "15 March 2024" + # When Admin runs inline COB job for Loan + When Admin creates a Loan re-aging transaction by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | reAgeInterestHandling | + | 1 | MONTHS | 01 April 2024 | 6 | EQUAL_AMORTIZATION_PAYABLE_INTEREST | + Then Loan Repayment schedule has 8 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 15 March 2024 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | 15 March 2024 | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 3 | 31 | 01 April 2024 | | 83.34 | 16.66 | 0.24 | 1.33 | 1.67 | 19.9 | 0.0 | 0.0 | 0.0 | 19.9 | + | 4 | 30 | 01 May 2024 | | 66.68 | 16.66 | 0.24 | 1.33 | 1.67 | 19.9 | 0.0 | 0.0 | 0.0 | 19.9 | + | 5 | 31 | 01 June 2024 | | 50.02 | 16.66 | 0.24 | 1.33 | 1.67 | 19.9 | 0.0 | 0.0 | 0.0 | 19.9 | + | 6 | 30 | 01 July 2024 | | 33.36 | 16.66 | 0.24 | 1.33 | 1.67 | 19.9 | 0.0 | 0.0 | 0.0 | 19.9 | + | 7 | 31 | 01 August 2024 | | 16.7 | 16.66 | 0.24 | 1.33 | 1.67 | 19.9 | 0.0 | 0.0 | 0.0 | 19.9 | + | 8 | 31 | 01 September 2024 | | 0.0 | 16.7 | 0.22 | 1.35 | 1.65 | 19.92 | 0.0 | 0.0 | 0.0 | 19.92 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 1.42 | 8.0 | 10.0 | 119.42 | 0.0 | 0.0 | 0.0 | 119.42 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 31 January 2024 | Accrual | 0.56 | 0.0 | 0.56 | 0.0 | 0.0 | 0.0 | false | false | + | 15 March 2024 | Re-age | 119.42 | 100.0 | 1.42 | 8.0 | 10.0 | 0.0 | false | false | + + When Admin sets the business date to "01 April 2024" + And Customer makes "AUTOPAY" repayment on "01 April 2024" with 19.9 EUR transaction amount + Then Loan has 99.52 outstanding amount + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 31 January 2024 | Accrual | 0.56 | 0.0 | 0.56 | 0.0 | 0.0 | 0.0 | false | false | + | 15 March 2024 | Re-age | 119.42 | 100.0 | 1.42 | 8.0 | 10.0 | 0.0 | false | false | + | 01 April 2024 | Repayment | 19.9 | 16.66 | 0.24 | 1.33 | 1.67 | 83.34 | false | false | + + When Admin sets the business date to "01 May 2024" + And Customer makes "AUTOPAY" repayment on "01 May 2024" with 19.9 EUR transaction amount + Then Loan has 79.62 outstanding amount + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 31 January 2024 | Accrual | 0.56 | 0.0 | 0.56 | 0.0 | 0.0 | 0.0 | false | false | + | 15 March 2024 | Re-age | 119.42 | 100.0 | 1.42 | 8.0 | 10.0 | 0.0 | false | false | + | 01 April 2024 | Repayment | 19.9 | 16.66 | 0.24 | 1.33 | 1.67 | 83.34 | false | false | + | 01 May 2024 | Repayment | 19.9 | 16.66 | 0.24 | 1.33 | 1.67 | 66.68 | false | false | + + When Admin sets the business date to "01 June 2024" + And Customer makes "AUTOPAY" repayment on "01 June 2024" with 19.9 EUR transaction amount + Then Loan has 59.72 outstanding amount + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 31 January 2024 | Accrual | 0.56 | 0.0 | 0.56 | 0.0 | 0.0 | 0.0 | false | false | + | 15 March 2024 | Re-age | 119.42 | 100.0 | 1.42 | 8.0 | 10.0 | 0.0 | false | false | + | 01 April 2024 | Repayment | 19.9 | 16.66 | 0.24 | 1.33 | 1.67 | 83.34 | false | false | + | 01 May 2024 | Repayment | 19.9 | 16.66 | 0.24 | 1.33 | 1.67 | 66.68 | false | false | + | 01 June 2024 | Repayment | 19.9 | 16.66 | 0.24 | 1.33 | 1.67 | 50.02 | false | false | + + When Admin sets the business date to "01 July 2024" + And Customer makes "AUTOPAY" repayment on "01 July 2024" with 19.9 EUR transaction amount + Then Loan has 39.82 outstanding amount + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 31 January 2024 | Accrual | 0.56 | 0.0 | 0.56 | 0.0 | 0.0 | 0.0 | false | false | + | 15 March 2024 | Re-age | 119.42 | 100.0 | 1.42 | 8.0 | 10.0 | 0.0 | false | false | + | 01 April 2024 | Repayment | 19.9 | 16.66 | 0.24 | 1.33 | 1.67 | 83.34 | false | false | + | 01 May 2024 | Repayment | 19.9 | 16.66 | 0.24 | 1.33 | 1.67 | 66.68 | false | false | + | 01 June 2024 | Repayment | 19.9 | 16.66 | 0.24 | 1.33 | 1.67 | 50.02 | false | false | + | 01 July 2024 | Repayment | 19.9 | 16.66 | 0.24 | 1.33 | 1.67 | 33.36 | false | false | + + When Admin sets the business date to "01 August 2024" + And Customer makes "AUTOPAY" repayment on "01 August 2024" with 19.9 EUR transaction amount + Then Loan has 19.92 outstanding amount + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 31 January 2024 | Accrual | 0.56 | 0.0 | 0.56 | 0.0 | 0.0 | 0.0 | false | false | + | 15 March 2024 | Re-age | 119.42 | 100.0 | 1.42 | 8.0 | 10.0 | 0.0 | false | false | + | 01 April 2024 | Repayment | 19.9 | 16.66 | 0.24 | 1.33 | 1.67 | 83.34 | false | false | + | 01 May 2024 | Repayment | 19.9 | 16.66 | 0.24 | 1.33 | 1.67 | 66.68 | false | false | + | 01 June 2024 | Repayment | 19.9 | 16.66 | 0.24 | 1.33 | 1.67 | 50.02 | false | false | + | 01 July 2024 | Repayment | 19.9 | 16.66 | 0.24 | 1.33 | 1.67 | 33.36 | false | false | + | 01 August 2024 | Repayment | 19.9 | 16.66 | 0.24 | 1.33 | 1.67 | 16.7 | false | false | + + When Admin sets the business date to "01 September 2024" + And Customer makes "AUTOPAY" repayment on "01 September 2024" with 19.92 EUR transaction amount + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 31 January 2024 | Accrual | 0.56 | 0.0 | 0.56 | 0.0 | 0.0 | 0.0 | false | false | + | 15 March 2024 | Re-age | 119.42 | 100.0 | 1.42 | 8.0 | 10.0 | 0.0 | false | false | + | 01 April 2024 | Repayment | 19.9 | 16.66 | 0.24 | 1.33 | 1.67 | 83.34 | false | false | + | 01 May 2024 | Repayment | 19.9 | 16.66 | 0.24 | 1.33 | 1.67 | 66.68 | false | false | + | 01 June 2024 | Repayment | 19.9 | 16.66 | 0.24 | 1.33 | 1.67 | 50.02 | false | false | + | 01 July 2024 | Repayment | 19.9 | 16.66 | 0.24 | 1.33 | 1.67 | 33.36 | false | false | + | 01 August 2024 | Repayment | 19.9 | 16.66 | 0.24 | 1.33 | 1.67 | 16.7 | false | false | + | 01 September 2024 | Repayment | 19.92 | 16.7 | 0.22 | 1.35 | 1.65 | 0.0 | false | false | + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + + @TestRailId:C_PS-2778 @TestRailId:C_PS-2778_4 @AdvancedPaymentAllocation + Scenario: Verify Loan re-aging transaction with repayment and charge - interest bearing loan with equal amortization; outstanding payable interest + outstanding principal - UC4 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When 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_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" + When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + + When Admin sets the business date to "01 February 2024" + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 17.01 EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 17.01 | 0.0 | 0.0 | 85.04 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + + And Admin adds "LOAN_SNOOZE_FEE" due date charge with "15 July 2024" due date and 10 EUR transaction amount + Then Loan Charges tab has the following data: + | Name | isPenalty | Payment due at | Due as of | Calculation type | Due | Paid | Waived | Outstanding | + | Snooze fee | false | Specified due date | 15 July 2024 | Flat | 10.0 | 0.0 | 0.0 | 10.0 | + + When Admin sets the business date to "15 March 2024" + When Admin creates a Loan re-aging transaction by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | reAgeInterestHandling | + | 1 | MONTHS | 01 April 2024 | 6 | EQUAL_AMORTIZATION_PAYABLE_INTEREST | + + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 15 March 2024 | Re-age | 94.28 | 83.57 | 0.71 | 10.0 | 0.0 | 0.0 | false | false | + And Loan Pay-off is made on "15 March 2024" + Then Loan status will be "CLOSED_OBLIGATIONS_MET" + + @TestRailId:C_PS-2778 @TestRailId:C_PS-2778_5 @AdvancedPaymentAllocation + Scenario: Verify Loan re-aging transaction with partially paid installment - interest bearing loan with equal amortization; outstanding payable interest + outstanding principal - UC5 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When 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_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" + When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + + When Admin sets the business date to "01 February 2024" + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 25 EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.0 | 16.57 | 0.44 | 0.0 | 0.0 | 17.01 | 7.99 | 7.99 | 0.0 | 9.02 | + | 3 | 31 | 01 April 2024 | | 50.38 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.66 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.85 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.85 | 0.1 | 0.0 | 0.0 | 16.95 | 0.0 | 0.0 | 0.0 | 16.95 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.0 | 0.0 | 0.0 | 102.0 | 25.0 | 7.99 | 0.0 | 77.0 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 25.0 | 24.42 | 0.58 | 0.0 | 0.0 | 75.58 | false | false | + + When Admin sets the business date to "15 March 2024" + When Admin creates a Loan re-aging transaction by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | reAgeInterestHandling | + | 1 | MONTHS | 01 April 2024 | 6 | EQUAL_AMORTIZATION_PAYABLE_INTEREST | + + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 25.0 | 24.42 | 0.58 | 0.0 | 0.0 | 75.58 | false | false | + | 15 March 2024 | Re-age | 76.22 | 75.58 | 0.64 | 0.0 | 0.0 | 0.0 | false | false | + And Loan Pay-off is made on "15 March 2024" + Then Loan status will be "CLOSED_OBLIGATIONS_MET" + + @TestRailId:C_PS-2778 @TestRailId:C_PS-2778_5.1 @AdvancedPaymentAllocation + Scenario: Verify Loan re-aging transaction with partially paid installment; adjust to last - interest bearing loan with equal amortization; outstanding payable interest + outstanding principal - UC5.1 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When 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_PYMNT_INTEREST_DAILY_EMI_360_30_IR_DAILY_TILL_PRECLOSE_LAST_INSTALLMENT_STRATEGY | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" + When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + + When Admin sets the business date to "01 February 2024" + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 25 EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.0 | 16.57 | 0.44 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.33 | 16.67 | 0.34 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.57 | 16.76 | 0.25 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.71 | 16.86 | 0.15 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.71 | 0.05 | 0.0 | 0.0 | 16.76 | 7.99 | 7.99 | 0.0 | 8.77 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 1.81 | 0.0 | 0.0 | 101.81 | 25.0 | 7.99 | 0.0 | 76.81 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 25.0 | 24.42 | 0.58 | 0.0 | 0.0 | 75.58 | false | false | + + When Admin sets the business date to "15 March 2024" + When Admin creates a Loan re-aging transaction by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | reAgeInterestHandling | + | 1 | MONTHS | 01 April 2024 | 6 | EQUAL_AMORTIZATION_PAYABLE_INTEREST | + Then Loan Repayment schedule has 8 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | 15 March 2024 | 83.57 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 3 | 31 | 01 April 2024 | | 70.98 | 12.59 | 0.11 | 0.0 | 0.0 | 12.7 | 0.0 | 0.0 | 0.0 | 12.7 | + | 4 | 30 | 01 May 2024 | | 58.39 | 12.59 | 0.11 | 0.0 | 0.0 | 12.7 | 0.0 | 0.0 | 0.0 | 12.7 | + | 5 | 31 | 01 June 2024 | | 45.8 | 12.59 | 0.11 | 0.0 | 0.0 | 12.7 | 0.0 | 0.0 | 0.0 | 12.7 | + | 6 | 30 | 01 July 2024 | | 25.22 | 20.58 | 0.11 | 0.0 | 0.0 | 20.69 | 7.99 | 7.99 | 0.0 | 12.7 | + | 7 | 31 | 01 August 2024 | | 12.63 | 12.59 | 0.11 | 0.0 | 0.0 | 12.7 | 0.0 | 0.0 | 0.0 | 12.7 | + | 8 | 31 | 01 September 2024 | | 0.0 | 12.63 | 0.09 | 0.0 | 0.0 | 12.72 | 0.0 | 0.0 | 0.0 | 12.72 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 1.22 | 0.0 | 0.0 | 101.22 | 25.0 | 7.99 | 0.0 | 76.22 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 25.0 | 24.42 | 0.58 | 0.0 | 0.0 | 75.58 | false | false | + | 15 March 2024 | Re-age | 76.22 | 75.58 | 0.64 | 0.0 | 0.0 | 0.0 | false | false | + And Loan Pay-off is made on "15 March 2024" + Then Loan status will be "CLOSED_OBLIGATIONS_MET" + + @TestRailId:C_PS-2778 @TestRailId:C_PS-2778_6 @AdvancedPaymentAllocation + Scenario: Verify Loan re-aging transaction with chargeback after re-age - interest bearing loan with equal amortization; outstanding payable interest + outstanding principal - UC6 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When 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_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" + When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + + When Admin sets the business date to "01 February 2024" + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 17.01 EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 17.01 | 0.0 | 0.0 | 85.04 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + + When Admin sets the business date to "15 March 2024" + When Admin creates a Loan re-aging transaction by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | reAgeInterestHandling | + | 1 | MONTHS | 01 April 2024 | 6 | EQUAL_AMORTIZATION_PAYABLE_INTEREST | + + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 15 March 2024 | Re-age | 84.28 | 83.57 | 0.71 | 0.0 | 0.0 | 0.0 | false | false | + + When Admin sets the business date to "01 April 2024" + When Admin makes "REPAYMENT_ADJUSTMENT_CHARGEBACK" chargeback with 17.01 EUR transaction amount + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 15 March 2024 | Re-age | 84.28 | 83.57 | 0.71 | 0.0 | 0.0 | 0.0 | false | false | + | 01 April 2024 | Chargeback | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | 100.58 | false | false | + And Loan Pay-off is made on "01 April 2024" + Then Loan status will be "CLOSED_OBLIGATIONS_MET" + + @TestRailId:C_PS-2778 @TestRailId:C_PS-2778_7 @AdvancedPaymentAllocation + Scenario: Verify Loan re-aging transaction with downpayment - interest bearing loan with equal amortization; outstanding payable interest + outstanding principal - UC7 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When 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_PYMNT_INTEREST_RECALCULATION_DAILY_EMI_360_30_MULTIDISBURSE_AUTO_DOWNPAYMENT | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" + When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount + Then Loan Repayment schedule has 7 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2024 | 01 January 2024 | 75.0 | 25.0 | 0.0 | 0.0 | 0.0 | 25.0 | 25.0 | 0.0 | 0.0 | 0.0 | + | 2 | 31 | 01 February 2024 | | 62.68 | 12.32 | 0.44 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 3 | 29 | 01 March 2024 | | 50.29 | 12.39 | 0.37 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 4 | 31 | 01 April 2024 | | 37.82 | 12.47 | 0.29 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 5 | 30 | 01 May 2024 | | 25.28 | 12.54 | 0.22 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 6 | 31 | 01 June 2024 | | 12.67 | 12.61 | 0.15 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 7 | 30 | 01 July 2024 | | 0.0 | 12.67 | 0.07 | 0.0 | 0.0 | 12.74 | 0.0 | 0.0 | 0.0 | 12.74 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 1.54 | 0.0 | 0.0 | 101.54 | 25.0 | 0.0 | 0.0 | 76.54 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 January 2024 | Down Payment | 25.0 | 25.0 | 0.0 | 0.0 | 0.0 | 75.0 | false | false | + + When Admin sets the business date to "01 February 2024" + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 12.76 EUR transaction amount + Then Loan Repayment schedule has 7 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2024 | 01 January 2024 | 75.0 | 25.0 | 0.0 | 0.0 | 0.0 | 25.0 | 25.0 | 0.0 | 0.0 | 0.0 | + | 2 | 31 | 01 February 2024 | 01 February 2024 | 62.68 | 12.32 | 0.44 | 0.0 | 0.0 | 12.76 | 12.76| 0.0 | 0.0 | 0.0 | + | 3 | 29 | 01 March 2024 | | 50.29 | 12.39 | 0.37 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 4 | 31 | 01 April 2024 | | 37.82 | 12.47 | 0.29 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 5 | 30 | 01 May 2024 | | 25.28 | 12.54 | 0.22 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 6 | 31 | 01 June 2024 | | 12.67 | 12.61 | 0.15 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 7 | 30 | 01 July 2024 | | 0.0 | 12.67 | 0.07 | 0.0 | 0.0 | 12.74 | 0.0 | 0.0 | 0.0 | 12.74 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 1.54 | 0.0 | 0.0 | 101.54 | 37.76 | 0.0 | 0.0 | 63.78 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 January 2024 | Down Payment | 25.0 | 25.0 | 0.0 | 0.0 | 0.0 | 75.0 | false | false | + | 01 February 2024 | Repayment | 12.76 | 12.32 | 0.44 | 0.0 | 0.0 | 62.68 | false | false | + + When Admin sets the business date to "15 March 2024" + When Admin creates a Loan re-aging transaction by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | reAgeInterestHandling | + | 1 | MONTHS | 01 April 2024 | 6 | EQUAL_AMORTIZATION_PAYABLE_INTEREST | + + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 January 2024 | Down Payment | 25.0 | 25.0 | 0.0 | 0.0 | 0.0 | 75.0 | false | false | + | 01 February 2024 | Repayment | 12.76 | 12.32 | 0.44 | 0.0 | 0.0 | 62.68 | false | false | + | 15 March 2024 | Re-age | 63.22 | 62.68 | 0.54 | 0.0 | 0.0 | 0.0 | false | false | + + When Loan Pay-off is made on "15 March 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + + @TestRailId:C_PS-2778 @TestRailId:C_PS-2778_8.1 @AdvancedPaymentAllocation + Scenario: Verify Loan re-aging transaction with repayment and 2nd disb before re-age - interest bearing multidisb loan with equal amortization; outstanding payable interest + outstanding principal - UC8.1 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When 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_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALC_DAILY_MULTIDISBURSE | 01 January 2024 | 150 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2024" with "150" amount and expected disbursement date on "01 January 2024" + When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + + When Admin sets the business date to "01 February 2024" + # When Admin runs inline COB job for Loan + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 17.01 EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 17.01 | 0.0 | 0.0 | 85.04 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + + When Admin successfully disburse the loan on "01 February 2024" with "50" EUR transaction amount + # When 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | | | 01 February 2024 | | 50.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 2 | 29 | 01 March 2024 | | 107.17 | 26.4 | 0.78 | 0.0 | 0.0 | 27.18 | 0.0 | 0.0 | 0.0 | 27.18 | + | 3 | 31 | 01 April 2024 | | 80.62 | 26.55 | 0.63 | 0.0 | 0.0 | 27.18 | 0.0 | 0.0 | 0.0 | 27.18 | + | 4 | 30 | 01 May 2024 | | 53.91 | 26.71 | 0.47 | 0.0 | 0.0 | 27.18 | 0.0 | 0.0 | 0.0 | 27.18 | + | 5 | 31 | 01 June 2024 | | 27.04 | 26.87 | 0.31 | 0.0 | 0.0 | 27.18 | 0.0 | 0.0 | 0.0 | 27.18 | + | 6 | 30 | 01 July 2024 | | 0.0 | 27.04 | 0.16 | 0.0 | 0.0 | 27.2 | 0.0 | 0.0 | 0.0 | 27.2 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 150.0 | 2.93 | 0.0 | 0.0 | 152.93 | 17.01 | 0.0 | 0.0 | 135.92 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 01 February 2024 | Disbursement | 50.0 | 0.0 | 0.0 | 0.0 | 0.0 | 133.57 | false | false | + + When Admin sets the business date to "15 March 2024" + # When Admin runs inline COB job for Loan + When Admin creates a Loan re-aging transaction by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | reAgeInterestHandling | + | 1 | MONTHS | 01 April 2024 | 6 | EQUAL_AMORTIZATION_PAYABLE_INTEREST | + Then Loan Repayment schedule has 8 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | | | 01 February 2024 | | 50.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 2 | 29 | 01 March 2024 | 15 March 2024 | 133.57 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 3 | 31 | 01 April 2024 | | 111.31 | 22.26 | 0.19 | 0.0 | 0.0 | 22.45 | 0.0 | 0.0 | 0.0 | 22.45 | + | 4 | 30 | 01 May 2024 | | 89.05 | 22.26 | 0.19 | 0.0 | 0.0 | 22.45 | 0.0 | 0.0 | 0.0 | 22.45 | + | 5 | 31 | 01 June 2024 | | 66.79 | 22.26 | 0.19 | 0.0 | 0.0 | 22.45 | 0.0 | 0.0 | 0.0 | 22.45 | + | 6 | 30 | 01 July 2024 | | 44.53 | 22.26 | 0.19 | 0.0 | 0.0 | 22.45 | 0.0 | 0.0 | 0.0 | 22.45 | + | 7 | 31 | 01 August 2024 | | 22.27 | 22.26 | 0.19 | 0.0 | 0.0 | 22.45 | 0.0 | 0.0 | 0.0 | 22.45 | + | 8 | 31 | 01 September 2024 | | 0.0 | 22.27 | 0.18 | 10.0 | 0.0 | 24.1 | 0.0 | 0.0 | 0.0 | 24.1 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 150.0 | 1.71 | 10.0 | 0.0 | 155.03 | 17.01 | 0.0 | 0.0 | 138.02 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 14 February 2024 | Accrual | 0.8 | 0.0 | 0.8 | 0.0 | 0.0 | 0.0 | false | false | + | 15 March 2024 | Re-age | 144.7 | 133.57 | 1.13 | 10.0 | 0.0 | 0.0 | false | false | + + When Loan Pay-off is made on "15 March 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + + @TestRailId:C_PS-2778 @TestRailId:C_PS-2778_8.2 @AdvancedPaymentAllocation + Scenario: Verify Loan re-aging transaction with partial chargeback(with custom pymnt alloc) and 2nd disb after re-age - interest bearing multidisb loan with equal amortization; outstanding payable interest + outstanding principal - UC8.2 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When 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_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALC_DAILY_MULTIDISBURSE_CHARGEBACK | 01 January 2024 | 150 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2024" with "150" amount and expected disbursement date on "01 January 2024" + When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + + When Admin sets the business date to "01 February 2024" + # When Admin runs inline COB job for Loan + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 17.01 EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 17.01 | 0.0 | 0.0 | 85.04 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + + When Admin sets the business date to "15 March 2024" + # When Admin runs inline COB job for Loan + When Admin creates a Loan re-aging transaction by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | reAgeInterestHandling | + | 1 | MONTHS | 01 April 2024 | 6 | EQUAL_AMORTIZATION_PAYABLE_INTEREST | + Then Loan Repayment schedule has 8 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | 15 March 2024 | 83.57 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 3 | 31 | 01 April 2024 | | 69.64 | 13.93 | 0.12 | 0.0 | 0.0 | 14.05 | 0.0 | 0.0 | 0.0 | 14.05 | + | 4 | 30 | 01 May 2024 | | 55.71 | 13.93 | 0.12 | 0.0 | 0.0 | 14.05 | 0.0 | 0.0 | 0.0 | 14.05 | + | 5 | 31 | 01 June 2024 | | 41.78 | 13.93 | 0.12 | 0.0 | 0.0 | 14.05 | 0.0 | 0.0 | 0.0 | 14.05 | + | 6 | 30 | 01 July 2024 | | 27.85 | 13.93 | 0.12 | 0.0 | 0.0 | 14.05 | 0.0 | 0.0 | 0.0 | 14.05 | + | 7 | 31 | 01 August 2024 | | 13.92 | 13.93 | 0.12 | 0.0 | 0.0 | 14.05 | 0.0 | 0.0 | 0.0 | 14.05 | + | 8 | 31 | 01 September 2024 | | 0.0 | 13.92 | 0.11 | 0.0 | 0.0 | 14.03 | 0.0 | 0.0 | 0.0 | 14.03 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 1.29 | 0.0 | 0.0 | 101.29 | 17.01 | 0.0 | 0.0 | 84.28 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 15 March 2024 | Re-age | 84.28 | 83.57 | 0.71 | 0.0 | 0.0 | 0.0 | false | false | + + When Admin sets the business date to "01 April 2024" +# When Admin runs inline COB job for Loan + When Admin successfully disburse the loan on "01 April 2024" with "50" EUR transaction amount + Then Loan Repayment schedule has 8 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | 15 March 2024 | 83.57 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 3 | 31 | 01 April 2024 | | 69.64 | 13.93 | 0.12 | 0.0 | 0.0 | 14.05 | 0.0 | 0.0 | 0.0 | 14.05 | + | | | 01 April 2024 | | 50.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 4 | 30 | 01 May 2024 | | 95.71 | 23.93 | 0.12 | 0.0 | 0.0 | 24.05 | 0.0 | 0.0 | 0.0 | 24.05 | + | 5 | 31 | 01 June 2024 | | 71.78 | 23.93 | 0.12 | 0.0 | 0.0 | 24.05 | 0.0 | 0.0 | 0.0 | 24.05 | + | 6 | 30 | 01 July 2024 | | 47.85 | 23.93 | 0.12 | 0.0 | 0.0 | 24.05 | 0.0 | 0.0 | 0.0 | 24.05 | + | 7 | 31 | 01 August 2024 | | 23.92 | 23.93 | 0.12 | 0.0 | 0.0 | 24.05 | 0.0 | 0.0 | 0.0 | 24.05 | + | 8 | 31 | 01 September 2024 | | 0.0 | 23.92 | 0.11 | 0.0 | 0.0 | 24.03 | 0.0 | 0.0 | 0.0 | 24.03 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 150.0 | 1.29 | 0.0 | 0.0 | 151.29 | 17.01 | 0.0 | 0.0 | 134.28 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 15 March 2024 | Re-age | 84.28 | 83.57 | 0.71 | 0.0 | 0.0 | 0.0 | false | false | + | 01 April 2024 | Disbursement | 50.0 | 0.0 | 0.0 | 0.0 | 0.0 | 133.57 | false | false | + + When Admin makes "REPAYMENT_ADJUSTMENT_CHARGEBACK" chargeback with 17.01 EUR transaction amount + Then Loan Repayment schedule has 8 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | 15 March 2024 | 83.57 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | + | 3 | 31 | 01 April 2024 | | 69.64 | 13.93 | 0.12 | 0.0 | 0.0 | 14.05 | 0.0 | 0.0 | 0.0 | 14.05 | + | | | 01 April 2024 | | 50.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 4 | 30 | 01 May 2024 | | 95.71 | 40.36 | 0.7 | 0.0 | 0.0 | 41.06 | 0.0 | 0.0 | 0.0 | 41.06 | + | 5 | 31 | 01 June 2024 | | 71.78 | 23.93 | 0.12 | 0.0 | 0.0 | 24.05 | 0.0 | 0.0 | 0.0 | 24.05 | + | 6 | 30 | 01 July 2024 | | 47.85 | 23.93 | 0.12 | 0.0 | 0.0 | 24.05 | 0.0 | 0.0 | 0.0 | 24.05 | + | 7 | 31 | 01 August 2024 | | 23.92 | 23.93 | 0.12 | 0.0 | 0.0 | 24.05 | 0.0 | 0.0 | 0.0 | 24.05 | + | 8 | 31 | 01 September 2024 | | 0.0 | 23.92 | 0.11 | 0.0 | 0.0 | 24.03 | 0.0 | 0.0 | 0.0 | 24.03 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 166.43 | 1.87 | 0.0 | 0.0 | 168.3 | 17.01 | 0.0 | 0.0 | 151.29 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 15 March 2024 | Re-age | 84.28 | 83.57 | 0.71 | 0.0 | 0.0 | 0.0 | false | false | + | 01 April 2024 | Disbursement | 50.0 | 0.0 | 0.0 | 0.0 | 0.0 | 133.57 | false | false | + | 01 April 2024 | Chargeback | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 150.0 | false | true | + + When Loan Pay-off is made on "01 April 2024" + Then Loan is closed with zero outstanding balance and it's all installments have obligations met + + + @TestRailId:C_PS-2778 @TestRailId:C_PS-2778_1 @AdvancedPaymentAllocation + Scenario: Verify Loan re-aging transaction with repayment - interest bearing loan with equal amortization; outstanding FULL interest + outstanding principal - UC1 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When 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_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" + When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + + When Admin sets the business date to "01 February 2024" + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 17.01 EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 17.01 | 0.0 | 0.0 | 85.04 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + + When Admin sets the business date to "15 March 2024" + When Admin creates a Loan re-aging transaction by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | reAgeInterestHandling | + | 1 | MONTHS | 01 April 2024 | 6 | EQUAL_AMORTIZATION_FULL_INTEREST | + + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 15 March 2024 | Re-age | 85.08 | 83.57 | 1.51 | 0.0 | 0.0 | 0.0 | false | false | + And Loan Pay-off is made on "15 March 2024" + Then Loan status will be "CLOSED_OBLIGATIONS_MET" + + @TestRailId:C_PS-2778 @TestRailId:C_PS-2778_2 @AdvancedPaymentAllocation + Scenario: Verify Loan re-aging transaction with repayment and charge - interest bearing loan with equal amortization; outstanding FULL interest + outstanding principal - UC2 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When 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_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" + When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + + When Admin sets the business date to "01 February 2024" + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 17.01 EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 17.01 | 0.0 | 0.0 | 85.04 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + + When Admin sets the business date to "15 February 2024" + And Admin adds "LOAN_SNOOZE_FEE" due date charge with "15 February 2024" due date and 10 EUR transaction amount + Then Loan Charges tab has the following data: + | Name | isPenalty | Payment due at | Due as of | Calculation type | Due | Paid | Waived | Outstanding | + | Snooze fee | false | Specified due date | 15 February 2024 | Flat | 10.0 | 0.0 | 0.0 | 10.0 | + + When Admin sets the business date to "15 March 2024" + When Admin creates a Loan re-aging transaction by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | reAgeInterestHandling | + | 1 | MONTHS | 01 April 2024 | 6 | EQUAL_AMORTIZATION_FULL_INTEREST | + + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 15 March 2024 | Re-age | 95.08 | 83.57 | 1.51 | 10.0 | 0.0 | 0.0 | false | false | + And Loan Pay-off is made on "15 March 2024" + Then Loan status will be "CLOSED_OBLIGATIONS_MET" + + @TestRailId:C_PS-2778 @TestRailId:C_PS-2778_3 @AdvancedPaymentAllocation + Scenario: Verify Loan re-aging transaction with repayment and chargeback - interest bearing loan with equal amortization; outstanding FULL interest + outstanding principal - UC3 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When 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_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" + When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + + When Admin sets the business date to "01 February 2024" + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 17.01 EUR transaction amount + When Admin makes "REPAYMENT_ADJUSTMENT_CHARGEBACK" chargeback with 17.01 EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.15 | 33.43 | 0.59 | 0.0 | 0.0 | 34.02 | 0.0 | 0.0 | 0.0 | 34.02 | + | 3 | 31 | 01 April 2024 | | 50.53 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.81 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 17.0 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 17.0 | 0.1 | 0.0 | 0.0 | 17.1 | 0.0 | 0.0 | 0.0 | 17.1 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 117.01 | 2.15 | 0.0 | 0.0 | 119.16 | 17.01 | 0.0 | 0.0 | 102.15 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 01 February 2024 | Chargeback | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | 100.58 | false | false | + + When Admin sets the business date to "15 March 2024" + When Admin creates a Loan re-aging transaction by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | reAgeInterestHandling | + | 1 | MONTHS | 01 April 2024 | 6 | EQUAL_AMORTIZATION_FULL_INTEREST | + + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 01 February 2024 | Chargeback | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | 100.58 | false | false | + | 15 March 2024 | Re-age | 102.25 | 100.58 | 1.67 | 0.0 | 0.0 | 0.0 | false | false | + And Loan Pay-off is made on "15 March 2024" + Then Loan status will be "CLOSED_OBLIGATIONS_MET" + + @TestRailId:C_PS-2778 @TestRailId:C_PS-2778_4 @AdvancedPaymentAllocation + Scenario: Verify Loan re-aging transaction with repayment and charge - interest bearing loan with equal amortization; outstanding FULL interest + outstanding principal - UC4 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When 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_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" + When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + + When Admin sets the business date to "01 February 2024" + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 17.01 EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 17.01 | 0.0 | 0.0 | 85.04 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + + And Admin adds "LOAN_SNOOZE_FEE" due date charge with "15 July 2024" due date and 10 EUR transaction amount + Then Loan Charges tab has the following data: + | Name | isPenalty | Payment due at | Due as of | Calculation type | Due | Paid | Waived | Outstanding | + | Snooze fee | false | Specified due date | 15 July 2024 | Flat | 10.0 | 0.0 | 0.0 | 10.0 | + + When Admin sets the business date to "15 March 2024" + When Admin creates a Loan re-aging transaction by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | reAgeInterestHandling | + | 1 | MONTHS | 01 April 2024 | 6 | EQUAL_AMORTIZATION_FULL_INTEREST | + + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 15 March 2024 | Re-age | 95.08 | 83.57 | 1.51 | 10.0 | 0.0 | 0.0 | false | false | + And Loan Pay-off is made on "15 March 2024" + Then Loan status will be "CLOSED_OBLIGATIONS_MET" + + @TestRailId:C_PS-2778 @TestRailId:C_PS-2778_5 @AdvancedPaymentAllocation + Scenario: Verify Loan re-aging transaction with partially paid installment - interest bearing loan with equal amortization; outstanding FULL interest + outstanding principal - UC5 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When 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_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" + When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + + When Admin sets the business date to "01 February 2024" + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 25 EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.0 | 16.57 | 0.44 | 0.0 | 0.0 | 17.01 | 7.99 | 7.99 | 0.0 | 9.02 | + | 3 | 31 | 01 April 2024 | | 50.38 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.66 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.85 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.85 | 0.1 | 0.0 | 0.0 | 16.95 | 0.0 | 0.0 | 0.0 | 16.95 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.0 | 0.0 | 0.0 | 102.0 | 25.0 | 7.99 | 0.0 | 77.0 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 25.0 | 24.42 | 0.58 | 0.0 | 0.0 | 75.58 | false | false | + + When Admin sets the business date to "15 March 2024" + When Admin creates a Loan re-aging transaction by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | reAgeInterestHandling | + | 1 | MONTHS | 01 April 2024 | 6 | EQUAL_AMORTIZATION_FULL_INTEREST | + + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 25.0 | 24.42 | 0.58 | 0.0 | 0.0 | 75.58 | false | false | + | 15 March 2024 | Re-age | 77.02 | 75.58 | 1.44 | 0.0 | 0.0 | 0.0 | false | false | + And Loan Pay-off is made on "15 March 2024" + Then Loan status will be "CLOSED_OBLIGATIONS_MET" + + @TestRailId:C_PS-2778 @TestRailId:C_PS-2778_5.1 @AdvancedPaymentAllocation + Scenario: Verify Loan re-aging transaction with partially paid installment; adjust to last - interest bearing loan with equal amortization; outstanding FULL interest + outstanding principal - UC5.1 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When 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_PYMNT_INTEREST_DAILY_EMI_360_30_IR_DAILY_TILL_PRECLOSE_LAST_INSTALLMENT_STRATEGY | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" + When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + + When Admin sets the business date to "01 February 2024" + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 25 EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.0 | 16.57 | 0.44 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.33 | 16.67 | 0.34 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.57 | 16.76 | 0.25 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.71 | 16.86 | 0.15 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.71 | 0.05 | 0.0 | 0.0 | 16.76 | 7.99 | 7.99 | 0.0 | 8.77 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 1.81 | 0.0 | 0.0 | 101.81 | 25.0 | 7.99 | 0.0 | 76.81 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 25.0 | 24.42 | 0.58 | 0.0 | 0.0 | 75.58 | false | false | + + When Admin sets the business date to "15 March 2024" + When Admin creates a Loan re-aging transaction by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | reAgeInterestHandling | + | 1 | MONTHS | 01 April 2024 | 6 | EQUAL_AMORTIZATION_FULL_INTEREST | + + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 25.0 | 24.42 | 0.58 | 0.0 | 0.0 | 75.58 | false | false | + | 15 March 2024 | Re-age | 76.86 | 75.58 | 1.28 | 0.0 | 0.0 | 0.0 | false | false | + And Loan Pay-off is made on "15 March 2024" + Then Loan status will be "CLOSED_OBLIGATIONS_MET" + + @TestRailId:C_PS-2778 @TestRailId:C_PS-2778_6 @AdvancedPaymentAllocation + Scenario: Verify Loan re-aging transaction with chargeback after re-age - interest bearing loan with equal amortization; outstanding FULL interest + outstanding principal - UC6 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When 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_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" + When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 0.0 | 0.0 | 0.0 | 102.05 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + + When Admin sets the business date to "01 February 2024" + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 17.01 EUR transaction amount + 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.05 | 16.52 | 0.49 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 3 | 31 | 01 April 2024 | | 50.43 | 16.62 | 0.39 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 4 | 30 | 01 May 2024 | | 33.71 | 16.72 | 0.29 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 5 | 31 | 01 June 2024 | | 16.9 | 16.81 | 0.2 | 0.0 | 0.0 | 17.01 | 0.0 | 0.0 | 0.0 | 17.01 | + | 6 | 30 | 01 July 2024 | | 0.0 | 16.9 | 0.1 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.05 | 0.0 | 0.0 | 102.05 | 17.01 | 0.0 | 0.0 | 85.04 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + + When Admin sets the business date to "15 March 2024" + When Admin creates a Loan re-aging transaction by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | reAgeInterestHandling | + | 1 | MONTHS | 01 April 2024 | 6 | EQUAL_AMORTIZATION_FULL_INTEREST | + + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 15 March 2024 | Re-age | 85.08 | 83.57 | 1.51 | 0.0 | 0.0 | 0.0 | false | false | + + When Admin sets the business date to "01 April 2024" + When Admin makes "REPAYMENT_ADJUSTMENT_CHARGEBACK" chargeback with 17.01 EUR transaction amount + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 | 0.0 | 0.0 | 83.57 | false | false | + | 15 March 2024 | Re-age | 85.08 | 83.57 | 1.51 | 0.0 | 0.0 | 0.0 | false | false | + | 01 April 2024 | Chargeback | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 | 100.58 | false | false | + And Loan Pay-off is made on "01 April 2024" + Then Loan status will be "CLOSED_OBLIGATIONS_MET" + + + @TestRailId:C_PS-2778 @TestRailId:C_PS-2778_7 @AdvancedPaymentAllocation + Scenario: Verify Loan re-aging transaction with downpayment - interest bearing loan with equal amortization; outstanding FULL interest + outstanding principal - UC7 + When Admin sets the business date to "01 January 2024" + When Admin creates a client with random data + When 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_PYMNT_INTEREST_RECALCULATION_DAILY_EMI_360_30_MULTIDISBURSE_AUTO_DOWNPAYMENT | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" + When Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount + Then Loan Repayment schedule has 7 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2024 | 01 January 2024 | 75.0 | 25.0 | 0.0 | 0.0 | 0.0 | 25.0 | 25.0 | 0.0 | 0.0 | 0.0 | + | 2 | 31 | 01 February 2024 | | 62.68 | 12.32 | 0.44 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 3 | 29 | 01 March 2024 | | 50.29 | 12.39 | 0.37 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 4 | 31 | 01 April 2024 | | 37.82 | 12.47 | 0.29 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 5 | 30 | 01 May 2024 | | 25.28 | 12.54 | 0.22 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 6 | 31 | 01 June 2024 | | 12.67 | 12.61 | 0.15 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 7 | 30 | 01 July 2024 | | 0.0 | 12.67 | 0.07 | 0.0 | 0.0 | 12.74 | 0.0 | 0.0 | 0.0 | 12.74 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 1.54 | 0.0 | 0.0 | 101.54 | 25.0 | 0.0 | 0.0 | 76.54 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 January 2024 | Down Payment | 25.0 | 25.0 | 0.0 | 0.0 | 0.0 | 75.0 | false | false | + + When Admin sets the business date to "01 February 2024" + And Customer makes "AUTOPAY" repayment on "01 February 2024" with 12.76 EUR transaction amount + Then Loan Repayment schedule has 7 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 | + | | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 0 | 01 January 2024 | 01 January 2024 | 75.0 | 25.0 | 0.0 | 0.0 | 0.0 | 25.0 | 25.0 | 0.0 | 0.0 | 0.0 | + | 2 | 31 | 01 February 2024 | 01 February 2024 | 62.68 | 12.32 | 0.44 | 0.0 | 0.0 | 12.76 | 12.76| 0.0 | 0.0 | 0.0 | + | 3 | 29 | 01 March 2024 | | 50.29 | 12.39 | 0.37 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 4 | 31 | 01 April 2024 | | 37.82 | 12.47 | 0.29 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 5 | 30 | 01 May 2024 | | 25.28 | 12.54 | 0.22 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 6 | 31 | 01 June 2024 | | 12.67 | 12.61 | 0.15 | 0.0 | 0.0 | 12.76 | 0.0 | 0.0 | 0.0 | 12.76 | + | 7 | 30 | 01 July 2024 | | 0.0 | 12.67 | 0.07 | 0.0 | 0.0 | 12.74 | 0.0 | 0.0 | 0.0 | 12.74 | + Then Loan Repayment schedule has the following data in Total row: + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 1.54 | 0.0 | 0.0 | 101.54 | 37.76 | 0.0 | 0.0 | 63.78 | + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 January 2024 | Down Payment | 25.0 | 25.0 | 0.0 | 0.0 | 0.0 | 75.0 | false | false | + | 01 February 2024 | Repayment | 12.76 | 12.32 | 0.44 | 0.0 | 0.0 | 62.68 | false | false | + + When Admin sets the business date to "15 March 2024" + When Admin creates a Loan re-aging transaction by Loan external ID with the following data: + | frequencyNumber | frequencyType | startDate | numberOfInstallments | reAgeInterestHandling | + | 1 | MONTHS | 01 April 2024 | 6 | EQUAL_AMORTIZATION_FULL_INTEREST | + + Then Loan Transactions tab has the following data: + | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | + | 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false | + | 01 January 2024 | Down Payment | 25.0 | 25.0 | 0.0 | 0.0 | 0.0 | 75.0 | false | false | + | 01 February 2024 | Repayment | 12.76 | 12.32 | 0.44 | 0.0 | 0.0 | 62.68 | false | false | + | 15 March 2024 | Re-age | 63.82 | 62.68 | 1.14 | 0.0 | 0.0 | 0.0 | false | false | + And Loan Pay-off is made on "15 March 2024" + Then Loan status will be "CLOSED_OBLIGATIONS_MET" diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java index fb55acbbd..6651161b9 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanRepaymentScheduleInstallment.java @@ -261,9 +261,21 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableWithUTCDa } public static LoanRepaymentScheduleInstallment newReAgedInstallment(final Loan loan, final Integer installmentNumber, - final LocalDate fromDate, final LocalDate dueDate, final BigDecimal principal) { - return new LoanRepaymentScheduleInstallment(loan, installmentNumber, fromDate, dueDate, principal, null, null, null, null, null, - null, null, false, false, true); + final LocalDate fromDate, final LocalDate dueDate, final BigDecimal principal, final BigDecimal interest, final BigDecimal fees, + final BigDecimal penalties, final BigDecimal interestAccrued, final BigDecimal feeAccrued, final BigDecimal penaltyAccrued) { + LoanRepaymentScheduleInstallment installment = new LoanRepaymentScheduleInstallment(loan, installmentNumber, fromDate, dueDate, + principal, interest, fees, penalties, null, null, null, null, false, false, true); + installment.setInterestAccrued(interestAccrued); + installment.setFeeAccrued(feeAccrued); + installment.setPenaltyAccrued(penaltyAccrued); + return installment; + } + + public static LoanRepaymentScheduleInstallment newReAgedInstallment(final Loan loan, final Integer installmentNumber, + final LocalDate fromDate, final LocalDate dueDate, final BigDecimal principal, final BigDecimal interest, final BigDecimal fees, + final BigDecimal penalties) { + return new LoanRepaymentScheduleInstallment(loan, installmentNumber, fromDate, dueDate, principal, interest, fees, penalties, null, + null, null, null, false, false, true); } public static LoanRepaymentScheduleInstallment getLastNonDownPaymentInstallment(List installments) { diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java index 7898ba170..bf5e185b0 100644 --- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java +++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessor.java @@ -43,6 +43,7 @@ import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Objects; @@ -57,6 +58,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.NotImplementedException; @@ -92,12 +94,14 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelation; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelationTypeEnum; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionToRepaymentScheduleMapping; import org.apache.fineract.portfolio.loanaccount.domain.SingleLoanChargeRepaymentScheduleProcessingWrapper; +import org.apache.fineract.portfolio.loanaccount.domain.reaging.LoanReAgeInterestHandlingType; import org.apache.fineract.portfolio.loanaccount.domain.reaging.LoanReAgeParameter; import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.AbstractLoanRepaymentScheduleTransactionProcessor; import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.MoneyHolder; import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.TransactionCtx; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType; +import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.ScheduledDateGenerator; import org.apache.fineract.portfolio.loanaccount.mapper.LoanConfigurationDetailsMapper; import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeValidator; import org.apache.fineract.portfolio.loanaccount.service.InterestRefundService; @@ -105,6 +109,7 @@ import org.apache.fineract.portfolio.loanaccount.service.LoanBalanceService; import org.apache.fineract.portfolio.loanaccount.service.LoanChargeService; import org.apache.fineract.portfolio.loanaccount.service.schedule.LoanScheduleComponent; import org.apache.fineract.portfolio.loanproduct.calc.EMICalculator; +import org.apache.fineract.portfolio.loanproduct.calc.data.EqualAmortizationValues; import org.apache.fineract.portfolio.loanproduct.calc.data.OutstandingDetails; import org.apache.fineract.portfolio.loanproduct.calc.data.PeriodDueDetails; import org.apache.fineract.portfolio.loanproduct.calc.data.ProgressiveLoanInterestScheduleModel; @@ -115,6 +120,7 @@ import org.apache.fineract.portfolio.loanproduct.domain.DueType; import org.apache.fineract.portfolio.loanproduct.domain.FutureInstallmentAllocationRule; import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail; import org.apache.fineract.portfolio.loanproduct.domain.PaymentAllocationType; +import org.apache.fineract.portfolio.util.InstallmentProcessingHelper; import org.apache.fineract.util.LoopContext; import org.apache.fineract.util.LoopGuard; @@ -129,17 +135,19 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep private final LoanScheduleComponent loanSchedule; private final LoanChargeService loanChargeService; private final SingleLoanChargeRepaymentScheduleProcessingWrapper loanChargeRepaymentScheduleProcessing; + private final ScheduledDateGenerator scheduledDateGenerator; public AdvancedPaymentScheduleTransactionProcessor(final EMICalculator emiCalculator, final InterestRefundService interestRefundService, final ExternalIdFactory externalIdFactory, final LoanScheduleComponent loanSchedule, final LoanChargeValidator loanChargeValidator, final LoanBalanceService loanBalanceService, - final LoanChargeService loanChargeService) { + final LoanChargeService loanChargeService, ScheduledDateGenerator scheduledDateGenerator) { super(externalIdFactory, loanChargeValidator, loanBalanceService); this.emiCalculator = emiCalculator; this.interestRefundService = interestRefundService; this.loanSchedule = loanSchedule; this.loanChargeService = loanChargeService; this.loanChargeRepaymentScheduleProcessing = new SingleLoanChargeRepaymentScheduleProcessingWrapper(); + this.scheduledDateGenerator = scheduledDateGenerator; } @Override @@ -466,15 +474,15 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep } } else { if (ctx instanceof ProgressiveTransactionCtx progCtx) { - final Money interestBeforeRefund = emiCalculator.getSumOfDueInterestsOnDate(progCtx.getModel(), - loanTransaction.getDateOf()); + LocalDate targetDate = loanTransaction.getDateOf(); + final Money interestBeforeRefund = emiCalculator.getSumOfDueInterestsOnDate(progCtx.getModel(), targetDate); final List unmodifiedTransactionIds = progCtx.getAlreadyProcessedTransactions().stream() .filter(LoanTransaction::isNotReversed).map(AbstractPersistableCustom::getId).toList(); final List modifiedTransactions = new ArrayList<>(progCtx.getAlreadyProcessedTransactions().stream() .filter(LoanTransaction::isNotReversed).filter(tr -> tr.getId() == null).toList()); if (!modifiedTransactions.isEmpty()) { - final Money interestAfterRefund = interestRefundService.totalInterestByTransactions(this, loan.getId(), - loanTransaction.getDateOf(), modifiedTransactions, unmodifiedTransactionIds); + final Money interestAfterRefund = interestRefundService.totalInterestByTransactions(this, loan.getId(), targetDate, + modifiedTransactions, unmodifiedTransactionIds); final Money newAmount = interestBeforeRefund.minus(progCtx.getSumOfInterestRefundAmount()).minus(interestAfterRefund); loanTransaction.updateAmount(newAmount.getAmount()); } @@ -2291,8 +2299,6 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep HorizontalPaymentAllocationContext paymentAllocationContext = new HorizontalPaymentAllocationContext(ctx, loanTransaction, paymentAllocationTypes, futureInstallmentAllocationRule, transactionMappings, balances); paymentAllocationContext.setTransactionAmountUnprocessed(transactionAmountUnprocessed); - boolean interestBearingAndInterestRecalculationEnabled = loanTransaction.getLoan() - .isInterestBearingAndInterestRecalculationEnabled(); if (isInterestRecalculationSupported(ctx, loanTransaction.getLoan())) { // Clear any previously skipped installments before re-evaluating @@ -2592,6 +2598,7 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep final boolean isFirstInstallment = installment.getInstallmentNumber().equals(firstInstallmentNumber); return charges.stream() .filter(loanCharge -> (loanCharge.isInstalmentFee() && loanCharge.hasInstallmentFor(installment)) + || (installment.isReAged() && loanCharge.hasInstallmentFor(installment)) || loanCharge.isDueInPeriod(installment.getFromDate(), installment.getDueDate(), isFirstInstallment)) .collect(Collectors.toSet()); } @@ -2760,6 +2767,39 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep private Money aggregatedPenaltyChargesPortion; } + @AllArgsConstructor + @Getter + @Setter + private static final class BalancesWithPaidInAdvance { + + private Money principal; + private Money interest; + private Money fee; + private Money penalty; + private Money paidInAdvance; + private Set loanTransactionToRepaymentScheduleMappings; + + private BalancesWithPaidInAdvance(MonetaryCurrency currency) { + this(Money.zero(currency), Money.zero(currency), Money.zero(currency), Money.zero(currency), Money.zero(currency), + new LinkedHashSet<>()); + } + + private BalancesWithPaidInAdvance(LoanRepaymentScheduleInstallment i, MonetaryCurrency currency) { + this(i.getPrincipalCompleted(currency), i.getInterestPaid(currency), i.getFeeChargesPaid(currency), + i.getPenaltyChargesPaid(currency), i.getTotalPaidInAdvance(currency), + new LinkedHashSet<>(i.getLoanTransactionToRepaymentScheduleMappings())); + } + + private static BalancesWithPaidInAdvance summarizerAccumulator(BalancesWithPaidInAdvance a, BalancesWithPaidInAdvance b) { + Set set = new LinkedHashSet<>( + a.getLoanTransactionToRepaymentScheduleMappings().size() + b.getLoanTransactionToRepaymentScheduleMappings().size()); + set.addAll(a.getLoanTransactionToRepaymentScheduleMappings()); + set.addAll(b.getLoanTransactionToRepaymentScheduleMappings()); + return new BalancesWithPaidInAdvance(a.getPrincipal().add(b.getPrincipal()), a.getInterest().add(b.getInterest()), + a.getFee().add(b.getFee()), a.getPenalty().add(b.getPenalty()), a.getPaidInAdvance().add(b.getPaidInAdvance()), set); + } + } + private void mergeReAgedInstallment(final LoanRepaymentScheduleInstallment target, final LoanRepaymentScheduleInstallment reAgedInstallment, MonetaryCurrency currency, LocalDate transactionDate) { target.setAdditional(false); @@ -2767,11 +2807,19 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep target.setFromDate(reAgedInstallment.getFromDate()); target.setDueDate(reAgedInstallment.getDueDate()); target.setPrincipal(MathUtil.add(reAgedInstallment.getPrincipal(), target.getPrincipalCompleted())); + target.setInterestCharged(MathUtil.add(reAgedInstallment.getInterestCharged(), target.getInterestPaid())); + target.setInterestAccrued(MathUtil.add(target.getInterestAccrued(), reAgedInstallment.getInterestAccrued())); + + target.setFeeChargesCharged(MathUtil.add(reAgedInstallment.getFeeChargesCharged(), target.getFeeChargesCharged())); + target.setFeeAccrued(MathUtil.add(target.getFeeAccrued(), reAgedInstallment.getFeeAccrued())); + target.setPenaltyCharges(MathUtil.add(reAgedInstallment.getPenaltyCharges(), target.getPenaltyCharges())); + target.setPenaltyAccrued(MathUtil.add(target.getPenaltyAccrued(), reAgedInstallment.getPenaltyAccrued())); + target.updateObligationsMet(currency, transactionDate); } - private void insertOrReplaceRelatedInstallment(List installments, + private LoanRepaymentScheduleInstallment insertOrReplaceRelatedInstallment(List installments, final LoanRepaymentScheduleInstallment reAgedInstallment, final MonetaryCurrency currency, final LocalDate transactionDate) { Optional first = installments.stream() .filter(installment -> Objects.equals(installment.getInstallmentNumber(), reAgedInstallment.getInstallmentNumber())) @@ -2785,107 +2833,71 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep // additional ( N+1 ) installment due date cannot be earlier than its original due date if (!target.getDueDate().isAfter(reAgedInstallment.getDueDate())) { mergeReAgedInstallment(target, reAgedInstallment, currency, transactionDate); + return target; } else { + InstallmentProcessingHelper.addOneToInstallmentNumberFromInstallment(installments, + reAgedInstallment.getInstallmentNumber()); installments.add(reAgedInstallment); reAgedInstallment.updateObligationsMet(currency, transactionDate); - installments.stream() - .filter(i -> i.getInstallmentNumber() != null && i.getInstallmentNumber() >= target.getInstallmentNumber()) - .forEach(i -> i.setInstallmentNumber(i.getInstallmentNumber() + 1)); + return reAgedInstallment; } } else { mergeReAgedInstallment(target, reAgedInstallment, currency, transactionDate); + return target; } } else { installments.add(reAgedInstallment); reAgedInstallment.updateObligationsMet(currency, transactionDate); + return reAgedInstallment; } } private void handleReAge(LoanTransaction loanTransaction, TransactionCtx ctx) { loanTransaction.resetDerivedComponents(); - MonetaryCurrency currency = ctx.getCurrency(); - List installments = ctx.getInstallments(); + Loan loan = loanTransaction.getLoan(); + LoanReAgeParameter loanReAgeParameter = loanTransaction.getLoanReAgeParameter(); - // re-aging logic for interest-bearing loans - if (ctx instanceof ProgressiveTransactionCtx progressiveTransactionCtx - && loanTransaction.getLoan().isInterestBearingAndInterestRecalculationEnabled()) { - handleReAgeWithInterestRecalculationEnabled(loanTransaction, progressiveTransactionCtx); - } else if (loanTransaction.getLoan().isInterestBearing() && !loanTransaction.getLoan().isInterestRecalculationEnabled()) { - // TODO: implement interestRecalculation = false logic - throw new NotImplementedException( - "Logic for re-aging when interest bearing loan has interestRecalculation disabled is not implemented"); - } else { - AtomicReference outstandingPrincipalBalance = new AtomicReference<>(Money.zero(currency)); - installments.forEach(i -> { - Money principalOutstanding = i.getPrincipalOutstanding(currency); - if (principalOutstanding.isGreaterThanZero()) { - outstandingPrincipalBalance.set(outstandingPrincipalBalance.get().add(principalOutstanding)); - i.addToPrincipal(loanTransaction.getTransactionDate(), principalOutstanding.negated()); + if (loan.isInterestBearing()) { + if (((loanReAgeParameter.getInterestHandlingType() == null) + || loanReAgeParameter.getInterestHandlingType().equals(LoanReAgeInterestHandlingType.DEFAULT))) { + + // re-aging logic for interest-bearing loans + if (ctx instanceof ProgressiveTransactionCtx progressiveTransactionCtx + && loanTransaction.getLoan().isInterestBearingAndInterestRecalculationEnabled()) { + handleReAgeWithInterestRecalculationEnabled(loanTransaction, progressiveTransactionCtx); + } else if (loanTransaction.getLoan().isInterestBearing() && !loanTransaction.getLoan().isInterestRecalculationEnabled()) { + // TODO: implement interestRecalculation = false logic + throw new NotImplementedException( + "Logic for re-aging when interest bearing loan has interestRecalculation disabled is not implemented"); } - }); - loanTransaction.updateComponentsAndTotal(outstandingPrincipalBalance.get(), Money.zero(currency), Money.zero(currency), - Money.zero(currency)); - - if (outstandingPrincipalBalance.get().isZero()) { - loanTransaction.reverse(); - return; - } - - Money calculatedPrincipal = Money.zero(currency); - Money adjustCalculatedPrincipal = Money.zero(currency); - if (outstandingPrincipalBalance.get().isGreaterThanZero()) { - calculatedPrincipal = outstandingPrincipalBalance.get() - .dividedBy(loanTransaction.getLoanReAgeParameter().getNumberOfInstallments(), MoneyHelper.getMathContext()); - Integer installmentAmountInMultiplesOf = loanTransaction.getLoan().getLoanProductRelatedDetail() - .getInstallmentAmountInMultiplesOf(); - if (installmentAmountInMultiplesOf != null) { - calculatedPrincipal = Money.roundToMultiplesOf(calculatedPrincipal, installmentAmountInMultiplesOf); - } - adjustCalculatedPrincipal = outstandingPrincipalBalance.get() - .minus(calculatedPrincipal.multipliedBy(loanTransaction.getLoanReAgeParameter().getNumberOfInstallments())); - } - - Optional lastNormalInstallmentOptional = installments.stream().filter(i -> !i.isDownPayment()) - .filter(i -> i.getDueDate().isBefore(loanTransaction.getTransactionDate())).reduce((first, second) -> second); - - int reAgedInstallmentNumber; - LocalDate fromDate; - Loan loan; - if (lastNormalInstallmentOptional.isEmpty()) { - LoanRepaymentScheduleInstallment firstNormalInstallment = installments.stream().filter(i -> !i.isDownPayment()) - .min(Comparator.comparing(LoanRepaymentScheduleInstallment::getDueDate)).orElseThrow(); - reAgedInstallmentNumber = firstNormalInstallment.getInstallmentNumber(); - fromDate = firstNormalInstallment.getFromDate(); - loan = firstNormalInstallment.getLoan(); + } else if (LoanReAgeInterestHandlingType.WAIVE_INTEREST.equals(loanReAgeParameter.getInterestHandlingType())) { + throw new NotImplementedException("WAIVE_INTEREST interest handling strategy for re-aging is not implemented"); } else { - LoanRepaymentScheduleInstallment lastNormalInstallment = lastNormalInstallmentOptional.get(); - reAgedInstallmentNumber = lastNormalInstallment.getInstallmentNumber() + 1; - fromDate = lastNormalInstallment.getDueDate(); - loan = lastNormalInstallment.getLoan(); - } - - LoanRepaymentScheduleInstallment reAgedInstallment = LoanRepaymentScheduleInstallment.newReAgedInstallment(loan, - reAgedInstallmentNumber, fromDate, loanTransaction.getLoanReAgeParameter().getStartDate(), - calculatedPrincipal.getAmount()); - insertOrReplaceRelatedInstallment(installments, reAgedInstallment, currency, loanTransaction.getTransactionDate()); - - for (int i = 1; i < loanTransaction.getLoanReAgeParameter().getNumberOfInstallments(); i++) { - LocalDate calculatedDueDate = calculateReAgedInstallmentDueDate(loanTransaction.getLoanReAgeParameter(), - reAgedInstallment.getDueDate()); - int nextReAgedInstallmentNumber = reAgedInstallment.getInstallmentNumber() + 1; - reAgedInstallment = LoanRepaymentScheduleInstallment.newReAgedInstallment(reAgedInstallment.getLoan(), - nextReAgedInstallmentNumber, reAgedInstallment.getDueDate(), calculatedDueDate, calculatedPrincipal.getAmount()); - if (i + 1 == loanTransaction.getLoanReAgeParameter().getNumberOfInstallments()) { - reAgedInstallment.addToPrincipal(loanTransaction.getTransactionDate(), adjustCalculatedPrincipal); + if (LoanReAgeInterestHandlingType.EQUAL_AMORTIZATION_FULL_INTEREST.equals(loanReAgeParameter.getInterestHandlingType())) { + CommonReAgeSettings settings = new CommonReAgeSettings(false, true, true, true); + if (ctx instanceof ProgressiveTransactionCtx progressiveTransactionCtx + && loanTransaction.getLoan().isInterestRecalculationEnabled()) { + handleReAgeEqualAmortizationEMICalculator(loanTransaction, settings, progressiveTransactionCtx); + } else { + handleReAgeWithCommonStrategy(loanTransaction, settings, ctx); + } + } else if (LoanReAgeInterestHandlingType.EQUAL_AMORTIZATION_PAYABLE_INTEREST + .equals(loanReAgeParameter.getInterestHandlingType())) { + CommonReAgeSettings settings = new CommonReAgeSettings(true, true, true, true); + if (ctx instanceof ProgressiveTransactionCtx progressiveTransactionCtx + && loanTransaction.getLoan().isInterestRecalculationEnabled()) { + handleReAgeEqualAmortizationEMICalculator(loanTransaction, settings, progressiveTransactionCtx); + } else { + handleReAgeWithCommonStrategy(loanTransaction, settings, ctx); + } } - insertOrReplaceRelatedInstallment(installments, reAgedInstallment, currency, loanTransaction.getTransactionDate()); } - int lastReAgedInstallmentNumber = reAgedInstallment.getInstallmentNumber(); - List toRemove = installments.stream().filter(i -> i != null && !i.isAdditional() - && i.getInstallmentNumber() != null && i.getInstallmentNumber() > lastReAgedInstallmentNumber).toList(); - toRemove.forEach(installments::remove); - reprocessInstallments(installments); + } else { + handleReAgeWithCommonStrategy(loanTransaction, new CommonReAgeSettings(), ctx); + } + if (loanTransaction.getAmount().compareTo(ZERO) == 0) { + loanTransaction.reverse(); } } @@ -2929,7 +2941,7 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep final LoanRepaymentScheduleInstallment lastInstallment = ctx.getInstallments().getLast(); final LoanRepaymentScheduleInstallment newInstallment = LoanRepaymentScheduleInstallment.newReAgedInstallment( loanTransaction.getLoan(), lastInstallment.getInstallmentNumber() + 1, rp.getFromDate(), rp.getDueDate(), - rp.getDuePrincipal().getAmount()); + rp.getDuePrincipal().getAmount(), null, null, null); if (rp.getDueInterest().isGreaterThanZero()) { newInstallment.addToInterest(transactionDate, rp.getDueInterest()); @@ -3193,6 +3205,294 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep } } + private BalancesWithPaidInAdvance liftEarlyRepaidBalances(List installments, + LocalDate transactionDate, MonetaryCurrency currency, List alreadyProcessedTransactions) { + return installments.stream().filter(i -> !i.isDownPayment() && !i.isAdditional() && !i.getDueDate().isBefore(transactionDate)) + .map(installment -> { + alreadyProcessedTransactions.forEach(tr -> { + Set relatedMapping = tr.getLoanTransactionToRepaymentScheduleMappings() + .stream().filter(m -> m.getInstallment().equals(installment)).collect(Collectors.toSet()); + installment.getLoanTransactionToRepaymentScheduleMappings().addAll(relatedMapping); + }); + BalancesWithPaidInAdvance res = new BalancesWithPaidInAdvance(installment, currency); + installment.resetDerivedComponents(); + installment.getLoanTransactionToRepaymentScheduleMappings() + .forEach(m -> m.getLoanTransaction().getLoanTransactionToRepaymentScheduleMappings().remove(m)); + installment.getLoanTransactionToRepaymentScheduleMappings().clear(); + return res; + }).reduce(new BalancesWithPaidInAdvance(currency), BalancesWithPaidInAdvance::summarizerAccumulator); + } + + private void handleReAgeEqualAmortizationEMICalculator(LoanTransaction loanTransaction, CommonReAgeSettings settings, + ProgressiveTransactionCtx ctx) { + ProgressiveLoanInterestScheduleModel model = ctx.getModel(); + MonetaryCurrency currency = ctx.getCurrency(); + List installments = ctx.getInstallments(); + LoanReAgeParameter loanReAgeParameter = loanTransaction.getLoanReAgeParameter(); + Integer numberOfReAgeInstallments = loanReAgeParameter.getNumberOfInstallments(); + LocalDate transactionDate = loanTransaction.getTransactionDate(); + + OutstandingDetails outstandingDetails = emiCalculator.precalculateReAgeEqualAmortizationAmount(model, transactionDate, + loanReAgeParameter); + + OutstandingBalances outstandingBalances = liftOutstandingBalances(installments, transactionDate, currency, + settings.isSkipDownPayments(), settings.isOnlyPayableInterest(), settings.isEqualInstallmentForInterest(), + settings.isEqualInstallmentForFeesAndPenalties(), ctx); + + loanTransaction.updateComponentsAndTotal(outstandingDetails.getOutstandingPrincipal(), outstandingDetails.getOutstandingInterest(), + outstandingBalances.fees, outstandingBalances.penalties); + + if (loanTransaction.getAmount().compareTo(ZERO) == 0) { + loanTransaction.reverse(); + } + + // handle non EMI calculator portions + + EqualAmortizationValues calculatedFees = emiCalculator.calculateEqualAmortizationValues(outstandingBalances.fees, + numberOfReAgeInstallments, null, currency); + EqualAmortizationValues calculatedPenalties = emiCalculator.calculateEqualAmortizationValues(outstandingBalances.penalties, + numberOfReAgeInstallments, null, currency); + EqualAmortizationValues calculatedInterestAccrued = emiCalculator + .calculateEqualAmortizationValues(outstandingBalances.interestAccrued, numberOfReAgeInstallments, null, currency); + EqualAmortizationValues calculatedFeeAccrued = emiCalculator.calculateEqualAmortizationValues(outstandingBalances.feesAccrued, + numberOfReAgeInstallments, null, currency); + EqualAmortizationValues calculatedPenaltyAccrued = emiCalculator + .calculateEqualAmortizationValues(outstandingBalances.penaltiesAccrued, numberOfReAgeInstallments, null, currency); + + List calculatedCharges = outstandingBalances.liftedLoanCharges().stream() + .map(loanCharge -> new ReAgedChargeEqualAmortizationValues(loanCharge, emiCalculator.calculateEqualAmortizationValues( + loanCharge.getAmountOutstanding(currency), numberOfReAgeInstallments, null, currency))) + .toList(); + + BalancesWithPaidInAdvance paidInAdvanceBalances = liftEarlyRepaidBalances(installments, transactionDate, currency, + ctx.getAlreadyProcessedTransactions()); + + // TODO add as Parameter here: paidInAdvanceBalances.getAggregatedFeeChargesPortion().isGreaterThanZero() || + // paidInAdvanceBalances.getAggregatedPenaltyChargesPortion().isGreaterThanZero() + emiCalculator.reAgeEqualAmortization(model, transactionDate, loanReAgeParameter, + outstandingBalances.fees.add(outstandingBalances.penalties), + new EqualAmortizationValues(calculatedFees.value().add(calculatedPenalties.value()), + calculatedFees.adjustment().add(calculatedPenalties.adjustment()))); + + installments.removeIf(i -> (i.getInstallmentNumber() != null && !i.isDownPayment() && !i.getDueDate().isBefore(transactionDate) + && !i.isAdditional()) || (!i.getDueDate().isAfter(model.getMaturityDate()) && i.isAdditional())); + + installments.stream().filter(LoanRepaymentScheduleInstallment::isAdditional).forEach(i -> { + i.setFromDate(model.getMaturityDate()); + i.setInstallmentNumber(model.repaymentPeriods().size()); + }); + + for (int index = 0; index < model.repaymentPeriods().size(); index++) { + RepaymentPeriod rp = model.repaymentPeriods().get(index); + if (rp.getDueDate().isBefore(transactionDate)) { + // update existing + Optional notReagedInstallment = installments.stream() + .filter(i -> i.getDueDate().isEqual(rp.getDueDate()) && i.getFromDate().isEqual(rp.getFromDate())).findFirst(); + LoanRepaymentScheduleInstallment installment = notReagedInstallment.orElseThrow(); + installment.setInterestCharged(installment.getInterestPaid()); + installment.setPrincipal(installment.getPrincipalCompleted(currency).getAmount()); + installment.setInstallmentNumber(index + 1); + + installment.updateObligationsMet(currency, transactionDate); + // TODO add remaining components + } else { + LoanRepaymentScheduleInstallment created = LoanRepaymentScheduleInstallment.newReAgedInstallment(loanTransaction.getLoan(), + index + 1, rp.getFromDate(), rp.getDueDate(), rp.getDuePrincipal().getAmount(), rp.getDueInterest().getAmount(), + ZERO, ZERO); + + if (rp.isReAgedEarlyRepaymentHolder()) { + created.setPrincipalCompleted(rp.getPaidPrincipal().getAmount()); + created.setInterestPaid(rp.getPaidInterest().getAmount()); + + created.setFeeChargesCharged(paidInAdvanceBalances.getFee().getAmount()); + created.setFeeChargesPaid(paidInAdvanceBalances.getFee().getAmount()); + created.setPenaltyCharges(paidInAdvanceBalances.getPenalty().getAmount()); + created.setPenaltyChargesPaid(paidInAdvanceBalances.getPenalty().getAmount()); + + created.setTotalPaidInAdvance(paidInAdvanceBalances.getPaidInAdvance().getAmount()); + + paidInAdvanceBalances.loanTransactionToRepaymentScheduleMappings.forEach(m -> m.setInstallment(created)); + } else { + boolean isLastRepaymentPeriod = model.isLastRepaymentPeriod(rp); + created.setFeeChargesCharged(calculatedFees.calculateValueBigDecimal(isLastRepaymentPeriod)); + created.setPenaltyCharges(calculatedPenalties.calculateValueBigDecimal(isLastRepaymentPeriod)); + + created.setInterestAccrued(calculatedInterestAccrued.calculateValueBigDecimal(isLastRepaymentPeriod)); + created.setFeeAccrued(calculatedFeeAccrued.calculateValueBigDecimal(isLastRepaymentPeriod)); + created.setPenaltyAccrued(calculatedPenaltyAccrued.calculateValueBigDecimal(isLastRepaymentPeriod)); + + createChargeMappingsForInstallment(created, calculatedCharges, isLastRepaymentPeriod); + } + created.updateObligationsMet(currency, transactionDate); + installments.add(created); + } + } + reprocessInstallments(installments); + + } + + private void handleReAgeWithCommonStrategy(LoanTransaction loanTransaction, CommonReAgeSettings settings, TransactionCtx ctx) { + MonetaryCurrency currency = ctx.getCurrency(); + Loan loan = loanTransaction.getLoan(); + List installments = ctx.getInstallments(); + LoanReAgeParameter loanReAgeParameter = loanTransaction.getLoanReAgeParameter(); + LocalDate transactionDate = loanTransaction.getTransactionDate(); + + Integer numberOfReAgeInstallments = loanReAgeParameter.getNumberOfInstallments(); + Integer installmentAmountInMultiplesOf = loanTransaction.getLoan().getLoanProductRelatedDetail() + .getInstallmentAmountInMultiplesOf(); + + OutstandingBalances outstandingBalances = liftOutstandingBalances(installments, transactionDate, currency, + settings.isSkipDownPayments(), settings.isOnlyPayableInterest(), settings.isEqualInstallmentForInterest(), + settings.isEqualInstallmentForFeesAndPenalties(), ctx); + + loanTransaction.updateComponentsAndTotal(outstandingBalances.principal, outstandingBalances.interest, outstandingBalances.fees, + outstandingBalances.penalties); + + if (MathUtil.isZero(loanTransaction.getAmount())) { + loanTransaction.reverse(); + return; + } + + EqualAmortizationValues calculatedInterest = emiCalculator.calculateEqualAmortizationValues(outstandingBalances.interest, + numberOfReAgeInstallments, null, currency); + EqualAmortizationValues calculatedFees = emiCalculator.calculateEqualAmortizationValues(outstandingBalances.fees, + numberOfReAgeInstallments, null, currency); + EqualAmortizationValues calculatedPenalties = emiCalculator.calculateEqualAmortizationValues(outstandingBalances.penalties, + numberOfReAgeInstallments, null, currency); + EqualAmortizationValues calculatedInterestAccrued = emiCalculator + .calculateEqualAmortizationValues(outstandingBalances.interestAccrued, numberOfReAgeInstallments, null, currency); + EqualAmortizationValues calculatedFeeAccrued = emiCalculator.calculateEqualAmortizationValues(outstandingBalances.feesAccrued, + numberOfReAgeInstallments, null, currency); + EqualAmortizationValues calculatedPenaltyAccrued = emiCalculator + .calculateEqualAmortizationValues(outstandingBalances.penaltiesAccrued, numberOfReAgeInstallments, null, currency); + + EqualAmortizationValues calculatedPrincipal = emiCalculator.calculateAdjustedEqualAmortizationValues(outstandingBalances.principal, + outstandingBalances.principal.add(outstandingBalances.interest).add(outstandingBalances.fees) + .add(outstandingBalances.penalties), + calculatedInterest.value().add(calculatedFees.value()).add(calculatedPenalties.value()), numberOfReAgeInstallments, + installmentAmountInMultiplesOf, currency); + + List calculatedCharges = outstandingBalances.liftedLoanCharges().stream() + .map(loanCharge -> new ReAgedChargeEqualAmortizationValues(loanCharge, emiCalculator.calculateEqualAmortizationValues( + loanCharge.getAmountOutstanding(currency), numberOfReAgeInstallments, null, currency))) + .toList(); + + FirstReAgeInstallmentProps firstReAgeInstallmentProps = calculateFirstReAgeInstallmentProps(installments, + loanReAgeParameter.getStartDate()); + + BalancesWithPaidInAdvance balances = installments.stream() + .filter(i -> !i.isDownPayment() && !i.isAdditional() && !i.getDueDate().isBefore(transactionDate)).map(installment -> { + + BalancesWithPaidInAdvance res = new BalancesWithPaidInAdvance(installment, currency); + installment.setPrincipal( + installment.getPrincipal(currency).minus(installment.getPrincipalCompleted(currency)).getAmount()); + installment.setPrincipalCompleted(null); + installment.setInterestCharged( + installment.getInterestCharged(currency).minus(installment.getInterestPaid(currency)).getAmount()); + installment.setInterestPaid(null); + installment.setFeeChargesCharged( + installment.getFeeChargesCharged(currency).minus(installment.getFeeChargesPaid(currency)).getAmount()); + installment.setFeeChargesPaid(null); + installment.setPenaltyCharges( + installment.getPenaltyChargesCharged(currency).minus(installment.getPenaltyChargesPaid(currency)).getAmount()); + installment.setPenaltyChargesPaid(null); + installment.setTotalPaidInAdvance(null); + return res; + }).reduce(new BalancesWithPaidInAdvance(currency), BalancesWithPaidInAdvance::summarizerAccumulator); + + if (!balances.getPrincipal().isZero() || !balances.getInterest().isZero() || !balances.getFee().isZero() + || !balances.getPenalty().isZero()) { + + final LoanRepaymentScheduleInstallment earlyRepaidInstallment = LoanRepaymentScheduleInstallment.newReAgedInstallment(loan, + firstReAgeInstallmentProps.reAgedInstallmentNumber(), firstReAgeInstallmentProps.fromDate(), transactionDate, + balances.getPrincipal().getAmount(), balances.getInterest().getAmount(), balances.getFee().getAmount(), + balances.getPenalty().getAmount(), null, null, null); + + earlyRepaidInstallment.setPrincipalCompleted(balances.getPrincipal().getAmount()); + earlyRepaidInstallment.setInterestPaid(balances.getInterest().getAmount()); + earlyRepaidInstallment.setFeeChargesPaid(balances.getFee().getAmount()); + earlyRepaidInstallment.setPenaltyChargesPaid(balances.getPenalty().getAmount()); + + earlyRepaidInstallment.setTotalPaidInAdvance(balances.getPaidInAdvance().getAmount()); + + earlyRepaidInstallment.updateObligationsMet(currency, transactionDate); + firstReAgeInstallmentProps = new FirstReAgeInstallmentProps(firstReAgeInstallmentProps.reAgedInstallmentNumber + 1, + transactionDate); + + InstallmentProcessingHelper.addOneToInstallmentNumberFromInstallment(installments, + earlyRepaidInstallment.getInstallmentNumber()); + loan.getRepaymentScheduleInstallments().add(earlyRepaidInstallment); + } + + LoanRepaymentScheduleInstallment reAgedInstallment = LoanRepaymentScheduleInstallment.newReAgedInstallment(loan, + firstReAgeInstallmentProps.reAgedInstallmentNumber, firstReAgeInstallmentProps.fromDate, loanReAgeParameter.getStartDate(), + calculatedPrincipal.value().getAmount(), calculatedInterest.value().getAmount(), calculatedFees.value().getAmount(), + calculatedPenalties.value().getAmount(), calculatedInterestAccrued.value().getAmount(), + calculatedFeeAccrued.value().getAmount(), calculatedPenaltyAccrued.value().getAmount()); + + reAgedInstallment = insertOrReplaceRelatedInstallment(installments, reAgedInstallment, currency, transactionDate); + createChargeMappingsForInstallment(reAgedInstallment, calculatedCharges, false); + + for (int i = 1; i < numberOfReAgeInstallments; i++) { + LocalDate calculatedDueDate = scheduledDateGenerator.getRepaymentPeriodDate(loanReAgeParameter.getFrequencyType(), + loanReAgeParameter.getFrequencyNumber(), reAgedInstallment.getDueDate()); + calculateReAgedInstallmentDueDate(loanReAgeParameter, reAgedInstallment.getDueDate()); + int nextReAgedInstallmentNumber = firstReAgeInstallmentProps.reAgedInstallmentNumber + i; + boolean isLastInstallment = i + 1 == numberOfReAgeInstallments; + + reAgedInstallment = LoanRepaymentScheduleInstallment.newReAgedInstallment(reAgedInstallment.getLoan(), + nextReAgedInstallmentNumber, reAgedInstallment.getDueDate(), calculatedDueDate, + calculatedPrincipal.calculateValueBigDecimal(isLastInstallment), + calculatedInterest.calculateValueBigDecimal(isLastInstallment), + calculatedFees.calculateValueBigDecimal(isLastInstallment), + calculatedPenalties.calculateValueBigDecimal(isLastInstallment), + calculatedInterestAccrued.calculateValueBigDecimal(isLastInstallment), + calculatedFeeAccrued.calculateValueBigDecimal(isLastInstallment), + calculatedPenaltyAccrued.calculateValueBigDecimal(isLastInstallment)); + + reAgedInstallment = insertOrReplaceRelatedInstallment(installments, reAgedInstallment, currency, transactionDate); + createChargeMappingsForInstallment(reAgedInstallment, calculatedCharges, isLastInstallment); + } + int lastReAgedInstallmentNumber = reAgedInstallment.getInstallmentNumber(); + List toRemove = installments.stream() + .filter(i -> i != null && !i.isAdditional() && i.getInstallmentNumber() != null + && i.getInstallmentNumber() > lastReAgedInstallmentNumber && i.getTotalPaid(currency).isZero()) + .toList(); + toRemove.forEach(installments::remove); + reprocessInstallments(installments); + } + + private void createChargeMappingsForInstallment(final LoanRepaymentScheduleInstallment installment, + List reAgedChargeEqualAmortizationValues, boolean isLastInstallment) { + reAgedChargeEqualAmortizationValues.forEach(amortizationValue -> { + installment.getInstallmentCharges() + .add(new LoanInstallmentCharge(amortizationValue.equalAmortizationValues.calculateValueBigDecimal(isLastInstallment), + amortizationValue.charge, installment)); + }); + } + + private FirstReAgeInstallmentProps calculateFirstReAgeInstallmentProps(List installments, + LocalDate startDate) { + int reAgedInstallmentNumber; + LocalDate fromDate; + + Optional lastNormalInstallmentOptional = installments.stream() + .filter(i -> !i.isDownPayment() && i.getDueDate().isBefore(startDate)) + .max(Comparator.comparing(LoanRepaymentScheduleInstallment::getDueDate)); + if (lastNormalInstallmentOptional.isEmpty()) { + LoanRepaymentScheduleInstallment firstNormalInstallment = installments.stream().filter(i -> !i.isDownPayment()) + .min(Comparator.comparing(LoanRepaymentScheduleInstallment::getDueDate)).orElseThrow(); + reAgedInstallmentNumber = firstNormalInstallment.getInstallmentNumber(); + fromDate = firstNormalInstallment.getFromDate(); + } else { + LoanRepaymentScheduleInstallment lastNormalInstallment = lastNormalInstallmentOptional.get(); + reAgedInstallmentNumber = lastNormalInstallment.getInstallmentNumber() + 1; + fromDate = lastNormalInstallment.getDueDate(); + } + return new FirstReAgeInstallmentProps(reAgedInstallmentNumber, fromDate); + } + private void handleReAgeWithInterestRecalculationEnabled(final LoanTransaction loanTransaction, final ProgressiveTransactionCtx ctx) { final MonetaryCurrency currency = ctx.getCurrency(); final Loan loan = loanTransaction.getLoan(); @@ -3250,6 +3550,105 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep reprocessInstallments(installments); } + OutstandingBalances liftOutstandingBalances(List installments, LocalDate transactionDate, + MonetaryCurrency currency, boolean skipDownPayments, boolean onlyPlayableInterest, boolean isEqualInstallmentForInterest, + boolean isEqualInstallmentForFeesAndPenalties, TransactionCtx ctx) { + + AtomicReference outstandingPrincipalBalance = new AtomicReference<>(Money.zero(currency)); + AtomicReference outstandingInterestBalance = new AtomicReference<>(Money.zero(currency)); + AtomicReference outstandingFeesBalance = new AtomicReference<>(Money.zero(currency)); + AtomicReference outstandingPenaltiesBalance = new AtomicReference<>(Money.zero(currency)); + AtomicReference accruedInterestToMove = new AtomicReference<>(Money.zero(currency)); + AtomicReference accruedFeeToMove = new AtomicReference<>(Money.zero(currency)); + AtomicReference accruedPenaltyToMove = new AtomicReference<>(Money.zero(currency)); + final List liftedLoanCharges = new ArrayList<>(); + + installments.stream().filter(i -> !skipDownPayments || !i.isDownPayment()).forEach(i -> { + Money principalOutstanding = i.getPrincipalOutstanding(currency); + if (principalOutstanding.isGreaterThanZero()) { + outstandingPrincipalBalance.set(outstandingPrincipalBalance.get().add(principalOutstanding)); + i.addToPrincipal(transactionDate, principalOutstanding.negated()); + } + Money interestOutstanding = i.getInterestOutstanding(currency); + if (isEqualInstallmentForInterest && interestOutstanding.isGreaterThanZero()) { + outstandingInterestBalance.set(outstandingInterestBalance.get().add(interestOutstanding)); + i.addToInterest(transactionDate, interestOutstanding.negated()); + BigDecimal paid = MathUtil.nullToZero(i.getInterestPaid()); + BigDecimal accrued = MathUtil.nullToZero(i.getInterestAccrued()); + if (paid.compareTo(accrued) < 0) { + accruedInterestToMove.set(Money.of(currency, accrued.subtract(paid))); + i.setInterestAccrued(paid); + } + } + + if (isEqualInstallmentForFeesAndPenalties) { + getLoanChargesOfInstallment(ctx.getCharges(), i, 1)// + .stream()// + .filter(c -> MathUtil.isGreaterThanZero(c.getAmountOutstanding()))// + .forEach(liftedLoanCharges::add); + Money feesOutstanding = i.getFeeChargesOutstanding(currency); + Money penaltiesOutstanding = i.getPenaltyChargesOutstanding(currency); + + outstandingFeesBalance.set(outstandingFeesBalance.get().add(feesOutstanding)); + outstandingPenaltiesBalance.set(outstandingPenaltiesBalance.get().add(penaltiesOutstanding)); + + i.setFeeChargesCharged(i.getFeeChargesPaid()); + i.setPenaltyCharges(i.getPenaltyChargesPaid()); + } + if (isEqualInstallmentForFeesAndPenalties) { + BigDecimal paid = MathUtil.nullToZero(i.getFeeChargesPaid()); + BigDecimal accrued = MathUtil.nullToZero(i.getFeeAccrued()); + if (paid.compareTo(accrued) < 0) { + accruedFeeToMove.set(Money.of(currency, accrued.subtract(paid))); + i.setFeeAccrued(paid); + } + } + if (isEqualInstallmentForFeesAndPenalties) { + BigDecimal paid = MathUtil.nullToZero(i.getPenaltyChargesPaid()); + BigDecimal accrued = MathUtil.nullToZero(i.getPenaltyAccrued()); + if (paid.compareTo(accrued) < 0) { + accruedPenaltyToMove.set(Money.of(currency, accrued.subtract(paid))); + i.setPenaltyAccrued(paid); + } + } + i.updateObligationsMet(currency, transactionDate); + }); + if (isEqualInstallmentForInterest && onlyPlayableInterest) { + if (ctx instanceof ProgressiveTransactionCtx progressiveCtx) { + ProgressiveLoanInterestScheduleModel model = progressiveCtx.getModel(); + outstandingInterestBalance + .set(emiCalculator.getOutstandingAmountsTillDate(model, transactionDate).getOutstandingInterest()); + } else { + throw new IllegalStateException("TODO Fix me: Only progressive transaction context is supported"); + } + } + return new OutstandingBalances(outstandingPrincipalBalance.get(), outstandingInterestBalance.get(), accruedInterestToMove.get(), + outstandingFeesBalance.get(), accruedFeeToMove.get(), outstandingPenaltiesBalance.get(), accruedPenaltyToMove.get(), + liftedLoanCharges); + } + + @Getter + @Setter + @NoArgsConstructor + @AllArgsConstructor + private static final class CommonReAgeSettings { + + boolean onlyPayableInterest = false; + boolean skipDownPayments = false; + boolean isEqualInstallmentForInterest = false; + boolean isEqualInstallmentForFeesAndPenalties = false; + } + + private record ReAgedChargeEqualAmortizationValues(LoanCharge charge, EqualAmortizationValues equalAmortizationValues) { + } + + private record FirstReAgeInstallmentProps(int reAgedInstallmentNumber, LocalDate fromDate) { + } + + private record OutstandingBalances(Money principal, Money interest, Money interestAccrued, Money fees, Money feesAccrued, + Money penalties, Money penaltiesAccrued, List liftedLoanCharges) { + } + private static LocalDate calculateFirstReAgedPeriodStartDate(final LoanTransaction loanTransaction) { final LoanReAgeParameter loanReAgeParameter = loanTransaction.getLoanReAgeParameter(); final LocalDate reAgingStartDate = loanReAgeParameter.getStartDate(); diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/EMICalculator.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/EMICalculator.java index 2706efb75..db0288428 100644 --- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/EMICalculator.java +++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/EMICalculator.java @@ -24,11 +24,14 @@ import java.math.MathContext; import java.time.LocalDate; import java.util.List; import java.util.Optional; +import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency; import org.apache.fineract.organisation.monetary.domain.Money; import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; +import org.apache.fineract.portfolio.loanaccount.domain.reaging.LoanReAgeParameter; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelRepaymentPeriod; +import org.apache.fineract.portfolio.loanproduct.calc.data.EqualAmortizationValues; import org.apache.fineract.portfolio.loanproduct.calc.data.OutstandingDetails; import org.apache.fineract.portfolio.loanproduct.calc.data.PeriodDueDetails; import org.apache.fineract.portfolio.loanproduct.calc.data.ProgressiveLoanInterestScheduleModel; @@ -151,4 +154,18 @@ public interface EMICalculator { */ @NotNull Money getOutstandingInterestTillDate(@NotNull ProgressiveLoanInterestScheduleModel scheduleModel, @NotNull LocalDate tillDate); + + OutstandingDetails precalculateReAgeEqualAmortizationAmount(ProgressiveLoanInterestScheduleModel interestSchedule, + LocalDate transactionDate, LoanReAgeParameter reageParameter); + + void reAgeEqualAmortization(ProgressiveLoanInterestScheduleModel interestSchedule, LocalDate transactionDate, + LoanReAgeParameter reageParameter, Money feesPenaltiesOutstanding, + EqualAmortizationValues feesPenaltiesEqualAmortizationValues); + + EqualAmortizationValues calculateEqualAmortizationValues(Money totalOutstanding, Integer numberOfInstallments, + Integer installmentAmountInMultiplesOf, MonetaryCurrency currency); + + EqualAmortizationValues calculateAdjustedEqualAmortizationValues(Money outstanding, Money total, + Money sumOfOtherEqualAmortizationValues, Integer numberOfInstallments, Integer installmentAmountInMultiplesOf, + MonetaryCurrency currency); } diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculator.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculator.java index cb51772eb..f34702421 100644 --- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculator.java +++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculator.java @@ -39,6 +39,7 @@ import org.apache.fineract.infrastructure.core.domain.LocalDateInterval; import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.core.service.MathUtil; import org.apache.fineract.organisation.monetary.data.CurrencyData; +import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency; import org.apache.fineract.organisation.monetary.domain.Money; import org.apache.fineract.portfolio.common.domain.DaysInMonthType; import org.apache.fineract.portfolio.common.domain.DaysInYearCustomStrategyType; @@ -47,11 +48,14 @@ import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType; import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariationType; +import org.apache.fineract.portfolio.loanaccount.domain.reaging.LoanReAgeInterestHandlingType; +import org.apache.fineract.portfolio.loanaccount.domain.reaging.LoanReAgeParameter; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelRepaymentPeriod; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.ScheduledDateGenerator; import org.apache.fineract.portfolio.loanproduct.calc.data.EmiAdjustment; import org.apache.fineract.portfolio.loanproduct.calc.data.EmiChangeOperation; +import org.apache.fineract.portfolio.loanproduct.calc.data.EqualAmortizationValues; import org.apache.fineract.portfolio.loanproduct.calc.data.InterestPeriod; import org.apache.fineract.portfolio.loanproduct.calc.data.OutstandingDetails; import org.apache.fineract.portfolio.loanproduct.calc.data.PeriodDueDetails; @@ -1584,4 +1588,185 @@ public final class ProgressiveEMICalculator implements EMICalculator { .filter(repaymentPeriod -> originalEmi.isLessThan(repaymentPeriod.getTotalPaidAmount())) // .count(); // } + + private void accelerateRepaymentDueDateTo(ProgressiveLoanInterestScheduleModel interestSchedule, RepaymentPeriod repaymentPeriod, + LocalDate transactionDate) { + repaymentPeriod.setDueDate(transactionDate); + repaymentPeriod.getInterestPeriods().getLast().setDueDate(transactionDate); + calculateRateFactorForRepaymentPeriod(repaymentPeriod, interestSchedule); + } + + private void accelerateMaturityDateTo(ProgressiveLoanInterestScheduleModel interestSchedule, LocalDate transactionDate) { + Optional repaymentPeriod = interestSchedule.findRepaymentPeriod(transactionDate); + if (repaymentPeriod.isPresent()) { + if (!repaymentPeriod.get().getDueDate().isEqual(transactionDate)) { + accelerateRepaymentDueDateTo(interestSchedule, repaymentPeriod.get(), transactionDate); + } + if (!interestSchedule.isLastRepaymentPeriod(repaymentPeriod.get())) { + interestSchedule.repaymentPeriods().removeIf(rp -> rp.getDueDate().isAfter(transactionDate)); + } + } + } + + private void updateEMIForReAgeEqualAmortization(List repaymentPeriods, Money principal, Money interest, + Money feesPenaltiesOutstanding, EqualAmortizationValues feesPenaltiesEqualAmortizationValues, MonetaryCurrency currency) { + EqualAmortizationValues interestEAV = calculateEqualAmortizationValues(interest, repaymentPeriods.size(), null, currency); + EqualAmortizationValues principalEAV = calculateAdjustedEqualAmortizationValues(principal, + principal.add(interest).add(feesPenaltiesOutstanding), + interestEAV.value().add(feesPenaltiesEqualAmortizationValues.value()), repaymentPeriods.size(), null, currency); + RepaymentPeriod last = repaymentPeriods.getLast(); + EqualAmortizationValues emiAEV = principalEAV.add(interestEAV); + repaymentPeriods.forEach(rp -> { + boolean isLast = last.equals(rp); + rp.setReAgedInterest(interestEAV.calculateValue(isLast)); + Money emi = emiAEV.calculateValue(isLast); + rp.setEmi(emi); + rp.setOriginalEmi(emi); + }); + } + + @Override + public OutstandingDetails precalculateReAgeEqualAmortizationAmount(ProgressiveLoanInterestScheduleModel interestSchedule, + LocalDate transactionDate, LoanReAgeParameter reageParameter) { + return getOutstandingAmountsTillDate(interestSchedule, + reageParameter.getInterestHandlingType().equals(LoanReAgeInterestHandlingType.EQUAL_AMORTIZATION_PAYABLE_INTEREST) + ? transactionDate + : interestSchedule.getMaturityDate()); + } + + @Override + public void reAgeEqualAmortization(ProgressiveLoanInterestScheduleModel interestSchedule, LocalDate transactionDate, + LoanReAgeParameter reageParameter, Money feesPenaltiesOutstanding, + EqualAmortizationValues feesPenaltiesEqualAmortizationValues) { + LocalDate originalMaturityDate = interestSchedule.getMaturityDate(); + boolean isAfterOriginalMaturityDate = transactionDate.isAfter(originalMaturityDate); + List reAgedRepaymentPeriods = new ArrayList<>(reageParameter.getNumberOfInstallments()); + OutstandingDetails reAgeingAmounts = precalculateReAgeEqualAmortizationAmount(interestSchedule, transactionDate, reageParameter); + + // calculate already paid balances from transaction date + OutstandingDetails paidBalancesFromTransactionDate = calculatePaidBalancesAfterDate(interestSchedule, transactionDate); + + // set maturity date to transaction date and remove all repayment periods after it. + accelerateMaturityDateTo(interestSchedule, transactionDate); + + // close all open repayment period while keep paid amounts + interestSchedule.repaymentPeriods().forEach(rp -> { + rp.getInterestPeriods().getLast() + .addCreditedInterestAmount(MathUtil.min(rp.getOutstandingInterest(), rp.getCreditedInterest(), false).negated()); + rp.setEmi(rp.getTotalPaidAmount()); + rp.setOutstandingMovedDueToReAging(true); + }); + + // stop calculate unrecognised interest at this point because all + interestSchedule.getLastRepaymentPeriod().setNoUnrecognisedInterest(true); + + if (!paidBalancesFromTransactionDate.getOutstandingInterest().isZero() + || !paidBalancesFromTransactionDate.getOutstandingPrincipal().isZero()) { + createRepaymentPeriodForEarlyRepaidAmountsDuringReAgeing(interestSchedule, + paidBalancesFromTransactionDate.getOutstandingPrincipal(), paidBalancesFromTransactionDate.getOutstandingInterest()); + } + + updateModelForReageEqualAmortization(interestSchedule, reageParameter, reAgedRepaymentPeriods, isAfterOriginalMaturityDate); + + updateEMIForReAgeEqualAmortization(reAgedRepaymentPeriods, reAgeingAmounts.getOutstandingPrincipal(), + reAgeingAmounts.getOutstandingInterest(), feesPenaltiesOutstanding, feesPenaltiesEqualAmortizationValues, + interestSchedule.zero().getCurrency()); + + calculateOutstandingBalance(interestSchedule); + + LocalDate zeroInterestFrom = DateUtils.min(transactionDate, originalMaturityDate); + interestSchedule.addInterestRate(zeroInterestFrom, BigDecimal.ZERO); + + calculateLastUnpaidRepaymentPeriodEMI(interestSchedule, transactionDate); + + } + + private void updateModelForReageEqualAmortization(ProgressiveLoanInterestScheduleModel interestSchedule, + LoanReAgeParameter reageParameter, List reAgedRepaymentPeriods, boolean isAfterOriginalMaturityDate) { + int numberOfInstallmentsToAdd = reageParameter.getNumberOfInstallments(); + LocalDate toDate = reageParameter.getStartDate(); + RepaymentPeriod previous = interestSchedule.getLastRepaymentPeriod(); + int frequency = reageParameter.getFrequencyNumber(); + PeriodFrequencyType frequencyType = reageParameter.getFrequencyType(); + + if (!isAfterOriginalMaturityDate) { + // merge first reaged period + RepaymentPeriod firstReAgedPeriod = interestSchedule.getLastRepaymentPeriod(); + firstReAgedPeriod.setDueDate(toDate); + firstReAgedPeriod.getLastInterestPeriod().setDueDate(toDate); + firstReAgedPeriod.setReAged(true); + firstReAgedPeriod.getPrevious().ifPresent(prev -> prev.setNoUnrecognisedInterest(true)); + reAgedRepaymentPeriods.add(firstReAgedPeriod); + + // update params for next reage repayment period calculation + numberOfInstallmentsToAdd--; + toDate = scheduledDateGenerator.getRepaymentPeriodDate(frequencyType, frequency, toDate); + } + + // insert new reaged repayment periods + for (int i = 0; i < numberOfInstallmentsToAdd; i++) { + RepaymentPeriod repaymentPeriod = RepaymentPeriod.create(previous, previous.getDueDate(), toDate, interestSchedule.zero(), + previous.getMc(), previous.getLoanProductRelatedDetail()); + repaymentPeriod.setTotalCapitalizedIncomeAmount(previous.getTotalCapitalizedIncomeAmount()); + repaymentPeriod.setTotalDisbursedAmount(previous.getTotalDisbursedAmount()); + repaymentPeriod.setReAged(true); + interestSchedule.repaymentPeriods().add(repaymentPeriod); + reAgedRepaymentPeriods.add(repaymentPeriod); + previous = repaymentPeriod; + toDate = scheduledDateGenerator.getRepaymentPeriodDate(frequencyType, frequency, toDate); + } + } + + private void createRepaymentPeriodForEarlyRepaidAmountsDuringReAgeing(ProgressiveLoanInterestScheduleModel interestSchedule, + Money totalPaidPrincipal, Money totalPaidInterest) { + RepaymentPeriod targetPeriod = interestSchedule.getLastRepaymentPeriod(); + + Money paidInterestToAdd = totalPaidInterest.minus(targetPeriod.getPaidInterest()); + Money paidPrincipalToAdd = totalPaidPrincipal.minus(targetPeriod.getPaidPrincipal()); + targetPeriod.addPaidInterestAmount(paidInterestToAdd); + targetPeriod.addPaidPrincipalAmount(paidPrincipalToAdd); + targetPeriod.setEmi(targetPeriod.getTotalPaidAmount()); + targetPeriod.setReAged(true); + targetPeriod.setReAgedEarlyRepaymentHolder(true); + + RepaymentPeriod repaymentPeriodToInsert = RepaymentPeriod.create(targetPeriod, targetPeriod.getDueDate(), + interestSchedule.getMaturityDate(), interestSchedule.zero(), interestSchedule.mc(), + interestSchedule.loanProductRelatedDetail()); + repaymentPeriodToInsert.setReAged(true); + interestSchedule.repaymentPeriods().add(repaymentPeriodToInsert); + } + + private OutstandingDetails calculatePaidBalancesAfterDate(ProgressiveLoanInterestScheduleModel interestSchedule, + LocalDate transactionDate) { + Money principal = interestSchedule.repaymentPeriods().stream().filter(rp -> !rp.getDueDate().isBefore(transactionDate)) + .map(RepaymentPeriod::getPaidPrincipal).reduce(interestSchedule.zero(), Money::add); + Money interest = interestSchedule.repaymentPeriods().stream().filter(rp -> !rp.getDueDate().isBefore(transactionDate)) + .map(RepaymentPeriod::getPaidInterest).reduce(interestSchedule.zero(), Money::add); + return new OutstandingDetails(principal, interest); + } + + @Override + public EqualAmortizationValues calculateEqualAmortizationValues(Money totalOutstanding, Integer numberOfInstallments, + Integer installmentAmountInMultiplesOf, MonetaryCurrency currency) { + if (totalOutstanding.isGreaterThanZero()) { + Money equalMonthlyValue = totalOutstanding.dividedBy(numberOfInstallments, totalOutstanding.getMc()); + if (installmentAmountInMultiplesOf != null) { + equalMonthlyValue = Money.roundToMultiplesOf(equalMonthlyValue, installmentAmountInMultiplesOf); + } + Money adjustmentForLastInstallment = totalOutstanding.minus(equalMonthlyValue.multipliedBy(numberOfInstallments)); + return new EqualAmortizationValues(equalMonthlyValue, adjustmentForLastInstallment); + } + return new EqualAmortizationValues(Money.zero(currency), Money.zero(currency)); + } + + @Override + public EqualAmortizationValues calculateAdjustedEqualAmortizationValues(Money outstanding, Money total, + Money sumOfOtherEqualAmortizationValues, Integer numberOfInstallments, Integer installmentAmountInMultiplesOf, + MonetaryCurrency currency) { + EqualAmortizationValues calculatedEMI = calculateEqualAmortizationValues(total, numberOfInstallments, + installmentAmountInMultiplesOf, currency); + Money value = calculatedEMI.value().minus(sumOfOtherEqualAmortizationValues); + Money adjust = outstanding.minus(value.multipliedBy(numberOfInstallments)); + return new EqualAmortizationValues(value, adjust); + } } diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/data/EqualAmortizationValues.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/data/EqualAmortizationValues.java new file mode 100644 index 000000000..b97b99e20 --- /dev/null +++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/data/EqualAmortizationValues.java @@ -0,0 +1,41 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.loanproduct.calc.data; + +import java.math.BigDecimal; +import org.apache.fineract.organisation.monetary.domain.Money; + +public record EqualAmortizationValues(Money value, Money adjustment) { + + public Money getAdjustedValue() { + return value.add(adjustment); + } + + public Money calculateValue(boolean isLast) { + return (isLast ? getAdjustedValue() : value); + } + + public BigDecimal calculateValueBigDecimal(boolean isLast) { + return calculateValue(isLast).getAmount(); + } + + public EqualAmortizationValues add(EqualAmortizationValues other) { + return new EqualAmortizationValues(value.add(other.value), adjustment.add(other.adjustment)); + } +} diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/data/InterestPeriod.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/data/InterestPeriod.java index e143cc4b4..cb5cbdb84 100644 --- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/data/InterestPeriod.java +++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/data/InterestPeriod.java @@ -138,7 +138,7 @@ public class InterestPeriod implements Comparable { } public BigDecimal getCalculatedDueInterest() { - if (isPaused()) { + if (isPaused() || getRepaymentPeriod().isReAged()) { return getCreditedInterest().getAmount(); } diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/data/RepaymentPeriod.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/data/RepaymentPeriod.java index 5d25eab78..dff87cfdb 100644 --- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/data/RepaymentPeriod.java +++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/data/RepaymentPeriod.java @@ -92,9 +92,23 @@ public class RepaymentPeriod { @Setter private boolean isOutstandingMovedDueToReAging = false; + @Setter + @Getter + private boolean noUnrecognisedInterest; + @Setter + @Getter + private boolean reAged = false; + @Setter + @Getter + private boolean reAgedEarlyRepaymentHolder = false; + @Getter + @Setter + private Money reAgedInterest; + protected RepaymentPeriod(RepaymentPeriod previous, LocalDate fromDate, LocalDate dueDate, List interestPeriods, Money emi, Money originalEmi, Money paidPrincipal, Money paidInterest, Money futureUnrecognizedInterest, MathContext mc, - ILoanConfigurationDetails loanProductRelatedDetail) { + ILoanConfigurationDetails loanProductRelatedDetail, boolean noUnrecognisedInterest, boolean reAged, + boolean reAgedEarlyRepaymentHolder, Money reAgedInterest) { this.previous = previous; this.fromDate = fromDate; this.dueDate = dueDate; @@ -106,17 +120,22 @@ public class RepaymentPeriod { this.futureUnrecognizedInterest = futureUnrecognizedInterest; this.mc = mc; this.loanProductRelatedDetail = loanProductRelatedDetail; + this.noUnrecognisedInterest = noUnrecognisedInterest; + this.reAged = reAged; + this.reAgedEarlyRepaymentHolder = reAgedEarlyRepaymentHolder; + this.reAgedInterest = reAgedInterest; } public static RepaymentPeriod empty(RepaymentPeriod previous, MathContext mc, ILoanConfigurationDetails loanProductRelatedDetail) { - return new RepaymentPeriod(previous, null, null, new ArrayList<>(), null, null, null, null, null, mc, loanProductRelatedDetail); + return new RepaymentPeriod(previous, null, null, new ArrayList<>(), null, null, null, null, null, mc, loanProductRelatedDetail, + false, false, false, null); } public static RepaymentPeriod create(RepaymentPeriod previous, LocalDate fromDate, LocalDate dueDate, Money emi, MathContext mc, ILoanConfigurationDetails loanProductRelatedDetail) { final Money zero = emi.zero(); final RepaymentPeriod newRepaymentPeriod = new RepaymentPeriod(previous, fromDate, dueDate, new ArrayList<>(), emi, emi, zero, zero, - zero, mc, loanProductRelatedDetail); + zero, mc, loanProductRelatedDetail, false, false, false, zero); // There is always at least 1 interest period, by default with same from-due date as repayment period newRepaymentPeriod.getInterestPeriods().add(InterestPeriod.withEmptyAmounts(newRepaymentPeriod, fromDate, dueDate)); return newRepaymentPeriod; @@ -126,7 +145,8 @@ public class RepaymentPeriod { final RepaymentPeriod newRepaymentPeriod = new RepaymentPeriod(previous, repaymentPeriod.getFromDate(), repaymentPeriod.getDueDate(), new ArrayList<>(), repaymentPeriod.getEmi(), repaymentPeriod.getOriginalEmi(), repaymentPeriod.getPaidPrincipal(), repaymentPeriod.getPaidInterest(), repaymentPeriod.getFutureUnrecognizedInterest(), mc, - repaymentPeriod.getLoanProductRelatedDetail()); + repaymentPeriod.getLoanProductRelatedDetail(), repaymentPeriod.isNoUnrecognisedInterest(), repaymentPeriod.isReAged(), + repaymentPeriod.isReAgedEarlyRepaymentHolder(), repaymentPeriod.getReAgedInterest()); newRepaymentPeriod.setOutstandingMovedDueToReAging(repaymentPeriod.isOutstandingMovedDueToReAging()); // There is always at least 1 interest period, by default with same from-due date as repayment period for (InterestPeriod interestPeriod : repaymentPeriod.getInterestPeriods()) { @@ -139,7 +159,8 @@ public class RepaymentPeriod { final Money zero = Money.zero(repaymentPeriod.getCurrency(), mc); final RepaymentPeriod newRepaymentPeriod = new RepaymentPeriod(previous, repaymentPeriod.getFromDate(), repaymentPeriod.getDueDate(), new ArrayList<>(), repaymentPeriod.getEmi(), repaymentPeriod.getOriginalEmi(), zero, zero, - zero, mc, repaymentPeriod.getLoanProductRelatedDetail()); + zero, mc, repaymentPeriod.getLoanProductRelatedDetail(), repaymentPeriod.isNoUnrecognisedInterest(), + repaymentPeriod.isReAged(), repaymentPeriod.isReAgedEarlyRepaymentHolder(), repaymentPeriod.getReAgedInterest()); newRepaymentPeriod.setOutstandingMovedDueToReAging(repaymentPeriod.isOutstandingMovedDueToReAging()); // There is always at least 1 interest period, by default with same from-due date as repayment period for (InterestPeriod interestPeriod : repaymentPeriod.getInterestPeriods()) { @@ -180,8 +201,8 @@ public class RepaymentPeriod { @NotNull public Money getCalculatedDueInterest() { if (calculatedDueInterestCalculation == null) { - calculatedDueInterestCalculation = Memo.of(this::calculateCalculatedDueInterest, () -> new Object[] { this.previous, - this.interestPeriods, this.futureUnrecognizedInterest, this.isInterestMoved, this.totalDisbursedAmount }); + calculatedDueInterestCalculation = Memo.of(this::calculateCalculatedDueInterest, () -> new Object[] { previous, interestPeriods, + futureUnrecognizedInterest, isInterestMoved, totalDisbursedAmount, reAgedInterest, reAged }); } return calculatedDueInterestCalculation.get(); } @@ -193,6 +214,7 @@ public class RepaymentPeriod { getInterestPeriods().stream().map(InterestPeriod::getCalculatedDueInterest).reduce(BigDecimal.ZERO, BigDecimal::add), mc); } + calculatedDueInterest = calculatedDueInterest.add(reAgedInterest); calculatedDueInterest = calculatedDueInterest.add(getFutureUnrecognizedInterest(), getMc()); if (getPrevious().isPresent()) { calculatedDueInterest = calculatedDueInterest.add(getPrevious().get().getUnrecognizedInterest(), getMc()); @@ -213,7 +235,7 @@ public class RepaymentPeriod { : MathUtil.min(getCalculatedDueInterest(), getEmiPlusCreditedAmountsPlusFutureUnrecognizedInterest(), false), getPaidInterest(), false), () -> new Object[] { paidPrincipal, paidInterest, interestPeriods, futureUnrecognizedInterest, totalDisbursedAmount, - emi }); + reAgedInterest, reAged, emi }); } return dueInterestCalculation.get(); } @@ -312,7 +334,7 @@ public class RepaymentPeriod { * @return */ public Money getUnrecognizedInterest() { - return getCalculatedDueInterest().minus(getDueInterest(), getMc()); + return noUnrecognisedInterest ? getZero() : getCalculatedDueInterest().minus(getDueInterest(), getMc()); } public Money getCreditedAmounts() { diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/util/InstallmentProcessingHelper.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/util/InstallmentProcessingHelper.java new file mode 100644 index 000000000..9a86f0eb1 --- /dev/null +++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/util/InstallmentProcessingHelper.java @@ -0,0 +1,33 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.util; + +import java.util.List; +import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; + +public final class InstallmentProcessingHelper { + + private InstallmentProcessingHelper() {} + + public static void addOneToInstallmentNumberFromInstallment(final List installments, + final int installmentNumber) { + installments.stream().filter(i -> i.getInstallmentNumber() != null && i.getInstallmentNumber() >= installmentNumber) + .forEach(i -> i.setInstallmentNumber(i.getInstallmentNumber() + 1)); + } +} diff --git a/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessorTest.java b/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessorTest.java index d03c7965f..dc7d467f9 100644 --- a/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessorTest.java +++ b/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanaccount/domain/transactionprocessor/impl/AdvancedPaymentScheduleTransactionProcessorTest.java @@ -71,6 +71,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType; import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.MoneyHolder; import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.TransactionCtx; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType; +import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.ScheduledDateGenerator; import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeValidator; import org.apache.fineract.portfolio.loanaccount.service.InterestRefundService; import org.apache.fineract.portfolio.loanaccount.service.LoanBalanceService; @@ -120,7 +121,7 @@ class AdvancedPaymentScheduleTransactionProcessorTest { public void setUp() { underTest = new AdvancedPaymentScheduleTransactionProcessor(emiCalculator, Mockito.mock(InterestRefundService.class), Mockito.mock(ExternalIdFactory.class), Mockito.mock(LoanScheduleComponent.class), Mockito.mock(LoanChargeValidator.class), - Mockito.mock(LoanBalanceService.class), Mockito.mock(LoanChargeService.class)); + Mockito.mock(LoanBalanceService.class), Mockito.mock(LoanChargeService.class), Mockito.mock(ScheduledDateGenerator.class)); ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null)); ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT); @@ -490,7 +491,7 @@ class AdvancedPaymentScheduleTransactionProcessorTest { // Set up TransactionCtx with installments and charges TransactionCtx ctx = new ProgressiveTransactionCtx(currency, installments, Set.of(), overpaymentHolder, changedTransactionDetail, - model); + model, null); // Mock additional necessary methods LoanCharge loanCharge = mock(LoanCharge.class); diff --git a/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculatorTest.java b/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculatorTest.java index 3cbaffb43..f0abeefa8 100644 --- a/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculatorTest.java +++ b/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanproduct/calc/ProgressiveEMICalculatorTest.java @@ -18,7 +18,7 @@ */ package org.apache.fineract.portfolio.loanproduct.calc; -import static org.mockito.Mockito.mock; +import static java.math.BigDecimal.ZERO; import java.math.BigDecimal; import java.math.MathContext; @@ -40,10 +40,16 @@ import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType; import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariationType; +import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction; +import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType; +import org.apache.fineract.portfolio.loanaccount.domain.reaging.LoanReAgeInterestHandlingType; +import org.apache.fineract.portfolio.loanaccount.domain.reaging.LoanReAgeParameter; +import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.DefaultScheduledDateGenerator; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelRepaymentPeriod; -import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.ScheduledDateGenerator; import org.apache.fineract.portfolio.loanaccount.service.ProgressiveLoanInterestScheduleModelParserServiceGsonImpl; +import org.apache.fineract.portfolio.loanproduct.calc.data.EqualAmortizationValues; import org.apache.fineract.portfolio.loanproduct.calc.data.InterestPeriod; +import org.apache.fineract.portfolio.loanproduct.calc.data.OutstandingDetails; import org.apache.fineract.portfolio.loanproduct.calc.data.PeriodDueDetails; import org.apache.fineract.portfolio.loanproduct.calc.data.ProgressiveLoanInterestScheduleModel; import org.apache.fineract.portfolio.loanproduct.calc.data.RepaymentPeriod; @@ -67,7 +73,7 @@ import org.springframework.lang.NonNull; @ExtendWith(MockitoExtension.class) class ProgressiveEMICalculatorTest { - private static ProgressiveEMICalculator emiCalculator = new ProgressiveEMICalculator(mock(ScheduledDateGenerator.class)); + private static ProgressiveEMICalculator emiCalculator = new ProgressiveEMICalculator(new DefaultScheduledDateGenerator()); private static MockedStatic threadLocalContextUtil = Mockito.mockStatic(ThreadLocalContextUtil.class); private static MockedStatic moneyHelper = Mockito.mockStatic(MoneyHelper.class); @@ -4174,6 +4180,582 @@ class ProgressiveEMICalculatorTest { } + @Nested + public class ReAgeEqualAmortization { + + @Test + public void test_transactionInMiddleOfPeriod_EQUAL_AMORTIZATION_FULL_INTEREST_noTransactionTilDate_noInterestRecalc() { + final List expectedRepaymentPeriods = new ArrayList<>(); + + expectedRepaymentPeriods.add(repayment(1, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1))); + expectedRepaymentPeriods.add(repayment(2, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1))); + expectedRepaymentPeriods.add(repayment(3, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 4, 1))); + expectedRepaymentPeriods.add(repayment(4, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 5, 1))); + expectedRepaymentPeriods.add(repayment(5, LocalDate.of(2024, 5, 1), LocalDate.of(2024, 6, 1))); + expectedRepaymentPeriods.add(repayment(6, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 7, 1))); + + final BigDecimal interestRate = BigDecimal.valueOf(15.678); + final Integer installmentAmountInMultiplesOf = null; + + Mockito.when(loanProductRelatedDetail.getAnnualNominalInterestRate()).thenReturn(interestRate); + Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_365.getValue()); + Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.ACTUAL.getValue()); + Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS); + Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1); + Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); + + final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( + expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + + final Money disbursedAmount = toMoney(100.0); + emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); + + checkPeriod(interestSchedule, 0, 0, 17.43, 0.0, 0.0, 1.33, 16.1, 83.9); + checkPeriod(interestSchedule, 0, 1, 17.43, 0.013315561644, 1.3315561644, 1.33, 16.1, 83.9); + checkPeriod(interestSchedule, 1, 0, 17.43, 0.012456493151, 1.04509977537, 1.05, 16.38, 67.52); + checkPeriod(interestSchedule, 2, 0, 17.43, 0.013315561644, 0.899066722202, 0.90, 16.53, 50.99); + checkPeriod(interestSchedule, 3, 0, 17.43, 0.012886027397, 0.657058536972, 0.66, 16.77, 34.22); + checkPeriod(interestSchedule, 4, 0, 17.43, 0.013315561644, 0.455658519458, 0.46, 16.97, 17.25); + checkPeriod(interestSchedule, 5, 0, 17.47, 0.012886027397, 0.222283972598, 0.22, 17.25, 0.0); + + // No repayment no interest recalculation + LocalDate reAgingStartDate = LocalDate.of(2024, 4, 20); + + OutstandingDetails outstandingAmountsTillDate = emiCalculator.getOutstandingAmountsTillDate(interestSchedule, + interestSchedule.getMaturityDate()); + + LoanTransaction loanTransaction = new LoanTransaction(null, null, LoanTransactionType.REAGE, LocalDate.of(2024, 4, 15), + outstandingAmountsTillDate.getOutstandingPrincipal().add(outstandingAmountsTillDate.getOutstandingInterest()) + .getAmount(), + outstandingAmountsTillDate.getOutstandingPrincipal().getAmount(), + outstandingAmountsTillDate.getOutstandingInterest().getAmount(), ZERO, ZERO, ZERO, false, null, null); + LoanReAgeParameter reageParameter = new LoanReAgeParameter(loanTransaction, PeriodFrequencyType.MONTHS, 1, reAgingStartDate, 6, + LoanReAgeInterestHandlingType.EQUAL_AMORTIZATION_FULL_INTEREST, null); + loanTransaction.setLoanReAgeParameter(reageParameter); + + // Update the existing model with re-aged periods + emiCalculator.reAgeEqualAmortization(interestSchedule, loanTransaction.getTransactionDate(), reageParameter, + Money.zero(currency), new EqualAmortizationValues(Money.zero(currency), Money.zero(currency))); + + OutstandingDetails outstandingAmountsTillDateAfterReage = emiCalculator.getOutstandingAmountsTillDate(interestSchedule, + interestSchedule.getMaturityDate()); + + Assertions.assertEquals(outstandingAmountsTillDate.getOutstandingInterest().getAmount(), + outstandingAmountsTillDateAfterReage.getOutstandingInterest().getAmount()); + Assertions.assertEquals(outstandingAmountsTillDate.getOutstandingPrincipal().getAmount(), + outstandingAmountsTillDateAfterReage.getOutstandingPrincipal().getAmount()); + + } + + @Test + public void test_transactionInMiddleOfPeriod_EQUAL_AMORTIZATION_FULL_INTEREST() { + final List expectedRepaymentPeriods = new ArrayList<>(); + + expectedRepaymentPeriods.add(repayment(1, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1))); + expectedRepaymentPeriods.add(repayment(2, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1))); + expectedRepaymentPeriods.add(repayment(3, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 4, 1))); + expectedRepaymentPeriods.add(repayment(4, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 5, 1))); + expectedRepaymentPeriods.add(repayment(5, LocalDate.of(2024, 5, 1), LocalDate.of(2024, 6, 1))); + expectedRepaymentPeriods.add(repayment(6, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 7, 1))); + + final BigDecimal interestRate = BigDecimal.valueOf(15.678); + final Integer installmentAmountInMultiplesOf = null; + + Mockito.when(loanProductRelatedDetail.getAnnualNominalInterestRate()).thenReturn(interestRate); + Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_365.getValue()); + Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.ACTUAL.getValue()); + Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS); + Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1); + Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); + + final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( + expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + + final Money disbursedAmount = toMoney(100.0); + emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); + + checkPeriod(interestSchedule, 0, 0, 17.43, 0.0, 0.0, 1.33, 16.1, 83.9); + checkPeriod(interestSchedule, 0, 1, 17.43, 0.013315561644, 1.3315561644, 1.33, 16.1, 83.9); + checkPeriod(interestSchedule, 1, 0, 17.43, 0.012456493151, 1.04509977537, 1.05, 16.38, 67.52); + checkPeriod(interestSchedule, 2, 0, 17.43, 0.013315561644, 0.899066722202, 0.90, 16.53, 50.99); + checkPeriod(interestSchedule, 3, 0, 17.43, 0.012886027397, 0.657058536972, 0.66, 16.77, 34.22); + checkPeriod(interestSchedule, 4, 0, 17.43, 0.013315561644, 0.455658519458, 0.46, 16.97, 17.25); + checkPeriod(interestSchedule, 5, 0, 17.47, 0.012886027397, 0.222283972598, 0.22, 17.25, 0.0); + + // repay EMI on first period due date + emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1), + Money.of(currency, BigDecimal.valueOf(16.1))); + emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1), + Money.of(currency, BigDecimal.valueOf(1.33))); + + // repay EMI on first period due date - next installment for 2nd period + emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 2, 1), + Money.of(currency, BigDecimal.valueOf(17.43))); + + // repay 20 for last installment on first period due date -- ie MIR + emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 7, 1), LocalDate.of(2024, 2, 1), + Money.of(currency, BigDecimal.valueOf(17.43))); + emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 2, 1), + Money.of(currency, BigDecimal.valueOf(2.57))); + + emiCalculator.addBalanceCorrection(interestSchedule, LocalDate.of(2024, 4, 1), + emiCalculator.getDueAmounts(interestSchedule, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 4, 1)).getDuePrincipal()); + + emiCalculator.addBalanceCorrection(interestSchedule, LocalDate.of(2024, 4, 15), emiCalculator + .getDueAmounts(interestSchedule, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 4, 1)).getDuePrincipal().negated()); + + LocalDate reAgingStartDate = LocalDate.of(2024, 4, 20); + + OutstandingDetails outstandingAmountsTillDate = emiCalculator.getOutstandingAmountsTillDate(interestSchedule, + interestSchedule.getMaturityDate()); + + LoanTransaction loanTransaction = new LoanTransaction(null, null, LoanTransactionType.REAGE, LocalDate.of(2024, 4, 15), + outstandingAmountsTillDate.getOutstandingPrincipal().add(outstandingAmountsTillDate.getOutstandingInterest()) + .getAmount(), + outstandingAmountsTillDate.getOutstandingPrincipal().getAmount(), + outstandingAmountsTillDate.getOutstandingInterest().getAmount(), ZERO, ZERO, ZERO, false, null, null); + LoanReAgeParameter reageParameter = new LoanReAgeParameter(loanTransaction, PeriodFrequencyType.MONTHS, 1, reAgingStartDate, 6, + LoanReAgeInterestHandlingType.EQUAL_AMORTIZATION_FULL_INTEREST, null); + loanTransaction.setLoanReAgeParameter(reageParameter); + + // Update the existing model with re-aged periods + emiCalculator.reAgeEqualAmortization(interestSchedule, loanTransaction.getTransactionDate(), reageParameter, + Money.zero(currency), new EqualAmortizationValues(Money.zero(currency), Money.zero(currency))); + + OutstandingDetails outstandingAmountsTillDateAfterReage = emiCalculator.getOutstandingAmountsTillDate(interestSchedule, + interestSchedule.getMaturityDate()); + + Assertions.assertEquals(outstandingAmountsTillDate.getOutstandingInterest().getAmount(), + outstandingAmountsTillDateAfterReage.getOutstandingInterest().getAmount()); + Assertions.assertEquals(outstandingAmountsTillDate.getOutstandingPrincipal().getAmount(), + outstandingAmountsTillDateAfterReage.getOutstandingPrincipal().getAmount()); + + } + + @Test + public void test_chargeback_transactionInMiddleOfPeriod_EQUAL_EQUAL_AMORTIZATION_PAYABLE_INTEREST() { + final List expectedRepaymentPeriods = new ArrayList<>(); + + expectedRepaymentPeriods.add(repayment(1, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1))); + expectedRepaymentPeriods.add(repayment(2, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1))); + expectedRepaymentPeriods.add(repayment(3, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 4, 1))); + expectedRepaymentPeriods.add(repayment(4, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 5, 1))); + expectedRepaymentPeriods.add(repayment(5, LocalDate.of(2024, 5, 1), LocalDate.of(2024, 6, 1))); + expectedRepaymentPeriods.add(repayment(6, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 7, 1))); + + final BigDecimal interestRate = BigDecimal.valueOf(7.0); + final Integer installmentAmountInMultiplesOf = null; + + Mockito.when(loanProductRelatedDetail.getAnnualNominalInterestRate()).thenReturn(interestRate); + Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_360.getValue()); + Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue()); + Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS); + Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1); + Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); + + final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( + expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + + final Money disbursedAmount = toMoney(100.0); + emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); + + // repay EMI on first period due date + emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1), + Money.of(currency, BigDecimal.valueOf(16.43))); + emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1), + Money.of(currency, BigDecimal.valueOf(0.58))); + + // chargeback + emiCalculator.creditPrincipal(interestSchedule, LocalDate.of(2024, 3, 15), Money.of(currency, BigDecimal.valueOf(16.43))); + emiCalculator.creditInterest(interestSchedule, LocalDate.of(2024, 3, 15), Money.of(currency, BigDecimal.valueOf(0.58))); + + LocalDate transactionDate = LocalDate.of(2024, 3, 15); + LocalDate reAgingStartDate = LocalDate.of(2024, 4, 1); + + OutstandingDetails outstandingAmountsTillDate = emiCalculator.getOutstandingAmountsTillDate(interestSchedule, transactionDate); + + LoanReAgeParameter reageParameter = new LoanReAgeParameter(null, PeriodFrequencyType.MONTHS, 1, reAgingStartDate, 6, + LoanReAgeInterestHandlingType.EQUAL_AMORTIZATION_PAYABLE_INTEREST, null); + + // Update the existing model with re-aged periods + emiCalculator.reAgeEqualAmortization(interestSchedule, transactionDate, reageParameter, Money.zero(currency), + new EqualAmortizationValues(Money.zero(currency), Money.zero(currency))); + + OutstandingDetails outstandingAmountsTillDateAfterReage = emiCalculator.getOutstandingAmountsTillDate(interestSchedule, + interestSchedule.getMaturityDate()); + + Assertions.assertEquals(outstandingAmountsTillDate.getOutstandingInterest().getAmount(), + outstandingAmountsTillDateAfterReage.getOutstandingInterest().getAmount()); + Assertions.assertEquals(outstandingAmountsTillDate.getOutstandingPrincipal().getAmount(), + outstandingAmountsTillDateAfterReage.getOutstandingPrincipal().getAmount()); + + } + + @Test + public void test_chargebackPartial_transactionInMiddleOfPeriod_EQUAL_EQUAL_AMORTIZATION_FULL_INTEREST() { + final List expectedRepaymentPeriods = new ArrayList<>(); + + expectedRepaymentPeriods.add(repayment(1, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1))); + expectedRepaymentPeriods.add(repayment(2, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1))); + expectedRepaymentPeriods.add(repayment(3, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 4, 1))); + expectedRepaymentPeriods.add(repayment(4, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 5, 1))); + expectedRepaymentPeriods.add(repayment(5, LocalDate.of(2024, 5, 1), LocalDate.of(2024, 6, 1))); + expectedRepaymentPeriods.add(repayment(6, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 7, 1))); + + final BigDecimal interestRate = BigDecimal.valueOf(7.0); + final Integer installmentAmountInMultiplesOf = null; + + Mockito.when(loanProductRelatedDetail.getAnnualNominalInterestRate()).thenReturn(interestRate); + Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_360.getValue()); + Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.DAYS_30.getValue()); + Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS); + Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1); + Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); + + final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( + expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + + final Money disbursedAmount = toMoney(100.0); + emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); + + // repay EMI on first period due date + emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1), + Money.of(currency, BigDecimal.valueOf(16.43))); + emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1), + Money.of(currency, BigDecimal.valueOf(0.58))); + + // chargeback + emiCalculator.creditPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), Money.of(currency, BigDecimal.valueOf(9.42))); + emiCalculator.creditInterest(interestSchedule, LocalDate.of(2024, 2, 1), Money.of(currency, BigDecimal.valueOf(0.58))); + + LocalDate transactionDate = LocalDate.of(2024, 3, 15); + LocalDate reAgingStartDate = LocalDate.of(2024, 4, 1); + + OutstandingDetails outstandingAmountsTillDate = emiCalculator.getOutstandingAmountsTillDate(interestSchedule, + interestSchedule.getMaturityDate()); + + LoanReAgeParameter reageParameter = new LoanReAgeParameter(null, PeriodFrequencyType.MONTHS, 1, reAgingStartDate, 6, + LoanReAgeInterestHandlingType.EQUAL_AMORTIZATION_FULL_INTEREST, null); + + // Update the existing model with re-aged periods + emiCalculator.reAgeEqualAmortization(interestSchedule, transactionDate, reageParameter, Money.zero(currency), + new EqualAmortizationValues(Money.zero(currency), Money.zero(currency))); + + OutstandingDetails outstandingAmountsTillDateAfterReage = emiCalculator.getOutstandingAmountsTillDate(interestSchedule, + interestSchedule.getMaturityDate()); + + Assertions.assertEquals(outstandingAmountsTillDate.getOutstandingInterest().getAmount(), + outstandingAmountsTillDateAfterReage.getOutstandingInterest().getAmount()); + Assertions.assertEquals(outstandingAmountsTillDate.getOutstandingPrincipal().getAmount(), + outstandingAmountsTillDateAfterReage.getOutstandingPrincipal().getAmount()); + + } + + @Test + public void test_transactionInMiddleOfPeriod_EQUAL_EQUAL_AMORTIZATION_PAYABLE_INTEREST() { + final List expectedRepaymentPeriods = new ArrayList<>(); + + expectedRepaymentPeriods.add(repayment(1, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1))); + expectedRepaymentPeriods.add(repayment(2, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1))); + expectedRepaymentPeriods.add(repayment(3, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 4, 1))); + expectedRepaymentPeriods.add(repayment(4, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 5, 1))); + expectedRepaymentPeriods.add(repayment(5, LocalDate.of(2024, 5, 1), LocalDate.of(2024, 6, 1))); + expectedRepaymentPeriods.add(repayment(6, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 7, 1))); + + final BigDecimal interestRate = BigDecimal.valueOf(15.678); + final Integer installmentAmountInMultiplesOf = null; + + Mockito.when(loanProductRelatedDetail.getAnnualNominalInterestRate()).thenReturn(interestRate); + Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_365.getValue()); + Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.ACTUAL.getValue()); + Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS); + Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1); + Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); + + final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( + expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + + final Money disbursedAmount = toMoney(100.0); + emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); + + checkPeriod(interestSchedule, 0, 0, 17.43, 0.0, 0.0, 1.33, 16.1, 83.9); + checkPeriod(interestSchedule, 0, 1, 17.43, 0.013315561644, 1.3315561644, 1.33, 16.1, 83.9); + checkPeriod(interestSchedule, 1, 0, 17.43, 0.012456493151, 1.04509977537, 1.05, 16.38, 67.52); + checkPeriod(interestSchedule, 2, 0, 17.43, 0.013315561644, 0.899066722202, 0.90, 16.53, 50.99); + checkPeriod(interestSchedule, 3, 0, 17.43, 0.012886027397, 0.657058536972, 0.66, 16.77, 34.22); + checkPeriod(interestSchedule, 4, 0, 17.43, 0.013315561644, 0.455658519458, 0.46, 16.97, 17.25); + checkPeriod(interestSchedule, 5, 0, 17.47, 0.012886027397, 0.222283972598, 0.22, 17.25, 0.0); + + // repay EMI on first period due date + emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1), + Money.of(currency, BigDecimal.valueOf(16.1))); + emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1), + Money.of(currency, BigDecimal.valueOf(1.33))); + + // repay EMI on first period due date - next installment for 2nd period + emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 2, 1), + Money.of(currency, BigDecimal.valueOf(17.43))); + + // repay 20 for last installment on first period due date -- ie MIR + emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 7, 1), LocalDate.of(2024, 2, 1), + Money.of(currency, BigDecimal.valueOf(17.43))); + emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 2, 1), + Money.of(currency, BigDecimal.valueOf(2.57))); + + emiCalculator.addBalanceCorrection(interestSchedule, LocalDate.of(2024, 4, 1), + emiCalculator.getDueAmounts(interestSchedule, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 4, 1)).getDuePrincipal()); + + emiCalculator.addBalanceCorrection(interestSchedule, LocalDate.of(2024, 4, 15), emiCalculator + .getDueAmounts(interestSchedule, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 4, 1)).getDuePrincipal().negated()); + + LocalDate transactionDate = LocalDate.of(2024, 4, 15); + LocalDate reAgingStartDate = LocalDate.of(2024, 4, 20); + + OutstandingDetails outstandingAmountsTillDate = emiCalculator.getOutstandingAmountsTillDate(interestSchedule, transactionDate); + + LoanReAgeParameter reageParameter = new LoanReAgeParameter(null, PeriodFrequencyType.MONTHS, 1, reAgingStartDate, 6, + LoanReAgeInterestHandlingType.EQUAL_AMORTIZATION_PAYABLE_INTEREST, null); + + // Update the existing model with re-aged periods + emiCalculator.reAgeEqualAmortization(interestSchedule, transactionDate, reageParameter, Money.zero(currency), + new EqualAmortizationValues(Money.zero(currency), Money.zero(currency))); + + OutstandingDetails outstandingAmountsTillDateAfterReage = emiCalculator.getOutstandingAmountsTillDate(interestSchedule, + interestSchedule.getMaturityDate()); + + Assertions.assertEquals(outstandingAmountsTillDate.getOutstandingInterest().getAmount(), + outstandingAmountsTillDateAfterReage.getOutstandingInterest().getAmount()); + Assertions.assertEquals(outstandingAmountsTillDate.getOutstandingPrincipal().getAmount(), + outstandingAmountsTillDateAfterReage.getOutstandingPrincipal().getAmount()); + + } + + @Test + public void test_transactionInMiddleOfPeriod_stringOnNextDueDate_EQUAL_EQUAL_AMORTIZATION_PAYABLE_INTEREST() { + final List expectedRepaymentPeriods = new ArrayList<>(); + + expectedRepaymentPeriods.add(repayment(1, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1))); + expectedRepaymentPeriods.add(repayment(2, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1))); + expectedRepaymentPeriods.add(repayment(3, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 4, 1))); + expectedRepaymentPeriods.add(repayment(4, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 5, 1))); + expectedRepaymentPeriods.add(repayment(5, LocalDate.of(2024, 5, 1), LocalDate.of(2024, 6, 1))); + expectedRepaymentPeriods.add(repayment(6, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 7, 1))); + + final BigDecimal interestRate = BigDecimal.valueOf(15.678); + final Integer installmentAmountInMultiplesOf = null; + + Mockito.when(loanProductRelatedDetail.getAnnualNominalInterestRate()).thenReturn(interestRate); + Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_365.getValue()); + Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.ACTUAL.getValue()); + Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS); + Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1); + Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); + + final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( + expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + + final Money disbursedAmount = toMoney(100.0); + emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); + + checkPeriod(interestSchedule, 0, 0, 17.43, 0.0, 0.0, 1.33, 16.1, 83.9); + checkPeriod(interestSchedule, 0, 1, 17.43, 0.013315561644, 1.3315561644, 1.33, 16.1, 83.9); + checkPeriod(interestSchedule, 1, 0, 17.43, 0.012456493151, 1.04509977537, 1.05, 16.38, 67.52); + checkPeriod(interestSchedule, 2, 0, 17.43, 0.013315561644, 0.899066722202, 0.90, 16.53, 50.99); + checkPeriod(interestSchedule, 3, 0, 17.43, 0.012886027397, 0.657058536972, 0.66, 16.77, 34.22); + checkPeriod(interestSchedule, 4, 0, 17.43, 0.013315561644, 0.455658519458, 0.46, 16.97, 17.25); + checkPeriod(interestSchedule, 5, 0, 17.47, 0.012886027397, 0.222283972598, 0.22, 17.25, 0.0); + + // repay EMI on first period due date + emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1), + Money.of(currency, BigDecimal.valueOf(16.1))); + emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1), + Money.of(currency, BigDecimal.valueOf(1.33))); + + // repay EMI on first period due date - next installment for 2nd period + emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 2, 1), + Money.of(currency, BigDecimal.valueOf(17.43))); + + // repay 20 for last installment on first period due date -- ie MIR + emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 7, 1), LocalDate.of(2024, 2, 1), + Money.of(currency, BigDecimal.valueOf(17.43))); + emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 2, 1), + Money.of(currency, BigDecimal.valueOf(2.57))); + + emiCalculator.addBalanceCorrection(interestSchedule, LocalDate.of(2024, 4, 1), + emiCalculator.getDueAmounts(interestSchedule, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 4, 1)).getDuePrincipal()); + + emiCalculator.addBalanceCorrection(interestSchedule, LocalDate.of(2024, 4, 15), emiCalculator + .getDueAmounts(interestSchedule, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 4, 1)).getDuePrincipal().negated()); + + LocalDate transactionDate = LocalDate.of(2024, 4, 15); + LocalDate reAgingStartDate = LocalDate.of(2024, 5, 1); + + OutstandingDetails outstandingAmountsTillDate = emiCalculator.getOutstandingAmountsTillDate(interestSchedule, transactionDate); + + LoanReAgeParameter reageParameter = new LoanReAgeParameter(null, PeriodFrequencyType.MONTHS, 1, reAgingStartDate, 6, + LoanReAgeInterestHandlingType.EQUAL_AMORTIZATION_PAYABLE_INTEREST, null); + + // Update the existing model with re-aged periods + emiCalculator.reAgeEqualAmortization(interestSchedule, transactionDate, reageParameter, Money.zero(currency), + new EqualAmortizationValues(Money.zero(currency), Money.zero(currency))); + + OutstandingDetails outstandingAmountsTillDateAfterReage = emiCalculator.getOutstandingAmountsTillDate(interestSchedule, + interestSchedule.getMaturityDate()); + + Assertions.assertEquals(outstandingAmountsTillDate.getOutstandingInterest().getAmount(), + outstandingAmountsTillDateAfterReage.getOutstandingInterest().getAmount()); + Assertions.assertEquals(outstandingAmountsTillDate.getOutstandingPrincipal().getAmount(), + outstandingAmountsTillDateAfterReage.getOutstandingPrincipal().getAmount()); + + } + + @Test + public void test_transactionOnMaturityDate_stringAfterMaturityDate_EQUAL_EQUAL_AMORTIZATION_PAYABLE_INTEREST() { + final List expectedRepaymentPeriods = new ArrayList<>(); + + expectedRepaymentPeriods.add(repayment(1, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1))); + expectedRepaymentPeriods.add(repayment(2, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1))); + expectedRepaymentPeriods.add(repayment(3, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 4, 1))); + expectedRepaymentPeriods.add(repayment(4, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 5, 1))); + expectedRepaymentPeriods.add(repayment(5, LocalDate.of(2024, 5, 1), LocalDate.of(2024, 6, 1))); + expectedRepaymentPeriods.add(repayment(6, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 7, 1))); + + final BigDecimal interestRate = BigDecimal.valueOf(15.678); + final Integer installmentAmountInMultiplesOf = null; + + Mockito.when(loanProductRelatedDetail.getAnnualNominalInterestRate()).thenReturn(interestRate); + Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_365.getValue()); + Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.ACTUAL.getValue()); + Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS); + Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1); + Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); + + final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( + expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + + final Money disbursedAmount = toMoney(100.0); + emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); + + checkPeriod(interestSchedule, 0, 0, 17.43, 0.0, 0.0, 1.33, 16.1, 83.9); + checkPeriod(interestSchedule, 0, 1, 17.43, 0.013315561644, 1.3315561644, 1.33, 16.1, 83.9); + checkPeriod(interestSchedule, 1, 0, 17.43, 0.012456493151, 1.04509977537, 1.05, 16.38, 67.52); + checkPeriod(interestSchedule, 2, 0, 17.43, 0.013315561644, 0.899066722202, 0.90, 16.53, 50.99); + checkPeriod(interestSchedule, 3, 0, 17.43, 0.012886027397, 0.657058536972, 0.66, 16.77, 34.22); + checkPeriod(interestSchedule, 4, 0, 17.43, 0.013315561644, 0.455658519458, 0.46, 16.97, 17.25); + checkPeriod(interestSchedule, 5, 0, 17.47, 0.012886027397, 0.222283972598, 0.22, 17.25, 0.0); + + // repay EMI on first period due date + emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1), + Money.of(currency, BigDecimal.valueOf(16.1))); + emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1), + Money.of(currency, BigDecimal.valueOf(1.33))); + + // repay EMI on first period due date - next installment for 2nd period + emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 2, 1), + Money.of(currency, BigDecimal.valueOf(17.43))); + + // repay 20 for last installment on first period due date -- ie MIR + emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 7, 1), LocalDate.of(2024, 2, 1), + Money.of(currency, BigDecimal.valueOf(17.43))); + emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 2, 1), + Money.of(currency, BigDecimal.valueOf(2.57))); + + LocalDate transactionDate = LocalDate.of(2024, 7, 1); + LocalDate reAgingStartDate = LocalDate.of(2024, 7, 15); + + OutstandingDetails outstandingAmountsTillDate = emiCalculator.getOutstandingAmountsTillDate(interestSchedule, transactionDate); + + LoanReAgeParameter reageParameter = new LoanReAgeParameter(null, PeriodFrequencyType.MONTHS, 1, reAgingStartDate, 6, + LoanReAgeInterestHandlingType.EQUAL_AMORTIZATION_PAYABLE_INTEREST, null); + + // Update the existing model with re-aged periods + emiCalculator.reAgeEqualAmortization(interestSchedule, transactionDate, reageParameter, Money.zero(currency), + new EqualAmortizationValues(Money.zero(currency), Money.zero(currency))); + + OutstandingDetails outstandingAmountsTillDateAfterReage = emiCalculator.getOutstandingAmountsTillDate(interestSchedule, + interestSchedule.getMaturityDate()); + + Assertions.assertEquals(outstandingAmountsTillDate.getOutstandingInterest().getAmount(), + outstandingAmountsTillDateAfterReage.getOutstandingInterest().getAmount()); + Assertions.assertEquals(outstandingAmountsTillDate.getOutstandingPrincipal().getAmount(), + outstandingAmountsTillDateAfterReage.getOutstandingPrincipal().getAmount()); + + } + + @Test + public void test_transactionAfterMaturityDate_EQUAL_EQUAL_AMORTIZATION_PAYABLE_INTEREST() { + final List expectedRepaymentPeriods = new ArrayList<>(); + + expectedRepaymentPeriods.add(repayment(1, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1))); + expectedRepaymentPeriods.add(repayment(2, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1))); + expectedRepaymentPeriods.add(repayment(3, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 4, 1))); + expectedRepaymentPeriods.add(repayment(4, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 5, 1))); + expectedRepaymentPeriods.add(repayment(5, LocalDate.of(2024, 5, 1), LocalDate.of(2024, 6, 1))); + expectedRepaymentPeriods.add(repayment(6, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 7, 1))); + + final BigDecimal interestRate = BigDecimal.valueOf(15.678); + final Integer installmentAmountInMultiplesOf = null; + + Mockito.when(loanProductRelatedDetail.getAnnualNominalInterestRate()).thenReturn(interestRate); + Mockito.when(loanProductRelatedDetail.getDaysInYearType()).thenReturn(DaysInYearType.DAYS_365.getValue()); + Mockito.when(loanProductRelatedDetail.getDaysInMonthType()).thenReturn(DaysInMonthType.ACTUAL.getValue()); + Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS); + Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1); + Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); + + final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( + expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + + final Money disbursedAmount = toMoney(100.0); + emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); + + checkPeriod(interestSchedule, 0, 0, 17.43, 0.0, 0.0, 1.33, 16.1, 83.9); + checkPeriod(interestSchedule, 0, 1, 17.43, 0.013315561644, 1.3315561644, 1.33, 16.1, 83.9); + checkPeriod(interestSchedule, 1, 0, 17.43, 0.012456493151, 1.04509977537, 1.05, 16.38, 67.52); + checkPeriod(interestSchedule, 2, 0, 17.43, 0.013315561644, 0.899066722202, 0.90, 16.53, 50.99); + checkPeriod(interestSchedule, 3, 0, 17.43, 0.012886027397, 0.657058536972, 0.66, 16.77, 34.22); + checkPeriod(interestSchedule, 4, 0, 17.43, 0.013315561644, 0.455658519458, 0.46, 16.97, 17.25); + checkPeriod(interestSchedule, 5, 0, 17.47, 0.012886027397, 0.222283972598, 0.22, 17.25, 0.0); + + // repay EMI on first period due date + emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1), + Money.of(currency, BigDecimal.valueOf(16.1))); + emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1), + Money.of(currency, BigDecimal.valueOf(1.33))); + + // repay EMI on first period due date - next installment for 2nd period + emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 2, 1), + Money.of(currency, BigDecimal.valueOf(17.43))); + + // repay 20 for last installment on first period due date -- ie MIR + emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 7, 1), LocalDate.of(2024, 2, 1), + Money.of(currency, BigDecimal.valueOf(17.43))); + emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 2, 1), + Money.of(currency, BigDecimal.valueOf(2.57))); + + LocalDate transactionDate = LocalDate.of(2024, 7, 10); + LocalDate reAgingStartDate = LocalDate.of(2024, 7, 15); + + OutstandingDetails outstandingAmountsTillDate = emiCalculator.getOutstandingAmountsTillDate(interestSchedule, transactionDate); + + LoanReAgeParameter reageParameter = new LoanReAgeParameter(null, PeriodFrequencyType.MONTHS, 1, reAgingStartDate, 6, + LoanReAgeInterestHandlingType.EQUAL_AMORTIZATION_PAYABLE_INTEREST, null); + + // Update the existing model with re-aged periods + emiCalculator.reAgeEqualAmortization(interestSchedule, transactionDate, reageParameter, Money.zero(currency), + new EqualAmortizationValues(Money.zero(currency), Money.zero(currency))); + + OutstandingDetails outstandingAmountsTillDateAfterReage = emiCalculator.getOutstandingAmountsTillDate(interestSchedule, + interestSchedule.getMaturityDate()); + + Assertions.assertEquals(outstandingAmountsTillDate.getOutstandingInterest().getAmount(), + outstandingAmountsTillDateAfterReage.getOutstandingInterest().getAmount()); + Assertions.assertEquals(outstandingAmountsTillDate.getOutstandingPrincipal().getAmount(), + outstandingAmountsTillDateAfterReage.getOutstandingPrincipal().getAmount()); + + } + } + // utilities private List generateExpectedRepaymentPeriods(LocalDate disbursementDate) { return switch (loanProductRelatedDetail.getRepaymentPeriodFrequencyType()) { diff --git a/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanproduct/calc/data/RepaymentPeriodTest.java b/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanproduct/calc/data/RepaymentPeriodTest.java index b257f7374..55048f285 100644 --- a/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanproduct/calc/data/RepaymentPeriodTest.java +++ b/fineract-progressive-loan/src/test/java/org/apache/fineract/portfolio/loanproduct/calc/data/RepaymentPeriodTest.java @@ -122,7 +122,12 @@ class RepaymentPeriodTest { null, // paidInterest null, // futureUnrecognizedInterest MC, // mc - loanProductRelatedDetail); + loanProductRelatedDetail, // + false, // noUnrecognizedInterest + false, // reAged + false, // reAgedEarlyRepaymentHolder + null // reAgedInterest + ); // Test that getters don't throw and return non-null assertDoesNotThrow(period::getEmi); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanInterestRefundServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanInterestRefundServiceImpl.java index c0f7efcb7..5742a5328 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanInterestRefundServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/ProgressiveLoanInterestRefundServiceImpl.java @@ -35,7 +35,6 @@ import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO; import org.apache.fineract.portfolio.loanaccount.data.TransactionChangeData; import org.apache.fineract.portfolio.loanaccount.domain.ChangedTransactionDetail; import org.apache.fineract.portfolio.loanaccount.domain.Loan; -import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType; import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor; @@ -62,8 +61,19 @@ public class ProgressiveLoanInterestRefundServiceImpl implements InterestRefundS private static void simulateRepaymentForDisbursements(LoanTransaction lt, final AtomicReference refundFinal, List collect) { - collect.add(new LoanTransaction(lt.getLoan(), lt.getLoan().getOffice(), lt.getTypeOf(), lt.getDateOf(), lt.getAmount(), - BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, false, null, null)); + LoanTransaction copy = new LoanTransaction(lt.getLoan(), lt.getLoan().getOffice(), lt.getTypeOf(), lt.getDateOf(), lt.getAmount(), + BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, false, null, null); + if (LoanTransactionType.CHARGE_PAYMENT.equals(copy.getTypeOf()) + || LoanTransactionType.REPAYMENT_AT_DISBURSEMENT.equals(copy.getTypeOf())) { + copy.getLoanChargesPaid().addAll(copy.getLoanChargesPaid()); + } + if (LoanTransactionType.REAGE.equals(copy.getTypeOf())) { + copy.setLoanReAgeParameter(lt.getLoanReAgeParameter().getCopy(copy)); + } + if (LoanTransactionType.REAMORTIZE.equals(copy.getTypeOf())) { + copy.setLoanReAmortizationParameter(lt.getLoanReAmortizationParameter()); + } + collect.add(copy); if (lt.getTypeOf().isDisbursement() && MathUtil.isGreaterThanZero(refundFinal.get())) { if (lt.getAmount().compareTo(refundFinal.get()) <= 0) { collect.add(new LoanTransaction(lt.getLoan(), lt.getLoan().getOffice(), REPAYMENT, lt.getDateOf(), lt.getAmount(), @@ -79,15 +89,14 @@ public class ProgressiveLoanInterestRefundServiceImpl implements InterestRefundS private Money recalculateTotalInterest(AdvancedPaymentScheduleTransactionProcessor processor, Loan loan, LocalDate relatedRefundTransactionDate, List transactionsToReprocess) { - List installmentsToReprocess = new ArrayList<>( - loan.getRepaymentScheduleInstallments().stream().filter(i -> !i.isReAged() && !i.isAdditional()).toList()); final ScheduleGeneratorDTO scheduleGeneratorDTO = loanUtilService.buildScheduleGeneratorDTO(loan, null); loanScheduleService.regenerateRepaymentSchedule(loan, scheduleGeneratorDTO); Pair reprocessResult = processor .reprocessProgressiveLoanTransactions(loan.getDisbursementDate(), relatedRefundTransactionDate, transactionsToReprocess, - loan.getCurrency(), installmentsToReprocess, loan.getActiveCharges()); + loan.getCurrency(), loan.getRepaymentScheduleInstallments(), loan.getActiveCharges()); + final List newTransactions = reprocessResult.getLeft().getTransactionChanges().stream() .map(TransactionChangeData::getNewTransaction).toList().stream().filter(LoanTransaction::isNotReversed).toList(); loan.getLoanTransactions().addAll(newTransactions); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reaging/LoanReAgingService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reaging/LoanReAgingService.java index 071ffc9f9..eefdb54a3 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reaging/LoanReAgingService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reaging/LoanReAgingService.java @@ -196,7 +196,11 @@ public class LoanReAgingService { } private void processReAgeTransaction(final Loan loan, final LoanTransaction reAgeTransaction, final boolean withPostTransactionChecks) { - if (reAgeTransaction.getTransactionDate().isBefore(reAgeTransaction.getSubmittedOnDate())) { + if (reAgeTransaction.getTransactionDate().isBefore(reAgeTransaction.getSubmittedOnDate()) + || LoanReAgeInterestHandlingType.EQUAL_AMORTIZATION_FULL_INTEREST + .equals(reAgeTransaction.getLoanReAgeParameter().getInterestHandlingType()) + || LoanReAgeInterestHandlingType.EQUAL_AMORTIZATION_PAYABLE_INTEREST + .equals(reAgeTransaction.getLoanReAgeParameter().getInterestHandlingType())) { final ScheduleGeneratorDTO scheduleGeneratorDTO = loanUtilService.buildScheduleGeneratorDTO(loan, null); loanScheduleService.regenerateRepaymentSchedule(loan, scheduleGeneratorDTO); if (withPostTransactionChecks) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reaging/LoanReAgingValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reaging/LoanReAgingValidator.java index 7f57f8b5b..3936e8798 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reaging/LoanReAgingValidator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/reaging/LoanReAgingValidator.java @@ -35,6 +35,7 @@ import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder; import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException; import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; import org.apache.fineract.infrastructure.core.serialization.JsonParserHelper; +import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants; import org.apache.fineract.portfolio.loanaccount.api.LoanReAgingApiConstants; import org.apache.fineract.portfolio.loanaccount.api.request.ReAgePreviewRequest; @@ -113,6 +114,13 @@ public class LoanReAgingValidator { } private void validateReAgeBusinessRules(Loan loan) { + // validate reaging shouldn't happen before maturity + // on progressive loans it can + if (!loan.isProgressiveSchedule() && DateUtils.isBefore(getBusinessLocalDate(), loan.getMaturityDate())) { + throw new GeneralPlatformDomainRuleException("error.msg.loan.reage.cannot.be.submitted.before.maturity", + "Loan cannot be re-aged before maturity", loan.getId()); + } + // validate reaging is only available for progressive schedule & advanced payment allocation LoanScheduleType loanScheduleType = LoanScheduleType.valueOf(loan.getLoanProductRelatedDetail().getLoanScheduleType().name()); boolean isProgressiveSchedule = LoanScheduleType.PROGRESSIVE.equals(loanScheduleType); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountAutoStarter.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountAutoStarter.java index 2574d5940..be1fadf72 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountAutoStarter.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/starter/LoanAccountAutoStarter.java @@ -32,6 +32,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.imp import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor; import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor; import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.RBILoanRepaymentScheduleTransactionProcessor; +import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.ScheduledDateGenerator; import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeValidator; import org.apache.fineract.portfolio.loanaccount.service.LoanBalanceService; import org.apache.fineract.portfolio.loanaccount.service.LoanChargeService; @@ -137,8 +138,8 @@ public class LoanAccountAutoStarter { final @Lazy ProgressiveLoanInterestRefundServiceImpl progressiveLoanInterestRefundService, final ExternalIdFactory externalIdFactory, final LoanScheduleComponent loanSchedule, final LoanChargeValidator loanChargeValidator, final LoanBalanceService loanBalanceService, - @Lazy final LoanChargeService loanChargeService) { + @Lazy final LoanChargeService loanChargeService, final ScheduledDateGenerator scheduledDateGenerator) { return new AdvancedPaymentScheduleTransactionProcessor(emiCalculator, progressiveLoanInterestRefundService, externalIdFactory, - loanSchedule, loanChargeValidator, loanBalanceService, loanChargeService); + loanSchedule, loanChargeValidator, loanBalanceService, loanChargeService, scheduledDateGenerator); } }