This is an automated email from the ASF dual-hosted git repository.
adamsaghy pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git
The following commit(s) were added to refs/heads/develop by this push:
new e1165e813 FINERACT-1971: added test scenarios to cover repayment
schedule with large charge amounts
e1165e813 is described below
commit e1165e813af1372cf78e145482a734a029750a3f
Author: Rustam Zeinalov <[email protected]>
AuthorDate: Wed Feb 26 16:16:19 2025 +0100
FINERACT-1971: added test scenarios to cover repayment schedule with large
charge amounts
---
.../main/resources/avro-templates/bigdecimal.avsc | 2 +-
.../org/apache/fineract/test/helper/Utils.java | 22 ++++++
.../fineract/test/stepdef/loan/LoanStepDef.java | 27 +++----
.../src/test/resources/features/LoanCharge.feature | 90 ++++++++++++++++++++++
4 files changed, 127 insertions(+), 14 deletions(-)
diff --git
a/fineract-avro-schemas/src/main/resources/avro-templates/bigdecimal.avsc
b/fineract-avro-schemas/src/main/resources/avro-templates/bigdecimal.avsc
index 9b1cec773..459854141 100644
--- a/fineract-avro-schemas/src/main/resources/avro-templates/bigdecimal.avsc
+++ b/fineract-avro-schemas/src/main/resources/avro-templates/bigdecimal.avsc
@@ -1,6 +1,6 @@
{
"logicalType": "decimal",
- "precision": 20,
+ "precision": 27,
"scale": 8,
"type": "bytes"
}
diff --git
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/Utils.java
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/Utils.java
index 70cfa1802..25c2eeac3 100644
---
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/Utils.java
+++
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/Utils.java
@@ -48,4 +48,26 @@ public final class Utils {
public static LocalDate now() {
return LocalDate.now(Clock.systemUTC());
}
+
+ /**
+ * A record that formats a double value based on whether it's a whole
number or not.
+ * <p>
+ * If the value is a whole number, the output will have one decimal place
(e.g., 16.0). Otherwise, it will have two
+ * decimal places (e.g., 16.90), but if the second decimal place is zero,
it will be removed (so 16.90 becomes
+ * 16.9).
+ */
+ public record DoubleFormatter(double value) {
+
+ public String format() {
+ boolean isWholeNumber = (value % 1.0 == 0);
+
+ String result = isWholeNumber ? String.format("%.1f", value) :
String.format("%.2f", value);
+
+ // For non-whole numbers, remove trailing '0' if it exists
+ if (!isWholeNumber && result.endsWith("0")) {
+ result = result.substring(0, result.length() - 1);
+ }
+ return result;
+ }
+ }
}
diff --git
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanStepDef.java
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanStepDef.java
index 8afb6eaac..fcbc8859f 100644
---
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanStepDef.java
+++
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanStepDef.java
@@ -1989,7 +1989,6 @@ public class LoanStepDef extends AbstractStepDef {
private List<List<String>>
getActualValuesList(List<GetLoansLoanIdLoanChargeData> charges, String
paymentDueAtExpected,
String dueAsOfExpected) {
List<GetLoansLoanIdLoanChargeData> result;
-
if (dueAsOfExpected != null) {
result = charges.stream().filter(t -> {
LocalDate dueDate = t.getDueDate();
@@ -1999,7 +1998,6 @@ public class LoanStepDef extends AbstractStepDef {
result = charges.stream().filter(t ->
paymentDueAtExpected.equals(t.getChargeTimeType().getValue()))
.collect(Collectors.toList());
}
-
return result.stream().map(t -> {
List<String> actualValues = new ArrayList<>();
actualValues.add(t.getName() == null ? null : t.getName());
@@ -2007,10 +2005,13 @@ public class LoanStepDef extends AbstractStepDef {
actualValues.add(t.getChargeTimeType().getValue() == null ? null :
t.getChargeTimeType().getValue());
actualValues.add(t.getDueDate() == null ? null :
FORMATTER.format(t.getDueDate()));
actualValues.add(t.getChargeCalculationType().getValue() == null ?
null : t.getChargeCalculationType().getValue());
- actualValues.add(t.getAmount() == null ? null :
String.valueOf(t.getAmount()));
- actualValues.add(t.getAmountPaid() == null ? null :
String.valueOf(t.getAmountPaid()));
- actualValues.add(t.getAmountWaived() == null ? null :
String.valueOf(t.getAmountWaived()));
- actualValues.add(t.getAmountOutstanding() == null ? null :
String.valueOf(t.getAmountOutstanding()));
+
+ actualValues.add(t.getAmount() == null ? null : new
Utils.DoubleFormatter(t.getAmount()).format());
+
+ actualValues.add(t.getAmountPaid() == null ? null : new
Utils.DoubleFormatter(t.getAmountPaid()).format());
+ actualValues.add(t.getAmountWaived() == null ? null : new
Utils.DoubleFormatter(t.getAmountWaived()).format());
+
+ actualValues.add(t.getAmountOutstanding() == null ? null : new
Utils.DoubleFormatter(t.getAmountOutstanding()).format());
return actualValues;
}).collect(Collectors.toList());
}
@@ -3203,12 +3204,12 @@ public class LoanStepDef extends AbstractStepDef {
actualValues.add(repaymentPeriod.getPrincipalDue() == null
? null : String.valueOf(repaymentPeriod.getPrincipalDue()));
case "Interest" ->
actualValues.add(repaymentPeriod.getInterestDue() == null
? null : String.valueOf(repaymentPeriod.getInterestDue()));
- case "Fees" -> actualValues
- .add(repaymentPeriod.getFeeChargesDue() == null ? null
: String.valueOf(repaymentPeriod.getFeeChargesDue()));
- case "Penalties" -> actualValues.add(
- repaymentPeriod.getPenaltyChargesDue() == null ? null
: String.valueOf(repaymentPeriod.getPenaltyChargesDue()));
- case "Due" -> actualValues.add(
- repaymentPeriod.getTotalDueForPeriod() == null ? null
: String.valueOf(repaymentPeriod.getTotalDueForPeriod()));
+ case "Fees" ->
actualValues.add(repaymentPeriod.getFeeChargesDue() == null ? null
+ : new
Utils.DoubleFormatter(repaymentPeriod.getFeeChargesDue()).format());
+ case "Penalties" ->
actualValues.add(repaymentPeriod.getPenaltyChargesDue() == null ? null
+ : new
Utils.DoubleFormatter(repaymentPeriod.getPenaltyChargesDue()).format());
+ case "Due" ->
actualValues.add(repaymentPeriod.getTotalDueForPeriod() == null ? null
+ : new
Utils.DoubleFormatter(repaymentPeriod.getTotalDueForPeriod()).format());
case "Paid" -> actualValues.add(
repaymentPeriod.getTotalPaidForPeriod() == null ? null
: String.valueOf(repaymentPeriod.getTotalPaidForPeriod()));
case "In advance" ->
actualValues.add(repaymentPeriod.getTotalPaidInAdvanceForPeriod() == null ? null
@@ -3218,7 +3219,7 @@ public class LoanStepDef extends AbstractStepDef {
case "Waived" ->
actualValues.add(repaymentPeriod.getTotalWaivedForPeriod() == null ? null
:
String.valueOf(repaymentPeriod.getTotalWaivedForPeriod()));
case "Outstanding" ->
actualValues.add(repaymentPeriod.getTotalOutstandingForPeriod() == null ? null
- :
String.valueOf(repaymentPeriod.getTotalOutstandingForPeriod()));
+ : new
Utils.DoubleFormatter(repaymentPeriod.getTotalOutstandingForPeriod()).format());
default -> throw new
IllegalStateException(String.format("Header name %s cannot be found",
headerName));
}
}
diff --git
a/fineract-e2e-tests-runner/src/test/resources/features/LoanCharge.feature
b/fineract-e2e-tests-runner/src/test/resources/features/LoanCharge.feature
index ad34d6efb..07f36010f 100644
--- a/fineract-e2e-tests-runner/src/test/resources/features/LoanCharge.feature
+++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanCharge.feature
@@ -2534,3 +2534,93 @@ Feature: LoanCharge
| 01 January 2024 | Repayment | 60.0 | 60.0 | 0.0 |
0.0 | 0.0 | 40.0 |
| 01 February 2024 | Charge Adjustment | 20.0 | 0.0 | 0.0 |
0.0 | 20.0 | 40.0 |
And LoanChargeAdjustmentPostBusinessEvent is raised on "01 February 2024"
+
+ @TestRailId:C3501
+ Scenario: Verify repayment schedule amounts after large charge amount added
- UC1
+ When Admin sets the business date to "20 February 2025"
+ And Admin creates a client with random data
+ When Admin creates a fully customized loan with the following data:
+ | LoanProduct |
submitted on date | with Principal | ANNUAL interest rate % | interest type
| interest calculation period | amortization type | loanTermFrequency |
loanTermFrequencyType | repaymentEvery | repaymentFrequencyType |
numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment |
interest free period | Payment strategy |
+ | LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL | 20
December 2024 | 800 | 0 | DECLINING_BALANCE |
DAILY | EQUAL_INSTALLMENTS | 4 | MONTHS
| 1 | MONTHS | 4 | 0
| 0 | 0 |
ADVANCED_PAYMENT_ALLOCATION |
+ And Admin successfully approves the loan on "20 December 2024" with "800"
amount and expected disbursement date on "20 December 2024"
+ When Admin successfully disburse the loan on "20 December 2024" with "800"
EUR transaction amount
+ Then Loan Repayment schedule has 4 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 |
+ | | | 20 December 2024 | | 800.0 |
| | 0.0 | | 0.0 | 0.0 | | |
|
+ | 1 | 31 | 20 January 2025 | | 600.0 | 200.0
| 0.0 | 0.0 | 0.0 | 200.0 | 0.0 | 0.0 | 0.0 | 200.0
|
+ | 2 | 31 | 20 February 2025 | | 400.0 | 200.0
| 0.0 | 0.0 | 0.0 | 200.0 | 0.0 | 0.0 | 0.0 | 200.0
|
+ | 3 | 28 | 20 March 2025 | | 200.0 | 200.0
| 0.0 | 0.0 | 0.0 | 200.0 | 0.0 | 0.0 | 0.0 | 200.0
|
+ | 4 | 31 | 20 April 2025 | | 0.0 | 200.0
| 0.0 | 0.0 | 0.0 | 200.0 | 0.0 | 0.0 | 0.0 | 200.0
|
+ And Loan Repayment schedule has the following data in Total row:
+ | Principal due | Interest | Fees | Penalties | Due | Paid | In
advance | Late | Outstanding |
+ | 800.0 | 0.0 | 0.0 | 0.0 | 800.0 | 0.0 | 0.0
| 0.0 | 800.0 |
+ And Loan Transactions tab has the following data:
+ | Transaction date | Transaction Type | Amount | Principal | Interest |
Fees | Penalties | Loan Balance | Reverted | Replayed |
+ | 20 December 2024 | Disbursement | 800.0 | 0.0 | 0.0 |
0.0 | 0.0 | 800.0 | false | false |
+ And Admin adds "LOAN_NSF_FEE" due date charge with "25 December 2024" due
date and 123456789012.12 EUR transaction amount
+ Then Loan Repayment schedule has 4 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 |
+ | | | 20 December 2024 | | 800.0 |
| | 0.0 | | 0.0 | 0.0 | |
| |
+ | 1 | 31 | 20 January 2025 | | 600.0 | 200.0
| 0.0 | 0.0 | 123456789012.12 | 123456789212.12 | 0.0 | 0.0 |
0.0 | 123456789212.12 |
+ | 2 | 31 | 20 February 2025 | | 400.0 | 200.0
| 0.0 | 0.0 | 0.0 | 200.0 | 0.0 | 0.0 |
0.0 | 200.0 |
+ | 3 | 28 | 20 March 2025 | | 200.0 | 200.0
| 0.0 | 0.0 | 0.0 | 200.0 | 0.0 | 0.0 |
0.0 | 200.0 |
+ | 4 | 31 | 20 April 2025 | | 0.0 | 200.0
| 0.0 | 0.0 | 0.0 | 200.0 | 0.0 | 0.0 |
0.0 | 200.0 |
+ And Loan Repayment schedule has the following data in Total row:
+ | Principal due | Interest | Fees | Penalties | Due |
Paid | In advance | Late | Outstanding |
+ | 800.0 | 0.0 | 0.0 | 123456789012.12 | 123456789812.12 |
0.0 | 0.0 | 0.0 | 123456789812.12 |
+ And Loan Transactions tab has the following data:
+ | Transaction date | Transaction Type | Amount | Principal | Interest |
Fees | Penalties | Loan Balance | Reverted | Replayed |
+ | 20 December 2024 | Disbursement | 800.0 | 0.0 | 0.0 |
0.0 | 0.0 | 800.0 | false | false |
+ Then Loan Charges tab has a given charge with the following data:
+ | Name | isPenalty | Payment due at | Due as of |
Calculation type | Due | Paid | Waived | Outstanding |
+ | NSF fee | true | Specified due date | 25 December 2024 | Flat
| 123456789012.12 | 0.0 | 0.0 | 123456789012.12 |
+
+ @TestRailId:C3502
+ Scenario: Verify repayment schedule amounts after a few large charges amount
added - UC2
+ When Admin sets the business date to "20 February 2025"
+ And Admin creates a client with random data
+ When Admin creates a fully customized loan with the following data:
+ | LoanProduct |
submitted on date | with Principal | ANNUAL interest rate % | interest type
| interest calculation period | amortization type | loanTermFrequency |
loanTermFrequencyType | repaymentEvery | repaymentFrequencyType |
numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment |
interest free period | Payment strategy |
+ | LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL | 20
December 2024 | 800 | 0 | DECLINING_BALANCE |
DAILY | EQUAL_INSTALLMENTS | 4 | MONTHS
| 1 | MONTHS | 4 | 0
| 0 | 0 |
ADVANCED_PAYMENT_ALLOCATION |
+ And Admin successfully approves the loan on "20 December 2024" with "800"
amount and expected disbursement date on "20 December 2024"
+ When Admin successfully disburse the loan on "20 December 2024" with "800"
EUR transaction amount
+ Then Loan Repayment schedule has 4 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 |
+ | | | 20 December 2024 | | 800.0 |
| | 0.0 | | 0.0 | 0.0 | | |
|
+ | 1 | 31 | 20 January 2025 | | 600.0 | 200.0
| 0.0 | 0.0 | 0.0 | 200.0 | 0.0 | 0.0 | 0.0 | 200.0
|
+ | 2 | 31 | 20 February 2025 | | 400.0 | 200.0
| 0.0 | 0.0 | 0.0 | 200.0 | 0.0 | 0.0 | 0.0 | 200.0
|
+ | 3 | 28 | 20 March 2025 | | 200.0 | 200.0
| 0.0 | 0.0 | 0.0 | 200.0 | 0.0 | 0.0 | 0.0 | 200.0
|
+ | 4 | 31 | 20 April 2025 | | 0.0 | 200.0
| 0.0 | 0.0 | 0.0 | 200.0 | 0.0 | 0.0 | 0.0 | 200.0
|
+ And Loan Repayment schedule has the following data in Total row:
+ | Principal due | Interest | Fees | Penalties | Due | Paid | In
advance | Late | Outstanding |
+ | 800.0 | 0.0 | 0.0 | 0.0 | 800.0 | 0.0 | 0.0
| 0.0 | 800.0 |
+ And Loan Transactions tab has the following data:
+ | Transaction date | Transaction Type | Amount | Principal | Interest |
Fees | Penalties | Loan Balance | Reverted | Replayed |
+ | 20 December 2024 | Disbursement | 800.0 | 0.0 | 0.0 |
0.0 | 0.0 | 800.0 | false | false |
+ And Admin adds "LOAN_NSF_FEE" due date charge with "25 December 2024" due
date and 123456789012.12 EUR transaction amount
+ When Admin adds "LOAN_SNOOZE_FEE" due date charge with "28 December 2024"
due date and 1003456789012.12 EUR transaction amount
+ When Admin adds "LOAN_NSF_FEE" due date charge with "31 January 2025" due
date and 5503456789012.12 EUR transaction amount
+ When Admin adds "LOAN_NSF_FEE" due date charge with "23 February 2025" due
date and 1003456789012.12 EUR transaction amount
+ When Admin adds "LOAN_NSF_FEE" due date charge with "03 April 2025" due
date and 1503456789012.12 EUR transaction amount
+ When Admin adds "LOAN_SNOOZE_FEE" due date charge with "09 April 2025" due
date and 103456789037.12 EUR transaction amount
+ Then Loan Repayment schedule has 4 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 |
+ | | | 20 December 2024 | | 800.0 |
| | 0.0 | | 0.0 | 0.0
| | | |
+ | 1 | 31 | 20 January 2025 | | 600.0 | 200.0
| 0.0 | 1003456789012.12 | 123456789012.12 | 1126913578224.24 | 0.0
| 0.0 | 0.0 | 1126913578224.24 |
+ | 2 | 31 | 20 February 2025 | | 400.0 | 200.0
| 0.0 | 0.0 | 5503456789012.12 | 5503456789212.12 | 0.0
| 0.0 | 0.0 | 5503456789212.12 |
+ | 3 | 28 | 20 March 2025 | | 200.0 | 200.0
| 0.0 | 0.0 | 1003456789012.12 | 1003456789212.12 | 0.0
| 0.0 | 0.0 | 1003456789212.12 |
+ | 4 | 31 | 20 April 2025 | | 0.0 | 200.0
| 0.0 | 103456789037.12 | 1503456789012.12 | 1606913578249.24 | 0.0
| 0.0 | 0.0 | 1606913578249.24 |
+ And Loan Repayment schedule has the following data in Total row:
+ | Principal due | Interest | Fees | Penalties | Due
| Paid | In advance | Late | Outstanding |
+ | 800.0 | 0.0 | 1106913578049.24 | 8133827156048.48 |
9240740734897.72 | 0.0 | 0.0 | 0.0 | 9240740734897.72 |
+ And Loan Transactions tab has the following data:
+ | Transaction date | Transaction Type | Amount | Principal | Interest |
Fees | Penalties | Loan Balance | Reverted | Replayed |
+ | 20 December 2024 | Disbursement | 800.0 | 0.0 | 0.0 |
0.0 | 0.0 | 800.0 | false | false |
+ Then Loan Charges tab has a given charge with the following data:
+ | Name | isPenalty | Payment due at | Due as of |
Calculation type | Due | Paid | Waived | Outstanding |
+ | NSF fee | true | Specified due date | 25 December 2024 | Flat
| 123456789012.12 | 0.0 | 0.0 | 123456789012.12 |
+ | Snooze fee | false | Specified due date | 28 December 2024 | Flat
| 1003456789012.12 | 0.0 | 0.0 | 1003456789012.12 |
+ | NSF fee | true | Specified due date | 31 January 2025 | Flat
| 5503456789012.12 | 0.0 | 0.0 | 5503456789012.12 |
+ | NSF fee | true | Specified due date | 23 February 2025 | Flat
| 1003456789012.12 | 0.0 | 0.0 | 1003456789012.12 |
+ | NSF fee | true | Specified due date | 03 April 2025 | Flat
| 1503456789012.12 | 0.0 | 0.0 | 1503456789012.12 |
+ | Snooze fee | false | Specified due date | 09 April 2025 | Flat
| 103456789037.12 | 0.0 | 0.0 | 103456789037.12 |