diff --git a/fineract-e2e-tests-runner/src/test/resources/features/LoanReschedule.feature b/fineract-e2e-tests-runner/src/test/resources/features/LoanReschedule.feature index 424461e37..eb8a5e45f 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/LoanReschedule.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanReschedule.feature @@ -917,7 +917,7 @@ Feature: LoanReschedule And 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 | - + @TestRailId:C3882 Scenario: Reschedule progressive loan to 0 percent interest then back to 10 percent When Admin sets the business date to "1 January 2024" @@ -943,8 +943,8 @@ Feature: LoanReschedule | 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 creates and approves Loan reschedule with the following data: - | rescheduleFromDate | submittedOnDate | adjustedDueDate | graceOnPrincipal | graceOnInterest | extraTerms | newInterestRate | - | 02 January 2024 | 01 January 2024 | | | | | 0 | + | rescheduleFromDate | submittedOnDate | adjustedDueDate | graceOnPrincipal | graceOnInterest | extraTerms | newInterestRate | + | 02 January 2024 | 01 January 2024 | | | | | 0 | 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 | | | | @@ -955,14 +955,14 @@ Feature: LoanReschedule | 5 | 31 | 01 June 2024 | | 16.65 | 16.67 | 0.0 | 0.0 | 0.0 | 16.67 | 0.0 | 0.0 | 0.0 | 16.67 | | 6 | 30 | 01 July 2024 | | 0.0 | 16.65 | 0.0 | 0.0 | 0.0 | 16.65 | 0.0 | 0.0 | 0.0 | 16.65 | Then Loan Repayment schedule has the following data in Total row: - | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | - | 100.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 100.0 | + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 100.0 | And 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 creates and approves Loan reschedule with the following data: - | rescheduleFromDate | submittedOnDate | adjustedDueDate | graceOnPrincipal | graceOnInterest | extraTerms | newInterestRate | - | 03 January 2024 | 01 January 2024 | | | | | 10 | + | rescheduleFromDate | submittedOnDate | adjustedDueDate | graceOnPrincipal | graceOnInterest | extraTerms | newInterestRate | + | 03 January 2024 | 01 January 2024 | | | | | 10 | 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 | | | | @@ -998,14 +998,14 @@ Feature: LoanReschedule | 5 | 31 | 01 June 2024 | | 16.65 | 16.67 | 0.0 | 0.0 | 0.0 | 16.67 | 0.0 | 0.0 | 0.0 | 16.67 | | 6 | 30 | 01 July 2024 | | 0.0 | 16.65 | 0.0 | 0.0 | 0.0 | 16.65 | 0.0 | 0.0 | 0.0 | 16.65 | Then Loan Repayment schedule has the following data in Total row: - | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | - | 100.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 100.0 | + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 100.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 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 100.0 | + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 0.0 | 0.0 | 0.0 | 100.0 | 0.0 | 0.0 | 0.0 | 100.0 | When Admin creates and approves Loan reschedule with the following data: - | rescheduleFromDate | submittedOnDate | adjustedDueDate | graceOnPrincipal | graceOnInterest | extraTerms | newInterestRate | - | 02 February 2024 | 01 January 2024 | | | | | 10 | + | rescheduleFromDate | submittedOnDate | adjustedDueDate | graceOnPrincipal | graceOnInterest | extraTerms | newInterestRate | + | 02 February 2024 | 01 January 2024 | | | | | 10 | 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 | | | | @@ -1061,8 +1061,8 @@ Feature: LoanReschedule | 5 | 31 | 01 June 2024 | | 16.99 | 16.88 | 0.28 | 0.0 | 0.0 | 17.16 | 0.0 | 0.0 | 0.0 | 17.16 | | 6 | 30 | 01 July 2024 | | 0.0 | 16.99 | 0.14 | 0.0 | 0.0 | 17.13 | 0.0 | 0.0 | 0.0 | 17.13 | 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.93 | 0.0 | 0.0 | 102.93 | 25.74 | 8.58 | 0.0 | 77.19 | + | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | + | 100.0 | 2.93 | 0.0 | 0.0 | 102.93 | 25.74 | 8.58 | 0.0 | 77.19 | 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 | @@ -1114,8 +1114,8 @@ Feature: LoanReschedule | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | | 24 July 2025 | Disbursement | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | 500.0 | false | false | When Admin creates and approves Loan reschedule with the following data: - | rescheduleFromDate | submittedOnDate | adjustedDueDate | graceOnPrincipal | graceOnInterest | extraTerms | newInterestRate | - | 24 July 2025 | 24 July 2025 | | | | | 5 | + | rescheduleFromDate | submittedOnDate | adjustedDueDate | graceOnPrincipal | graceOnInterest | extraTerms | newInterestRate | + | 24 July 2025 | 24 July 2025 | | | | | 5 | 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 | | | | 24 July 2025 | | 500.0 | | | 0.0 | | 0.0 | 0.0 | | | | @@ -1127,19 +1127,19 @@ Feature: LoanReschedule | 6 | 31 | 24 January 2026 | | 0.0 | 84.21 | 0.35 | 0.0 | 0.0 | 84.56 | 0.0 | 0.0 | 0.0 | 84.56 | Then Loan Repayment schedule has the following data in Total row: | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding | - | 500.0 | 7.31 | 0.0 | 0.0 | 507.31 | 0.0 | 0.0 | 0.0 | 507.31 | + | 500.0 | 7.31 | 0.0 | 0.0 | 507.31 | 0.0 | 0.0 | 0.0 | 507.31 | And Loan Transactions tab has the following data: | Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed | | 24 July 2025 | Disbursement | 500.0 | 0.0 | 0.0 | 0.0 | 0.0 | 500.0 | false | false | Then LoanRescheduledDueAdjustScheduleBusinessEvent is raised on "24 July 2025" @TestRailId:C4225 - Scenario: Verify after reschedule of loan by changing due date, the last Accrual Activity transaction is reversed-replayed only once + Scenario: Verify after backdated repayment, the last Accrual Activity transaction is reversed-replayed only once When Admin sets the business date to "05 September 2025" And Admin creates a client with random data And Admin creates a fully customized loan with the following data: - | LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | - | LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_ACCRUAL_ACTIVITY | 31 December 2024 | 1111 | 24.99 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 24 | MONTHS | 1 | MONTHS | 24 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + | 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_ACTUAL_ACTUAL_ACCRUAL_ACTIVITY | 31 December 2024 | 1111 | 24.99 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 24 | MONTHS | 1 | MONTHS | 24 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | And Admin successfully approves the loan on "31 December 2024" with "1111" amount and expected disbursement date on "31 December 2024" And Admin successfully disburse the loan on "31 December 2024" with "1111" EUR transaction amount And Customer makes "AUTOPAY" repayment on "31 January 2025" with 59.26 EUR transaction amount @@ -1169,8 +1169,267 @@ Feature: LoanReschedule When Admin runs inline COB job for Loan When Admin sets the business date to "10 November 2025" When Admin runs inline COB job for Loan + And Customer makes "AUTOPAY" repayment on "29 June 2025" with 60 EUR transaction amount + Then In Loan Transactions the "1"th Transaction of "Accrual Activity" on "31 October 2025" has "1" relationship with type="REPLAYED" + + Scenario: Verify progressive loan due date reschedule maintains EMI + When Admin sets the business date to "05 September 2025" + And Admin creates a client with random data + And Admin creates a fully customized loan with the following data: + | LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy | + | LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_ACCRUAL_ACTIVITY | 31 December 2024 | 1111 | 24.99 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 24 | MONTHS | 1 | MONTHS | 24 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "31 December 2024" with "1111" amount and expected disbursement date on "31 December 2024" + And Admin successfully disburse the loan on "31 December 2024" with "1111" EUR transaction amount + And Customer makes "AUTOPAY" repayment on "31 January 2025" with 59.26 EUR transaction amount + And Customer makes "AUTOPAY" repayment on "28 February 2025" with 59.26 EUR transaction amount + And Customer makes "AUTOPAY" repayment on "31 March 2025" with 59.26 EUR transaction amount + And Customer makes "AUTOPAY" repayment on "30 April 2025" with 59.26 EUR transaction amount + And Customer makes "AUTOPAY" repayment on "30 May 2025" with 59.26 EUR transaction amount + And Customer makes "AUTOPAY" repayment on "29 June 2025" with 59.26 EUR transaction amount + And Customer makes "AUTOPAY" repayment on "31 July 2025" with 59.26 EUR transaction amount + And Customer makes "AUTOPAY" repayment on "31 August 2025" with 59.26 EUR transaction amount + When Admin sets the business date to "06 September 2025" + When Admin runs inline COB job for Loan + When Admin sets the business date to "11 September 2025" + When Customer undo "1"th "Repayment" transaction made on "31 August 2025" + When Admin sets the business date to "30 September 2025" + And Customer makes "AUTOPAY" repayment on "30 September 2025" with 59.26 EUR transaction amount + And Customer makes "AUTOPAY" repayment on "30 September 2025" with 59.26 EUR transaction amount + When Admin runs inline COB job for Loan + When Admin sets the business date to "10 October 2025" + When Customer undo "1"th "Repayment" transaction made on "30 September 2025" + When Customer undo "2"th "Repayment" transaction made on "30 September 2025" + When Admin sets the business date to "16 October 2025" + And Customer makes "AUTOPAY" repayment on "16 October 2025" with 60 EUR transaction amount + When Admin sets the business date to "31 October 2025" + And Customer makes "AUTOPAY" repayment on "31 October 2025" with 59.26 EUR transaction amount + And Customer makes "AUTOPAY" repayment on "31 October 2025" with 58.52 EUR transaction amount + When Admin runs inline COB job for Loan + When Admin sets the business date to "10 November 2025" + Then Loan Repayment schedule has 24 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 | + | | | 31 December 2024 | | 1111.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 31 January 2025 | 31 January 2025 | 1075.32 | 35.68 | 23.58 | 0.0 | 0.0 | 59.26 | 59.26 | 0.0 | 0.0 | 0.0 | + | 2 | 28 | 28 February 2025 | 28 February 2025 | 1036.67 | 38.65 | 20.61 | 0.0 | 0.0 | 59.26 | 59.26 | 0.0 | 0.0 | 0.0 | + | 3 | 31 | 31 March 2025 | 31 March 2025 | 999.41 | 37.26 | 22.0 | 0.0 | 0.0 | 59.26 | 59.26 | 0.0 | 0.0 | 0.0 | + | 4 | 30 | 30 April 2025 | 30 April 2025 | 960.68 | 38.73 | 20.53 | 0.0 | 0.0 | 59.26 | 59.26 | 0.0 | 0.0 | 0.0 | + | 5 | 31 | 31 May 2025 | 30 May 2025 | 921.81 | 38.87 | 20.39 | 0.0 | 0.0 | 59.26 | 59.26 | 59.26 | 0.0 | 0.0 | + | 6 | 30 | 30 June 2025 | 29 June 2025 | 881.48 | 40.33 | 18.93 | 0.0 | 0.0 | 59.26 | 59.26 | 59.26 | 0.0 | 0.0 | + | 7 | 31 | 31 July 2025 | 31 July 2025 | 840.93 | 40.55 | 18.71 | 0.0 | 0.0 | 59.26 | 59.26 | 0.0 | 0.0 | 0.0 | + | 8 | 31 | 31 August 2025 | 16 October 2025 | 799.52 | 41.41 | 17.85 | 0.0 | 0.0 | 59.26 | 59.26 | 0.0 | 59.26 | 0.0 | + | 9 | 30 | 30 September 2025 | 31 October 2025 | 756.68 | 42.84 | 16.42 | 0.0 | 0.0 | 59.26 | 59.26 | 0.0 | 59.26 | 0.0 | + | 10 | 31 | 31 October 2025 | 31 October 2025 | 713.48 | 43.2 | 16.06 | 0.0 | 0.0 | 59.26 | 59.26 | 0.0 | 0.0 | 0.0 | + | 11 | 30 | 30 November 2025 | | 668.87 | 44.61 | 14.65 | 0.0 | 0.0 | 59.26 | 0.0 | 0.0 | 0.0 | 59.26 | + | 12 | 31 | 31 December 2025 | | 623.81 | 45.06 | 14.2 | 0.0 | 0.0 | 59.26 | 0.0 | 0.0 | 0.0 | 59.26 | + | 13 | 31 | 31 January 2026 | | 577.79 | 46.02 | 13.24 | 0.0 | 0.0 | 59.26 | 0.0 | 0.0 | 0.0 | 59.26 | + | 14 | 28 | 28 February 2026 | | 529.61 | 48.18 | 11.08 | 0.0 | 0.0 | 59.26 | 0.0 | 0.0 | 0.0 | 59.26 | + | 15 | 31 | 31 March 2026 | | 481.59 | 48.02 | 11.24 | 0.0 | 0.0 | 59.26 | 0.0 | 0.0 | 0.0 | 59.26 | + | 16 | 30 | 30 April 2026 | | 432.22 | 49.37 | 9.89 | 0.0 | 0.0 | 59.26 | 0.0 | 0.0 | 0.0 | 59.26 | + | 17 | 31 | 31 May 2026 | | 382.13 | 50.09 | 9.17 | 0.0 | 0.0 | 59.26 | 0.0 | 0.0 | 0.0 | 59.26 | + | 18 | 30 | 30 June 2026 | | 330.72 | 51.41 | 7.85 | 0.0 | 0.0 | 59.26 | 0.0 | 0.0 | 0.0 | 59.26 | + | 19 | 31 | 31 July 2026 | | 278.48 | 52.24 | 7.02 | 0.0 | 0.0 | 59.26 | 0.0 | 0.0 | 0.0 | 59.26 | + | 20 | 31 | 31 August 2026 | | 225.13 | 53.35 | 5.91 | 0.0 | 0.0 | 59.26 | 0.0 | 0.0 | 0.0 | 59.26 | + | 21 | 30 | 30 September 2026 | | 170.49 | 54.64 | 4.62 | 0.0 | 0.0 | 59.26 | 0.0 | 0.0 | 0.0 | 59.26 | + | 22 | 31 | 31 October 2026 | | 114.85 | 55.64 | 3.62 | 0.0 | 0.0 | 59.26 | 0.0 | 0.0 | 0.0 | 59.26 | + | 23 | 30 | 30 November 2026 | | 57.95 | 56.9 | 2.36 | 0.0 | 0.0 | 59.26 | 0.0 | 0.0 | 0.0 | 59.26 | + | 24 | 31 | 31 December 2026 | | 0.0 | 57.95 | 1.23 | 0.0 | 0.0 | 59.18 | 0.0 | 0.0 | 0.0 | 59.18 | When Admin creates and approves Loan reschedule with the following data: | rescheduleFromDate | submittedOnDate | adjustedDueDate | graceOnPrincipal | graceOnInterest | extraTerms | newInterestRate | | 30 November 2025 | 10 November 2025 | 31 January 2026 | | | | | - Then In Loan Transactions the "1"th Transaction of "Accrual Activity" on "31 October 2025" has "1" relationship with type="REPLAYED" + Then Loan Repayment schedule has 24 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 | + | | | 31 December 2024 | | 1111.0 | | | 0.0 | | 0.0 | 0.0 | | | | + | 1 | 31 | 31 January 2025 | 31 January 2025 | 1075.32 | 35.68 | 23.58 | 0.0 | 0.0 | 59.26 | 59.26 | 0.0 | 0.0 | 0.0 | + | 2 | 28 | 28 February 2025 | 28 February 2025 | 1036.67 | 38.65 | 20.61 | 0.0 | 0.0 | 59.26 | 59.26 | 0.0 | 0.0 | 0.0 | + | 3 | 31 | 31 March 2025 | 31 March 2025 | 999.41 | 37.26 | 22.0 | 0.0 | 0.0 | 59.26 | 59.26 | 0.0 | 0.0 | 0.0 | + | 4 | 30 | 30 April 2025 | 30 April 2025 | 960.68 | 38.73 | 20.53 | 0.0 | 0.0 | 59.26 | 59.26 | 0.0 | 0.0 | 0.0 | + | 5 | 31 | 31 May 2025 | 30 May 2025 | 921.81 | 38.87 | 20.39 | 0.0 | 0.0 | 59.26 | 59.26 | 59.26 | 0.0 | 0.0 | + | 6 | 30 | 30 June 2025 | 29 June 2025 | 881.48 | 40.33 | 18.93 | 0.0 | 0.0 | 59.26 | 59.26 | 59.26 | 0.0 | 0.0 | + | 7 | 31 | 31 July 2025 | 31 July 2025 | 840.93 | 40.55 | 18.71 | 0.0 | 0.0 | 59.26 | 59.26 | 0.0 | 0.0 | 0.0 | + | 8 | 31 | 31 August 2025 | 16 October 2025 | 799.52 | 41.41 | 17.85 | 0.0 | 0.0 | 59.26 | 59.26 | 0.0 | 59.26 | 0.0 | + | 9 | 30 | 30 September 2025 | 31 October 2025 | 756.68 | 42.84 | 16.42 | 0.0 | 0.0 | 59.26 | 59.26 | 0.0 | 59.26 | 0.0 | + | 10 | 31 | 31 October 2025 | 31 October 2025 | 713.48 | 43.2 | 16.06 | 0.0 | 0.0 | 59.26 | 59.26 | 0.0 | 0.0 | 0.0 | + | 11 | 92 | 31 January 2026 | | 699.16 | 14.32 | 44.94 | 0.0 | 0.0 | 59.26 | 0.0 | 0.0 | 0.0 | 59.26 | + | 12 | 28 | 28 February 2026 | | 653.3 | 45.86 | 13.4 | 0.0 | 0.0 | 59.26 | 0.0 | 0.0 | 0.0 | 59.26 | + | 13 | 31 | 31 March 2026 | | 607.91 | 45.39 | 13.87 | 0.0 | 0.0 | 59.26 | 0.0 | 0.0 | 0.0 | 59.26 | + | 14 | 30 | 30 April 2026 | | 561.14 | 46.77 | 12.49 | 0.0 | 0.0 | 59.26 | 0.0 | 0.0 | 0.0 | 59.26 | + | 15 | 31 | 31 May 2026 | | 513.79 | 47.35 | 11.91 | 0.0 | 0.0 | 59.26 | 0.0 | 0.0 | 0.0 | 59.26 | + | 16 | 30 | 30 June 2026 | | 465.08 | 48.71 | 10.55 | 0.0 | 0.0 | 59.26 | 0.0 | 0.0 | 0.0 | 59.26 | + | 17 | 31 | 31 July 2026 | | 415.69 | 49.39 | 9.87 | 0.0 | 0.0 | 59.26 | 0.0 | 0.0 | 0.0 | 59.26 | + | 18 | 31 | 31 August 2026 | | 365.25 | 50.44 | 8.82 | 0.0 | 0.0 | 59.26 | 0.0 | 0.0 | 0.0 | 59.26 | + | 19 | 30 | 30 September 2026 | | 313.49 | 51.76 | 7.5 | 0.0 | 0.0 | 59.26 | 0.0 | 0.0 | 0.0 | 59.26 | + | 20 | 31 | 31 October 2026 | | 260.88 | 52.61 | 6.65 | 0.0 | 0.0 | 59.26 | 0.0 | 0.0 | 0.0 | 59.26 | + | 21 | 30 | 30 November 2026 | | 206.98 | 53.9 | 5.36 | 0.0 | 0.0 | 59.26 | 0.0 | 0.0 | 0.0 | 59.26 | + | 22 | 31 | 31 December 2026 | | 152.11 | 54.87 | 4.39 | 0.0 | 0.0 | 59.26 | 0.0 | 0.0 | 0.0 | 59.26 | + | 23 | 31 | 31 January 2027 | | 96.08 | 56.03 | 3.23 | 0.0 | 0.0 | 59.26 | 0.0 | 0.0 | 0.0 | 59.26 | + | 24 | 28 | 28 February 2027 | | 0.0 | 96.08 | 1.84 | 0.0 | 0.0 | 97.92 | 0.0 | 0.0 | 0.0 | 97.92 | + Scenario: Verify basic loan rescheduling + When Admin sets the business date to "1 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 | 1 January 2024 | 100 | 9.4822 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "1 January 2024" with "100" amount and expected disbursement date on "1 January 2024" + When Admin successfully disburse the loan on "1 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.66 | 16.34 | 0.79 | 0.0 | 0.0 | 17.13 | 0.0 | 0.0 | 0.0 | 17.13 | + | 2 | 29 | 01 March 2024 | | 67.19 | 16.47 | 0.66 | 0.0 | 0.0 | 17.13 | 0.0 | 0.0 | 0.0 | 17.13 | + | 3 | 31 | 01 April 2024 | | 50.59 | 16.6 | 0.53 | 0.0 | 0.0 | 17.13 | 0.0 | 0.0 | 0.0 | 17.13 | + | 4 | 30 | 01 May 2024 | | 33.86 | 16.73 | 0.4 | 0.0 | 0.0 | 17.13 | 0.0 | 0.0 | 0.0 | 17.13 | + | 5 | 31 | 01 June 2024 | | 17.0 | 16.86 | 0.27 | 0.0 | 0.0 | 17.13 | 0.0 | 0.0 | 0.0 | 17.13 | + | 6 | 30 | 01 July 2024 | | 0.0 | 17.0 | 0.13 | 0.0 | 0.0 | 17.13 | 0.0 | 0.0 | 0.0 | 17.13 | + 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.78 | 0.0 | 0.0 | 102.78 | 0.0 | 0.0 | 0.0 | 102.78 | + And 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 "1 February 2024" + And Customer makes "AUTOPAY" repayment on "1 February 2024" with 17.13 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.66 | 16.34 | 0.79 | 0.0 | 0.0 | 17.13 | 17.13 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.19 | 16.47 | 0.66 | 0.0 | 0.0 | 17.13 | 0.0 | 0.0 | 0.0 | 17.13 | + | 3 | 31 | 01 April 2024 | | 50.59 | 16.6 | 0.53 | 0.0 | 0.0 | 17.13 | 0.0 | 0.0 | 0.0 | 17.13 | + | 4 | 30 | 01 May 2024 | | 33.86 | 16.73 | 0.4 | 0.0 | 0.0 | 17.13 | 0.0 | 0.0 | 0.0 | 17.13 | + | 5 | 31 | 01 June 2024 | | 17.0 | 16.86 | 0.27 | 0.0 | 0.0 | 17.13 | 0.0 | 0.0 | 0.0 | 17.13 | + | 6 | 30 | 01 July 2024 | | 0.0 | 17.0 | 0.13 | 0.0 | 0.0 | 17.13 | 0.0 | 0.0 | 0.0 | 17.13 | + 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.78 | 0.0 | 0.0 | 102.78 | 17.13 | 0.0 | 0.0 | 85.65 | + And 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.13 | 16.34 | 0.79 | 0.0 | 0.0 | 83.66 | false | false | + When Admin sets the business date to "1 March 2024" + When Admin creates and approves Loan reschedule with the following data: + | rescheduleFromDate | submittedOnDate | adjustedDueDate | graceOnPrincipal | graceOnInterest | extraTerms | newInterestRate | + | 1 March 2024 | 1 March 2024 | 15 March 2024 | | | | | + 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.66 | 16.34 | 0.79 | 0.0 | 0.0 | 17.13 | 17.13 | 0.0 | 0.0 | 0.0 | + | 2 | 43 | 15 March 2024 | | 67.49 | 16.17 | 0.96 | 0.0 | 0.0 | 17.13 | 0.0 | 0.0 | 0.0 | 17.13 | + | 3 | 31 | 15 April 2024 | | 50.89 | 16.6 | 0.53 | 0.0 | 0.0 | 17.13 | 0.0 | 0.0 | 0.0 | 17.13 | + | 4 | 30 | 15 May 2024 | | 34.16 | 16.73 | 0.4 | 0.0 | 0.0 | 17.13 | 0.0 | 0.0 | 0.0 | 17.13 | + | 5 | 31 | 15 June 2024 | | 17.3 | 16.86 | 0.27 | 0.0 | 0.0 | 17.13 | 0.0 | 0.0 | 0.0 | 17.13 | + | 6 | 30 | 15 July 2024 | | 0.0 | 17.3 | 0.14 | 0.0 | 0.0 | 17.44 | 0.0 | 0.0 | 0.0 | 17.44 | + + Scenario: Verify loan rescheduling with N+1 period + When Admin sets the business date to "1 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 | 1 January 2024 | 100 | 9.4822 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "1 January 2024" with "100" amount and expected disbursement date on "1 January 2024" + When Admin successfully disburse the loan on "1 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.66 | 16.34 | 0.79 | 0.0 | 0.0 | 17.13 | 0.0 | 0.0 | 0.0 | 17.13 | + | 2 | 29 | 01 March 2024 | | 67.19 | 16.47 | 0.66 | 0.0 | 0.0 | 17.13 | 0.0 | 0.0 | 0.0 | 17.13 | + | 3 | 31 | 01 April 2024 | | 50.59 | 16.6 | 0.53 | 0.0 | 0.0 | 17.13 | 0.0 | 0.0 | 0.0 | 17.13 | + | 4 | 30 | 01 May 2024 | | 33.86 | 16.73 | 0.4 | 0.0 | 0.0 | 17.13 | 0.0 | 0.0 | 0.0 | 17.13 | + | 5 | 31 | 01 June 2024 | | 17.0 | 16.86 | 0.27 | 0.0 | 0.0 | 17.13 | 0.0 | 0.0 | 0.0 | 17.13 | + | 6 | 30 | 01 July 2024 | | 0.0 | 17.0 | 0.13 | 0.0 | 0.0 | 17.13 | 0.0 | 0.0 | 0.0 | 17.13 | + 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.78 | 0.0 | 0.0 | 102.78 | 0.0 | 0.0 | 0.0 | 102.78 | + And 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 "1 February 2024" + And Customer makes "AUTOPAY" repayment on "1 February 2024" with 17.13 EUR transaction amount + When Admin sets the business date to "15 July 2024" + And Admin adds "LOAN_SNOOZE_FEE" due date charge with "15 July 2024" due date and 10 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 | 31 | 01 February 2024 | 01 February 2024 | 83.66 | 16.34 | 0.79 | 0.0 | 0.0 | 17.13 | 17.13 | 0.0 | 0.0 | 0.0 | + | 2 | 29 | 01 March 2024 | | 67.19 | 16.47 | 0.66 | 0.0 | 0.0 | 17.13 | 0.0 | 0.0 | 0.0 | 17.13 | + | 3 | 31 | 01 April 2024 | | 50.59 | 16.6 | 0.53 | 0.0 | 0.0 | 17.13 | 0.0 | 0.0 | 0.0 | 17.13 | + | 4 | 30 | 01 May 2024 | | 33.86 | 16.73 | 0.4 | 0.0 | 0.0 | 17.13 | 0.0 | 0.0 | 0.0 | 17.13 | + | 5 | 31 | 01 June 2024 | | 17.0 | 16.86 | 0.27 | 0.0 | 0.0 | 17.13 | 0.0 | 0.0 | 0.0 | 17.13 | + | 6 | 30 | 01 July 2024 | | 0.0 | 17.0 | 0.13 | 0.0 | 0.0 | 17.13 | 0.0 | 0.0 | 0.0 | 17.13 | + | 7 | 14 | 15 July 2024 | | 0.0 | 0.0 | 0.0 | 10.0 | 0.0 | 10.0 | 0.0 | 0.0 | 0.0 | 10.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.78 | 10.0 | 0.0 | 112.78 | 17.13 | 0.0 | 0.0 | 95.65 | + And 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.13 | 16.34 | 0.79 | 0.0 | 0.0 | 83.66 | false | false | + When Admin sets the business date to "1 March 2024" + When Admin creates and approves Loan reschedule with the following data: + | rescheduleFromDate | submittedOnDate | adjustedDueDate | graceOnPrincipal | graceOnInterest | extraTerms | newInterestRate | + | 1 March 2024 | 1 March 2024 | 30 March 2024 | | | | | + 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.66 | 16.34 | 0.79 | 0.0 | 0.0 | 17.13 | 17.13 | 0.0 | 0.0 | 0.0 | + | 2 | 58 | 30 March 2024 | | 67.81 | 15.85 | 1.28 | 0.0 | 0.0 | 17.13 | 0.0 | 0.0 | 0.0 | 17.13 | + | 3 | 31 | 30 April 2024 | | 51.22 | 16.59 | 0.54 | 0.0 | 0.0 | 17.13 | 0.0 | 0.0 | 0.0 | 17.13 | + | 4 | 30 | 30 May 2024 | | 34.49 | 16.73 | 0.4 | 0.0 | 0.0 | 17.13 | 0.0 | 0.0 | 0.0 | 17.13 | + | 5 | 31 | 30 June 2024 | | 17.63 | 16.86 | 0.27 | 0.0 | 0.0 | 17.13 | 0.0 | 0.0 | 0.0 | 17.13 | + | 6 | 30 | 30 July 2024 | | 0.0 | 17.63 | 0.14 | 10.0 | 0.0 | 27.77 | 0.0 | 0.0 | 0.0 | 27.77 | + + Scenario: Verify loan rescheduling with automatic down payment + When Admin sets the business date to "1 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 | 1 January 2024 | 100 | 9.4822 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 5 | MONTHS | 1 | MONTHS | 5 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | + And Admin successfully approves the loan on "1 January 2024" with "100" amount and expected disbursement date on "1 January 2024" + When Admin successfully disburse the loan on "1 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 | 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 | | 60.23 | 14.77 | 0.59 | 0.0 | 0.0 | 15.36 | 0.0 | 0.0 | 0.0 | 15.36 | + | 3 | 29 | 01 March 2024 | | 45.35 | 14.88 | 0.48 | 0.0 | 0.0 | 15.36 | 0.0 | 0.0 | 0.0 | 15.36 | + | 4 | 31 | 01 April 2024 | | 30.35 | 15.0 | 0.36 | 0.0 | 0.0 | 15.36 | 0.0 | 0.0 | 0.0 | 15.36 | + | 5 | 30 | 01 May 2024 | | 15.23 | 15.12 | 0.24 | 0.0 | 0.0 | 15.36 | 0.0 | 0.0 | 0.0 | 15.36 | + | 6 | 31 | 01 June 2024 | | 0.0 | 15.23 | 0.12 | 0.0 | 0.0 | 15.35 | 0.0 | 0.0 | 0.0 | 15.35 | + 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.79 | 0.0 | 0.0 | 101.79 | 25.0 | 0.0 | 0.0 | 76.79 | + And 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 | + And Admin sets the business date to "1 February 2024" + And Customer makes "AUTOPAY" repayment on "1 February 2024" with 15.36 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 | 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 | 60.23 | 14.77 | 0.59 | 0.0 | 0.0 | 15.36 | 15.36 | 0.0 | 0.0 | 0.0 | + | 3 | 29 | 01 March 2024 | | 45.35 | 14.88 | 0.48 | 0.0 | 0.0 | 15.36 | 0.0 | 0.0 | 0.0 | 15.36 | + | 4 | 31 | 01 April 2024 | | 30.35 | 15.0 | 0.36 | 0.0 | 0.0 | 15.36 | 0.0 | 0.0 | 0.0 | 15.36 | + | 5 | 30 | 01 May 2024 | | 15.23 | 15.12 | 0.24 | 0.0 | 0.0 | 15.36 | 0.0 | 0.0 | 0.0 | 15.36 | + | 6 | 31 | 01 June 2024 | | 0.0 | 15.23 | 0.12 | 0.0 | 0.0 | 15.35 | 0.0 | 0.0 | 0.0 | 15.35 | + 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.79 | 0.0 | 0.0 | 101.79 | 40.36 | 0.0 | 0.0 | 61.43 | + And 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 | 15.36 | 14.77 | 0.59 | 0.0 | 0.0 | 60.23 | false | false | + When Admin sets the business date to "1 March 2024" + When Admin creates and approves Loan reschedule with the following data: + | rescheduleFromDate | submittedOnDate | adjustedDueDate | graceOnPrincipal | graceOnInterest | extraTerms | newInterestRate | + | 1 March 2024 | 1 March 2024 | 15 March 2024 | | | | | + 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 | 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 | 60.23 | 14.77 | 0.59 | 0.0 | 0.0 | 15.36 | 15.36 | 0.0 | 0.0 | 0.0 | + | 3 | 43 | 15 March 2024 | | 45.56 | 14.67 | 0.69 | 0.0 | 0.0 | 15.36 | 0.0 | 0.0 | 0.0 | 15.36 | + | 4 | 31 | 15 April 2024 | | 30.56 | 15.0 | 0.36 | 0.0 | 0.0 | 15.36 | 0.0 | 0.0 | 0.0 | 15.36 | + | 5 | 30 | 15 May 2024 | | 15.44 | 15.12 | 0.24 | 0.0 | 0.0 | 15.36 | 0.0 | 0.0 | 0.0 | 15.36 | + | 6 | 31 | 15 June 2024 | | 0.0 | 15.44 | 0.12 | 0.0 | 0.0 | 15.56 | 0.0 | 0.0 | 0.0 | 15.56 | \ No newline at end of file diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGenerator.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGenerator.java index ad25cee25..f0e75b4d4 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGenerator.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/DefaultScheduledDateGenerator.java @@ -76,6 +76,11 @@ public class DefaultScheduledDateGenerator implements ScheduledDateGenerator { private LocalDate applyLoanTermVariations(final LoanApplicationTerms loanApplicationTerms, final LocalDate scheduledDueDate) { LocalDate modifiedScheduledDueDate = scheduledDueDate; + + if (LoanScheduleType.PROGRESSIVE.equals(loanApplicationTerms.getLoanScheduleType())) { + return modifiedScheduledDueDate; + } + // due date changes should be applied only for that dueDate if (loanApplicationTerms.getLoanTermVariations() != null) { if (loanApplicationTerms.getLoanTermVariations().hasDueDateVariation(scheduledDueDate)) { 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 d5695acc0..b0965cf55 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 @@ -55,6 +55,7 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; +import java.util.stream.IntStream; import java.util.stream.Stream; import lombok.AllArgsConstructor; import lombok.Getter; @@ -225,8 +226,7 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep .collect(Collectors.toCollection(ArrayList::new)); final Integer installmentAmountInMultiplesOf = loan.getLoanProductRelatedDetail().getInstallmentAmountInMultiplesOf(); ProgressiveLoanInterestScheduleModel scheduleModel = emiCalculator.generateInstallmentInterestScheduleModel(installments, - LoanConfigurationDetailsMapper.map(loan), loanTermVariations, installmentAmountInMultiplesOf, - overpaymentHolder.getMoneyObject().getMc()); + LoanConfigurationDetailsMapper.map(loan), installmentAmountInMultiplesOf, overpaymentHolder.getMoneyObject().getMc()); ProgressiveTransactionCtx ctx = new ProgressiveTransactionCtx(currency, installments, charges, overpaymentHolder, changedTransactionDetail, scheduleModel); @@ -236,8 +236,8 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep List overpaidTransactions = new ArrayList<>(); for (final ChangeOperation changeOperation : changeOperations) { if (changeOperation.isLoanTermVariationsData()) { - final LoanTermVariationsData interestRateChange = changeOperation.getLoanTermVariationsData().get(); - processLoanTermVariation(installments, interestRateChange, scheduleModel); + final LoanTermVariationsData termVariationsData = changeOperation.getLoanTermVariationsData().get(); + processLoanTermVariation(installments, termVariationsData, scheduleModel); } else if (changeOperation.isTransaction()) { LoanTransaction transaction = changeOperation.getLoanTransaction().get(); if (loan.getStatus().isOverpaid() && transaction.isAccrualActivity()) { @@ -309,10 +309,92 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep case INTEREST_PAUSE -> handleInterestPause(installments, termVariationsData, scheduleModel); case INTEREST_RATE_FROM_INSTALLMENT -> handleChangeInterestRate(installments, termVariationsData, scheduleModel); case EXTEND_REPAYMENT_PERIOD -> handleExtraRepaymentPeriod(installments, termVariationsData, scheduleModel); + case DUE_DATE -> handleDueDateChangeOnRepaymentPeriod(installments, termVariationsData, scheduleModel); default -> throw new IllegalStateException("Unhandled LoanTermVariationType."); } } + private void handleDueDateChangeOnRepaymentPeriod(final List installments, + final LoanTermVariationsData termVariationsData, final ProgressiveLoanInterestScheduleModel scheduleModel) { + final LocalDate targetRepaymentPeriodDueDate = termVariationsData.getTermVariationApplicableFrom(); + final LocalDate newDueDate = termVariationsData.getDateValue(); + final Loan loan = installments.getFirst().getLoan(); + final LoanApplicationTerms loanApplicationTerms = new LoanApplicationTerms.Builder() // + .currency(loan.getCurrency().toData()) // + .repaymentEvery(loan.getLoanProductRelatedDetail().getRepayEvery()) // + .repaymentPeriodFrequencyType(loan.getLoanProductRelatedDetail().getRepaymentPeriodFrequencyType()) // + .fixedLength(loan.getLoanProductRelatedDetail().getFixedLength()) // + .seedDate(newDueDate) // + .build(); + emiCalculator.changeDueDate(scheduleModel, loanApplicationTerms, targetRepaymentPeriodDueDate, newDueDate); + + IntStream.range(0, installments.size()).filter(i -> installments.get(i).getDueDate().equals(targetRepaymentPeriodDueDate)) + .findFirst().ifPresent(targetInstallmentIndex -> { + long scheduleModelStartIndex = installments.subList(0, targetInstallmentIndex).stream() + .filter(inst -> !inst.isDownPayment() && !inst.isAdditional()).count(); + + for (int i = targetInstallmentIndex; i < installments.size(); i++) { + final LoanRepaymentScheduleInstallment installment = installments.get(i); + if (installment.isDownPayment() || installment.isAdditional()) { + continue; + } + if (scheduleModelStartIndex >= scheduleModel.repaymentPeriods().size()) { + break; + } + + final RepaymentPeriod repaymentPeriod = scheduleModel.repaymentPeriods().get((int) scheduleModelStartIndex); + + if (isNotObligationsMet(installment)) { + installment.updateFromDate(repaymentPeriod.getFromDate()); + installment.updateDueDate(repaymentPeriod.getDueDate()); + installment.updatePrincipal(repaymentPeriod.getDuePrincipal().getAmount()); + installment.updateInterestCharged(repaymentPeriod.getDueInterest().getAmount()); + } + + scheduleModelStartIndex++; + } + }); + + mergeAdditionalInstallmentsBeforeMaturityDate(installments, scheduleModel, loan); + + installments.sort(Comparator.comparing(LoanRepaymentScheduleInstallment::getDueDate)); + int installmentNumber = 1; + for (LoanRepaymentScheduleInstallment installment : installments) { + installment.updateInstallmentNumber(installmentNumber++); + } + } + + private void mergeAdditionalInstallmentsBeforeMaturityDate(final List installments, + final ProgressiveLoanInterestScheduleModel scheduleModel, final Loan loan) { + final LocalDate newMaturityDate = scheduleModel.repaymentPeriods().getLast().getDueDate(); + + final Optional lastRegularInstallmentOptional = installments.stream() // + .filter(i -> !i.isDownPayment() && !i.isAdditional() && !i.isReAged()) // + .reduce((first, second) -> second); + + lastRegularInstallmentOptional.ifPresent(lastRegularInstallment -> { + final MonetaryCurrency currency = loan.getCurrency(); + installments.stream() // + .filter(i -> i.isAdditional() && i.getDueDate() != null && i.getDueDate().isBefore(newMaturityDate)) + .forEach(additionalInstallment -> { + final Money mergedFees = lastRegularInstallment.getFeeChargesCharged(currency) + .plus(additionalInstallment.getFeeChargesCharged(currency)); + lastRegularInstallment.setFeeChargesCharged(mergedFees.getAmount()); + + final Money mergedPenalties = lastRegularInstallment.getPenaltyChargesCharged(currency) + .plus(additionalInstallment.getPenaltyChargesCharged(currency)); + lastRegularInstallment.setPenaltyCharges(mergedPenalties.getAmount()); + + additionalInstallment.getInstallmentCharges().forEach(charge -> { + lastRegularInstallment.getInstallmentCharges().add(charge); + charge.setInstallment(lastRegularInstallment); + }); + }); + + installments.removeIf(i -> i.isAdditional() && i.getDueDate() != null && i.getDueDate().isBefore(newMaturityDate)); + }); + } + private void handleExtraRepaymentPeriod(final List installments, final LoanTermVariationsData termVariationsData, final ProgressiveLoanInterestScheduleModel scheduleModel) { final LocalDate interestRateChangeSubmittedOnDate = termVariationsData.getTermVariationApplicableFrom(); @@ -1266,7 +1348,7 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep .collect(Collectors.groupingBy(ltvd -> LoanTermVariationType.fromInt(ltvd.getTermType().getId().intValue()))); Stream.of(LoanTermVariationType.INTEREST_RATE_FROM_INSTALLMENT, LoanTermVariationType.INTEREST_PAUSE, - LoanTermVariationType.EXTEND_REPAYMENT_PERIOD).forEach(key -> { + LoanTermVariationType.EXTEND_REPAYMENT_PERIOD, LoanTermVariationType.DUE_DATE).forEach(key -> { if (loanTermVariationsMap.get(key) != null) { changeOperations.addAll(loanTermVariationsMap.get(key).stream().map(ChangeOperation::new).toList()); } diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ProgressiveLoanScheduleGenerator.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ProgressiveLoanScheduleGenerator.java index 85299a29f..e67ff4c23 100644 --- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ProgressiveLoanScheduleGenerator.java +++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/loanschedule/domain/ProgressiveLoanScheduleGenerator.java @@ -37,7 +37,6 @@ import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency; import org.apache.fineract.organisation.monetary.domain.Money; import org.apache.fineract.portfolio.loanaccount.data.DisbursementData; import org.apache.fineract.portfolio.loanaccount.data.HolidayDetailDTO; -import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData; import org.apache.fineract.portfolio.loanaccount.data.OutstandingAmountsDTO; import org.apache.fineract.portfolio.loanaccount.domain.Loan; import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge; @@ -106,11 +105,8 @@ public class ProgressiveLoanScheduleGenerator implements LoanScheduleGenerator { // generate list of proposed schedule due dates final List expectedRepaymentPeriods = scheduledDateGenerator.generateRepaymentPeriods(mc, periodStartDate, loanApplicationTerms, holidayDetailDTO); - List loanTermVariations = loanApplicationTerms.getLoanTermVariations() != null - ? loanApplicationTerms.getLoanTermVariations().getExceptionData() - : null; final ProgressiveLoanInterestScheduleModel interestScheduleModel = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanApplicationTerms.toLoanConfigurationDetails(), loanTermVariations, + expectedRepaymentPeriods, loanApplicationTerms.toLoanConfigurationDetails(), loanApplicationTerms.getInstallmentAmountInMultiplesOf(), mc); final List periods = new ArrayList<>(expectedRepaymentPeriods.size()); diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/InterestScheduleModelServiceGsonContext.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/InterestScheduleModelServiceGsonContext.java index 59ce097db..3b28767c5 100644 --- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/InterestScheduleModelServiceGsonContext.java +++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/service/InterestScheduleModelServiceGsonContext.java @@ -58,7 +58,7 @@ public class InterestScheduleModelServiceGsonContext { public ProgressiveLoanInterestScheduleModel createProgressiveLoanInterestScheduleModelInstance(Type type) { if (type == ProgressiveLoanInterestScheduleModel.class) { setPrev(null); - return new ProgressiveLoanInterestScheduleModel(new ArrayList<>(), getLoanProductRelatedDetail(), new ArrayList<>(), + return new ProgressiveLoanInterestScheduleModel(new ArrayList<>(), getLoanProductRelatedDetail(), installmentAmountInMultipliesOf, getMc()); } throw new IllegalArgumentException("Unsupported ProgressiveLoanInterestScheduleModel type: " + type); 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 c5ff13992..d35f1c8bb 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 @@ -26,7 +26,6 @@ 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; @@ -46,8 +45,7 @@ public interface EMICalculator { */ @NotNull ProgressiveLoanInterestScheduleModel generatePeriodInterestScheduleModel(@NotNull List periods, - @NotNull ILoanConfigurationDetails loanProductRelatedDetail, List loanTermVariations, - Integer installmentAmountInMultiplesOf, MathContext mc); + @NotNull ILoanConfigurationDetails loanProductRelatedDetail, Integer installmentAmountInMultiplesOf, MathContext mc); /** * This method creates an Interest model with repayment periods from the installments which retrieved from the @@ -56,7 +54,7 @@ public interface EMICalculator { @NotNull ProgressiveLoanInterestScheduleModel generateInstallmentInterestScheduleModel( @NotNull List installments, @NotNull ILoanConfigurationDetails loanProductRelatedDetail, - List loanTermVariations, Integer installmentAmountInMultiplesOf, MathContext mc); + Integer installmentAmountInMultiplesOf, MathContext mc); /** * Find repayment period based on Due Date. @@ -169,4 +167,7 @@ public interface EMICalculator { EqualAmortizationValues calculateAdjustedEqualAmortizationValues(Money outstanding, Money total, Money sumOfOtherEqualAmortizationValues, Integer numberOfInstallments, Integer installmentAmountInMultiplesOf, MonetaryCurrency currency); + + void changeDueDate(ProgressiveLoanInterestScheduleModel scheduleModel, LoanApplicationTerms loanApplicationTerms, + LocalDate targetRepaymentPeriodDueDate, LocalDate newDueDate); } 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 bcb383da7..95593fd9c 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 @@ -45,9 +45,7 @@ import org.apache.fineract.portfolio.common.domain.DaysInMonthType; import org.apache.fineract.portfolio.common.domain.DaysInYearCustomStrategyType; import org.apache.fineract.portfolio.common.domain.DaysInYearType; 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; @@ -77,28 +75,26 @@ public final class ProgressiveEMICalculator implements EMICalculator { @Override @NotNull public ProgressiveLoanInterestScheduleModel generatePeriodInterestScheduleModel(@NotNull List periods, - @NotNull ILoanConfigurationDetails loanProductRelatedDetail, List loanTermVariations, - final Integer installmentAmountInMultiplesOf, final MathContext mc) { + @NotNull ILoanConfigurationDetails loanProductRelatedDetail, final Integer installmentAmountInMultiplesOf, + final MathContext mc) { return generateInterestScheduleModel(periods, LoanScheduleModelRepaymentPeriod::periodFromDate, - LoanScheduleModelRepaymentPeriod::periodDueDate, loanProductRelatedDetail, loanTermVariations, - installmentAmountInMultiplesOf, mc); + LoanScheduleModelRepaymentPeriod::periodDueDate, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); } @Override @NotNull public ProgressiveLoanInterestScheduleModel generateInstallmentInterestScheduleModel( @NotNull List installments, @NotNull ILoanConfigurationDetails loanProductRelatedDetail, - List loanTermVariations, final Integer installmentAmountInMultiplesOf, final MathContext mc) { + final Integer installmentAmountInMultiplesOf, final MathContext mc) { installments = installments.stream().filter(installment -> !installment.isDownPayment() && !installment.isAdditional()).toList(); return generateInterestScheduleModel(installments, LoanRepaymentScheduleInstallment::getFromDate, - LoanRepaymentScheduleInstallment::getDueDate, loanProductRelatedDetail, loanTermVariations, installmentAmountInMultiplesOf, - mc); + LoanRepaymentScheduleInstallment::getDueDate, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); } @NotNull private ProgressiveLoanInterestScheduleModel generateInterestScheduleModel(@NotNull List periods, Function from, Function to, @NotNull ILoanConfigurationDetails loanProductRelatedDetail, - List loanTermVariations, final Integer installmentAmountInMultiplesOf, final MathContext mc) { + final Integer installmentAmountInMultiplesOf, final MathContext mc) { final Money zero = Money.zero(loanProductRelatedDetail.getCurrencyData(), mc); final AtomicReference prev = new AtomicReference<>(); List repaymentPeriods = periods.stream().map(e -> { @@ -106,8 +102,7 @@ public final class ProgressiveEMICalculator implements EMICalculator { prev.set(rp); return rp; }).toList(); - return new ProgressiveLoanInterestScheduleModel(repaymentPeriods, loanProductRelatedDetail, loanTermVariations, - installmentAmountInMultiplesOf, mc); + return new ProgressiveLoanInterestScheduleModel(repaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); } @Override @@ -566,8 +561,7 @@ public final class ProgressiveEMICalculator implements EMICalculator { } calculateOutstandingBalance(scheduleModel); calculateLastUnpaidRepaymentPeriodEMI(scheduleModel, calculateFromRepaymentPeriodDueDate); - if (onlyOnActualModelShouldApply && (scheduleModel.loanTermVariations() == null - || scheduleModel.loanTermVariations().get(LoanTermVariationType.DUE_DATE) == null)) { + if (onlyOnActualModelShouldApply) { checkAndAdjustEmiIfNeededOnRelatedRepaymentPeriods(scheduleModel, relatedRepaymentPeriods); } } @@ -638,6 +632,62 @@ public final class ProgressiveEMICalculator implements EMICalculator { .reduce(scheduleModel.zero(), Money::add); } + @Override + public void changeDueDate(final ProgressiveLoanInterestScheduleModel scheduleModel, final LoanApplicationTerms loanApplicationTerms, + final LocalDate targetRepaymentPeriodDueDate, LocalDate newDueDate) { + final RepaymentPeriod targetRepaymentPeriod = scheduleModel.findRepaymentPeriod(targetRepaymentPeriodDueDate).orElseThrow(); + targetRepaymentPeriod.setDueDate(newDueDate); + + if (!targetRepaymentPeriod.getInterestPeriods().isEmpty()) { + final InterestPeriod lastInterestPeriod = targetRepaymentPeriod.getInterestPeriods().getLast(); + lastInterestPeriod.setDueDate(newDueDate); + } + + final int targetRepaymentPeriodIndex = scheduleModel.repaymentPeriods().indexOf(targetRepaymentPeriod); + final int lastRepaymentPeriodIndex = scheduleModel.repaymentPeriods().size() - 1; + final LocalDate originalNewDueDate = newDueDate; + for (int i = targetRepaymentPeriodIndex + 1; i < scheduleModel.repaymentPeriods().size(); ++i) { + final RepaymentPeriod nextRepaymentPeriod = scheduleModel.repaymentPeriods().get(i); + nextRepaymentPeriod.setFromDate(newDueDate); + + LocalDate nextRepaymentDate = scheduledDateGenerator.generateNextRepaymentDate(newDueDate, loanApplicationTerms, false); + + if (i == lastRepaymentPeriodIndex && loanApplicationTerms.getFixedLength() != null) { + nextRepaymentDate = calculateDateForFixedLength(scheduleModel, loanApplicationTerms, targetRepaymentPeriodDueDate, + originalNewDueDate); + } + nextRepaymentPeriod.setDueDate(nextRepaymentDate); + + if (!nextRepaymentPeriod.getInterestPeriods().isEmpty()) { + nextRepaymentPeriod.getInterestPeriods().getFirst().setFromDate(newDueDate); + final InterestPeriod lastInterestPeriod = nextRepaymentPeriod.getInterestPeriods().getLast(); + lastInterestPeriod.setDueDate(nextRepaymentDate); + } + + newDueDate = nextRepaymentDate; + } + + final List relatedRepaymentPeriods = scheduleModel.getRelatedRepaymentPeriods(targetRepaymentPeriodDueDate); + calculateRateFactorForPeriods(relatedRepaymentPeriods, scheduleModel); + calculateOutstandingBalance(scheduleModel); + calculateLastUnpaidRepaymentPeriodEMI(scheduleModel, targetRepaymentPeriodDueDate); + } + + private LocalDate calculateDateForFixedLength(final ProgressiveLoanInterestScheduleModel scheduleModel, + final LoanApplicationTerms loanApplicationTerms, final LocalDate targetRepaymentPeriodDueDate, final LocalDate newDueDate) { + final long variationDays = DateUtils.getDifferenceInDays(targetRepaymentPeriodDueDate, newDueDate); + final LocalDate repaymentStartDate = scheduleModel.repaymentPeriods().getFirst().getFromDate(); + + return switch (loanApplicationTerms.getRepaymentPeriodFrequencyType()) { + case DAYS -> repaymentStartDate.plusDays(loanApplicationTerms.getFixedLength() + variationDays); + case WEEKS -> repaymentStartDate.plusWeeks(loanApplicationTerms.getFixedLength() + variationDays); + case MONTHS -> repaymentStartDate.plusMonths(loanApplicationTerms.getFixedLength() + variationDays); + case YEARS -> repaymentStartDate.plusYears(loanApplicationTerms.getFixedLength() + variationDays); + case INVALID, WHOLE_TERM -> throw new IllegalArgumentException( + "Unsupported period frequency type for fixed length: " + loanApplicationTerms.getRepaymentPeriodFrequencyType()); + }; + } + private List findPossiblyOverdueRepaymentPeriods(final LocalDate targetDate, final ProgressiveLoanInterestScheduleModel model) { return model.repaymentPeriods().stream() // @@ -767,7 +817,7 @@ public final class ProgressiveEMICalculator implements EMICalculator { final List expectedRepaymentPeriods = scheduledDateGenerator.generateRepaymentPeriods(mc, periodStartDate, loanApplicationTerms, null); final ProgressiveLoanInterestScheduleModel temporaryReAgedScheduleModel = generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanApplicationTerms.toLoanConfigurationDetails(), null, + expectedRepaymentPeriods, loanApplicationTerms.toLoanConfigurationDetails(), loanApplicationTerms.getInstallmentAmountInMultiplesOf(), mc); addDisbursement(temporaryReAgedScheduleModel, EmiChangeOperation.disburse(periodStartDate, loanApplicationTerms.getPrincipal())); diff --git a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/data/ProgressiveLoanInterestScheduleModel.java b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/data/ProgressiveLoanInterestScheduleModel.java index c822717c1..c5fd1f0c0 100644 --- a/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/data/ProgressiveLoanInterestScheduleModel.java +++ b/fineract-progressive-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/calc/data/ProgressiveLoanInterestScheduleModel.java @@ -40,7 +40,6 @@ import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; -import java.util.stream.Collectors; import lombok.AllArgsConstructor; import lombok.Data; import lombok.Setter; @@ -49,8 +48,6 @@ import org.apache.fineract.infrastructure.core.serialization.gson.JsonExclude; import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.infrastructure.core.service.MathUtil; import org.apache.fineract.organisation.monetary.domain.Money; -import org.apache.fineract.portfolio.loanaccount.data.LoanTermVariationsData; -import org.apache.fineract.portfolio.loanaccount.domain.LoanTermVariationType; import org.apache.fineract.portfolio.loanproduct.domain.ILoanConfigurationDetails; @Data @@ -62,7 +59,6 @@ public class ProgressiveLoanInterestScheduleModel { private final TreeSet interestRates; @JsonExclude private final ILoanConfigurationDetails loanProductRelatedDetail; - private final Map> loanTermVariations; private final Integer installmentAmountInMultiplesOf; @JsonExclude private final MathContext mc; @@ -74,12 +70,10 @@ public class ProgressiveLoanInterestScheduleModel { private LocalDate lastOverdueBalanceChange; public ProgressiveLoanInterestScheduleModel(final List repaymentPeriods, - final ILoanConfigurationDetails loanProductRelatedDetail, final List loanTermVariations, - final Integer installmentAmountInMultiplesOf, final MathContext mc) { + final ILoanConfigurationDetails loanProductRelatedDetail, final Integer installmentAmountInMultiplesOf, final MathContext mc) { this.repaymentPeriods = new ArrayList<>(repaymentPeriods); this.interestRates = new TreeSet<>(Collections.reverseOrder()); this.loanProductRelatedDetail = loanProductRelatedDetail; - this.loanTermVariations = buildLoanTermVariationMap(loanTermVariations); this.installmentAmountInMultiplesOf = installmentAmountInMultiplesOf; this.mc = mc; this.zero = Money.zero(loanProductRelatedDetail.getCurrencyData(), mc); @@ -88,15 +82,13 @@ public class ProgressiveLoanInterestScheduleModel { } private ProgressiveLoanInterestScheduleModel(final List repaymentPeriods, final TreeSet interestRates, - final ILoanConfigurationDetails loanProductRelatedDetail, - final Map> loanTermVariations, final Integer installmentAmountInMultiplesOf, - final MathContext mc, final boolean isCopiedForCalculation) { + final ILoanConfigurationDetails loanProductRelatedDetail, final Integer installmentAmountInMultiplesOf, final MathContext mc, + final boolean isCopiedForCalculation) { this.mc = mc; this.repaymentPeriods = copyRepaymentPeriods(repaymentPeriods, (previousPeriod, repaymentPeriod) -> RepaymentPeriod.copy(previousPeriod, repaymentPeriod, mc)); this.interestRates = new TreeSet<>(interestRates); this.loanProductRelatedDetail = loanProductRelatedDetail; - this.loanTermVariations = loanTermVariations; this.installmentAmountInMultiplesOf = installmentAmountInMultiplesOf; this.zero = Money.zero(loanProductRelatedDetail.getCurrencyData(), mc); modifiers = new HashMap<>(Map.of(EMI_RECALCULATION, true, COPY, isCopiedForCalculation, INTEREST_RECALCULATION_ENABLED, @@ -104,14 +96,14 @@ public class ProgressiveLoanInterestScheduleModel { } public ProgressiveLoanInterestScheduleModel deepCopy(MathContext mc) { - return new ProgressiveLoanInterestScheduleModel(repaymentPeriods, interestRates, loanProductRelatedDetail, loanTermVariations, + return new ProgressiveLoanInterestScheduleModel(repaymentPeriods, interestRates, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc, false); } public ProgressiveLoanInterestScheduleModel copyWithoutPaidAmounts() { final List repaymentPeriodCopies = copyRepaymentPeriods(repaymentPeriods, (previousPeriod, repaymentPeriod) -> RepaymentPeriod.copyWithoutPaidAmounts(previousPeriod, repaymentPeriod, mc)); - return new ProgressiveLoanInterestScheduleModel(repaymentPeriodCopies, interestRates, loanProductRelatedDetail, loanTermVariations, + return new ProgressiveLoanInterestScheduleModel(repaymentPeriodCopies, interestRates, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc, true); } @@ -416,15 +408,6 @@ public class ProgressiveLoanInterestScheduleModel { : date.isAfter(previousInterestPeriod.getDueDate()) ? previousInterestPeriod.getDueDate() : date; } - private Map> buildLoanTermVariationMap( - final List loanTermVariationsData) { - if (loanTermVariationsData == null) { - return new HashMap<>(); - } - return loanTermVariationsData.stream() - .collect(Collectors.groupingBy(ltvd -> LoanTermVariationType.fromInt(ltvd.getTermType().getId().intValue()))); - } - public void disableEMIRecalculation() { this.modifiers.put(EMI_RECALCULATION, false); } 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 dff87cfdb..2520cdf67 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 @@ -44,8 +44,9 @@ public class RepaymentPeriod { @JsonExclude private final RepaymentPeriod previous; + @Setter @Getter - private final LocalDate fromDate; + private LocalDate fromDate; @Setter @Getter private LocalDate dueDate; @@ -97,10 +98,10 @@ public class RepaymentPeriod { private boolean noUnrecognisedInterest; @Setter @Getter - private boolean reAged = false; + private boolean reAged; @Setter @Getter - private boolean reAgedEarlyRepaymentHolder = false; + private boolean reAgedEarlyRepaymentHolder; @Getter @Setter private Money reAgedInterest; 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 d3591bb5c..eef9f3d00 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 @@ -37,14 +37,13 @@ import org.apache.fineract.portfolio.common.domain.DaysInMonthType; import org.apache.fineract.portfolio.common.domain.DaysInYearCustomStrategyType; import org.apache.fineract.portfolio.common.domain.DaysInYearType; 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.LoanApplicationTerms; import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelRepaymentPeriod; import org.apache.fineract.portfolio.loanaccount.service.ProgressiveLoanInterestScheduleModelParserServiceGsonImpl; import org.apache.fineract.portfolio.loanproduct.calc.data.EqualAmortizationValues; @@ -198,7 +197,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestScheduleModel = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); Assertions.assertTrue(interestScheduleModel != null); Assertions.assertTrue(interestScheduleModel.loanProductRelatedDetail() != null); @@ -237,7 +236,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -281,7 +280,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -317,7 +316,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -353,7 +352,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -401,7 +400,7 @@ class ProgressiveEMICalculatorTest { threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024, 2, 14)); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -443,7 +442,7 @@ class ProgressiveEMICalculatorTest { threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024, 2, 14)); final ProgressiveLoanInterestScheduleModel interestModel = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestModel, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -493,7 +492,7 @@ class ProgressiveEMICalculatorTest { threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024, 2, 14)); final ProgressiveLoanInterestScheduleModel interestModel = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestModel, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -540,7 +539,7 @@ class ProgressiveEMICalculatorTest { threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024, 2, 14)); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -586,7 +585,7 @@ class ProgressiveEMICalculatorTest { threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024, 2, 15)); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -701,7 +700,7 @@ class ProgressiveEMICalculatorTest { threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024, 2, 15)); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -783,7 +782,7 @@ class ProgressiveEMICalculatorTest { threadLocalContextUtil.when(ThreadLocalContextUtil::getBusinessDate).thenReturn(LocalDate.of(2024, 2, 15)); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -870,7 +869,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); Money disbursedAmount = toMoney(100); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -919,7 +918,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -968,7 +967,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 5), disbursedAmount); @@ -1014,7 +1013,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2023, 12, 12), disbursedAmount); @@ -1050,7 +1049,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), toMoney(300.0)); Assertions.assertEquals(6.15, toDouble(interestSchedule.getTotalDueInterest())); @@ -1098,7 +1097,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(1000.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -1131,7 +1130,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -1164,7 +1163,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -1197,7 +1196,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -1239,7 +1238,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(1000.0); LocalDate disbursementDate = LocalDate.of(2024, 1, 1); @@ -1288,7 +1287,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestModel = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(1000.0); emiCalculator.addDisbursement(interestModel, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -1350,7 +1349,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestModel = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(1000.0); emiCalculator.addDisbursement(interestModel, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -1416,7 +1415,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestModel = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount1st = toMoney(1000.0); final Money disbursedAmount2nd = toMoney(1000.0); @@ -1489,7 +1488,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -1527,7 +1526,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -1563,10 +1562,9 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS); Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1); Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); - List loanTermVariations = new ArrayList<>(); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, loanTermVariations, installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -1602,10 +1600,9 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS); Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1); Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); - List loanTermVariations = new ArrayList<>(); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, loanTermVariations, installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -1641,10 +1638,9 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS); Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1); Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); - List loanTermVariations = new ArrayList<>(); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, loanTermVariations, installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -1680,10 +1676,9 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS); Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1); Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); - List loanTermVariations = new ArrayList<>(); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, loanTermVariations, installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -1719,10 +1714,9 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS); Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1); Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); - List loanTermVariations = new ArrayList<>(); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, loanTermVariations, installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -1761,10 +1755,9 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS); Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1); Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); - List loanTermVariations = new ArrayList<>(); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, loanTermVariations, installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -1806,10 +1799,9 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS); Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1); Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); - List loanTermVariations = new ArrayList<>(); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, loanTermVariations, installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -1847,10 +1839,9 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS); Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1); Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); - List loanTermVariations = new ArrayList<>(); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, loanTermVariations, installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -1885,10 +1876,9 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS); Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1); Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); - List loanTermVariations = new ArrayList<>(); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, loanTermVariations, installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -1906,12 +1896,12 @@ class ProgressiveEMICalculatorTest { @Test public void test_reschedule_disbursedAmt100_dayInYears360_daysInMonth30_repayEvery1Month() { final List expectedRepaymentPeriods = List.of( - repayment(1, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 3, 1)), - repayment(2, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 4, 1)), - repayment(3, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 5, 1)), - repayment(4, LocalDate.of(2024, 5, 1), LocalDate.of(2024, 6, 1)), - repayment(5, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 7, 1)), - repayment(6, LocalDate.of(2024, 7, 1), LocalDate.of(2024, 8, 1))); + repayment(1, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1)), + repayment(2, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1)), + repayment(3, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 4, 1)), + repayment(4, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 5, 1)), + repayment(5, LocalDate.of(2024, 5, 1), LocalDate.of(2024, 6, 1)), + repayment(6, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 7, 1))); final BigDecimal interestRate = BigDecimal.valueOf(7); final Integer installmentAmountInMultiplesOf = null; @@ -1922,35 +1912,39 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS); Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1); Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); - List loanTermVariationsData = List.of(// - new LoanTermVariationsData(1L, LoanTermVariationType.DUE_DATE.getValue(), // - LocalDate.of(2024, 2, 1), null, // - LocalDate.of(2024, 3, 1), false)); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, loanTermVariationsData, installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); + final LoanApplicationTerms loanApplicationTerms = Mockito.mock(LoanApplicationTerms.class); + Mockito.when(loanApplicationTerms.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS); + Mockito.when(loanApplicationTerms.getRepaymentEvery()).thenReturn(1); + Mockito.when(loanApplicationTerms.getSeedDate()).thenReturn(LocalDate.of(2024, 1, 1)); + Mockito.when(loanApplicationTerms.getCalculatedRepaymentsStartingFromLocalDate()).thenReturn(LocalDate.of(2024, 1, 1)); + + emiCalculator.changeDueDate(interestSchedule, loanApplicationTerms, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1)); + checkPeriod(interestSchedule, 0, 0, 17.01, 0.0, 0.0, 1.17, 15.84, 84.16); checkPeriod(interestSchedule, 0, 1, 17.01, 0.005833333333, 1.1666666667, 1.17, 15.84, 84.16); checkPeriod(interestSchedule, 1, 0, 17.01, 0.005833333333, 0.490933333306, 0.49, 16.52, 67.64); checkPeriod(interestSchedule, 2, 0, 17.01, 0.005833333333, 0.394566666645, 0.39, 16.62, 51.02); checkPeriod(interestSchedule, 3, 0, 17.01, 0.005833333333, 0.29761666665, 0.30, 16.71, 34.31); checkPeriod(interestSchedule, 4, 0, 17.01, 0.005833333333, 0.200141666655, 0.20, 16.81, 17.50); - checkPeriod(interestSchedule, 5, 0, 17.60, 0.005833333333, 0.102083333328, 0.10, 17.50, 0.0); + checkPeriod(interestSchedule, 5, 0, 19.85, 0.005833333333, 2.34791666667, 2.35, 17.50, 0.0); } @Test public void test_two_reschedules_disbursedAmt100_dayInYears360_daysInMonth30_repayEvery1Month() { final List expectedRepaymentPeriods = List.of( - repayment(1, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 3, 1)), - repayment(2, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 4, 1)), - repayment(3, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 6, 1)), - repayment(4, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 7, 1)), - repayment(5, LocalDate.of(2024, 7, 1), LocalDate.of(2024, 8, 1)), - repayment(6, LocalDate.of(2024, 8, 1), LocalDate.of(2024, 9, 1))); + repayment(1, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1)), + repayment(2, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1)), + repayment(3, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 4, 1)), + repayment(4, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 5, 1)), + repayment(5, LocalDate.of(2024, 5, 1), LocalDate.of(2024, 6, 1)), + repayment(6, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 7, 1))); final BigDecimal interestRate = BigDecimal.valueOf(7); final Integer installmentAmountInMultiplesOf = null; @@ -1961,38 +1955,40 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS); Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1); Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); - List loanTermVariationsData = List.of(// - new LoanTermVariationsData(1L, LoanTermVariationType.DUE_DATE.getValue(), // - LocalDate.of(2024, 2, 1), null, // - LocalDate.of(2024, 3, 1), false), // - new LoanTermVariationsData(2L, LoanTermVariationType.DUE_DATE.getValue(), // - LocalDate.of(2024, 5, 1), null, // - LocalDate.of(2024, 6, 1), false)); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, loanTermVariationsData, installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); + final LoanApplicationTerms loanApplicationTerms = Mockito.mock(LoanApplicationTerms.class); + Mockito.when(loanApplicationTerms.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS); + Mockito.when(loanApplicationTerms.getRepaymentEvery()).thenReturn(1); + Mockito.when(loanApplicationTerms.getSeedDate()).thenReturn(LocalDate.of(2024, 1, 1)); + Mockito.when(loanApplicationTerms.getCalculatedRepaymentsStartingFromLocalDate()).thenReturn(LocalDate.of(2024, 1, 1)); + + emiCalculator.changeDueDate(interestSchedule, loanApplicationTerms, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1)); + emiCalculator.changeDueDate(interestSchedule, loanApplicationTerms, LocalDate.of(2024, 5, 1), LocalDate.of(2024, 6, 1)); + checkPeriod(interestSchedule, 0, 0, 17.01, 0.0, 0.0, 1.17, 15.84, 84.16); checkPeriod(interestSchedule, 0, 1, 17.01, 0.005833333333, 1.1666666667, 1.17, 15.84, 84.16); checkPeriod(interestSchedule, 1, 0, 17.01, 0.005833333333, 0.490933333306, 0.49, 16.52, 67.64); checkPeriod(interestSchedule, 2, 0, 17.01, 0.005833333333, 0.789133333354, 0.79, 16.22, 51.42); checkPeriod(interestSchedule, 3, 0, 17.01, 0.005833333333, 0.299949999983, 0.30, 16.71, 34.71); checkPeriod(interestSchedule, 4, 0, 17.01, 0.005833333333, 0.202474999988, 0.20, 16.81, 17.90); - checkPeriod(interestSchedule, 5, 0, 18.00, 0.005833333333, 0.104416666661, 0.10, 17.90, 0.0); + checkPeriod(interestSchedule, 5, 0, 20.41, 0.005833333333, 2.506, 2.51, 17.90, 0.0); } @Test public void test_reschedule_partial_period_disbursedAmt100_dayInYears360_daysInMonth30_repayEvery1Month() { final List expectedRepaymentPeriods = List.of( repayment(1, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1)), - repayment(2, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 4, 15)), - repayment(3, LocalDate.of(2024, 4, 15), LocalDate.of(2024, 5, 15)), - repayment(4, LocalDate.of(2024, 5, 15), LocalDate.of(2024, 6, 15)), - repayment(5, LocalDate.of(2024, 6, 15), LocalDate.of(2024, 7, 15)), - repayment(6, LocalDate.of(2024, 7, 15), LocalDate.of(2024, 8, 15))); + repayment(2, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1)), + repayment(3, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 4, 1)), + repayment(4, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 5, 1)), + repayment(5, LocalDate.of(2024, 5, 1), LocalDate.of(2024, 6, 1)), + repayment(6, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 7, 1))); final BigDecimal interestRate = BigDecimal.valueOf(7); final Integer installmentAmountInMultiplesOf = null; @@ -2003,24 +1999,27 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS); Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1); Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); - List loanTermVariationsData = List.of(// - new LoanTermVariationsData(1L, LoanTermVariationType.DUE_DATE.getValue(), // - LocalDate.of(2024, 3, 1), null, // - LocalDate.of(2024, 4, 15), false)); - final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, loanTermVariationsData, installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); + LoanApplicationTerms loanApplicationTerms = Mockito.mock(LoanApplicationTerms.class); + Mockito.when(loanApplicationTerms.getRepaymentPeriodFrequencyType()).thenReturn(PeriodFrequencyType.MONTHS); + Mockito.when(loanApplicationTerms.getRepaymentEvery()).thenReturn(1); + Mockito.when(loanApplicationTerms.getSeedDate()).thenReturn(LocalDate.of(2024, 1, 1)); + Mockito.when(loanApplicationTerms.getCalculatedRepaymentsStartingFromLocalDate()).thenReturn(LocalDate.of(2024, 1, 1)); + + emiCalculator.changeDueDate(interestSchedule, loanApplicationTerms, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 4, 15)); + checkPeriod(interestSchedule, 0, 0, 17.01, 0.0, 0.0, 0.58, 16.43, 83.57); checkPeriod(interestSchedule, 0, 1, 17.01, 0.005833333333, 0.5833333333, 0.58, 16.43, 83.57); checkPeriod(interestSchedule, 1, 0, 17.01, 0.005833333333, 1.20247944445, 1.20, 15.81, 67.76); checkPeriod(interestSchedule, 2, 0, 17.01, 0.005833333333, 0.395266666644, 0.40, 16.61, 51.15); checkPeriod(interestSchedule, 3, 0, 17.01, 0.005833333333, 0.298374999983, 0.3, 16.71, 34.44); checkPeriod(interestSchedule, 4, 0, 17.01, 0.005833333333, 0.200899999989, 0.20, 16.81, 17.63); - checkPeriod(interestSchedule, 5, 0, 17.73, 0.005833333333, 0.102841666661, 0.10, 17.63, 0.0); + checkPeriod(interestSchedule, 5, 0, 21.59, 0.005833333333, 3.96283222223, 3.96, 17.63, 0.0); } @Test @@ -2045,7 +2044,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(5000.0); LocalDate disbursementDate = LocalDate.of(2023, 11, 13); @@ -2094,7 +2093,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(5000.0); LocalDate disbursementDate = LocalDate.of(2023, 11, 13); @@ -2139,7 +2138,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(5000.0); LocalDate disbursementDate = LocalDate.of(2023, 11, 13); @@ -2189,7 +2188,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(2450.0); LocalDate disbursementDate = LocalDate.of(2023, 10, 31); @@ -2226,7 +2225,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(10000.0); LocalDate disbursementDate = LocalDate.of(2023, 10, 30); @@ -2263,7 +2262,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(3333.0); LocalDate disbursementDate = LocalDate.of(2023, 10, 29); @@ -2300,7 +2299,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(245000.0); LocalDate disbursementDate = LocalDate.of(2023, 10, 31); @@ -2337,7 +2336,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(1500.0); LocalDate disbursementDate = LocalDate.of(2021, 10, 30); @@ -2374,7 +2373,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(5000); LocalDate disbursementDate = LocalDate.of(2022, 10, 29); @@ -2410,7 +2409,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator - .generatePeriodInterestScheduleModel(expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), null, mc); + .generatePeriodInterestScheduleModel(expectedRepaymentPeriods, loanProductRelatedDetail, null, mc); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2023, 11, 13), Money.of(currency, BigDecimal.valueOf(5000), mc)); checkPeriod(interestSchedule, 0, 857.71, 41.05, 816.66, 4183.34, false); @@ -2443,7 +2442,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.isInterestRecognitionOnDisbursementDate()).thenReturn(true); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator - .generatePeriodInterestScheduleModel(expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), null, mc); + .generatePeriodInterestScheduleModel(expectedRepaymentPeriods, loanProductRelatedDetail, null, mc); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2023, 11, 13), Money.of(currency, BigDecimal.valueOf(5000), mc)); checkPeriod(interestSchedule, 0, 857.72, 41.05, 816.67, 4183.33, false); @@ -2478,7 +2477,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -2535,7 +2534,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -2603,7 +2602,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -2662,7 +2661,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -2720,7 +2719,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -2772,7 +2771,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -2830,7 +2829,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -2887,7 +2886,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -2955,7 +2954,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(10000.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2023, 12, 12), disbursedAmount); @@ -2993,7 +2992,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(15000.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 7, 23), disbursedAmount); @@ -3030,7 +3029,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(245000.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2023, 10, 31), disbursedAmount); @@ -3070,7 +3069,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(2450); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 10, 31), disbursedAmount); @@ -3109,7 +3108,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(5000.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2022, 10, 29), disbursedAmount); @@ -3145,7 +3144,7 @@ class ProgressiveEMICalculatorTest { .thenReturn(DaysInYearCustomStrategyType.FEB_29_PERIOD_ONLY); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -3181,7 +3180,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -3246,7 +3245,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestScheduleExpected = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); ProgressiveLoanInterestScheduleModel interestScheduleActual = copyJson(interestScheduleExpected); @@ -3332,7 +3331,7 @@ class ProgressiveEMICalculatorTest { final Integer installmentAmountInMultiplesOf = null; final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); emiCalculator.addDisbursement(interestSchedule, disbursementDate, toMoney(700.0)); checkPeriod(interestSchedule, 0, 181.94, 7.11, 174.83, 525.17, false); // @@ -3371,7 +3370,7 @@ class ProgressiveEMICalculatorTest { final Integer installmentAmountInMultiplesOf = null; final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); emiCalculator.addDisbursement(interestSchedule, disbursementDate, toMoney(750.0)); checkPeriod(interestSchedule, 0, 195.00, 7.50, 187.50, 562.50, false); // @@ -3410,7 +3409,7 @@ class ProgressiveEMICalculatorTest { final Integer installmentAmountInMultiplesOf = null; final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); emiCalculator.addDisbursement(interestSchedule, disbursementDate, toMoney(600.0)); checkPeriod(interestSchedule, 0, 151.38, 1.38, 150.00, 450.00, false); // @@ -3449,7 +3448,7 @@ class ProgressiveEMICalculatorTest { final Integer installmentAmountInMultiplesOf = null; final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); emiCalculator.addDisbursement(interestSchedule, disbursementDate, toMoney(400.0)); checkPeriod(interestSchedule, 0, 103.93, 3.93, 100.00, 300.00, false); // @@ -3503,7 +3502,7 @@ class ProgressiveEMICalculatorTest { final Integer installmentAmountInMultiplesOf = null; final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); emiCalculator.addDisbursement(interestSchedule, disbursementDate, toMoney(1000.0)); @@ -3532,7 +3531,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getRepayEvery()).thenReturn(1); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); emiCalculator.addDisbursement(interestSchedule, disbursementDate, toMoney(1000.0)); @@ -3563,7 +3562,7 @@ class ProgressiveEMICalculatorTest { final Integer installmentAmountInMultiplesOf = null; final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); emiCalculator.addDisbursement(interestSchedule, disbursementDate, toMoney(1000.0)); @@ -3595,7 +3594,7 @@ class ProgressiveEMICalculatorTest { final Integer installmentAmountInMultiplesOf = null; final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); emiCalculator.addDisbursement(interestSchedule, disbursementDate, toMoney(1000.0)); @@ -3628,7 +3627,7 @@ class ProgressiveEMICalculatorTest { final Integer installmentAmountInMultiplesOf = null; final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); emiCalculator.addDisbursement(interestSchedule, disbursementDate, toMoney(1000.0)); @@ -3659,7 +3658,7 @@ class ProgressiveEMICalculatorTest { final Integer installmentAmountInMultiplesOf = null; final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); emiCalculator.addDisbursement(interestSchedule, disbursementDate, toMoney(1000.0)); @@ -3696,7 +3695,7 @@ class ProgressiveEMICalculatorTest { final Integer installmentAmountInMultiplesOf = null; final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); emiCalculator.addDisbursement(interestSchedule, disbursementDate, toMoney(1000.0)); @@ -3737,7 +3736,7 @@ class ProgressiveEMICalculatorTest { final Integer installmentAmountInMultiplesOf = null; final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); emiCalculator.addDisbursement(interestSchedule, disbursementDate, toMoney(7500.0)); emiCalculator.addDisbursement(interestSchedule, disbursementDate, toMoney(2500.0)); @@ -3812,7 +3811,7 @@ class ProgressiveEMICalculatorTest { final Integer installmentAmountInMultiplesOf = null; final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); emiCalculator.addDisbursement(interestSchedule, disbursementDate, toMoney(1000.0)); @@ -3862,7 +3861,7 @@ class ProgressiveEMICalculatorTest { final Integer installmentAmountInMultiplesOf = null; final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); emiCalculator.addDisbursement(interestSchedule, disbursementDate, toMoney(500.0)); checkPeriod(interestSchedule, 0, 170.01, 5.00, 165.01, 334.99, false); // @@ -3899,7 +3898,7 @@ class ProgressiveEMICalculatorTest { final Integer installmentAmountInMultiplesOf = null; final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); emiCalculator.addDisbursement(interestSchedule, disbursementDate, toMoney(500.0)); checkPeriod(interestSchedule, 0, 170.01, 5.00, 165.01, 334.99, false); // @@ -3935,7 +3934,7 @@ class ProgressiveEMICalculatorTest { final Integer installmentAmountInMultiplesOf = null; final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); emiCalculator.addDisbursement(interestSchedule, disbursementDate, toMoney(500.0)); checkPeriod(interestSchedule, 0, 170.01, 5.00, 165.01, 334.99, false); // @@ -3993,7 +3992,7 @@ class ProgressiveEMICalculatorTest { final Integer installmentAmountInMultiplesOf = null; final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); emiCalculator.addDisbursement(interestSchedule, disbursementDate, toMoney(500.0)); checkPeriod(interestSchedule, 0, 170.01, 5.00, 165.01, 334.99, false); // @@ -4040,7 +4039,7 @@ class ProgressiveEMICalculatorTest { final Integer installmentAmountInMultiplesOf = null; final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); emiCalculator.addDisbursement(interestSchedule, disbursementDate, toMoney(1000)); @@ -4079,7 +4078,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.isAllowPartialPeriodInterestCalculation()).thenReturn(true); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); emiCalculator.addDisbursement(interestSchedule, disbursementDate, toMoney(1000)); @@ -4116,7 +4115,7 @@ class ProgressiveEMICalculatorTest { final Integer installmentAmountInMultiplesOf = null; final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); emiCalculator.addDisbursement(interestSchedule, disbursementDate, toMoney(1000)); @@ -4177,7 +4176,7 @@ class ProgressiveEMICalculatorTest { final Integer installmentAmountInMultiplesOf = null; final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); emiCalculator.addDisbursement(interestSchedule, disbursementDate, toMoney(1000)); @@ -4262,7 +4261,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -4326,7 +4325,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -4415,7 +4414,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -4474,7 +4473,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -4534,7 +4533,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -4617,7 +4616,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -4700,7 +4699,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount); @@ -4773,7 +4772,7 @@ class ProgressiveEMICalculatorTest { Mockito.when(loanProductRelatedDetail.getCurrencyData()).thenReturn(currency); final ProgressiveLoanInterestScheduleModel interestSchedule = emiCalculator.generatePeriodInterestScheduleModel( - expectedRepaymentPeriods, loanProductRelatedDetail, List.of(), installmentAmountInMultiplesOf, mc); + expectedRepaymentPeriods, loanProductRelatedDetail, installmentAmountInMultiplesOf, mc); final Money disbursedAmount = toMoney(100.0); emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount);