FINERACT-2354: Re-age - Excess payment handling - Default Behavior, interestRecalculation = true
This commit is contained in:
committed by
Adam Saghy
parent
2bde43ea83
commit
b18912cc9d
File diff suppressed because it is too large
Load Diff
@@ -535,17 +535,18 @@ Feature: LoanReAgingPreview
|
||||
When Admin creates a Loan re-aging preview by Loan external ID with the following data:
|
||||
| frequencyNumber | frequencyType | startDate | numberOfInstallments |
|
||||
| 1 | MONTHS | 01 April 2024| 6 |
|
||||
Then Loan Repayment schedule preview has 8 periods, with the following data for periods:
|
||||
Then Loan Repayment schedule preview has 9 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 | 0.0 | 0.0 | 0.0 | | | |
|
||||
| 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 |
|
||||
| 2 | 29 | 01 March 2024 | 15 March 2024 | 83.57 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||
| 3 | 31 | 01 April 2024 | | 70.25 | 13.32 | 0.98 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 4 | 30 | 01 May 2024 | | 56.36 | 13.89 | 0.41 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 5 | 31 | 01 June 2024 | | 42.39 | 13.97 | 0.33 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 6 | 30 | 01 July 2024 | | 28.34 | 14.05 | 0.25 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 7 | 31 | 01 August 2024 | | 14.21 | 14.13 | 0.17 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 8 | 31 | 01 September 2024| | 0.0 | 14.21 | 0.08 | 0.0 | 0.0 | 14.29 | 0.0 | 0.0 | 0.0 | 14.29 |
|
||||
| 3 | 14 | 15 March 2024 | 15 March 2024 | 83.57 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||
| 4 | 17 | 01 April 2024 | | 70.25 | 13.32 | 0.98 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 5 | 30 | 01 May 2024 | | 56.36 | 13.89 | 0.41 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 6 | 31 | 01 June 2024 | | 42.39 | 13.97 | 0.33 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 7 | 30 | 01 July 2024 | | 28.34 | 14.05 | 0.25 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 8 | 31 | 01 August 2024 | | 14.21 | 14.13 | 0.17 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 9 | 31 | 01 September 2024| | 0.0 | 14.21 | 0.08 | 0.0 | 0.0 | 14.29 | 0.0 | 0.0 | 0.0 | 14.29 |
|
||||
Then Loan Repayment schedule preview has the following data in Total row:
|
||||
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| 100.0 | 2.8 | 0.0 | 0.0 | 102.8 | 17.01 | 0.0 | 0.0 | 85.79 |
|
||||
@@ -604,17 +605,18 @@ Feature: LoanReAgingPreview
|
||||
When Admin creates a Loan re-aging preview by Loan external ID with the following data:
|
||||
| frequencyNumber | frequencyType | startDate | numberOfInstallments |
|
||||
| 1 | MONTHS | 01 April 2024| 6 |
|
||||
Then Loan Repayment schedule preview has 8 periods, with the following data for periods:
|
||||
Then Loan Repayment schedule preview has 9 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 | 0.0 | 0.0 | 0.0 | | | |
|
||||
| 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 |
|
||||
| 2 | 29 | 01 March 2024 | | 83.57 | 0.0 | 0.0 | 10.0 | 0.0 | 10.0 | 0.0 | 0.0 | 0.0 | 10.0 |
|
||||
| 3 | 31 | 01 April 2024 | | 70.25 | 13.32 | 0.98 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 4 | 30 | 01 May 2024 | | 56.36 | 13.89 | 0.41 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 5 | 31 | 01 June 2024 | | 42.39 | 13.97 | 0.33 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 6 | 30 | 01 July 2024 | | 28.34 | 14.05 | 0.25 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 7 | 31 | 01 August 2024 | | 14.21 | 14.13 | 0.17 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 8 | 31 | 01 September 2024| | 0.0 | 14.21 | 0.08 | 0.0 | 0.0 | 14.29 | 0.0 | 0.0 | 0.0 | 14.29 |
|
||||
| 3 | 14 | 15 March 2024 | 15 March 2024 | 83.57 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||
| 4 | 17 | 01 April 2024 | | 70.25 | 13.32 | 0.98 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 5 | 30 | 01 May 2024 | | 56.36 | 13.89 | 0.41 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 6 | 31 | 01 June 2024 | | 42.39 | 13.97 | 0.33 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 7 | 30 | 01 July 2024 | | 28.34 | 14.05 | 0.25 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 8 | 31 | 01 August 2024 | | 14.21 | 14.13 | 0.17 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 9 | 31 | 01 September 2024| | 0.0 | 14.21 | 0.08 | 0.0 | 0.0 | 14.29 | 0.0 | 0.0 | 0.0 | 14.29 |
|
||||
Then Loan Repayment schedule preview has the following data in Total row:
|
||||
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| 100.0 | 2.8 | 10.0 | 0.0 | 112.8 | 17.01 | 0.0 | 0.0 | 95.79 |
|
||||
@@ -671,17 +673,18 @@ Feature: LoanReAgingPreview
|
||||
When Admin creates a Loan re-aging preview by Loan external ID with the following data:
|
||||
| frequencyNumber | frequencyType | startDate | numberOfInstallments |
|
||||
| 1 | MONTHS | 01 April 2024| 6 |
|
||||
Then Loan Repayment schedule preview has 8 periods, with the following data for periods:
|
||||
Then Loan Repayment schedule preview has 9 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 | 0.0 | 0.0 | 0.0 | | | |
|
||||
| 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 |
|
||||
| 2 | 29 | 01 March 2024 | 15 March 2024 | 83.57 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||
| 3 | 31 | 01 April 2024 | | 70.25 | 13.32 | 0.98 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 4 | 30 | 01 May 2024 | | 56.36 | 13.89 | 0.41 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 5 | 31 | 01 June 2024 | | 42.39 | 13.97 | 0.33 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 6 | 30 | 01 July 2024 | | 28.34 | 14.05 | 0.25 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 7 | 31 | 01 August 2024 | | 14.21 | 14.13 | 0.17 | 10.0 | 0.0 | 24.3 | 0.0 | 0.0 | 0.0 | 24.3 |
|
||||
| 8 | 31 | 01 September 2024| | 0.0 | 14.21 | 0.08 | 0.0 | 0.0 | 14.29 | 0.0 | 0.0 | 0.0 | 14.29 |
|
||||
| 3 | 14 | 15 March 2024 | 15 March 2024 | 83.57 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||
| 4 | 17 | 01 April 2024 | | 70.25 | 13.32 | 0.98 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 5 | 30 | 01 May 2024 | | 56.36 | 13.89 | 0.41 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 6 | 31 | 01 June 2024 | | 42.39 | 13.97 | 0.33 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 7 | 30 | 01 July 2024 | | 28.34 | 14.05 | 0.25 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 8 | 31 | 01 August 2024 | | 14.21 | 14.13 | 0.17 | 10.0 | 0.0 | 24.3 | 0.0 | 0.0 | 0.0 | 24.3 |
|
||||
| 9 | 31 | 01 September 2024| | 0.0 | 14.21 | 0.08 | 0.0 | 0.0 | 14.29 | 0.0 | 0.0 | 0.0 | 14.29 |
|
||||
Then Loan Repayment schedule preview has the following data in Total row:
|
||||
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| 100.0 | 2.8 | 10.0 | 0.0 | 112.8 | 17.01 | 0.0 | 0.0 | 95.79 |
|
||||
@@ -735,17 +738,18 @@ Feature: LoanReAgingPreview
|
||||
When Admin creates a Loan re-aging preview by Loan external ID with the following data:
|
||||
| frequencyNumber | frequencyType | startDate | numberOfInstallments |
|
||||
| 1 | MONTHS | 01 April 2024| 6 |
|
||||
Then Loan Repayment schedule preview has 8 periods, with the following data for periods:
|
||||
Then Loan Repayment schedule preview has 9 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 | 0.0 | 0.0 | 0.0 | | | |
|
||||
| 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 |
|
||||
| 2 | 29 | 01 March 2024 | 15 March 2024 | 75.58 | 7.99 | 0.0 | 0.0 | 0.0 | 7.99 | 7.99 | 7.99 | 0.0 | 0.0 |
|
||||
| 3 | 31 | 01 April 2024 | | 63.53 | 12.05 | 0.88 | 0.0 | 0.0 | 12.93 | 0.0 | 0.0 | 0.0 | 12.93 |
|
||||
| 4 | 30 | 01 May 2024 | | 50.97 | 12.56 | 0.37 | 0.0 | 0.0 | 12.93 | 0.0 | 0.0 | 0.0 | 12.93 |
|
||||
| 5 | 31 | 01 June 2024 | | 38.34 | 12.63 | 0.3 | 0.0 | 0.0 | 12.93 | 0.0 | 0.0 | 0.0 | 12.93 |
|
||||
| 6 | 30 | 01 July 2024 | | 25.63 | 12.71 | 0.22 | 0.0 | 0.0 | 12.93 | 0.0 | 0.0 | 0.0 | 12.93 |
|
||||
| 7 | 31 | 01 August 2024 | | 12.85 | 12.78 | 0.15 | 0.0 | 0.0 | 12.93 | 0.0 | 0.0 | 0.0 | 12.93 |
|
||||
| 8 | 31 | 01 September 2024| | 0.0 | 12.85 | 0.07 | 0.0 | 0.0 | 12.92 | 0.0 | 0.0 | 0.0 | 12.92 |
|
||||
| 3 | 14 | 15 March 2024 | 15 March 2024 | 75.58 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||
| 4 | 17 | 01 April 2024 | | 63.53 | 12.05 | 0.88 | 0.0 | 0.0 | 12.93 | 0.0 | 0.0 | 0.0 | 12.93 |
|
||||
| 5 | 30 | 01 May 2024 | | 50.97 | 12.56 | 0.37 | 0.0 | 0.0 | 12.93 | 0.0 | 0.0 | 0.0 | 12.93 |
|
||||
| 6 | 31 | 01 June 2024 | | 38.34 | 12.63 | 0.3 | 0.0 | 0.0 | 12.93 | 0.0 | 0.0 | 0.0 | 12.93 |
|
||||
| 7 | 30 | 01 July 2024 | | 25.63 | 12.71 | 0.22 | 0.0 | 0.0 | 12.93 | 0.0 | 0.0 | 0.0 | 12.93 |
|
||||
| 8 | 31 | 01 August 2024 | | 12.85 | 12.78 | 0.15 | 0.0 | 0.0 | 12.93 | 0.0 | 0.0 | 0.0 | 12.93 |
|
||||
| 9 | 31 | 01 September 2024| | 0.0 | 12.85 | 0.07 | 0.0 | 0.0 | 12.92 | 0.0 | 0.0 | 0.0 | 12.92 |
|
||||
Then Loan Repayment schedule preview has the following data in Total row:
|
||||
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| 100.0 | 2.57 | 0.0 | 0.0 | 102.57 | 25.0 | 7.99 | 0.0 | 77.57 |
|
||||
@@ -804,18 +808,19 @@ Feature: LoanReAgingPreview
|
||||
When Admin creates a Loan re-aging preview by Loan external ID with the following data:
|
||||
| frequencyNumber | frequencyType | startDate | numberOfInstallments |
|
||||
| 1 | MONTHS | 01 April 2024 | 6 |
|
||||
Then Loan Repayment schedule preview has 9 periods, with the following data for periods:
|
||||
Then Loan Repayment schedule preview has 10 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 | 0.0 | 0.0 | 0.0 | | | |
|
||||
| 1 | 0 | 01 January 2024 | 01 January 2024 | 75.0 | 25.0 | 0.0 | 0.0 | 0.0 | 25.0 | 25.0 | 0.0 | 0.0 | 0.0 |
|
||||
| 2 | 31 | 01 February 2024 | 01 February 2024 | 62.68 | 12.32 | 0.44 | 0.0 | 0.0 | 12.76 | 12.76 | 0.0 | 0.0 | 0.0 |
|
||||
| 3 | 29 | 01 March 2024 | 15 March 2024 | 62.68 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||
| 4 | 31 | 01 April 2024 | | 52.69 | 9.99 | 0.74 | 0.0 | 0.0 | 10.73 | 0.0 | 0.0 | 0.0 | 10.73 |
|
||||
| 5 | 30 | 01 May 2024 | | 42.27 | 10.42 | 0.31 | 0.0 | 0.0 | 10.73 | 0.0 | 0.0 | 0.0 | 10.73 |
|
||||
| 6 | 31 | 01 June 2024 | | 31.79 | 10.48 | 0.25 | 0.0 | 0.0 | 10.73 | 0.0 | 0.0 | 0.0 | 10.73 |
|
||||
| 7 | 30 | 01 July 2024 | | 21.25 | 10.54 | 0.19 | 0.0 | 0.0 | 10.73 | 0.0 | 0.0 | 0.0 | 10.73 |
|
||||
| 8 | 31 | 01 August 2024 | | 10.64 | 10.61 | 0.12 | 0.0 | 0.0 | 10.73 | 0.0 | 0.0 | 0.0 | 10.73 |
|
||||
| 9 | 31 | 01 September 2024 | | 0.0 | 10.64 | 0.06 | 0.0 | 0.0 | 10.7 | 0.0 | 0.0 | 0.0 | 10.7 |
|
||||
| 4 | 14 | 15 March 2024 | 15 March 2024 | 62.68 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||
| 5 | 17 | 01 April 2024 | | 52.69 | 9.99 | 0.74 | 0.0 | 0.0 | 10.73 | 0.0 | 0.0 | 0.0 | 10.73 |
|
||||
| 6 | 30 | 01 May 2024 | | 42.27 | 10.42 | 0.31 | 0.0 | 0.0 | 10.73 | 0.0 | 0.0 | 0.0 | 10.73 |
|
||||
| 7 | 31 | 01 June 2024 | | 31.79 | 10.48 | 0.25 | 0.0 | 0.0 | 10.73 | 0.0 | 0.0 | 0.0 | 10.73 |
|
||||
| 8 | 30 | 01 July 2024 | | 21.25 | 10.54 | 0.19 | 0.0 | 0.0 | 10.73 | 0.0 | 0.0 | 0.0 | 10.73 |
|
||||
| 9 | 31 | 01 August 2024 | | 10.64 | 10.61 | 0.12 | 0.0 | 0.0 | 10.73 | 0.0 | 0.0 | 0.0 | 10.73 |
|
||||
| 10 | 31 | 01 September 2024 | | 0.0 | 10.64 | 0.06 | 0.0 | 0.0 | 10.7 | 0.0 | 0.0 | 0.0 | 10.7 |
|
||||
Then Loan Repayment schedule preview has the following data in Total row:
|
||||
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| 100.0 | 2.11 | 0.0 | 0.0 | 102.11 | 37.76 | 0.0 | 0.0 | 64.35 |
|
||||
@@ -870,17 +875,18 @@ Feature: LoanReAgingPreview
|
||||
When Admin creates a Loan re-aging transaction with the following data:
|
||||
| frequencyNumber | frequencyType | startDate | numberOfInstallments |
|
||||
| 1 | MONTHS | 01 April 2024 | 6 |
|
||||
Then Loan Repayment schedule has 8 periods, with the following data for periods:
|
||||
Then Loan Repayment schedule has 9 periods, with the following data for periods:
|
||||
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | |
|
||||
| 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 |
|
||||
| 2 | 29 | 01 March 2024 | 15 March 2024 | 83.57 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||
| 3 | 31 | 01 April 2024 | | 70.25 | 13.32 | 0.98 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 4 | 30 | 01 May 2024 | | 56.36 | 13.89 | 0.41 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 5 | 31 | 01 June 2024 | | 42.39 | 13.97 | 0.33 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 6 | 30 | 01 July 2024 | | 28.34 | 14.05 | 0.25 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 7 | 31 | 01 August 2024 | | 14.21 | 14.13 | 0.17 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 8 | 31 | 01 September 2024| | 0.0 | 14.21 | 0.08 | 0.0 | 0.0 | 14.29 | 0.0 | 0.0 | 0.0 | 14.29 |
|
||||
| 3 | 14 | 15 March 2024 | 15 March 2024 | 83.57 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||
| 4 | 17 | 01 April 2024 | | 70.25 | 13.32 | 0.98 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 5 | 30 | 01 May 2024 | | 56.36 | 13.89 | 0.41 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 6 | 31 | 01 June 2024 | | 42.39 | 13.97 | 0.33 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 7 | 30 | 01 July 2024 | | 28.34 | 14.05 | 0.25 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 8 | 31 | 01 August 2024 | | 14.21 | 14.13 | 0.17 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 9 | 31 | 01 September 2024| | 0.0 | 14.21 | 0.08 | 0.0 | 0.0 | 14.29 | 0.0 | 0.0 | 0.0 | 14.29 |
|
||||
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.8 | 0.0 | 0.0 | 102.8 | 17.01 | 0.0 | 0.0 | 85.79 |
|
||||
@@ -912,17 +918,18 @@ Feature: LoanReAgingPreview
|
||||
When Admin creates a Loan re-aging preview by Loan external ID with the following data:
|
||||
| frequencyNumber | frequencyType | startDate | numberOfInstallments |
|
||||
| 1 | MONTHS | 01 April 2024 | 6 |
|
||||
Then Loan Repayment schedule preview has 8 periods, with the following data for periods:
|
||||
Then Loan Repayment schedule preview has 9 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 | 0.0 | 0.0 | 0.0 | | | |
|
||||
| 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 |
|
||||
| 2 | 29 | 01 March 2024 | 01 April 2024 | 83.57 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||
| 3 | 31 | 01 April 2024 | | 70.25 | 13.32 | 0.98 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 4 | 30 | 01 May 2024 | | 56.36 | 13.89 | 0.41 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 5 | 31 | 01 June 2024 | | 42.39 | 13.97 | 0.33 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 6 | 30 | 01 July 2024 | | 28.34 | 14.05 | 0.25 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 7 | 31 | 01 August 2024 | | 14.21 | 14.13 | 0.17 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 8 | 31 | 01 September 2024| | 0.0 | 14.21 | 0.08 | 0.0 | 0.0 | 14.29 | 0.0 | 0.0 | 0.0 | 14.29 |
|
||||
| 3 | 31 | 01 April 2024 | 01 April 2024 | 83.57 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||
| 4 | 0 | 01 April 2024 | | 70.25 | 13.32 | 0.98 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 5 | 30 | 01 May 2024 | | 56.36 | 13.89 | 0.41 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 6 | 31 | 01 June 2024 | | 42.39 | 13.97 | 0.33 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 7 | 30 | 01 July 2024 | | 28.34 | 14.05 | 0.25 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 8 | 31 | 01 August 2024 | | 14.21 | 14.13 | 0.17 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 9 | 31 | 01 September 2024| | 0.0 | 14.21 | 0.08 | 0.0 | 0.0 | 14.29 | 0.0 | 0.0 | 0.0 | 14.29 |
|
||||
Then Loan Repayment schedule preview has the following data in Total row:
|
||||
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| 100.0 | 2.8 | 0.0 | 0.0 | 102.8 | 17.01 | 0.0 | 0.0 | 85.79 |
|
||||
@@ -1133,17 +1140,18 @@ Feature: LoanReAgingPreview
|
||||
When Admin creates a Loan re-aging preview by Loan external ID with the following data:
|
||||
| frequencyNumber | frequencyType | startDate | numberOfInstallments |
|
||||
| 1 | MONTHS | 01 April 2024 | 6 |
|
||||
Then Loan Repayment schedule preview has 8 periods, with the following data for periods:
|
||||
Then Loan Repayment schedule preview has 9 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 | 0.0 | 0.0 | 0.0 | | | |
|
||||
| 1 | 31 | 01 February 2024 | 01 February 2024 | 83.57 | 16.43 | 0.58 | 0.0 | 0.0 | 17.01 | 17.01 | 0.0 | 0.0 | 0.0 |
|
||||
| 2 | 29 | 01 March 2024 | 15 March 2024 | 83.57 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||
| 3 | 31 | 01 April 2024 | | 70.25 | 13.32 | 0.98 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 4 | 30 | 01 May 2024 | | 56.36 | 13.89 | 0.41 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 5 | 31 | 01 June 2024 | | 42.39 | 13.97 | 0.33 | 10.0 | 0.0 | 24.3 | 0.0 | 0.0 | 0.0 | 24.3 |
|
||||
| 6 | 30 | 01 July 2024 | | 28.34 | 14.05 | 0.25 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 7 | 31 | 01 August 2024 | | 14.21 | 14.13 | 0.17 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 8 | 31 | 01 September 2024| | 0.0 | 14.21 | 0.08 | 0.0 | 0.0 | 14.29 | 0.0 | 0.0 | 0.0 | 14.29 |
|
||||
| 3 | 14 | 15 March 2024 | 15 March 2024 | 83.57 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||
| 4 | 17 | 01 April 2024 | | 70.25 | 13.32 | 0.98 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 5 | 30 | 01 May 2024 | | 56.36 | 13.89 | 0.41 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 6 | 31 | 01 June 2024 | | 42.39 | 13.97 | 0.33 | 10.0 | 0.0 | 24.3 | 0.0 | 0.0 | 0.0 | 24.3 |
|
||||
| 7 | 30 | 01 July 2024 | | 28.34 | 14.05 | 0.25 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 8 | 31 | 01 August 2024 | | 14.21 | 14.13 | 0.17 | 0.0 | 0.0 | 14.3 | 0.0 | 0.0 | 0.0 | 14.3 |
|
||||
| 9 | 31 | 01 September 2024| | 0.0 | 14.21 | 0.08 | 0.0 | 0.0 | 14.29 | 0.0 | 0.0 | 0.0 | 14.29 |
|
||||
Then Loan Repayment schedule preview has the following data in Total row:
|
||||
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| 100.0 | 2.8 | 10.0 | 0.0 | 112.8 | 17.01 | 0.0 | 0.0 | 95.79 |
|
||||
|
||||
+7
@@ -278,6 +278,13 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableWithUTCDa
|
||||
null, null, null, false, false, true);
|
||||
}
|
||||
|
||||
public static LoanRepaymentScheduleInstallment newInstallmentWithMovedPaidAmountDuringReAging(final Loan loan,
|
||||
final Integer installmentNumber, final LocalDate fromDate, final LocalDate dueDate, final BigDecimal principal,
|
||||
final BigDecimal interest) {
|
||||
return new LoanRepaymentScheduleInstallment(loan, installmentNumber, fromDate, dueDate, principal, interest, null, null, null, null,
|
||||
null, null, false, false, false);
|
||||
}
|
||||
|
||||
public static LoanRepaymentScheduleInstallment getLastNonDownPaymentInstallment(List<LoanRepaymentScheduleInstallment> installments) {
|
||||
return installments.stream().filter(i -> !i.isDownPayment()).reduce((first, second) -> second).orElseThrow();
|
||||
}
|
||||
|
||||
+2
-1
@@ -62,7 +62,8 @@ public class ProgressivePossibleNextRepaymentCalculationServiceImpl extends Abst
|
||||
ctx.setWrittenOff(loan.isClosedWrittenOff());
|
||||
ctx.setContractTerminated(loan.isContractTermination());
|
||||
advancedPaymentScheduleTransactionProcessor.recalculateInterestForDate(nextPaymentDueDate, ctx, false);
|
||||
RepaymentPeriod repaymentPeriod = scheduleModel.findRepaymentPeriodByDueDate(nextPaymentDueDate)
|
||||
RepaymentPeriod repaymentPeriod = scheduleModel
|
||||
.findRepaymentPeriodByFromAndDueDate(nextInstallment.getFromDate(), nextInstallment.getDueDate())
|
||||
.orElseGet(scheduleModel::getLastRepaymentPeriod);
|
||||
|
||||
return repaymentPeriod.getOutstandingPrincipal().add(repaymentPeriod.getOutstandingInterest())
|
||||
|
||||
+132
-77
@@ -45,10 +45,10 @@ import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
@@ -365,10 +365,11 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
|
||||
private void updateInstallmentIfInterestPeriodPresent(final ProgressiveLoanInterestScheduleModel scheduleModel,
|
||||
final LoanRepaymentScheduleInstallment installment) {
|
||||
emiCalculator.findRepaymentPeriod(scheduleModel, installment.getDueDate()).ifPresent(interestRepaymentPeriod -> {
|
||||
installment.updateInterestCharged(interestRepaymentPeriod.getDueInterest().getAmount());
|
||||
installment.updatePrincipal(interestRepaymentPeriod.getDuePrincipal().getAmount());
|
||||
});
|
||||
emiCalculator.findRepaymentPeriod(scheduleModel, installment.getFromDate(), installment.getDueDate())
|
||||
.ifPresent(interestRepaymentPeriod -> {
|
||||
installment.updateInterestCharged(interestRepaymentPeriod.getDueInterest().getAmount());
|
||||
installment.updatePrincipal(interestRepaymentPeriod.getDuePrincipal().getAmount());
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -592,7 +593,8 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
updateRepaymentPeriods(loanTransaction, progressiveTransactionCtx);
|
||||
|
||||
if (repaidAmount.isGreaterThanZero()) {
|
||||
emiCalculator.payPrincipal(model, currentInstallment.getDueDate(), transactionDate, repaidAmount);
|
||||
emiCalculator.payPrincipal(model, currentInstallment.getFromDate(), currentInstallment.getDueDate(),
|
||||
transactionDate, repaidAmount);
|
||||
updateRepaymentPeriods(loanTransaction, progressiveTransactionCtx);
|
||||
currentInstallment.payPrincipalComponent(transactionDate, repaidAmount);
|
||||
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(loanTransaction,
|
||||
@@ -629,7 +631,8 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
updateRepaymentPeriods(loanTransaction, progressiveTransactionCtx);
|
||||
|
||||
if (repaidAmount.isGreaterThanZero()) {
|
||||
emiCalculator.payPrincipal(model, currentInstallment.getDueDate(), transactionDate, repaidAmount);
|
||||
emiCalculator.payPrincipal(model, currentInstallment.getFromDate(), currentInstallment.getDueDate(),
|
||||
transactionDate, repaidAmount);
|
||||
updateRepaymentPeriods(loanTransaction, progressiveTransactionCtx);
|
||||
currentInstallment.payPrincipalComponent(transactionDate, repaidAmount);
|
||||
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(loanTransaction,
|
||||
@@ -1581,7 +1584,8 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
private void updateInstallmentsPrincipalAndInterestByModel(ProgressiveTransactionCtx ctx) {
|
||||
ctx.getModel().repaymentPeriods().forEach(repayment -> {
|
||||
LoanRepaymentScheduleInstallment installment = ctx.getInstallments().stream()
|
||||
.filter(ri -> !ri.isDownPayment() && Objects.equals(ri.getFromDate(), repayment.getFromDate())) //
|
||||
.filter(ri -> !ri.isDownPayment() && Objects.equals(ri.getFromDate(), repayment.getFromDate()) //
|
||||
&& Objects.equals(ri.getDueDate(), repayment.getDueDate()))
|
||||
.findFirst().orElse(null);
|
||||
if (installment != null) {
|
||||
installment.updatePrincipal(repayment.getDuePrincipal().getAmount());
|
||||
@@ -1774,7 +1778,7 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
&& loan.isInterestBearingAndInterestRecalculationEnabled()) {
|
||||
final BigDecimal interestOutstanding = currentInstallment.getInterestOutstanding(loan.getCurrency()).getAmount();
|
||||
final BigDecimal newInterest = emiCalculator.getPeriodInterestTillDate(progressiveTransactionCtx.getModel(),
|
||||
currentInstallment.getDueDate(), transactionDate, true).getAmount();
|
||||
currentInstallment.getFromDate(), currentInstallment.getDueDate(), transactionDate, true).getAmount();
|
||||
if (interestOutstanding.compareTo(BigDecimal.ZERO) > 0 || newInterest.compareTo(BigDecimal.ZERO) > 0) {
|
||||
currentInstallment.updateInterestCharged(newInterest);
|
||||
}
|
||||
@@ -1887,7 +1891,7 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
&& installment.getDueDate().isAfter(transactionDate)).forEach(installment -> {
|
||||
final BigDecimal interestOutstanding = installment.getInterestOutstanding(currency).getAmount();
|
||||
final BigDecimal newInterest = emiCalculator.getPeriodInterestTillDate(progressiveTransactionCtx.getModel(),
|
||||
installment.getDueDate(), transactionDate, true).getAmount();
|
||||
installment.getFromDate(), installment.getDueDate(), transactionDate, true).getAmount();
|
||||
if (MathUtil.isGreaterThanZero(interestOutstanding) || MathUtil.isGreaterThanZero(newInterest)) {
|
||||
final BigDecimal interestRemoved = MathUtil.subtract(MathUtil.nullToZero(installment.getInterestCharged()),
|
||||
newInterest);
|
||||
@@ -2503,10 +2507,10 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
loanTransactionToRepaymentScheduleMapping, charges, balances, LoanRepaymentScheduleInstallment.PaymentAction.PAY);
|
||||
|
||||
if (PRINCIPAL.equals(paymentAllocationType.getAllocationType())) {
|
||||
emiCalculator.payPrincipal(model, installment.getDueDate(), payDate, paidPortion);
|
||||
emiCalculator.payPrincipal(model, installment.getFromDate(), installment.getDueDate(), payDate, paidPortion);
|
||||
updateRepaymentPeriods(loanTransaction, ctx);
|
||||
} else if (INTEREST.equals(paymentAllocationType.getAllocationType())) {
|
||||
emiCalculator.payInterest(model, installment.getDueDate(), payDate, paidPortion);
|
||||
emiCalculator.payInterest(model, installment.getFromDate(), installment.getDueDate(), payDate, paidPortion);
|
||||
updateRepaymentPeriods(loanTransaction, ctx);
|
||||
}
|
||||
return paidPortion;
|
||||
@@ -2514,8 +2518,9 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
|
||||
private void updateRepaymentPeriods(LoanTransaction loanTransaction, ProgressiveTransactionCtx ctx) {
|
||||
ctx.getModel().repaymentPeriods().forEach(rm -> {
|
||||
LoanRepaymentScheduleInstallment installment = ctx.getInstallments().stream()
|
||||
.filter(ri -> ri.getDueDate().equals(rm.getDueDate()) && !ri.isDownPayment()).findFirst().orElse(null);
|
||||
LoanRepaymentScheduleInstallment installment = ctx.getInstallments().stream().filter(
|
||||
ri -> ri.getFromDate().equals(rm.getFromDate()) && ri.getDueDate().equals(rm.getDueDate()) && !ri.isDownPayment())
|
||||
.findFirst().orElse(null);
|
||||
if (installment != null) {
|
||||
installment.updatePrincipal(rm.getDuePrincipal().getAmount());
|
||||
installment.updateInterestCharged(rm.getDueInterest().getAmount());
|
||||
@@ -2528,7 +2533,8 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
|
||||
private void updateRepaymentPeriodBalances(PaymentAllocationType paymentAllocationType,
|
||||
LoanRepaymentScheduleInstallment inAdvanceInstallment, ProgressiveTransactionCtx ctx, LocalDate payDate) {
|
||||
PeriodDueDetails payableDetails = emiCalculator.getDueAmounts(ctx.getModel(), inAdvanceInstallment.getDueDate(), payDate);
|
||||
PeriodDueDetails payableDetails = emiCalculator.getDueAmounts(ctx.getModel(), inAdvanceInstallment.getFromDate(),
|
||||
inAdvanceInstallment.getDueDate(), payDate);
|
||||
|
||||
if (payableDetails.getDueInterest().isZero() && payableDetails.getDuePrincipal().isZero()) {
|
||||
ctx.getSkipRepaymentScheduleInstallments().add(inAdvanceInstallment);
|
||||
@@ -2777,16 +2783,17 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
private Money fee;
|
||||
private Money penalty;
|
||||
private Money paidInAdvance;
|
||||
private BigDecimal paidLate;
|
||||
private Set<LoanTransactionToRepaymentScheduleMapping> loanTransactionToRepaymentScheduleMappings;
|
||||
|
||||
private BalancesWithPaidInAdvance(MonetaryCurrency currency) {
|
||||
this(Money.zero(currency), Money.zero(currency), Money.zero(currency), Money.zero(currency), Money.zero(currency),
|
||||
new LinkedHashSet<>());
|
||||
BigDecimal.ZERO, new LinkedHashSet<>());
|
||||
}
|
||||
|
||||
private BalancesWithPaidInAdvance(LoanRepaymentScheduleInstallment i, MonetaryCurrency currency) {
|
||||
this(i.getPrincipalCompleted(currency), i.getInterestPaid(currency), i.getFeeChargesPaid(currency),
|
||||
i.getPenaltyChargesPaid(currency), i.getTotalPaidInAdvance(currency),
|
||||
i.getPenaltyChargesPaid(currency), i.getTotalPaidInAdvance(currency), i.getTotalPaidLate(),
|
||||
new LinkedHashSet<>(i.getLoanTransactionToRepaymentScheduleMappings()));
|
||||
}
|
||||
|
||||
@@ -2796,7 +2803,8 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
set.addAll(a.getLoanTransactionToRepaymentScheduleMappings());
|
||||
set.addAll(b.getLoanTransactionToRepaymentScheduleMappings());
|
||||
return new BalancesWithPaidInAdvance(a.getPrincipal().add(b.getPrincipal()), a.getInterest().add(b.getInterest()),
|
||||
a.getFee().add(b.getFee()), a.getPenalty().add(b.getPenalty()), a.getPaidInAdvance().add(b.getPaidInAdvance()), set);
|
||||
a.getFee().add(b.getFee()), a.getPenalty().add(b.getPenalty()), a.getPaidInAdvance().add(b.getPaidInAdvance()),
|
||||
MathUtil.nullToZero(a.getPaidLate()).add(MathUtil.nullToZero(b.getPaidLate())), set);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2901,58 +2909,118 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanupInstallmentsAfterReAging(final ProgressiveTransactionCtx ctx) {
|
||||
private void updateInstallmentsByModelForReAging(final LoanTransaction loanTransaction, final ProgressiveTransactionCtx ctx,
|
||||
final LocalDate reAgePeriodStartDate) {
|
||||
final List<LoanRepaymentScheduleInstallment> installments = ctx.getInstallments();
|
||||
final LocalDate transactionDate = loanTransaction.getTransactionDate();
|
||||
|
||||
// Find the last re-aged installment number
|
||||
final OptionalInt lastReAgedInstallmentNumberOpt = installments.stream().filter(LoanRepaymentScheduleInstallment::isReAged)
|
||||
.mapToInt(LoanRepaymentScheduleInstallment::getInstallmentNumber).max();
|
||||
final Optional<RepaymentPeriod> reAgeSpecialRepaymentPeriodOpt = ctx.getModel().repaymentPeriods().stream()
|
||||
.filter(RepaymentPeriod::isReAgedEarlyRepaymentHolder).findFirst();
|
||||
final LoanRepaymentScheduleInstallment installmentWithMovedPaidAmounts = reAgeSpecialRepaymentPeriodOpt
|
||||
.map(repaymentPeriod -> createInstallmentWithMovedPaidAmounts(ctx, loanTransaction, installments, repaymentPeriod))
|
||||
.orElse(null);
|
||||
|
||||
if (lastReAgedInstallmentNumberOpt.isPresent()) {
|
||||
final int lastReAgedInstallmentNumber = lastReAgedInstallmentNumberOpt.getAsInt();
|
||||
// Remove installments with numbers greater than the last re-aged installment
|
||||
final List<LoanRepaymentScheduleInstallment> installmentsToRemove = installments.stream().filter(i -> i != null
|
||||
&& !i.isAdditional() && i.getInstallmentNumber() != null && i.getInstallmentNumber() > lastReAgedInstallmentNumber)
|
||||
.toList();
|
||||
installmentsToRemove.forEach(installments::remove);
|
||||
}
|
||||
}
|
||||
final List<LoanCharge> liftedLoanCharges = new ArrayList<>();
|
||||
installments.stream().filter(installment -> !installment.getDueDate().isBefore(transactionDate)).forEach(i -> {
|
||||
liftedLoanCharges.addAll(getLoanChargesOfInstallment(ctx.getCharges(), i, 1));
|
||||
});
|
||||
|
||||
installments.removeIf(i -> i.getInstallmentNumber() != null && !i.isDownPayment() && !i.getDueDate().isBefore(transactionDate));
|
||||
|
||||
final ListIterator<LoanRepaymentScheduleInstallment> iterator = installments.listIterator();
|
||||
|
||||
final AtomicInteger installmentCounter = new AtomicInteger();
|
||||
|
||||
private void updateInstallmentsByModelForReAging(final LoanTransaction loanTransaction, final ProgressiveTransactionCtx ctx) {
|
||||
ctx.getModel().repaymentPeriods().forEach(rp -> {
|
||||
final LoanRepaymentScheduleInstallment installment = ctx.getInstallments().stream()
|
||||
.filter(ri -> ri.getFromDate().equals(rp.getFromDate()) && !ri.isDownPayment()).findFirst().orElse(null);
|
||||
final LocalDate transactionDate = loanTransaction.getTransactionDate();
|
||||
LoanRepaymentScheduleInstallment installment = null;
|
||||
while (iterator.hasNext() && (installment == null || installment.isAdditional() || installment.isDownPayment())) {
|
||||
installment = iterator.next();
|
||||
installmentCounter.getAndIncrement();
|
||||
}
|
||||
|
||||
if (installment != null) {
|
||||
installment.setFromDate(rp.getFromDate());
|
||||
installment.setDueDate(rp.getDueDate());
|
||||
if (installment.isNotFullyPaidOff() || !installment.getFromDate().isBefore(reAgePeriodStartDate)) {
|
||||
installment.setFromDate(rp.getFromDate());
|
||||
installment.setDueDate(rp.getDueDate());
|
||||
|
||||
if (rp.getEmi().isZero()) {
|
||||
installment.updatePrincipal(BigDecimal.ZERO);
|
||||
installment.updateInterestCharged(BigDecimal.ZERO);
|
||||
} else {
|
||||
installment.updatePrincipal(rp.getDuePrincipal().getAmount());
|
||||
installment.updateInterestCharged(rp.getDueInterest().getAmount());
|
||||
if (rp.getEmi().isZero()) {
|
||||
installment.updatePrincipal(ZERO);
|
||||
installment.updateInterestCharged(ZERO);
|
||||
} else {
|
||||
installment.updatePrincipal(rp.getDuePrincipal().getAmount());
|
||||
installment.updateInterestCharged(rp.getDueInterest().getAmount());
|
||||
}
|
||||
if (!installment.getFromDate().isBefore(reAgePeriodStartDate)) {
|
||||
installment.setReAged(true);
|
||||
}
|
||||
installment.setAdditional(false);
|
||||
installment.updateObligationsMet(ctx.getCurrency(), transactionDate);
|
||||
}
|
||||
installment.setReAged(true);
|
||||
installment.setAdditional(false);
|
||||
installment.updateObligationsMet(ctx.getCurrency(), transactionDate);
|
||||
} else {
|
||||
final LoanRepaymentScheduleInstallment lastInstallment = ctx.getInstallments().getLast();
|
||||
final LoanRepaymentScheduleInstallment newInstallment = LoanRepaymentScheduleInstallment.newReAgedInstallment(
|
||||
loanTransaction.getLoan(), lastInstallment.getInstallmentNumber() + 1, rp.getFromDate(), rp.getDueDate(),
|
||||
rp.getDuePrincipal().getAmount(), null, null, null);
|
||||
if (rp.isReAgedEarlyRepaymentHolder()) {
|
||||
iterator.add(installmentWithMovedPaidAmounts);
|
||||
} else {
|
||||
installmentCounter.getAndIncrement();
|
||||
final LoanRepaymentScheduleInstallment newInstallment = LoanRepaymentScheduleInstallment.newReAgedInstallment(
|
||||
loanTransaction.getLoan(), installmentCounter.get(), rp.getFromDate(), rp.getDueDate(),
|
||||
rp.getDuePrincipal().getAmount(), null, null, null);
|
||||
|
||||
if (rp.getDueInterest().isGreaterThanZero()) {
|
||||
newInstallment.addToInterest(transactionDate, rp.getDueInterest());
|
||||
if (rp.getDueInterest().isGreaterThanZero()) {
|
||||
newInstallment.addToInterest(transactionDate, rp.getDueInterest());
|
||||
}
|
||||
|
||||
newInstallment.updateObligationsMet(ctx.getCurrency(), transactionDate);
|
||||
iterator.add(newInstallment);
|
||||
}
|
||||
|
||||
newInstallment.updateObligationsMet(ctx.getCurrency(), transactionDate);
|
||||
ctx.getInstallments().add(newInstallment);
|
||||
}
|
||||
});
|
||||
|
||||
cleanupInstallmentsAfterReAging(ctx);
|
||||
for (LoanCharge loanCharge : liftedLoanCharges) {
|
||||
loanChargeRepaymentScheduleProcessing.reprocess(ctx.getCurrency(), loanTransaction.getLoan().getDisbursementDate(),
|
||||
installments, loanCharge);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a special installment to preserve paid amounts during the re-aging process.
|
||||
*
|
||||
* @param loanTransaction
|
||||
* the re-aging transaction
|
||||
* @param installments
|
||||
* list of existing loan repayment schedule installments
|
||||
* @param rp
|
||||
* repayment period with moved paid amounts
|
||||
* @return new installment with moved paid amounts
|
||||
*/
|
||||
private LoanRepaymentScheduleInstallment createInstallmentWithMovedPaidAmounts(final ProgressiveTransactionCtx ctx,
|
||||
final LoanTransaction loanTransaction, final List<LoanRepaymentScheduleInstallment> installments, final RepaymentPeriod rp) {
|
||||
final MonetaryCurrency currency = loanTransaction.getLoan().loanCurrency();
|
||||
final LocalDate transactionDate = loanTransaction.getTransactionDate();
|
||||
final Optional<LoanRepaymentScheduleInstallment> firstReAgedInstallment = installments.stream()
|
||||
.filter(i -> (i.getInstallmentNumber() != null && !i.isDownPayment() && !i.getDueDate().isBefore(transactionDate)))
|
||||
.findFirst();
|
||||
|
||||
int installmentNumberToInsertPaidInstallment = installments.getLast().getInstallmentNumber() + 1;
|
||||
if (firstReAgedInstallment.isPresent()) {
|
||||
installmentNumberToInsertPaidInstallment = firstReAgedInstallment.get().getInstallmentNumber();
|
||||
}
|
||||
|
||||
final LoanRepaymentScheduleInstallment newInstallment = LoanRepaymentScheduleInstallment
|
||||
.newInstallmentWithMovedPaidAmountDuringReAging(loanTransaction.getLoan(), installmentNumberToInsertPaidInstallment,
|
||||
rp.getFromDate(), rp.getDueDate(), rp.getDuePrincipal().getAmount(), rp.getDueInterest().getAmount());
|
||||
|
||||
newInstallment.payPrincipalComponent(transactionDate, rp.getPaidPrincipal());
|
||||
newInstallment.payInterestComponent(transactionDate, rp.getPaidInterest());
|
||||
|
||||
final BalancesWithPaidInAdvance paidInAdvanceBalances = liftEarlyRepaidBalances(installments, transactionDate, currency,
|
||||
ctx.getAlreadyProcessedTransactions());
|
||||
|
||||
newInstallment.setTotalPaidInAdvance(paidInAdvanceBalances.getPaidInAdvance().getAmount());
|
||||
newInstallment.setTotalPaidLate(paidInAdvanceBalances.getPaidLate());
|
||||
paidInAdvanceBalances.loanTransactionToRepaymentScheduleMappings.forEach(m -> m.setInstallment(newInstallment));
|
||||
newInstallment.updateObligationsMet(currency, transactionDate);
|
||||
|
||||
return newInstallment;
|
||||
}
|
||||
|
||||
private void reprocessInstallments(final List<LoanRepaymentScheduleInstallment> installments) {
|
||||
@@ -3030,8 +3098,8 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
final BigDecimal totalPrincipal = periodsToRemove.stream().map(rp -> rp.getDuePrincipal().getAmount()).reduce(BigDecimal.ZERO,
|
||||
BigDecimal::add);
|
||||
|
||||
final BigDecimal newInterest = emiCalculator
|
||||
.getPeriodInterestTillDate(transactionCtx.getModel(), lastPeriod.getDueDate(), transactionDate, false).getAmount();
|
||||
final BigDecimal newInterest = emiCalculator.getPeriodInterestTillDate(transactionCtx.getModel(), lastPeriod.getFromDate(),
|
||||
lastPeriod.getDueDate(), transactionDate, false).getAmount();
|
||||
|
||||
lastPeriod.setEmi(lastPeriod.getDuePrincipal().add(totalPrincipal).add(newInterest));
|
||||
|
||||
@@ -3074,9 +3142,8 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
} else if (isInPeriod) {
|
||||
if (transactionCtx instanceof ProgressiveTransactionCtx progressiveTransactionCtx
|
||||
&& loan.isInterestBearingAndInterestRecalculationEnabled()) {
|
||||
interest = emiCalculator
|
||||
.getPeriodInterestTillDate(progressiveTransactionCtx.getModel(), installment.getDueDate(), chargeOffDate, true)
|
||||
.getAmount();
|
||||
interest = emiCalculator.getPeriodInterestTillDate(progressiveTransactionCtx.getModel(), installment.getFromDate(),
|
||||
installment.getDueDate(), chargeOffDate, true).getAmount();
|
||||
} else {
|
||||
final BigDecimal totalInterest = installment.getInterestOutstanding(currency).getAmount();
|
||||
if (LoanChargeOffBehaviour.ZERO_INTEREST.equals(loan.getLoanProductRelatedDetail().getChargeOffBehaviour())
|
||||
@@ -3500,18 +3567,6 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
final List<LoanRepaymentScheduleInstallment> installments = ctx.getInstallments();
|
||||
final LocalDate reAgingStartDate = loanTransaction.getLoanReAgeParameter().getStartDate();
|
||||
|
||||
final List<LoanRepaymentScheduleInstallment> installmentsBeforeReAging = installments.stream()
|
||||
.filter(rp -> rp.getFromDate().isBefore(reAgingStartDate)).toList();
|
||||
|
||||
// Define the date, which must match reAgingStartDate
|
||||
final LocalDate expectedReAgingDate = installmentsBeforeReAging.isEmpty() ? installments.getFirst().getFromDate()
|
||||
: installmentsBeforeReAging.getLast().getDueDate();
|
||||
|
||||
if (!expectedReAgingDate.isEqual(reAgingStartDate)) {
|
||||
// TODO: implement logic when re-aging changes the due dates
|
||||
throw new NotImplementedException("Logic when re-aging changes the due dates not implemented");
|
||||
}
|
||||
|
||||
final Money interestFromZeroedInstallments = emiCalculator.getOutstandingInterestTillDate(ctx.getModel(),
|
||||
loanTransaction.getTransactionDate());
|
||||
|
||||
@@ -3537,13 +3592,13 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
loan.getLoanProduct().getLoanProductRelatedDetail().isAllowPartialPeriodInterestCalculation())
|
||||
.mc(mc).build();
|
||||
|
||||
LocalDate reAgePeriodStartDate = calculateFirstReAgedPeriodStartDate(loanTransaction);
|
||||
LocalDate reageFirstDueDate = loanTransaction.getLoanReAgeParameter().getStartDate();
|
||||
final LocalDate reAgePeriodStartDate = calculateFirstReAgedPeriodStartDate(loanTransaction);
|
||||
final LocalDate reAgeFirstDueDate = loanTransaction.getLoanReAgeParameter().getStartDate();
|
||||
// Update the existing model with re-aged periods
|
||||
emiCalculator.updateModelRepaymentPeriodsDuringReAge(ctx.getModel(), reAgePeriodStartDate, reageFirstDueDate,
|
||||
emiCalculator.updateModelRepaymentPeriodsDuringReAge(ctx.getModel(), reAgePeriodStartDate, reAgeFirstDueDate,
|
||||
loanTransaction.getTransactionDate(), loanApplicationTerms, mc);
|
||||
|
||||
updateInstallmentsByModelForReAging(loanTransaction, ctx);
|
||||
updateInstallmentsByModelForReAging(loanTransaction, ctx, reAgePeriodStartDate);
|
||||
|
||||
loanTransaction.updateComponentsAndTotal(totalOutstandingPrincipal, interestFromZeroedInstallments, Money.zero(currency),
|
||||
Money.zero(currency));
|
||||
|
||||
+13
-12
@@ -126,19 +126,20 @@ public class ProgressiveLoanScheduleGenerator implements LoanScheduleGenerator {
|
||||
chargesDueAtTimeOfDisbursement, false, mc);
|
||||
repaymentPeriod.setPeriodNumber(scheduleParams.getInstalmentNumber());
|
||||
|
||||
emiCalculator.findRepaymentPeriod(interestScheduleModel, repaymentPeriod.getDueDate()).ifPresent(interestRepaymentPeriod -> {
|
||||
final Money principalDue = interestRepaymentPeriod.getDuePrincipal();
|
||||
final Money interestDue = interestRepaymentPeriod.getDueInterest();
|
||||
emiCalculator.findRepaymentPeriod(interestScheduleModel, repaymentPeriod.getFromDate(), repaymentPeriod.getDueDate())
|
||||
.ifPresent(interestRepaymentPeriod -> {
|
||||
final Money principalDue = interestRepaymentPeriod.getDuePrincipal();
|
||||
final Money interestDue = interestRepaymentPeriod.getDueInterest();
|
||||
|
||||
repaymentPeriod.addPrincipalAmount(principalDue);
|
||||
repaymentPeriod.addInterestAmount(interestDue);
|
||||
repaymentPeriod.setOutstandingLoanBalance(interestRepaymentPeriod.getOutstandingLoanBalance());
|
||||
repaymentPeriod.addPrincipalAmount(principalDue);
|
||||
repaymentPeriod.addInterestAmount(interestDue);
|
||||
repaymentPeriod.setOutstandingLoanBalance(interestRepaymentPeriod.getOutstandingLoanBalance());
|
||||
|
||||
scheduleParams.addTotalCumulativePrincipal(principalDue);
|
||||
scheduleParams.addTotalCumulativeInterest(interestDue);
|
||||
// add everything
|
||||
scheduleParams.addTotalRepaymentExpected(principalDue.plus(interestDue, mc));
|
||||
});
|
||||
scheduleParams.addTotalCumulativePrincipal(principalDue);
|
||||
scheduleParams.addTotalCumulativeInterest(interestDue);
|
||||
// add everything
|
||||
scheduleParams.addTotalRepaymentExpected(principalDue.plus(interestDue, mc));
|
||||
});
|
||||
|
||||
applyChargesForCurrentPeriod(repaymentPeriod, loanCharges, scheduleParams, currency, mc);
|
||||
periods.add(repaymentPeriod);
|
||||
@@ -254,7 +255,7 @@ public class ProgressiveLoanScheduleGenerator implements LoanScheduleGenerator {
|
||||
}
|
||||
Optional<ProgressiveLoanInterestScheduleModel> savedModel = interestScheduleModelRepositoryWrapper.getSavedModel(loan, targetDate);
|
||||
ProgressiveLoanInterestScheduleModel model = savedModel.orElseThrow();
|
||||
return emiCalculator.getPeriodInterestTillDate(model, installment.getDueDate(), targetDate, false);
|
||||
return emiCalculator.getPeriodInterestTillDate(model, installment.getFromDate(), installment.getDueDate(), targetDate, false);
|
||||
}
|
||||
|
||||
// Private, internal methods
|
||||
|
||||
+10
-9
@@ -61,7 +61,8 @@ public interface EMICalculator {
|
||||
/**
|
||||
* Find repayment period based on Due Date.
|
||||
*/
|
||||
Optional<RepaymentPeriod> findRepaymentPeriod(ProgressiveLoanInterestScheduleModel scheduleModel, LocalDate dueDate);
|
||||
Optional<RepaymentPeriod> findRepaymentPeriod(ProgressiveLoanInterestScheduleModel scheduleModel, LocalDate fromDate,
|
||||
LocalDate dueDate);
|
||||
|
||||
/**
|
||||
* Applies the disbursement on the interest model. This method recalculates the EMI amounts from the action date.
|
||||
@@ -95,14 +96,14 @@ public interface EMICalculator {
|
||||
/**
|
||||
* This method used for pay interest portion during the repayment transaction.
|
||||
*/
|
||||
void payInterest(ProgressiveLoanInterestScheduleModel scheduleModel, LocalDate repaymentPeriodDueDate, LocalDate transactionDate,
|
||||
Money interestAmount);
|
||||
void payInterest(ProgressiveLoanInterestScheduleModel scheduleModel, LocalDate repaymentPeriodFromDate,
|
||||
LocalDate repaymentPeriodDueDate, LocalDate transactionDate, Money interestAmount);
|
||||
|
||||
/**
|
||||
* This method used for pay principal portion during the repayment transaction.
|
||||
*/
|
||||
void payPrincipal(ProgressiveLoanInterestScheduleModel scheduleModel, LocalDate repaymentPeriodDueDate, LocalDate transactionDate,
|
||||
Money principalAmount);
|
||||
void payPrincipal(ProgressiveLoanInterestScheduleModel scheduleModel, LocalDate repaymentPeriodFromDate,
|
||||
LocalDate repaymentPeriodDueDate, LocalDate transactionDate, Money principalAmount);
|
||||
|
||||
/**
|
||||
* This method used for credit principal portion. This method increases the outstanding balance. This method creates
|
||||
@@ -120,15 +121,15 @@ public interface EMICalculator {
|
||||
* This method gives back the maximum of the due principal and maximum of the due interest for a requested day.
|
||||
*/
|
||||
@NotNull
|
||||
PeriodDueDetails getDueAmounts(@NotNull ProgressiveLoanInterestScheduleModel scheduleModel, @NotNull LocalDate periodDueDate,
|
||||
@NotNull LocalDate targetDate);
|
||||
PeriodDueDetails getDueAmounts(@NotNull ProgressiveLoanInterestScheduleModel scheduleModel, @NotNull LocalDate periodFromDate,
|
||||
@NotNull LocalDate periodDueDate, @NotNull LocalDate targetDate);
|
||||
|
||||
/**
|
||||
* Gives back the sum of the interest from the whole model on the given date.
|
||||
*/
|
||||
@NotNull
|
||||
Money getPeriodInterestTillDate(@NotNull ProgressiveLoanInterestScheduleModel scheduleModel, @NotNull LocalDate periodDueDate,
|
||||
@NotNull LocalDate targetDate, boolean includeChargebackInterest);
|
||||
Money getPeriodInterestTillDate(@NotNull ProgressiveLoanInterestScheduleModel scheduleModel, @NotNull LocalDate periodFromDate,
|
||||
@NotNull LocalDate periodDueDate, @NotNull LocalDate targetDate, boolean includeChargebackInterest);
|
||||
|
||||
Money getOutstandingLoanBalanceOfPeriod(ProgressiveLoanInterestScheduleModel interestScheduleModel, LocalDate targetDate);
|
||||
|
||||
|
||||
+93
-65
@@ -112,11 +112,11 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
||||
|
||||
@Override
|
||||
public Optional<RepaymentPeriod> findRepaymentPeriod(final ProgressiveLoanInterestScheduleModel scheduleModel,
|
||||
final LocalDate repaymentPeriodDueDate) {
|
||||
final LocalDate repaymentPeriodFromDate, final LocalDate repaymentPeriodDueDate) {
|
||||
if (scheduleModel == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return scheduleModel.findRepaymentPeriodByDueDate(repaymentPeriodDueDate);
|
||||
return scheduleModel.findRepaymentPeriodByFromAndDueDate(repaymentPeriodFromDate, repaymentPeriodDueDate);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -263,9 +263,9 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void payInterest(ProgressiveLoanInterestScheduleModel scheduleModel, LocalDate repaymentPeriodDueDate, LocalDate transactionDate,
|
||||
Money interestAmount) {
|
||||
Optional<RepaymentPeriod> repaymentPeriod = findRepaymentPeriod(scheduleModel, repaymentPeriodDueDate);
|
||||
public void payInterest(ProgressiveLoanInterestScheduleModel scheduleModel, LocalDate repaymentPeriodFromDate,
|
||||
LocalDate repaymentPeriodDueDate, LocalDate transactionDate, Money interestAmount) {
|
||||
Optional<RepaymentPeriod> repaymentPeriod = findRepaymentPeriod(scheduleModel, repaymentPeriodFromDate, repaymentPeriodDueDate);
|
||||
|
||||
Optional<RepaymentPeriod> latestNotLastOpenRepaymentPeriodBeforeDate = getLatestNotLastOpenRepaymentPeriodBeforeDate(scheduleModel,
|
||||
transactionDate);
|
||||
@@ -280,12 +280,12 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void payPrincipal(ProgressiveLoanInterestScheduleModel scheduleModel, LocalDate repaymentPeriodDueDate,
|
||||
LocalDate transactionDate, Money principalAmount) {
|
||||
public void payPrincipal(ProgressiveLoanInterestScheduleModel scheduleModel, LocalDate repaymentPeriodFromDate,
|
||||
LocalDate repaymentPeriodDueDate, LocalDate transactionDate, Money principalAmount) {
|
||||
if (MathUtil.isEmpty(principalAmount)) {
|
||||
return;
|
||||
}
|
||||
Optional<RepaymentPeriod> repaymentPeriod = findRepaymentPeriod(scheduleModel, repaymentPeriodDueDate);
|
||||
Optional<RepaymentPeriod> repaymentPeriod = findRepaymentPeriod(scheduleModel, repaymentPeriodFromDate, repaymentPeriodDueDate);
|
||||
repaymentPeriod.ifPresent(rp -> rp.addPaidPrincipalAmount(principalAmount));
|
||||
// If it is paid late, we need to calculate with the period due date
|
||||
LocalDate balanceCorrectionDate = DateUtils.isBefore(repaymentPeriodDueDate, transactionDate) ? repaymentPeriodDueDate
|
||||
@@ -379,11 +379,12 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
||||
*/
|
||||
@Override
|
||||
@NotNull
|
||||
public PeriodDueDetails getDueAmounts(@NotNull ProgressiveLoanInterestScheduleModel scheduleModel, @NotNull LocalDate periodDueDate,
|
||||
@NotNull LocalDate targetDate) {
|
||||
public PeriodDueDetails getDueAmounts(@NotNull ProgressiveLoanInterestScheduleModel scheduleModel, @NotNull LocalDate periodFromDate,
|
||||
@NotNull LocalDate periodDueDate, @NotNull LocalDate targetDate) {
|
||||
ProgressiveLoanInterestScheduleModel recalculatedScheduleModelTillDate = recalculateScheduleModelTillDate(scheduleModel,
|
||||
targetDate);
|
||||
RepaymentPeriod repaymentPeriod = recalculatedScheduleModelTillDate.findRepaymentPeriodByDueDate(periodDueDate).orElseThrow();
|
||||
RepaymentPeriod repaymentPeriod = recalculatedScheduleModelTillDate
|
||||
.findRepaymentPeriodByFromAndDueDate(periodFromDate, periodDueDate).orElseThrow();
|
||||
long notFullyRepaidRepaymentPeriodCount = recalculatedScheduleModelTillDate.repaymentPeriods().stream()
|
||||
.filter(rp -> !rp.isFullyPaid()).count();
|
||||
boolean multiplePeriodIsUnpaid = notFullyRepaidRepaymentPeriodCount > 1L;
|
||||
@@ -413,11 +414,12 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public Money getPeriodInterestTillDate(@NotNull ProgressiveLoanInterestScheduleModel scheduleModel, @NotNull LocalDate periodDueDate,
|
||||
@NotNull LocalDate targetDate, boolean includeCreditedInterest) {
|
||||
public Money getPeriodInterestTillDate(@NotNull ProgressiveLoanInterestScheduleModel scheduleModel, @NotNull LocalDate periodFromDate,
|
||||
@NotNull LocalDate periodDueDate, @NotNull LocalDate targetDate, boolean includeCreditedInterest) {
|
||||
ProgressiveLoanInterestScheduleModel recalculatedScheduleModelTillDate = recalculateScheduleModelTillDate(scheduleModel,
|
||||
targetDate);
|
||||
RepaymentPeriod repaymentPeriod = recalculatedScheduleModelTillDate.findRepaymentPeriodByDueDate(periodDueDate).orElseThrow();
|
||||
RepaymentPeriod repaymentPeriod = recalculatedScheduleModelTillDate
|
||||
.findRepaymentPeriodByFromAndDueDate(periodFromDate, periodDueDate).orElseThrow();
|
||||
return includeCreditedInterest ? repaymentPeriod.getCalculatedDueInterest()
|
||||
: repaymentPeriod.getCalculatedDueInterest().minus(repaymentPeriod.getCreditedInterest(),
|
||||
recalculatedScheduleModelTillDate.mc());
|
||||
@@ -572,15 +574,20 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
||||
|
||||
@Override
|
||||
public void updateModelRepaymentPeriodsDuringReAge(final ProgressiveLoanInterestScheduleModel scheduleModel,
|
||||
final LocalDate reAgePeriodStartDate, LocalDate reageFirstDueDate, LocalDate targetDate,
|
||||
final LocalDate reAgePeriodStartDate, final LocalDate reAgeFirstDueDate, final LocalDate targetDate,
|
||||
final LoanApplicationTerms loanApplicationTerms, final MathContext mc) {
|
||||
moveOutstandingAmountsFromPeriodsBeforeReAging(scheduleModel.repaymentPeriods(), targetDate);
|
||||
|
||||
moveOutstandingAmountsFromPeriodsBeforeReAging(scheduleModel.repaymentPeriods(), reageFirstDueDate);
|
||||
// calculate already paid balances from transaction date
|
||||
final OutstandingDetails paidBalancesFromTransactionDate = calculatePaidBalancesAfterDate(scheduleModel, targetDate);
|
||||
|
||||
accelerateMaturityDateTo(scheduleModel, targetDate);
|
||||
|
||||
final ProgressiveLoanInterestScheduleModel temporaryReAgedScheduleModel = generateTemporaryReAgedScheduleModel(loanApplicationTerms,
|
||||
mc, reAgePeriodStartDate);
|
||||
|
||||
mergeNewInterestScheduleModelWithExistingOne(scheduleModel, temporaryReAgedScheduleModel, reageFirstDueDate, targetDate);
|
||||
mergeNewInterestScheduleModelWithExistingOne(scheduleModel, temporaryReAgedScheduleModel, reAgeFirstDueDate, targetDate,
|
||||
paidBalancesFromTransactionDate);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -634,7 +641,9 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
||||
private List<RepaymentPeriod> findPossiblyOverdueRepaymentPeriods(final LocalDate targetDate,
|
||||
final ProgressiveLoanInterestScheduleModel model) {
|
||||
return model.repaymentPeriods().stream() //
|
||||
.filter(repaymentPeriod -> DateUtils.isAfter(targetDate, repaymentPeriod.getDueDate())).toList();
|
||||
.filter(repaymentPeriod -> !repaymentPeriod.isReAgedEarlyRepaymentHolder()
|
||||
&& DateUtils.isAfter(targetDate, repaymentPeriod.getDueDate()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
private boolean adjustOverduePrincipal(final LocalDate currentDate, final RepaymentPeriod currentInstallment,
|
||||
@@ -694,8 +703,8 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
||||
* significantly from other periods.
|
||||
*/
|
||||
private void mergeNewInterestScheduleModelWithExistingOne(final ProgressiveLoanInterestScheduleModel scheduleModel,
|
||||
final ProgressiveLoanInterestScheduleModel temporaryReAgedScheduleModel, final LocalDate reageFirstDueDate,
|
||||
LocalDate targetDate) {
|
||||
final ProgressiveLoanInterestScheduleModel temporaryReAgedScheduleModel, final LocalDate reAgeFirstDueDate,
|
||||
final LocalDate targetDate, final OutstandingDetails paidBalancesFromTransactionDate) {
|
||||
final List<RepaymentPeriod> newPeriods = temporaryReAgedScheduleModel.repaymentPeriods();
|
||||
|
||||
if (newPeriods.isEmpty()) {
|
||||
@@ -706,46 +715,44 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
||||
final RepaymentPeriod firstRepaymentPeriod = existingRepaymentPeriods.getFirst();
|
||||
final Money disbursedAmount = firstRepaymentPeriod.getTotalDisbursedAmount();
|
||||
|
||||
final Optional<RepaymentPeriod> firstExistingReAgedRepaymentPeriodOpt = existingRepaymentPeriods.stream()
|
||||
.filter(period -> period.getDueDate().equals(reageFirstDueDate)).findFirst();
|
||||
if (!paidBalancesFromTransactionDate.getOutstandingInterest().isZero()
|
||||
|| !paidBalancesFromTransactionDate.getOutstandingPrincipal().isZero()) {
|
||||
createRepaymentPeriodForEarlyRepaidAmountsDuringReAgeing(scheduleModel,
|
||||
paidBalancesFromTransactionDate.getOutstandingPrincipal(), paidBalancesFromTransactionDate.getOutstandingInterest(),
|
||||
false);
|
||||
}
|
||||
|
||||
for (final RepaymentPeriod newPeriod : newPeriods) {
|
||||
final Optional<RepaymentPeriod> existingRepaymentPeriodOpt = existingRepaymentPeriods.stream().filter(
|
||||
period -> period.getFromDate().equals(newPeriod.getFromDate()) && period.getDueDate().equals(newPeriod.getDueDate()))
|
||||
.findFirst();
|
||||
Optional<RepaymentPeriod> previousExistingRepaymentPeriodOpt = Optional.empty();
|
||||
if (existingRepaymentPeriodOpt.isPresent() && firstExistingReAgedRepaymentPeriodOpt.isPresent()
|
||||
&& existingRepaymentPeriodOpt.get().equals(firstExistingReAgedRepaymentPeriodOpt.get())) {
|
||||
previousExistingRepaymentPeriodOpt = existingRepaymentPeriodOpt.get().getPrevious();
|
||||
}
|
||||
|
||||
final Money newPrincipal = newPeriod.getDuePrincipal();
|
||||
final Money newInterest = newPeriod.getDueInterest();
|
||||
|
||||
final RepaymentPeriod rp = RepaymentPeriod.create(
|
||||
previousExistingRepaymentPeriodOpt.orElseGet(existingRepaymentPeriods::getLast), newPeriod.getFromDate(),
|
||||
newPeriod.getDueDate(), newPrincipal.add(newInterest), scheduleModel.mc(), scheduleModel.loanProductRelatedDetail());
|
||||
rp.setTotalDisbursedAmount(disbursedAmount);
|
||||
if (reAgeFirstDueDate.isEqual(scheduleModel.getStartDate()) && newPeriod.equals(newPeriods.getFirst())) {
|
||||
final RepaymentPeriod firstPeriod = existingRepaymentPeriods.getFirst();
|
||||
firstPeriod.setDueDate(newPeriod.getDueDate());
|
||||
firstPeriod.getInterestPeriods().getLast().setDueDate(newPeriod.getDueDate());
|
||||
firstPeriod.setEmi(newPrincipal.add(newInterest));
|
||||
calculateRateFactorForRepaymentPeriod(firstRepaymentPeriod, scheduleModel);
|
||||
} else {
|
||||
final RepaymentPeriod rp = RepaymentPeriod.create(
|
||||
!existingRepaymentPeriods.isEmpty() ? existingRepaymentPeriods.getLast() : null,
|
||||
(newPeriod.equals(newPeriods.getFirst()) && !existingRepaymentPeriods.isEmpty())
|
||||
? existingRepaymentPeriods.getLast().getDueDate()
|
||||
: newPeriod.getFromDate(),
|
||||
newPeriod.getDueDate(), newPrincipal.add(newInterest), scheduleModel.mc(),
|
||||
scheduleModel.loanProductRelatedDetail());
|
||||
rp.setTotalDisbursedAmount(disbursedAmount);
|
||||
|
||||
existingRepaymentPeriodOpt.ifPresent(existingRepaymentPeriods::remove);
|
||||
|
||||
existingRepaymentPeriods.add(rp);
|
||||
calculateRateFactorForRepaymentPeriod(rp, scheduleModel);
|
||||
existingRepaymentPeriods.add(rp);
|
||||
calculateRateFactorForRepaymentPeriod(rp, scheduleModel);
|
||||
}
|
||||
}
|
||||
|
||||
final List<RepaymentPeriod> reAgedRepaymentPeriods = existingRepaymentPeriods.stream()
|
||||
.filter(repaymentPeriod -> (!repaymentPeriod.getFromDate().isBefore(reageFirstDueDate)
|
||||
|| repaymentPeriod.getDueDate().isEqual(reageFirstDueDate))
|
||||
&& !repaymentPeriod.getDueDate().isAfter(newPeriods.getLast().getDueDate()))
|
||||
.filter(repaymentPeriod -> (repaymentPeriod.getFromDate().isEqual(targetDate)
|
||||
&& repaymentPeriod.getDueDate().isEqual(reAgeFirstDueDate))
|
||||
|| !repaymentPeriod.getFromDate().isBefore(reAgeFirstDueDate))
|
||||
.toList();
|
||||
|
||||
// cleanup repayment periods after re-aging
|
||||
if (reAgedRepaymentPeriods.getLast() != null) {
|
||||
final List<RepaymentPeriod> repaymentPeriodsToRemove = existingRepaymentPeriods.stream()
|
||||
.filter(rp -> !rp.getFromDate().isBefore(reAgedRepaymentPeriods.getLast().getDueDate())).toList();
|
||||
repaymentPeriodsToRemove.forEach(existingRepaymentPeriods::remove);
|
||||
}
|
||||
|
||||
calculateOutstandingBalance(scheduleModel);
|
||||
calculateLastUnpaidRepaymentPeriodEMI(scheduleModel, targetDate);
|
||||
checkAndAdjustEmiIfNeededOnRelatedRepaymentPeriods(scheduleModel, reAgedRepaymentPeriods);
|
||||
@@ -773,13 +780,20 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
||||
* principal that was moved.
|
||||
*/
|
||||
private static void moveOutstandingAmountsFromPeriodsBeforeReAging(final List<RepaymentPeriod> existingRepaymentPeriods,
|
||||
final LocalDate reAgingStartDate) {
|
||||
final LocalDate transactionDate) {
|
||||
final List<RepaymentPeriod> periodsBeforeReAging = existingRepaymentPeriods.stream()
|
||||
.filter(rp -> rp.getFromDate().isBefore(reAgingStartDate) && !rp.isFullyPaid()).toList();
|
||||
.filter(rp -> !rp.getFromDate().isAfter(transactionDate) && !rp.isFullyPaid()).toList();
|
||||
|
||||
periodsBeforeReAging.forEach(rp -> {
|
||||
rp.getInterestPeriods().stream().filter(ip -> ip.getDueDate().isEqual(transactionDate)).forEach(ip -> {
|
||||
if (!ip.getBalanceCorrectionAmount().isZero()) {
|
||||
ip.addBalanceCorrectionAmount(ip.getBalanceCorrectionAmount().negated());
|
||||
}
|
||||
});
|
||||
final InterestPeriod lastInterestPeriod = rp.getInterestPeriods().getLast();
|
||||
lastInterestPeriod.addBalanceCorrectionAmount(rp.getOutstandingPrincipal().negated());
|
||||
if (!lastInterestPeriod.getBalanceCorrectionAmount().isZero()) {
|
||||
lastInterestPeriod.addBalanceCorrectionAmount(rp.getOutstandingPrincipal().negated());
|
||||
}
|
||||
rp.setEmi(rp.getTotalPaidAmount());
|
||||
rp.setOutstandingMovedDueToReAging(true);
|
||||
});
|
||||
@@ -876,10 +890,12 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
||||
if (newScheduleModel == null) {
|
||||
newScheduleModel = scheduleModel.deepCopy(mc);
|
||||
}
|
||||
final LocalDate relatedPeriodsFirstFromDate = relatedRepaymentPeriods.getFirst().getFromDate();
|
||||
final LocalDate relatedPeriodsFirstDueDate = relatedRepaymentPeriods.getFirst().getDueDate();
|
||||
newScheduleModel.repaymentPeriods().forEach(period -> {
|
||||
if (!period.getDueDate().isBefore(relatedPeriodsFirstDueDate)
|
||||
&& !adjustedEqualMonthlyInstallmentValue.isLessThan(period.getTotalPaidAmount())) {
|
||||
if (!period.getFromDate().isBefore(relatedPeriodsFirstFromDate) && !period.getDueDate().isBefore(relatedPeriodsFirstDueDate)
|
||||
&& !adjustedEqualMonthlyInstallmentValue.isLessThan(period.getTotalPaidAmount())
|
||||
&& !period.isReAgedEarlyRepaymentHolder()) {
|
||||
period.setEmi(adjustedEqualMonthlyInstallmentValue);
|
||||
period.setOriginalEmi(adjustedEqualMonthlyInstallmentValue);
|
||||
}
|
||||
@@ -891,7 +907,8 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
||||
}
|
||||
|
||||
final Iterator<RepaymentPeriod> relatedPeriodFromNewModelIterator = newScheduleModel.repaymentPeriods().stream()//
|
||||
.filter(period -> !period.getDueDate().isBefore(relatedPeriodsFirstDueDate))//
|
||||
.filter(period -> !period.getFromDate().isBefore(relatedPeriodsFirstFromDate)
|
||||
&& !period.getDueDate().isBefore(relatedPeriodsFirstDueDate) && !period.isReAgedEarlyRepaymentHolder())//
|
||||
.toList().iterator();//
|
||||
|
||||
relatedRepaymentPeriods.forEach(relatedRepaymentPeriod -> {
|
||||
@@ -1071,7 +1088,10 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
||||
calculatedDate = seedDate.plus(multiplicator, chronoUnit);
|
||||
multiplicator++;
|
||||
} while (calculatedDate.isBefore(repaymentPeriod.getDueDate()));
|
||||
return calculatedDate.equals(repaymentPeriod.getDueDate()) ? seedDate : repaymentPeriod.getFromDate();
|
||||
return calculatedDate.equals(repaymentPeriod.getDueDate()) && calculatedDate
|
||||
.minus(scheduleModel.loanProductRelatedDetail().getRepayEvery(), chronoUnit).isEqual(repaymentPeriod.getFromDate())
|
||||
? seedDate
|
||||
: repaymentPeriod.getFromDate();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1563,8 +1583,9 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
||||
*/
|
||||
@Override
|
||||
public Money getSumOfDueInterestsOnDate(ProgressiveLoanInterestScheduleModel scheduleModel, LocalDate subjectDate) {
|
||||
return scheduleModel.repaymentPeriods().stream().map(RepaymentPeriod::getDueDate) //
|
||||
.map(repaymentPeriodDueDate -> getDueAmounts(scheduleModel, repaymentPeriodDueDate, subjectDate) //
|
||||
return scheduleModel.repaymentPeriods().stream() //
|
||||
.map(repaymentPeriod -> getDueAmounts(scheduleModel, repaymentPeriod.getFromDate(), repaymentPeriod.getDueDate(),
|
||||
subjectDate) //
|
||||
.getDueInterest()) //
|
||||
.reduce(scheduleModel.zero(), Money::add); //
|
||||
}
|
||||
@@ -1663,7 +1684,9 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
||||
if (!paidBalancesFromTransactionDate.getOutstandingInterest().isZero()
|
||||
|| !paidBalancesFromTransactionDate.getOutstandingPrincipal().isZero()) {
|
||||
createRepaymentPeriodForEarlyRepaidAmountsDuringReAgeing(interestSchedule,
|
||||
paidBalancesFromTransactionDate.getOutstandingPrincipal(), paidBalancesFromTransactionDate.getOutstandingInterest());
|
||||
paidBalancesFromTransactionDate.getOutstandingPrincipal(), paidBalancesFromTransactionDate.getOutstandingInterest(),
|
||||
true);
|
||||
addFirstReAgedPeriod(interestSchedule, interestSchedule.getLastRepaymentPeriod());
|
||||
}
|
||||
|
||||
updateModelForReageEqualAmortization(interestSchedule, reageParameter, reAgedRepaymentPeriods, isAfterOriginalMaturityDate);
|
||||
@@ -1717,18 +1740,23 @@ public final class ProgressiveEMICalculator implements EMICalculator {
|
||||
}
|
||||
}
|
||||
|
||||
private void createRepaymentPeriodForEarlyRepaidAmountsDuringReAgeing(ProgressiveLoanInterestScheduleModel interestSchedule,
|
||||
Money totalPaidPrincipal, Money totalPaidInterest) {
|
||||
RepaymentPeriod targetPeriod = interestSchedule.getLastRepaymentPeriod();
|
||||
private void createRepaymentPeriodForEarlyRepaidAmountsDuringReAgeing(final ProgressiveLoanInterestScheduleModel interestSchedule,
|
||||
final Money totalPaidPrincipal, final Money totalPaidInterest, final boolean isReAged) {
|
||||
final RepaymentPeriod targetPeriod = interestSchedule.getLastRepaymentPeriod();
|
||||
|
||||
Money paidInterestToAdd = totalPaidInterest.minus(targetPeriod.getPaidInterest());
|
||||
Money paidPrincipalToAdd = totalPaidPrincipal.minus(targetPeriod.getPaidPrincipal());
|
||||
final Money paidInterestToAdd = totalPaidInterest.minus(targetPeriod.getPaidInterest());
|
||||
final Money paidPrincipalToAdd = totalPaidPrincipal.minus(targetPeriod.getPaidPrincipal());
|
||||
targetPeriod.addPaidInterestAmount(paidInterestToAdd);
|
||||
targetPeriod.addPaidPrincipalAmount(paidPrincipalToAdd);
|
||||
targetPeriod.setEmi(targetPeriod.getTotalPaidAmount());
|
||||
targetPeriod.setReAged(true);
|
||||
if (isReAged) {
|
||||
targetPeriod.setReAged(true);
|
||||
}
|
||||
targetPeriod.setReAgedEarlyRepaymentHolder(true);
|
||||
calculateRateFactorForRepaymentPeriod(targetPeriod, interestSchedule);
|
||||
}
|
||||
|
||||
private static void addFirstReAgedPeriod(ProgressiveLoanInterestScheduleModel interestSchedule, RepaymentPeriod targetPeriod) {
|
||||
RepaymentPeriod repaymentPeriodToInsert = RepaymentPeriod.create(targetPeriod, targetPeriod.getDueDate(),
|
||||
interestSchedule.getMaturityDate(), interestSchedule.zero(), interestSchedule.mc(),
|
||||
interestSchedule.loanProductRelatedDetail());
|
||||
|
||||
+4
-2
@@ -143,12 +143,14 @@ public class ProgressiveLoanInterestScheduleModel {
|
||||
interestRates.add(new InterestRate(newInterestEffectiveDate, newInterestRate));
|
||||
}
|
||||
|
||||
public Optional<RepaymentPeriod> findRepaymentPeriodByDueDate(final LocalDate repaymentPeriodDueDate) {
|
||||
public Optional<RepaymentPeriod> findRepaymentPeriodByFromAndDueDate(final LocalDate repaymentPeriodFromDate,
|
||||
final LocalDate repaymentPeriodDueDate) {
|
||||
if (repaymentPeriodDueDate == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
return repaymentPeriods.stream()//
|
||||
.filter(repaymentPeriodItem -> DateUtils.isEqual(repaymentPeriodItem.getDueDate(), repaymentPeriodDueDate))//
|
||||
.filter(repaymentPeriodItem -> DateUtils.isEqual(repaymentPeriodItem.getFromDate(), repaymentPeriodFromDate)
|
||||
&& DateUtils.isEqual(repaymentPeriodItem.getDueDate(), repaymentPeriodDueDate))//
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -507,9 +507,10 @@ class AdvancedPaymentScheduleTransactionProcessorTest {
|
||||
ArgumentCaptor<Money> paidPortionCaptor = ArgumentCaptor.forClass(Money.class);
|
||||
ArgumentCaptor<LocalDate> payDateCaptor = ArgumentCaptor.forClass(LocalDate.class);
|
||||
|
||||
final LocalDate repaymentPeriodFromDate = transactionDate.minusMonths(1);
|
||||
// Verify `payPrincipal` is called when allocation type is DUE_PRINCIPAL
|
||||
Mockito.verify(emiCalculator, atLeastOnce()).payPrincipal(eq(model), eq(transactionDate), payDateCaptor.capture(),
|
||||
paidPortionCaptor.capture());
|
||||
Mockito.verify(emiCalculator, atLeastOnce()).payPrincipal(eq(model), eq(repaymentPeriodFromDate), eq(transactionDate),
|
||||
payDateCaptor.capture(), paidPortionCaptor.capture());
|
||||
Money paidPortion = paidPortionCaptor.getValue();
|
||||
LocalDate payDate = payDateCaptor.getValue();
|
||||
|
||||
|
||||
+216
-147
@@ -447,10 +447,13 @@ class ProgressiveEMICalculatorTest {
|
||||
|
||||
final Money disbursedAmount = toMoney(100.0);
|
||||
emiCalculator.addDisbursement(interestModel, LocalDate.of(2024, 1, 1), disbursedAmount);
|
||||
emiCalculator.payInterest(interestModel, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1), toMoney(0.58));
|
||||
emiCalculator.payPrincipal(interestModel, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1), toMoney(16.43));
|
||||
emiCalculator.payInterest(interestModel, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
toMoney(0.58));
|
||||
emiCalculator.payPrincipal(interestModel, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
toMoney(16.43));
|
||||
|
||||
emiCalculator.payPrincipal(interestModel, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 2, 1), toMoney(16.90));
|
||||
emiCalculator.payPrincipal(interestModel, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1), LocalDate.of(2024, 2, 1),
|
||||
toMoney(16.90));
|
||||
|
||||
final BigDecimal interestRateNewValue = BigDecimal.valueOf(4.0);
|
||||
final LocalDate interestChangeDate = LocalDate.of(2024, 2, 2);
|
||||
@@ -495,7 +498,8 @@ class ProgressiveEMICalculatorTest {
|
||||
final Money disbursedAmount = toMoney(100.0);
|
||||
emiCalculator.addDisbursement(interestModel, LocalDate.of(2024, 1, 1), disbursedAmount);
|
||||
|
||||
emiCalculator.payPrincipal(interestModel, LocalDate.of(2024, 7, 1), LocalDate.of(2024, 1, 15), toMoney(17.01));
|
||||
emiCalculator.payPrincipal(interestModel, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 7, 1), LocalDate.of(2024, 1, 15),
|
||||
toMoney(17.01));
|
||||
|
||||
final BigDecimal interestRateNewValue = BigDecimal.valueOf(4.0);
|
||||
final LocalDate interestChangeDate = LocalDate.of(2024, 1, 20);
|
||||
@@ -588,12 +592,14 @@ class ProgressiveEMICalculatorTest {
|
||||
emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount);
|
||||
|
||||
// schedule 1st period 1st day
|
||||
PeriodDueDetails dueAmounts = emiCalculator.getDueAmounts(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 1, 1));
|
||||
PeriodDueDetails dueAmounts = emiCalculator.getDueAmounts(interestSchedule, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1),
|
||||
LocalDate.of(2024, 1, 1));
|
||||
Assertions.assertEquals(17.01, toDouble(dueAmounts.getDuePrincipal()));
|
||||
Assertions.assertEquals(0.0, toDouble(dueAmounts.getDueInterest()));
|
||||
|
||||
// schedule 2nd period last day
|
||||
dueAmounts = emiCalculator.getDueAmounts(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 3, 1));
|
||||
dueAmounts = emiCalculator.getDueAmounts(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1),
|
||||
LocalDate.of(2024, 3, 1));
|
||||
Assertions.assertEquals(16.52, toDouble(dueAmounts.getDuePrincipal()));
|
||||
Assertions.assertEquals(0.49, toDouble(dueAmounts.getDueInterest()));
|
||||
|
||||
@@ -603,13 +609,15 @@ class ProgressiveEMICalculatorTest {
|
||||
final Money op1stCorrectionAmount = toMoney(16.77);
|
||||
|
||||
// get remaining balance and dues for a date
|
||||
final PeriodDueDetails repaymentDetails1st = emiCalculator.getDueAmounts(interestSchedule, op1stCorrectionPeriodDueDate,
|
||||
op1stCorrectionDate);
|
||||
final PeriodDueDetails repaymentDetails1st = emiCalculator.getDueAmounts(interestSchedule, LocalDate.of(2024, 2, 1),
|
||||
op1stCorrectionPeriodDueDate, op1stCorrectionDate);
|
||||
Assertions.assertEquals(16.77, toDouble(repaymentDetails1st.getDuePrincipal()));
|
||||
Assertions.assertEquals(0.24, toDouble(repaymentDetails1st.getDueInterest()));
|
||||
|
||||
emiCalculator.payPrincipal(interestSchedule, op1stCorrectionPeriodDueDate, op1stCorrectionDate, op1stCorrectionAmount);
|
||||
emiCalculator.payInterest(interestSchedule, op1stCorrectionPeriodDueDate, op1stCorrectionDate, toMoney(0.24));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), op1stCorrectionPeriodDueDate, op1stCorrectionDate,
|
||||
op1stCorrectionAmount);
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 2, 1), op1stCorrectionPeriodDueDate, op1stCorrectionDate,
|
||||
toMoney(0.24));
|
||||
|
||||
checkPeriod(interestSchedule, 0, 1, 17.01, 0.005833333333, 0.5833333333, 0.58, 16.43, 83.57);
|
||||
checkPeriod(interestSchedule, 1, 0, 17.01, 0.002816091954, 0.235340804584, 0.24, 16.77, 66.80);
|
||||
@@ -625,13 +633,15 @@ class ProgressiveEMICalculatorTest {
|
||||
final Money op2ndCorrectionAmount = toMoney(16.42);
|
||||
|
||||
// get remaining balance and dues for a date
|
||||
final PeriodDueDetails repaymentDetails2st = emiCalculator.getDueAmounts(interestSchedule, op2ndCorrectionPeriodDueDate,
|
||||
op2ndCorrectionDate);
|
||||
final PeriodDueDetails repaymentDetails2st = emiCalculator.getDueAmounts(interestSchedule, LocalDate.of(2024, 3, 1),
|
||||
op2ndCorrectionPeriodDueDate, op2ndCorrectionDate);
|
||||
Assertions.assertEquals(16.81, toDouble(repaymentDetails2st.getDuePrincipal()));
|
||||
Assertions.assertEquals(0.20, toDouble(repaymentDetails2st.getDueInterest()));
|
||||
|
||||
emiCalculator.payPrincipal(interestSchedule, op2ndCorrectionPeriodDueDate, op2ndCorrectionDate, op2ndCorrectionAmount);
|
||||
emiCalculator.payInterest(interestSchedule, op2ndCorrectionPeriodDueDate, op2ndCorrectionDate, toMoney(0.49));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 3, 1), op2ndCorrectionPeriodDueDate, op2ndCorrectionDate,
|
||||
op2ndCorrectionAmount);
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 3, 1), op2ndCorrectionPeriodDueDate, op2ndCorrectionDate,
|
||||
toMoney(0.49));
|
||||
|
||||
checkPeriod(interestSchedule, 0, 1, 17.01, 0.005833333333, 0.5833333333, 0.58, 16.43, 83.57);
|
||||
checkPeriod(interestSchedule, 1, 0, 17.01, 0.002816091954, 0.235340804584, 0.24, 16.77, 50.38);
|
||||
@@ -644,14 +654,16 @@ class ProgressiveEMICalculatorTest {
|
||||
// check numbers on last period due date
|
||||
LocalDate periodDueDate = LocalDate.of(2024, 7, 1);
|
||||
LocalDate payDate = LocalDate.of(2024, 7, 1);
|
||||
final PeriodDueDetails repaymentDetails3rd = emiCalculator.getDueAmounts(interestSchedule, periodDueDate, payDate);
|
||||
final PeriodDueDetails repaymentDetails3rd = emiCalculator.getDueAmounts(interestSchedule, LocalDate.of(2024, 6, 1), periodDueDate,
|
||||
payDate);
|
||||
Assertions.assertEquals(16.75, toDouble(repaymentDetails3rd.getDuePrincipal()));
|
||||
Assertions.assertEquals(0.1, toDouble(repaymentDetails3rd.getDueInterest()));
|
||||
|
||||
// check numbers after the last period due date
|
||||
periodDueDate = LocalDate.of(2024, 7, 1);
|
||||
payDate = LocalDate.of(2024, 7, 15);
|
||||
final PeriodDueDetails repaymentDetails4th = emiCalculator.getDueAmounts(interestSchedule, periodDueDate, payDate);
|
||||
final PeriodDueDetails repaymentDetails4th = emiCalculator.getDueAmounts(interestSchedule, LocalDate.of(2024, 6, 1), periodDueDate,
|
||||
payDate);
|
||||
Assertions.assertEquals(16.75, toDouble(repaymentDetails4th.getDuePrincipal()));
|
||||
Assertions.assertEquals(0.1, toDouble(repaymentDetails4th.getDueInterest()));
|
||||
|
||||
@@ -700,30 +712,41 @@ class ProgressiveEMICalculatorTest {
|
||||
final Money op1stCorrectionAmount = toMoney(15.0);
|
||||
|
||||
// get remaining balance and dues for a date
|
||||
final PeriodDueDetails repaymentDetails1st = emiCalculator.getDueAmounts(interestSchedule, op1stCorrectionPeriodDueDate,
|
||||
op1stCorrectionDate);
|
||||
final PeriodDueDetails repaymentDetails1st = emiCalculator.getDueAmounts(interestSchedule, LocalDate.of(2024, 2, 1),
|
||||
op1stCorrectionPeriodDueDate, op1stCorrectionDate);
|
||||
Assertions.assertEquals(16.77, toDouble(repaymentDetails1st.getDuePrincipal()));
|
||||
Assertions.assertEquals(0.24, toDouble(repaymentDetails1st.getDueInterest()));
|
||||
|
||||
// check getDueAmounts forcast
|
||||
PeriodDueDetails details = emiCalculator.getDueAmounts(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 3, 1));
|
||||
PeriodDueDetails details = emiCalculator.getDueAmounts(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1),
|
||||
LocalDate.of(2024, 3, 1));
|
||||
Assertions.assertEquals(16.52, toDouble(details.getDuePrincipal()));
|
||||
Assertions.assertEquals(0.49, toDouble(details.getDueInterest()));
|
||||
|
||||
// apply balance change and check again
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), op1stCorrectionDate, op1stCorrectionAmount);
|
||||
details = emiCalculator.getDueAmounts(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 3, 1));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1), op1stCorrectionDate,
|
||||
op1stCorrectionAmount);
|
||||
details = emiCalculator.getDueAmounts(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1),
|
||||
LocalDate.of(2024, 3, 1));
|
||||
Assertions.assertEquals(16.52, toDouble(details.getDuePrincipal()));
|
||||
Assertions.assertEquals(0.49, toDouble(details.getDueInterest()));
|
||||
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 15), toMoney(1.43));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 15), toMoney(0.58));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 2, 15), toMoney(16.77));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 2, 15), toMoney(0.24));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 2, 15), toMoney(17.01));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 5, 1), LocalDate.of(2024, 2, 15), toMoney(17.01));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 2, 15), toMoney(17.01));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 7, 1), LocalDate.of(2024, 2, 15), toMoney(15.77));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 15),
|
||||
toMoney(1.43));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 15),
|
||||
toMoney(0.58));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1), LocalDate.of(2024, 2, 15),
|
||||
toMoney(16.77));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1), LocalDate.of(2024, 2, 15),
|
||||
toMoney(0.24));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 4, 1), LocalDate.of(2024, 2, 15),
|
||||
toMoney(17.01));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 5, 1), LocalDate.of(2024, 2, 15),
|
||||
toMoney(17.01));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 5, 1), LocalDate.of(2024, 6, 1), LocalDate.of(2024, 2, 15),
|
||||
toMoney(17.01));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 7, 1), LocalDate.of(2024, 2, 15),
|
||||
toMoney(15.77));
|
||||
|
||||
// check periods in model
|
||||
|
||||
@@ -766,28 +789,37 @@ class ProgressiveEMICalculatorTest {
|
||||
emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount);
|
||||
|
||||
// get remaining balance and dues on due date
|
||||
PeriodDueDetails dueAmounts = emiCalculator.getDueAmounts(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1));
|
||||
PeriodDueDetails dueAmounts = emiCalculator.getDueAmounts(interestSchedule, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1),
|
||||
LocalDate.of(2024, 2, 1));
|
||||
Assertions.assertEquals(16.43, toDouble(dueAmounts.getDuePrincipal()));
|
||||
Assertions.assertEquals(0.58, toDouble(dueAmounts.getDueInterest()));
|
||||
|
||||
// check numbers on payoff date
|
||||
dueAmounts = emiCalculator.getDueAmounts(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 1, 15));
|
||||
dueAmounts = emiCalculator.getDueAmounts(interestSchedule, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1),
|
||||
LocalDate.of(2024, 1, 15));
|
||||
Assertions.assertEquals(16.75, toDouble(dueAmounts.getDuePrincipal()));
|
||||
Assertions.assertEquals(0.26, toDouble(dueAmounts.getDueInterest()));
|
||||
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 1, 15), toMoney(16.75));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 1, 15), toMoney(0.26));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1), LocalDate.of(2024, 1, 15),
|
||||
toMoney(16.75));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1), LocalDate.of(2024, 1, 15),
|
||||
toMoney(0.26));
|
||||
|
||||
// check again numbers are zero
|
||||
// dueAmounts = emiCalculator.getdueAmounts(interestSchedule, LocalDate.of(2024, 2, 1),
|
||||
// LocalDate.of(2024, 2, 1));
|
||||
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 1, 15), toMoney(17.01));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 1, 15), toMoney(17.01));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 5, 1), LocalDate.of(2024, 1, 15), toMoney(17.01));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 1, 15), toMoney(17.01));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1), LocalDate.of(2024, 1, 15),
|
||||
toMoney(17.01));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 4, 1), LocalDate.of(2024, 1, 15),
|
||||
toMoney(17.01));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 5, 1), LocalDate.of(2024, 1, 15),
|
||||
toMoney(17.01));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 5, 1), LocalDate.of(2024, 6, 1), LocalDate.of(2024, 1, 15),
|
||||
toMoney(17.01));
|
||||
|
||||
dueAmounts = emiCalculator.getDueAmounts(interestSchedule, LocalDate.of(2024, 7, 1), LocalDate.of(2024, 7, 1));
|
||||
dueAmounts = emiCalculator.getDueAmounts(interestSchedule, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 7, 1),
|
||||
LocalDate.of(2024, 7, 1));
|
||||
Assertions.assertEquals(15.21, toDouble(dueAmounts.getDuePrincipal()));
|
||||
Assertions.assertEquals(0.5, toDouble(dueAmounts.getDueInterest()));
|
||||
|
||||
@@ -801,7 +833,8 @@ class ProgressiveEMICalculatorTest {
|
||||
checkPeriod(interestSchedule, 4, 0, 17.01, 0.005833333333, 0.0887249999949, 0.0, 17.01, 15.21);
|
||||
checkPeriod(interestSchedule, 5, 0, 15.71, 0.005833333333, 0.0887249999949, 0.5, 15.21, 0.0);
|
||||
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 7, 1), LocalDate.of(2024, 1, 15), toMoney(15.21));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 7, 1), LocalDate.of(2024, 1, 15),
|
||||
toMoney(15.21));
|
||||
|
||||
// check periods in model
|
||||
checkPeriod(interestSchedule, 0, 0, 17.01, 0.0, 0.0, 0.26, 16.75, 0.0);
|
||||
@@ -1023,12 +1056,18 @@ class ProgressiveEMICalculatorTest {
|
||||
Assertions.assertEquals(6.15, toDouble(interestSchedule.getTotalDueInterest()));
|
||||
|
||||
// pay back the whole loan on first day
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 1, 1), toMoney(51.03));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 1, 1), toMoney(51.03));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 1, 1), toMoney(51.03));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 5, 1), LocalDate.of(2024, 1, 1), toMoney(51.03));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 1, 1), toMoney(51.03));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 7, 1), LocalDate.of(2024, 1, 1), toMoney(44.85));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1), LocalDate.of(2024, 1, 1),
|
||||
toMoney(51.03));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1), LocalDate.of(2024, 1, 1),
|
||||
toMoney(51.03));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 4, 1), LocalDate.of(2024, 1, 1),
|
||||
toMoney(51.03));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 5, 1), LocalDate.of(2024, 1, 1),
|
||||
toMoney(51.03));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 5, 1), LocalDate.of(2024, 6, 1), LocalDate.of(2024, 1, 1),
|
||||
toMoney(51.03));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 7, 1), LocalDate.of(2024, 1, 1),
|
||||
toMoney(44.85));
|
||||
|
||||
checkTotalInterestDue(interestSchedule, 0.0);
|
||||
|
||||
@@ -1208,11 +1247,12 @@ class ProgressiveEMICalculatorTest {
|
||||
emiCalculator.addDisbursement(interestSchedule, disbursementDate, disbursedAmount);
|
||||
|
||||
for (int i = 0; i < 12; i++) {
|
||||
LocalDate fromDate = expectedRepaymentPeriods.get(i).getFromDate();
|
||||
LocalDate dueDate = expectedRepaymentPeriods.get(i).getDueDate();
|
||||
PeriodDueDetails dueAmounts = emiCalculator.getDueAmounts(interestSchedule, dueDate, disbursementDate);
|
||||
PeriodDueDetails dueAmounts = emiCalculator.getDueAmounts(interestSchedule, fromDate, dueDate, disbursementDate);
|
||||
Money duePrincipal = dueAmounts.getDuePrincipal();
|
||||
if (duePrincipal.isGreaterThanZero()) {
|
||||
emiCalculator.payPrincipal(interestSchedule, dueDate, disbursementDate, duePrincipal);
|
||||
emiCalculator.payPrincipal(interestSchedule, fromDate, dueDate, disbursementDate, duePrincipal);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1321,7 +1361,7 @@ class ProgressiveEMICalculatorTest {
|
||||
final LocalDate dueDate = LocalDate.of(2024, 2, 1);
|
||||
final LocalDate startDay = LocalDate.of(2024, 1, 1);
|
||||
|
||||
emiCalculator.payInterest(interestModel, dueDate, startDay.plusDays(3), toMoney(0.56));
|
||||
emiCalculator.payInterest(interestModel, startDay, dueDate, startDay.plusDays(3), toMoney(0.56));
|
||||
emiCalculator.creditInterest(interestModel, startDay.plusDays(3), toMoney(0.0));
|
||||
emiCalculator.addBalanceCorrection(interestModel, startDay.plusDays(3), toMoney(0.0));
|
||||
|
||||
@@ -2019,9 +2059,9 @@ class ProgressiveEMICalculatorTest {
|
||||
checkPeriod(interestSchedule, 4, 857.71, 14.33, 843.38, 850.76, false);
|
||||
checkPeriod(interestSchedule, 5, 857.73, 6.97, 850.76, 0, false);
|
||||
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2023, 12, 13), LocalDate.of(2023, 12, 10),
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2023, 11, 13), LocalDate.of(2023, 12, 13), LocalDate.of(2023, 12, 10),
|
||||
Money.of(currency, BigDecimal.valueOf(820.76)));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2023, 12, 13), LocalDate.of(2023, 12, 10),
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2023, 11, 13), LocalDate.of(2023, 12, 13), LocalDate.of(2023, 12, 10),
|
||||
Money.of(currency, BigDecimal.valueOf(36.95)));
|
||||
|
||||
checkPeriod(interestSchedule, 0, 857.71, 36.95, 820.76, 4179.24, true);
|
||||
@@ -2062,8 +2102,9 @@ class ProgressiveEMICalculatorTest {
|
||||
emiCalculator.addDisbursement(interestSchedule, disbursementDate, disbursedAmount);
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
LocalDate fromDate = expectedRepaymentPeriods.get(i).getFromDate();
|
||||
LocalDate dueDate = expectedRepaymentPeriods.get(i).getDueDate();
|
||||
PeriodDueDetails dueAmounts = emiCalculator.getDueAmounts(interestSchedule, dueDate, dueDate);
|
||||
PeriodDueDetails dueAmounts = emiCalculator.getDueAmounts(interestSchedule, fromDate, dueDate, dueDate);
|
||||
Money duePrincipal = dueAmounts.getDuePrincipal();
|
||||
emiCalculator.addBalanceCorrection(interestSchedule, dueDate, duePrincipal);
|
||||
}
|
||||
@@ -2105,14 +2146,15 @@ class ProgressiveEMICalculatorTest {
|
||||
|
||||
emiCalculator.addDisbursement(interestSchedule, disbursementDate, disbursedAmount);
|
||||
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2023, 12, 13), LocalDate.of(2023, 12, 10),
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2023, 11, 13), LocalDate.of(2023, 12, 13), LocalDate.of(2023, 12, 10),
|
||||
Money.of(currency, BigDecimal.valueOf(36.95)));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2023, 12, 13), LocalDate.of(2023, 12, 10),
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2023, 11, 13), LocalDate.of(2023, 12, 13), LocalDate.of(2023, 12, 10),
|
||||
Money.of(currency, BigDecimal.valueOf(820.76)));
|
||||
|
||||
for (int i = 1; i < 6; i++) {
|
||||
LocalDate fromDate = expectedRepaymentPeriods.get(i).getFromDate();
|
||||
LocalDate dueDate = expectedRepaymentPeriods.get(i).getDueDate();
|
||||
PeriodDueDetails dueAmounts = emiCalculator.getDueAmounts(interestSchedule, dueDate, dueDate);
|
||||
PeriodDueDetails dueAmounts = emiCalculator.getDueAmounts(interestSchedule, fromDate, dueDate, dueDate);
|
||||
Money duePrincipal = dueAmounts.getDuePrincipal();
|
||||
emiCalculator.addBalanceCorrection(interestSchedule, dueDate, duePrincipal);
|
||||
}
|
||||
@@ -2450,11 +2492,15 @@ class ProgressiveEMICalculatorTest {
|
||||
checkPeriod(interestSchedule, 5, 0, 17.00, 0.005833333333, 0.0985833333276, 0.1, 16.9, 0.0);
|
||||
|
||||
// repay 1st period
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1), toMoney(16.43));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1), toMoney(0.58));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
toMoney(16.43));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
toMoney(0.58));
|
||||
// repay 2nd period
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 3, 1), toMoney(16.52));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 3, 1), toMoney(0.49));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1), LocalDate.of(2024, 3, 1),
|
||||
toMoney(16.52));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1), LocalDate.of(2024, 3, 1),
|
||||
toMoney(0.49));
|
||||
|
||||
// full chargeback on duedate
|
||||
emiCalculator.creditPrincipal(interestSchedule, LocalDate.of(2024, 3, 1), toMoney(17.01));
|
||||
@@ -2503,11 +2549,15 @@ class ProgressiveEMICalculatorTest {
|
||||
checkPeriod(interestSchedule, 5, 0, 17.00, 0.005833333333, 0.0985833333276, 0.1, 16.9, 0.0);
|
||||
|
||||
// repay 1st period
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1), toMoney(16.43));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1), toMoney(0.58));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
toMoney(16.43));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
toMoney(0.58));
|
||||
// repay 2nd period
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 3, 1), toMoney(16.52));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 3, 1), toMoney(0.49));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1), LocalDate.of(2024, 3, 1),
|
||||
toMoney(16.52));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1), LocalDate.of(2024, 3, 1),
|
||||
toMoney(0.49));
|
||||
|
||||
// partial chargeback
|
||||
emiCalculator.creditPrincipal(interestSchedule, LocalDate.of(2024, 3, 1), toMoney(15.0));
|
||||
@@ -2567,11 +2617,15 @@ class ProgressiveEMICalculatorTest {
|
||||
checkPeriod(interestSchedule, 5, 0, 17.00, 0.005833333333, 0.0985833333276, 0.1, 16.9, 0.0);
|
||||
|
||||
// repay 1st period
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1), toMoney(16.43));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1), toMoney(0.58));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
toMoney(16.43));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
toMoney(0.58));
|
||||
// repay 2nd period
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 3, 1), toMoney(16.52));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 3, 1), toMoney(0.49));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1), LocalDate.of(2024, 3, 1),
|
||||
toMoney(16.52));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1), LocalDate.of(2024, 3, 1),
|
||||
toMoney(0.49));
|
||||
|
||||
// full chargeback on duedate
|
||||
emiCalculator.creditPrincipal(interestSchedule, LocalDate.of(2024, 3, 15), toMoney(17.01));
|
||||
@@ -2623,13 +2677,13 @@ class ProgressiveEMICalculatorTest {
|
||||
|
||||
// repay 1st period
|
||||
LocalDate txnDate = LocalDate.of(2024, 2, 1);
|
||||
emiCalculator.payPrincipal(interestSchedule, txnDate, txnDate, toMoney(16.43));
|
||||
emiCalculator.payInterest(interestSchedule, txnDate, txnDate, toMoney(0.58));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 1, 1), txnDate, txnDate, toMoney(16.43));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 1, 1), txnDate, txnDate, toMoney(0.58));
|
||||
|
||||
// repay 2nd period
|
||||
txnDate = LocalDate.of(2024, 3, 1);
|
||||
emiCalculator.payPrincipal(interestSchedule, txnDate, txnDate, toMoney(16.52));
|
||||
emiCalculator.payInterest(interestSchedule, txnDate, txnDate, toMoney(0.49));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), txnDate, txnDate, toMoney(16.52));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 2, 1), txnDate, txnDate, toMoney(0.49));
|
||||
|
||||
// chargeback
|
||||
txnDate = LocalDate.of(2024, 3, 1);
|
||||
@@ -2681,13 +2735,13 @@ class ProgressiveEMICalculatorTest {
|
||||
|
||||
// repay 1st period
|
||||
LocalDate txnDate = LocalDate.of(2024, 2, 1);
|
||||
emiCalculator.payPrincipal(interestSchedule, txnDate, txnDate, toMoney(16.43));
|
||||
emiCalculator.payInterest(interestSchedule, txnDate, txnDate, toMoney(0.58));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 1, 1), txnDate, txnDate, toMoney(16.43));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 1, 1), txnDate, txnDate, toMoney(0.58));
|
||||
|
||||
// repay 2nd period
|
||||
txnDate = LocalDate.of(2024, 3, 1);
|
||||
emiCalculator.payPrincipal(interestSchedule, txnDate, txnDate, toMoney(16.52));
|
||||
emiCalculator.payInterest(interestSchedule, txnDate, txnDate, toMoney(0.49));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), txnDate, txnDate, toMoney(16.52));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 2, 1), txnDate, txnDate, toMoney(0.49));
|
||||
|
||||
// chargeback
|
||||
txnDate = LocalDate.of(2024, 7, 1);
|
||||
@@ -2733,13 +2787,13 @@ class ProgressiveEMICalculatorTest {
|
||||
|
||||
// repay 1st period
|
||||
LocalDate txnDate = LocalDate.of(2024, 2, 1);
|
||||
emiCalculator.payPrincipal(interestSchedule, txnDate, txnDate, toMoney(16.43));
|
||||
emiCalculator.payInterest(interestSchedule, txnDate, txnDate, toMoney(0.58));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 1, 1), txnDate, txnDate, toMoney(16.43));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 1, 1), txnDate, txnDate, toMoney(0.58));
|
||||
|
||||
// repay 2nd period
|
||||
txnDate = LocalDate.of(2024, 3, 1);
|
||||
emiCalculator.payPrincipal(interestSchedule, txnDate, txnDate, toMoney(16.52));
|
||||
emiCalculator.payInterest(interestSchedule, txnDate, txnDate, toMoney(0.49));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), txnDate, txnDate, toMoney(16.52));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 2, 1), txnDate, txnDate, toMoney(0.49));
|
||||
|
||||
// chargeback
|
||||
txnDate = LocalDate.of(2024, 3, 1);
|
||||
@@ -2791,13 +2845,13 @@ class ProgressiveEMICalculatorTest {
|
||||
|
||||
// repay 1st period
|
||||
LocalDate txnDate = LocalDate.of(2024, 2, 1);
|
||||
emiCalculator.payPrincipal(interestSchedule, txnDate, txnDate, toMoney(16.43));
|
||||
emiCalculator.payInterest(interestSchedule, txnDate, txnDate, toMoney(0.58));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 1, 1), txnDate, txnDate, toMoney(16.43));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 1, 1), txnDate, txnDate, toMoney(0.58));
|
||||
|
||||
// repay 2nd period
|
||||
txnDate = LocalDate.of(2024, 3, 1);
|
||||
emiCalculator.payPrincipal(interestSchedule, txnDate, txnDate, toMoney(16.52));
|
||||
emiCalculator.payInterest(interestSchedule, txnDate, txnDate, toMoney(0.49));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), txnDate, txnDate, toMoney(16.52));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 2, 1), txnDate, txnDate, toMoney(0.49));
|
||||
|
||||
// chargeback
|
||||
txnDate = LocalDate.of(2024, 3, 1);
|
||||
@@ -2848,13 +2902,13 @@ class ProgressiveEMICalculatorTest {
|
||||
|
||||
// repay 1st period
|
||||
LocalDate txnDate = LocalDate.of(2024, 2, 1);
|
||||
emiCalculator.payPrincipal(interestSchedule, txnDate, txnDate, toMoney(16.43));
|
||||
emiCalculator.payInterest(interestSchedule, txnDate, txnDate, toMoney(0.58));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 1, 1), txnDate, txnDate, toMoney(16.43));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 1, 1), txnDate, txnDate, toMoney(0.58));
|
||||
|
||||
// repay 2nd period
|
||||
txnDate = LocalDate.of(2024, 3, 1);
|
||||
emiCalculator.payPrincipal(interestSchedule, txnDate, txnDate, toMoney(16.52));
|
||||
emiCalculator.payInterest(interestSchedule, txnDate, txnDate, toMoney(0.49));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), txnDate, txnDate, toMoney(16.52));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 2, 1), txnDate, txnDate, toMoney(0.49));
|
||||
|
||||
// chargeback 1st
|
||||
txnDate = LocalDate.of(2024, 3, 1);
|
||||
@@ -3142,20 +3196,21 @@ class ProgressiveEMICalculatorTest {
|
||||
|
||||
// repay 1st period
|
||||
LocalDate txnDate = LocalDate.of(2024, 2, 1);
|
||||
emiCalculator.payPrincipal(interestSchedule, txnDate, txnDate, toMoney(16.43));
|
||||
emiCalculator.payInterest(interestSchedule, txnDate, txnDate, toMoney(0.58));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 1, 1), txnDate, txnDate, toMoney(16.43));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 1, 1), txnDate, txnDate, toMoney(0.58));
|
||||
|
||||
// repay 2nd period
|
||||
txnDate = LocalDate.of(2024, 3, 1);
|
||||
emiCalculator.payPrincipal(interestSchedule, txnDate, txnDate, toMoney(16.52));
|
||||
emiCalculator.payInterest(interestSchedule, txnDate, txnDate, toMoney(0.49));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), txnDate, txnDate, toMoney(16.52));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 2, 1), txnDate, txnDate, toMoney(0.49));
|
||||
|
||||
// chargeback
|
||||
txnDate = LocalDate.of(2024, 3, 15);
|
||||
emiCalculator.creditPrincipal(interestSchedule, txnDate, toMoney(16.52));
|
||||
emiCalculator.creditInterest(interestSchedule, txnDate, toMoney(0.49));
|
||||
|
||||
PeriodDueDetails dueAmounts = emiCalculator.getDueAmounts(interestSchedule, LocalDate.of(2024, 4, 1), txnDate);
|
||||
PeriodDueDetails dueAmounts = emiCalculator.getDueAmounts(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 4, 1),
|
||||
txnDate);
|
||||
Assertions.assertEquals(33.09, toDouble(interestSchedule.repaymentPeriods().get(2).getDuePrincipal()));
|
||||
Assertions.assertEquals(33.35, toDouble(dueAmounts.getDuePrincipal()));
|
||||
Assertions.assertEquals(0.67, toDouble(dueAmounts.getDueInterest()));
|
||||
@@ -3204,10 +3259,10 @@ class ProgressiveEMICalculatorTest {
|
||||
|
||||
// repay 1st period
|
||||
LocalDate txnDate = LocalDate.of(2024, 2, 1);
|
||||
emiCalculator.payPrincipal(interestScheduleExpected, txnDate, txnDate, toMoney(16.43));
|
||||
emiCalculator.payInterest(interestScheduleExpected, txnDate, txnDate, toMoney(0.58));
|
||||
emiCalculator.payPrincipal(interestScheduleActual, txnDate, txnDate, toMoney(16.43));
|
||||
emiCalculator.payInterest(interestScheduleActual, txnDate, txnDate, toMoney(0.58));
|
||||
emiCalculator.payPrincipal(interestScheduleExpected, LocalDate.of(2024, 1, 1), txnDate, txnDate, toMoney(16.43));
|
||||
emiCalculator.payInterest(interestScheduleExpected, LocalDate.of(2024, 1, 1), txnDate, txnDate, toMoney(0.58));
|
||||
emiCalculator.payPrincipal(interestScheduleActual, LocalDate.of(2024, 1, 1), txnDate, txnDate, toMoney(16.43));
|
||||
emiCalculator.payInterest(interestScheduleActual, LocalDate.of(2024, 1, 1), txnDate, txnDate, toMoney(0.58));
|
||||
|
||||
verifyAllPeriods(interestScheduleExpected, interestScheduleActual);
|
||||
interestScheduleActual = copyJson(interestScheduleExpected);
|
||||
@@ -3215,10 +3270,10 @@ class ProgressiveEMICalculatorTest {
|
||||
|
||||
// repay 2nd period
|
||||
txnDate = LocalDate.of(2024, 3, 1);
|
||||
emiCalculator.payPrincipal(interestScheduleExpected, txnDate, txnDate, toMoney(16.52));
|
||||
emiCalculator.payInterest(interestScheduleExpected, txnDate, txnDate, toMoney(0.49));
|
||||
emiCalculator.payPrincipal(interestScheduleActual, txnDate, txnDate, toMoney(16.52));
|
||||
emiCalculator.payInterest(interestScheduleActual, txnDate, txnDate, toMoney(0.49));
|
||||
emiCalculator.payPrincipal(interestScheduleExpected, LocalDate.of(2024, 2, 1), txnDate, txnDate, toMoney(16.52));
|
||||
emiCalculator.payInterest(interestScheduleExpected, LocalDate.of(2024, 1, 1), txnDate, txnDate, toMoney(0.49));
|
||||
emiCalculator.payPrincipal(interestScheduleActual, LocalDate.of(2024, 2, 1), txnDate, txnDate, toMoney(16.52));
|
||||
emiCalculator.payInterest(interestScheduleActual, LocalDate.of(2024, 2, 1), txnDate, txnDate, toMoney(0.49));
|
||||
|
||||
verifyAllPeriods(interestScheduleExpected, interestScheduleActual);
|
||||
interestScheduleActual = copyJson(interestScheduleExpected);
|
||||
@@ -3235,8 +3290,10 @@ class ProgressiveEMICalculatorTest {
|
||||
interestScheduleActual = copyJson(interestScheduleExpected);
|
||||
verifyAllPeriods(interestScheduleExpected, interestScheduleActual);
|
||||
|
||||
PeriodDueDetails dueAmountsExpected = emiCalculator.getDueAmounts(interestScheduleExpected, LocalDate.of(2024, 4, 1), txnDate);
|
||||
PeriodDueDetails dueAmountsActual = emiCalculator.getDueAmounts(interestScheduleActual, LocalDate.of(2024, 4, 1), txnDate);
|
||||
PeriodDueDetails dueAmountsExpected = emiCalculator.getDueAmounts(interestScheduleExpected, LocalDate.of(2024, 3, 1),
|
||||
LocalDate.of(2024, 4, 1), txnDate);
|
||||
PeriodDueDetails dueAmountsActual = emiCalculator.getDueAmounts(interestScheduleActual, LocalDate.of(2024, 3, 1),
|
||||
LocalDate.of(2024, 4, 1), txnDate);
|
||||
|
||||
Assertions.assertEquals(toDouble(dueAmountsExpected.getDuePrincipal()), toDouble(dueAmountsActual.getDuePrincipal()));
|
||||
Assertions.assertEquals(toDouble(dueAmountsExpected.getDueInterest()), toDouble(dueAmountsActual.getDueInterest()));
|
||||
@@ -4069,11 +4126,11 @@ class ProgressiveEMICalculatorTest {
|
||||
checkPeriod(interestSchedule, 3, 256.29, 2.54, 253.75, 0.00, false); //
|
||||
|
||||
// simulate merchant issued refund allocated on last installment ( fully repaid ) on first date
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 10, 1), LocalDate.of(2024, 6, 1),
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 9, 1), LocalDate.of(2024, 10, 1), LocalDate.of(2024, 6, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(256.29D)));
|
||||
|
||||
// simulate early repayment on day 0
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 7, 1), LocalDate.of(2024, 6, 1),
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 7, 1), LocalDate.of(2024, 6, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(256.28D)));
|
||||
|
||||
// verify 1st and 4th installments are fully repaid
|
||||
@@ -4130,9 +4187,9 @@ class ProgressiveEMICalculatorTest {
|
||||
checkPeriod(interestSchedule, 3, 260.00, 10.00, 250.00, 0.00, false); //
|
||||
|
||||
// simulate merchant issued refund allocated on last installment ( fully repaid ) on first date
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 10, 1), LocalDate.of(2024, 6, 1),
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 9, 1), LocalDate.of(2024, 10, 1), LocalDate.of(2024, 6, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(250.0D)));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 10, 1), LocalDate.of(2024, 6, 1),
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 9, 1), LocalDate.of(2024, 10, 1), LocalDate.of(2024, 6, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(10.0D)));
|
||||
|
||||
checkPeriod(interestSchedule, 0, 260.00, 10.00, 250.00, 500.00, false); //
|
||||
@@ -4141,9 +4198,9 @@ class ProgressiveEMICalculatorTest {
|
||||
checkPeriod(interestSchedule, 3, 260.00, 10.00, 250.00, 0.00, true); //
|
||||
|
||||
// simulate early repayment on day 0
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 7, 1), LocalDate.of(2024, 6, 1),
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 7, 1), LocalDate.of(2024, 6, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(250.0D)));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 7, 1), LocalDate.of(2024, 6, 1),
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 7, 1), LocalDate.of(2024, 6, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(10.0D)));
|
||||
|
||||
// verify 1st and 4th installments are fully repaid
|
||||
@@ -4283,26 +4340,30 @@ class ProgressiveEMICalculatorTest {
|
||||
checkPeriod(interestSchedule, 5, 0, 17.47, 0.012886027397, 0.222283972598, 0.22, 17.25, 0.0);
|
||||
|
||||
// repay EMI on first period due date
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(16.1)));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(1.33)));
|
||||
|
||||
// repay EMI on first period due date - next installment for 2nd period
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 2, 1),
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1), LocalDate.of(2024, 2, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(17.43)));
|
||||
|
||||
// repay 20 for last installment on first period due date -- ie MIR
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 7, 1), LocalDate.of(2024, 2, 1),
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 7, 1), LocalDate.of(2024, 2, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(17.43)));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 2, 1),
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 5, 1), LocalDate.of(2024, 6, 1), LocalDate.of(2024, 2, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(2.57)));
|
||||
|
||||
emiCalculator.addBalanceCorrection(interestSchedule, LocalDate.of(2024, 4, 1),
|
||||
emiCalculator.getDueAmounts(interestSchedule, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 4, 1)).getDuePrincipal());
|
||||
emiCalculator
|
||||
.getDueAmounts(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 4, 1), LocalDate.of(2024, 4, 1))
|
||||
.getDuePrincipal());
|
||||
|
||||
emiCalculator.addBalanceCorrection(interestSchedule, LocalDate.of(2024, 4, 15), emiCalculator
|
||||
.getDueAmounts(interestSchedule, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 4, 1)).getDuePrincipal().negated());
|
||||
emiCalculator.addBalanceCorrection(interestSchedule, LocalDate.of(2024, 4, 15),
|
||||
emiCalculator
|
||||
.getDueAmounts(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 4, 1), LocalDate.of(2024, 4, 1))
|
||||
.getDuePrincipal().negated());
|
||||
|
||||
LocalDate reAgingStartDate = LocalDate.of(2024, 4, 20);
|
||||
|
||||
@@ -4360,9 +4421,9 @@ class ProgressiveEMICalculatorTest {
|
||||
emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount);
|
||||
|
||||
// repay EMI on first period due date
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(16.43)));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(0.58)));
|
||||
|
||||
// chargeback
|
||||
@@ -4419,9 +4480,9 @@ class ProgressiveEMICalculatorTest {
|
||||
emiCalculator.addDisbursement(interestSchedule, LocalDate.of(2024, 1, 1), disbursedAmount);
|
||||
|
||||
// repay EMI on first period due date
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(16.43)));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(0.58)));
|
||||
|
||||
// chargeback
|
||||
@@ -4487,26 +4548,30 @@ class ProgressiveEMICalculatorTest {
|
||||
checkPeriod(interestSchedule, 5, 0, 17.47, 0.012886027397, 0.222283972598, 0.22, 17.25, 0.0);
|
||||
|
||||
// repay EMI on first period due date
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(16.1)));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(1.33)));
|
||||
|
||||
// repay EMI on first period due date - next installment for 2nd period
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 2, 1),
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1), LocalDate.of(2024, 2, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(17.43)));
|
||||
|
||||
// repay 20 for last installment on first period due date -- ie MIR
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 7, 1), LocalDate.of(2024, 2, 1),
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 7, 1), LocalDate.of(2024, 2, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(17.43)));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 2, 1),
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 5, 1), LocalDate.of(2024, 6, 1), LocalDate.of(2024, 2, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(2.57)));
|
||||
|
||||
emiCalculator.addBalanceCorrection(interestSchedule, LocalDate.of(2024, 4, 1),
|
||||
emiCalculator.getDueAmounts(interestSchedule, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 4, 1)).getDuePrincipal());
|
||||
emiCalculator
|
||||
.getDueAmounts(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 4, 1), LocalDate.of(2024, 4, 1))
|
||||
.getDuePrincipal());
|
||||
|
||||
emiCalculator.addBalanceCorrection(interestSchedule, LocalDate.of(2024, 4, 15), emiCalculator
|
||||
.getDueAmounts(interestSchedule, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 4, 1)).getDuePrincipal().negated());
|
||||
emiCalculator.addBalanceCorrection(interestSchedule, LocalDate.of(2024, 4, 15),
|
||||
emiCalculator
|
||||
.getDueAmounts(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 4, 1), LocalDate.of(2024, 4, 1))
|
||||
.getDuePrincipal().negated());
|
||||
|
||||
LocalDate transactionDate = LocalDate.of(2024, 4, 15);
|
||||
LocalDate reAgingStartDate = LocalDate.of(2024, 4, 20);
|
||||
@@ -4566,26 +4631,30 @@ class ProgressiveEMICalculatorTest {
|
||||
checkPeriod(interestSchedule, 5, 0, 17.47, 0.012886027397, 0.222283972598, 0.22, 17.25, 0.0);
|
||||
|
||||
// repay EMI on first period due date
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(16.1)));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(1.33)));
|
||||
|
||||
// repay EMI on first period due date - next installment for 2nd period
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 2, 1),
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1), LocalDate.of(2024, 2, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(17.43)));
|
||||
|
||||
// repay 20 for last installment on first period due date -- ie MIR
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 7, 1), LocalDate.of(2024, 2, 1),
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 7, 1), LocalDate.of(2024, 2, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(17.43)));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 2, 1),
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 5, 1), LocalDate.of(2024, 6, 1), LocalDate.of(2024, 2, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(2.57)));
|
||||
|
||||
emiCalculator.addBalanceCorrection(interestSchedule, LocalDate.of(2024, 4, 1),
|
||||
emiCalculator.getDueAmounts(interestSchedule, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 4, 1)).getDuePrincipal());
|
||||
emiCalculator
|
||||
.getDueAmounts(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 4, 1), LocalDate.of(2024, 4, 1))
|
||||
.getDuePrincipal());
|
||||
|
||||
emiCalculator.addBalanceCorrection(interestSchedule, LocalDate.of(2024, 4, 15), emiCalculator
|
||||
.getDueAmounts(interestSchedule, LocalDate.of(2024, 4, 1), LocalDate.of(2024, 4, 1)).getDuePrincipal().negated());
|
||||
emiCalculator.addBalanceCorrection(interestSchedule, LocalDate.of(2024, 4, 15),
|
||||
emiCalculator
|
||||
.getDueAmounts(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 4, 1), LocalDate.of(2024, 4, 1))
|
||||
.getDuePrincipal().negated());
|
||||
|
||||
LocalDate transactionDate = LocalDate.of(2024, 4, 15);
|
||||
LocalDate reAgingStartDate = LocalDate.of(2024, 5, 1);
|
||||
@@ -4645,19 +4714,19 @@ class ProgressiveEMICalculatorTest {
|
||||
checkPeriod(interestSchedule, 5, 0, 17.47, 0.012886027397, 0.222283972598, 0.22, 17.25, 0.0);
|
||||
|
||||
// repay EMI on first period due date
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(16.1)));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(1.33)));
|
||||
|
||||
// repay EMI on first period due date - next installment for 2nd period
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 2, 1),
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1), LocalDate.of(2024, 2, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(17.43)));
|
||||
|
||||
// repay 20 for last installment on first period due date -- ie MIR
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 7, 1), LocalDate.of(2024, 2, 1),
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 7, 1), LocalDate.of(2024, 2, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(17.43)));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 2, 1),
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 5, 1), LocalDate.of(2024, 6, 1), LocalDate.of(2024, 2, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(2.57)));
|
||||
|
||||
LocalDate transactionDate = LocalDate.of(2024, 7, 1);
|
||||
@@ -4718,19 +4787,19 @@ class ProgressiveEMICalculatorTest {
|
||||
checkPeriod(interestSchedule, 5, 0, 17.47, 0.012886027397, 0.222283972598, 0.22, 17.25, 0.0);
|
||||
|
||||
// repay EMI on first period due date
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(16.1)));
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
emiCalculator.payInterest(interestSchedule, LocalDate.of(2024, 1, 1), LocalDate.of(2024, 2, 1), LocalDate.of(2024, 2, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(1.33)));
|
||||
|
||||
// repay EMI on first period due date - next installment for 2nd period
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 3, 1), LocalDate.of(2024, 2, 1),
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 2, 1), LocalDate.of(2024, 3, 1), LocalDate.of(2024, 2, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(17.43)));
|
||||
|
||||
// repay 20 for last installment on first period due date -- ie MIR
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 7, 1), LocalDate.of(2024, 2, 1),
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 7, 1), LocalDate.of(2024, 2, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(17.43)));
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 6, 1), LocalDate.of(2024, 2, 1),
|
||||
emiCalculator.payPrincipal(interestSchedule, LocalDate.of(2024, 5, 1), LocalDate.of(2024, 6, 1), LocalDate.of(2024, 2, 1),
|
||||
Money.of(currency, BigDecimal.valueOf(2.57)));
|
||||
|
||||
LocalDate transactionDate = LocalDate.of(2024, 7, 10);
|
||||
@@ -4809,9 +4878,9 @@ class ProgressiveEMICalculatorTest {
|
||||
|
||||
private static void checkDailyInterest(final ProgressiveLoanInterestScheduleModel interestModel, final LocalDate repaymentPeriodDueDate,
|
||||
final LocalDate interestStartDay, final int dayOffset, final double dailyInterest, final double interest) {
|
||||
Money previousInterest = emiCalculator.getPeriodInterestTillDate(interestModel, repaymentPeriodDueDate,
|
||||
Money previousInterest = emiCalculator.getPeriodInterestTillDate(interestModel, interestStartDay, repaymentPeriodDueDate,
|
||||
interestStartDay.plusDays(dayOffset - 1), true);
|
||||
Money currentInterest = emiCalculator.getPeriodInterestTillDate(interestModel, repaymentPeriodDueDate,
|
||||
Money currentInterest = emiCalculator.getPeriodInterestTillDate(interestModel, interestStartDay, repaymentPeriodDueDate,
|
||||
interestStartDay.plusDays(dayOffset), true);
|
||||
Assertions.assertEquals(dailyInterest, toDouble(currentInterest.minus(previousInterest)));
|
||||
Assertions.assertEquals(interest, toDouble(currentInterest));
|
||||
|
||||
Reference in New Issue
Block a user