MIFOSX-1918 : added Pre-closure interest calculation strategy
This commit is contained in:
+31
-2
@@ -11566,6 +11566,13 @@ An enumeration that indicates the type of transaction processing strategy to be
|
||||
<tr>
|
||||
<td class=fielddesc>Specifies rest frequency start date for interest recalculation.<br>
|
||||
</tr>
|
||||
<tr class=alt>
|
||||
<td>preCloseInterestCalculationStrategy</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class=fielddesc>Specifies applicable days for interest calculation on pre close of a loan.<br>
|
||||
<span>Example Values:</span>1=Calculate till pre closure date, 2=Calculate till rest frequency date</td>
|
||||
</tr>
|
||||
<tr class=alt>
|
||||
<td>isArrearsBasedOnOriginalSchedule</td>
|
||||
</tr>
|
||||
@@ -11687,6 +11694,11 @@ GET https://DomainName/api/v1/loanproducts
|
||||
"code":"interestRecalculationFrequencyType.same.as.repayment.period",
|
||||
"value":"Same as repayment period"
|
||||
},
|
||||
"preCloseInterestCalculationStrategy": {
|
||||
"id":1,
|
||||
"code":"loanPreCloseInterestCalculationStrategy.tillPreClosureDate",
|
||||
"value":"Till preclose Date"
|
||||
},
|
||||
"isArrearsBasedOnOriginalSchedule" : true
|
||||
},
|
||||
"accountingRule": {
|
||||
@@ -11789,7 +11801,11 @@ GET https://DomainName/api/v1/loanproducts/template
|
||||
"id": 3,
|
||||
"code": "loanRescheduleStrategyMethod.reduce.emi.amount",
|
||||
"value": "Reduce EMI amount"
|
||||
}
|
||||
},"preCloseInterestCalculationStrategy": {
|
||||
"id":1,
|
||||
"code":"loanPreCloseInterestCalculationStrategy.tillPreClosureDate",
|
||||
"value":"Till preclose Date"
|
||||
}
|
||||
},
|
||||
"paymentTypeOptions": [
|
||||
{
|
||||
@@ -11825,6 +11841,18 @@ GET https://DomainName/api/v1/loanproducts/template
|
||||
"value": "Months"
|
||||
}
|
||||
],
|
||||
"preCloseInterestCalculationStrategyOptions": [
|
||||
{
|
||||
"id":1,
|
||||
"code":"loanPreCloseInterestCalculationStrategy.tillPreClosureDate",
|
||||
"value":"Till preclose Date"
|
||||
},
|
||||
{
|
||||
"id":2,
|
||||
"code":"loanPreCloseInterestCalculationStrategy.tillRestFrequencyDate",
|
||||
"value":"Till rest Frequency Date"
|
||||
}
|
||||
],
|
||||
"interestRateFrequencyTypeOptions": [
|
||||
{
|
||||
"id": 2,
|
||||
@@ -12855,7 +12883,7 @@ GET https://DomainName/api/v1/loanproducts/{productId}
|
||||
<td><div class="mifosXHeading2">Additional Optional Fields if interest recalculation is enabled(true) </div></td>
|
||||
</tr>
|
||||
<tr class=alt>
|
||||
<td>isArrearsBasedOnOriginalSchedule</td>
|
||||
<td>isArrearsBasedOnOriginalSchedule, preCloseInterestCalculationStrategy</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class=matrixHeading>
|
||||
@@ -12981,6 +13009,7 @@ Request Body:
|
||||
"interestRecalculationCompoundingMethod":"0",
|
||||
"rescheduleStrategyMethod":"3",
|
||||
"recalculationRestFrequencyType":"1",
|
||||
"preCloseInterestCalculationStrategy":1,
|
||||
"accountingRule":"2",
|
||||
"fundSourceAccountId":"4",
|
||||
"loanPortfolioAccountId":"8",
|
||||
|
||||
+359
-145
@@ -1722,9 +1722,8 @@ public class ClientLoanIntegrationTest {
|
||||
|
||||
System.out.println("----------Make repayment 3 advance------------");
|
||||
this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3303"), loanID);
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011",
|
||||
new JournalEntry(Float.valueOf("3303"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3149.11"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011", new JournalEntry(Float.valueOf("3303"),
|
||||
JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3149.11"), JournalEntry.TransactionType.CREDIT));
|
||||
this.journalEntryHelper.checkJournalEntryForIncomeAccount(incomeAccount, "20 November 2011",
|
||||
new JournalEntry(Float.valueOf("31.51"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("122.38"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
@@ -2327,9 +2326,8 @@ public class ClientLoanIntegrationTest {
|
||||
|
||||
System.out.println("----------Make repayment 3 advance------------");
|
||||
this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3303"), loanID);
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011",
|
||||
new JournalEntry(Float.valueOf("3303"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("31.51"),
|
||||
JournalEntry.TransactionType.CREDIT),
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011", new JournalEntry(Float.valueOf("3303"),
|
||||
JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("31.51"), JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(Float.valueOf("122.38"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3149.11"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
this.loanTransactionHelper.addChargesForLoan(
|
||||
@@ -2948,9 +2946,8 @@ public class ClientLoanIntegrationTest {
|
||||
|
||||
System.out.println("----------Make repayment 3 advance------------");
|
||||
this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3303"), loanID);
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011",
|
||||
new JournalEntry(Float.valueOf("3303"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("31.51"),
|
||||
JournalEntry.TransactionType.CREDIT),
|
||||
this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011", new JournalEntry(Float.valueOf("3303"),
|
||||
JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("31.51"), JournalEntry.TransactionType.CREDIT),
|
||||
new JournalEntry(Float.valueOf("122.38"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3149.11"),
|
||||
JournalEntry.TransactionType.CREDIT));
|
||||
|
||||
@@ -3173,7 +3170,8 @@ public class ClientLoanIntegrationTest {
|
||||
final Integer loanProductID = createLoanProductWithInterestRecalculation(LoanProductTestBuilder.MIFOS_STANDARD_STRATEGY,
|
||||
LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_NONE,
|
||||
LoanProductTestBuilder.RECALCULATION_STRATEGY_REDUCE_EMI_AMOUN,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, "0", null, null);
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, "0", null,
|
||||
LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null);
|
||||
|
||||
final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, LOAN_DISBURSEMENT_DATE, null,
|
||||
LoanApplicationTestBuilder.MIFOS_STANDARD_STRATEGY, new ArrayList<HashMap>(0));
|
||||
@@ -3185,10 +3183,10 @@ public class ClientLoanIntegrationTest {
|
||||
ArrayList<HashMap> loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
List<Map<String, Object>> expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2494.22", "34.69", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2505.73", "23.18", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2517.29", "11.62", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2494.22", "34.69", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2505.73", "23.18", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2517.29", "11.62", "0.0", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
System.out.println("-----------------------------------APPROVE LOAN-----------------------------------------");
|
||||
@@ -3203,10 +3201,10 @@ public class ClientLoanIntegrationTest {
|
||||
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2505.67", "23.24", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2528.81", "11.67", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2505.67", "23.24", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2528.81", "11.67", "0.0", "0.0");
|
||||
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
@@ -3219,10 +3217,10 @@ public class ClientLoanIntegrationTest {
|
||||
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2494.22", "34.69", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2505.73", "23.18", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2517.29", "11.62", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2494.22", "34.69", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2505.73", "23.18", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2517.29", "11.62", "0.0", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
Float earlyPayment = new Float("4000");
|
||||
@@ -3233,14 +3231,107 @@ public class ClientLoanIntegrationTest {
|
||||
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "3965.31", "34.69", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "1771.88", "16.39", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "1780.05", "8.22", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "3965.31", "34.69", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "1771.88", "16.39", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "1780.05", "8.22", "0.0", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
HashMap prepayDetail = this.loanTransactionHelper.getPrepayAmount(this.requestSpec, this.responseSpec, loanID);
|
||||
String prepayAmount = String.valueOf(prepayDetail.get("amount"));
|
||||
validateNumberForEqualWithMsg("verify pre-close amount", "3551.93", prepayAmount);
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
String LOAN_REPAYMENT_DATE = dateFormat.format(todaysDate.getTime());
|
||||
this.loanTransactionHelper.makeRepayment(LOAN_REPAYMENT_DATE, new Float(prepayAmount), loanID);
|
||||
loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
|
||||
LoanStatusChecker.verifyLoanAccountIsClosed(loanStatusHashMap);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoanScheduleWithInterestRecalculation_WITH_REST_SAME_AS_REPAYMENT_INTEREST_COMPOUND_NONE_STRATEGY_REDUCE_EMI_PRE_CLOSE_INTEREST_PRE_CLOSE_DATE() {
|
||||
String preCloseInterestStrategy = LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE;
|
||||
String preCloseAmount = "7561.84";
|
||||
testLoanScheduleWithInterestRecalculation_WITH_REST_SAME_AS_REPAYMENT_INTEREST_COMPOUND_NONE_STRATEGY_REDUCE_EMI_PRE_CLOSE_INTEREST(
|
||||
preCloseInterestStrategy, preCloseAmount);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoanScheduleWithInterestRecalculation_WITH_REST_SAME_AS_REPAYMENT_INTEREST_COMPOUND_NONE_STRATEGY_REDUCE_EMI_PRE_CLOSE_INTEREST_REST_DATE() {
|
||||
String preCloseInterestStrategy = LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_REST_DATE;
|
||||
String preCloseAmount = "7578.4";
|
||||
testLoanScheduleWithInterestRecalculation_WITH_REST_SAME_AS_REPAYMENT_INTEREST_COMPOUND_NONE_STRATEGY_REDUCE_EMI_PRE_CLOSE_INTEREST(
|
||||
preCloseInterestStrategy, preCloseAmount);
|
||||
}
|
||||
|
||||
private void testLoanScheduleWithInterestRecalculation_WITH_REST_SAME_AS_REPAYMENT_INTEREST_COMPOUND_NONE_STRATEGY_REDUCE_EMI_PRE_CLOSE_INTEREST(
|
||||
String preCloseInterestStrategy, String preCloseAmount) {
|
||||
this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec);
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy");
|
||||
|
||||
Calendar todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
todaysDate.add(Calendar.DAY_OF_MONTH, -16);
|
||||
final String LOAN_DISBURSEMENT_DATE = dateFormat.format(todaysDate.getTime());
|
||||
|
||||
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
|
||||
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
|
||||
final Integer loanProductID = createLoanProductWithInterestRecalculation(LoanProductTestBuilder.MIFOS_STANDARD_STRATEGY,
|
||||
LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_NONE,
|
||||
LoanProductTestBuilder.RECALCULATION_STRATEGY_REDUCE_EMI_AMOUN,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, "0", null, preCloseInterestStrategy, null);
|
||||
|
||||
final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, LOAN_DISBURSEMENT_DATE, null,
|
||||
LoanApplicationTestBuilder.MIFOS_STANDARD_STRATEGY, new ArrayList<HashMap>(0));
|
||||
|
||||
Assert.assertNotNull(loanID);
|
||||
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
|
||||
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
||||
|
||||
ArrayList<HashMap> loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
List<Map<String, Object>> expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -9, true, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2494.22", "34.69", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2505.73", "23.18", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2517.29", "11.62", "0.0", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
System.out.println("-----------------------------------APPROVE LOAN-----------------------------------------");
|
||||
loanStatusHashMap = this.loanTransactionHelper.approveLoan(LOAN_DISBURSEMENT_DATE, loanID);
|
||||
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
|
||||
LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap);
|
||||
|
||||
System.out.println("-------------------------------DISBURSE LOAN-------------------------------------------");
|
||||
loanStatusHashMap = this.loanTransactionHelper.disburseLoan(LOAN_DISBURSEMENT_DATE, loanID);
|
||||
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
|
||||
|
||||
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -9, true, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2499.12", "29.79", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2535.36", "11.7", "0.0", "0.0");
|
||||
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
todaysDate.add(Calendar.DAY_OF_MONTH, -9);
|
||||
final String LOAN_FIRST_REPAYMENT_DATE = dateFormat.format(todaysDate.getTime());
|
||||
Float totalDueForCurrentPeriod = (Float) loanSchedule.get(1).get("totalDueForPeriod");
|
||||
this.loanTransactionHelper.makeRepayment(LOAN_FIRST_REPAYMENT_DATE, totalDueForCurrentPeriod, loanID);
|
||||
|
||||
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -9, true, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2494.22", "34.69", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2502.44", "26.47", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2520.58", "11.63", "0.0", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
HashMap prepayDetail = this.loanTransactionHelper.getPrepayAmount(this.requestSpec, this.responseSpec, loanID);
|
||||
String prepayAmount = String.valueOf(prepayDetail.get("amount"));
|
||||
validateNumberForEqualWithMsg("verify pre-close amount", preCloseAmount, prepayAmount);
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
String LOAN_REPAYMENT_DATE = dateFormat.format(todaysDate.getTime());
|
||||
this.loanTransactionHelper.makeRepayment(LOAN_REPAYMENT_DATE, new Float(prepayAmount), loanID);
|
||||
@@ -3263,7 +3354,8 @@ public class ClientLoanIntegrationTest {
|
||||
final Integer loanProductID = createLoanProductWithInterestRecalculation(LoanProductTestBuilder.MIFOS_STANDARD_STRATEGY,
|
||||
LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_NONE,
|
||||
LoanProductTestBuilder.RECALCULATION_STRATEGY_REDUCE_EMI_AMOUN,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, "0", null, null);
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, "0", null,
|
||||
LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null);
|
||||
|
||||
List<HashMap> charges = new ArrayList<>();
|
||||
Integer installmentCharge = ChargesHelper.createCharges(requestSpec, responseSpec,
|
||||
@@ -3279,10 +3371,10 @@ public class ClientLoanIntegrationTest {
|
||||
ArrayList<HashMap> loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
List<Map<String, Object>> expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "4.62", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2494.22", "34.69", "3.47", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2505.73", "23.18", "2.32", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2517.29", "11.62", "1.16", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "4.62", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2494.22", "34.69", "3.47", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2505.73", "23.18", "2.32", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2517.29", "11.62", "1.16", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
System.out.println("-----------------------------------APPROVE LOAN-----------------------------------------");
|
||||
@@ -3297,10 +3389,10 @@ public class ClientLoanIntegrationTest {
|
||||
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "4.62", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2482.76", "46.15", "4.62", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2505.67", "23.24", "2.32", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2528.81", "11.67", "1.17", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "4.62", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2482.76", "46.15", "4.62", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2505.67", "23.24", "2.32", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2528.81", "11.67", "1.17", "0.0");
|
||||
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
@@ -3313,10 +3405,10 @@ public class ClientLoanIntegrationTest {
|
||||
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "4.62", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2494.22", "34.69", "3.47", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2505.73", "23.18", "2.32", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2517.29", "11.62", "1.16", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "4.62", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2494.22", "34.69", "3.47", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2505.73", "23.18", "2.32", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2517.29", "11.62", "1.16", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
Float earlyPayment = new Float("4000");
|
||||
@@ -3327,10 +3419,10 @@ public class ClientLoanIntegrationTest {
|
||||
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "4.62", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "3961.84", "34.69", "3.47", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "1773.61", "16.41", "1.64", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "1781.79", "8.22", "0.82", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "4.62", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "3961.84", "34.69", "3.47", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "1773.61", "16.41", "1.64", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "1781.79", "8.22", "0.82", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
HashMap prepayDetail = this.loanTransactionHelper.getPrepayAmount(this.requestSpec, this.responseSpec, loanID);
|
||||
@@ -3357,7 +3449,8 @@ public class ClientLoanIntegrationTest {
|
||||
final Integer loanProductID = createLoanProductWithInterestRecalculation(LoanProductTestBuilder.RBI_INDIA_STRATEGY,
|
||||
LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_INTEREST,
|
||||
LoanProductTestBuilder.RECALCULATION_STRATEGY_REDUCE_NUMBER_OF_INSTALLMENTS,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_DAILY, "1", LOAN_DISBURSEMENT_DATE, null);
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_DAILY, "1", LOAN_DISBURSEMENT_DATE,
|
||||
LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null);
|
||||
|
||||
final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, LOAN_DISBURSEMENT_DATE,
|
||||
LOAN_DISBURSEMENT_DATE, LoanApplicationTestBuilder.RBI_INDIA_STRATEGY, new ArrayList<HashMap>(0));
|
||||
@@ -3369,10 +3462,10 @@ public class ClientLoanIntegrationTest {
|
||||
ArrayList<HashMap> loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
List<Map<String, Object>> expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2494.22", "34.69", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2505.73", "23.18", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2517.29", "11.62", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2494.22", "34.69", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2505.73", "23.18", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2517.29", "11.62", "0.0", "0.0");
|
||||
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
@@ -3388,19 +3481,19 @@ public class ClientLoanIntegrationTest {
|
||||
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2482.54", "46.37", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2505.67", "23.24", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2529.03", "11.67", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2482.54", "46.37", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2505.67", "23.24", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2529.03", "11.67", "0.0", "0.0");
|
||||
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
loanSchedule = this.loanTransactionHelper.getLoanFutureRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, 0, "4965.3", "92.52", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2505.67", "23.24", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2529.03", "11.67", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 0, false, "4965.3", "92.52", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2505.67", "23.24", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2529.03", "11.67", "0.0", "0.0");
|
||||
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues, 0);
|
||||
|
||||
@@ -3413,10 +3506,10 @@ public class ClientLoanIntegrationTest {
|
||||
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2494.22", "34.69", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2505.73", "23.18", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2517.29", "11.62", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2494.22", "34.69", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2505.73", "23.18", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2517.29", "11.62", "0.0", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
Float earlyPayment = new Float("4000");
|
||||
@@ -3434,10 +3527,10 @@ public class ClientLoanIntegrationTest {
|
||||
paymentday.put("interestDue", "9.91");
|
||||
paymentday.put("feeChargesDue", "0");
|
||||
paymentday.put("penaltyChargesDue", "0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "0.0", "0.0");
|
||||
expectedvalues.add(paymentday);
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2517.28", "11.63", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "1009.87", "4.66", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2517.28", "11.63", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "1009.87", "4.66", "0.0", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
HashMap prepayDetail = this.loanTransactionHelper.getPrepayAmount(this.requestSpec, this.responseSpec, loanID);
|
||||
@@ -3482,7 +3575,8 @@ public class ClientLoanIntegrationTest {
|
||||
final Integer loanProductID = createLoanProductWithInterestRecalculation(LoanProductTestBuilder.MIFOS_STANDARD_STRATEGY,
|
||||
LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_INTEREST_AND_FEE,
|
||||
LoanProductTestBuilder.RECALCULATION_STRATEGY_RESCHEDULE_NEXT_REPAYMENTS,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_WEEKLY, "1", REST_START_DATE, null);
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_WEEKLY, "1", REST_START_DATE,
|
||||
LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null);
|
||||
|
||||
final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, LOAN_DISBURSEMENT_DATE,
|
||||
REST_START_DATE, LoanApplicationTestBuilder.MIFOS_STANDARD_STRATEGY, charges);
|
||||
@@ -3494,10 +3588,10 @@ public class ClientLoanIntegrationTest {
|
||||
ArrayList<HashMap> loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
List<Map<String, Object>> expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "100.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2486.04", "42.87", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2497.5", "31.41", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2533.7", "19.93", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "100.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2486.04", "42.87", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2497.5", "31.41", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2533.7", "19.93", "0.0", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
System.out.println("-----------------------------------APPROVE LOAN-----------------------------------------");
|
||||
@@ -3512,10 +3606,10 @@ public class ClientLoanIntegrationTest {
|
||||
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "100.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2482.57", "46.34", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2497.49", "31.42", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2537.18", "19.95", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "100.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2482.57", "46.34", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2497.49", "31.42", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2537.18", "19.95", "0.0", "0.0");
|
||||
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
@@ -3528,10 +3622,10 @@ public class ClientLoanIntegrationTest {
|
||||
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "100.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2486.04", "42.87", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2497.5", "31.41", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2533.7", "19.93", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "100.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2486.04", "42.87", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2497.5", "31.41", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2533.7", "19.93", "0.0", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
Float earlyPayment = new Float("5100");
|
||||
@@ -3543,10 +3637,10 @@ public class ClientLoanIntegrationTest {
|
||||
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "100.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "5057.13", "42.87", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "0", "19.55", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2460.11", "11.35", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "100.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "5100.0", "36.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "0", "11.16", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2417.24", "11.16", "0.0", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
HashMap prepayDetail = this.loanTransactionHelper.getPrepayAmount(this.requestSpec, this.responseSpec, loanID);
|
||||
@@ -3559,6 +3653,118 @@ public class ClientLoanIntegrationTest {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoanScheduleWithInterestRecalculation_WITH_REST_WEEKLY_INTEREST_COMPOUND_INTEREST_FEE_STRATEGY_REDUCE_NEXT_INSTALLMENTS_PRE_CLOSE_INTEREST_PRE_CLOSE_DATE() {
|
||||
String preCloseInterestStrategy = LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE;
|
||||
String preCloseAmount = "7766.75";
|
||||
testLoanScheduleWithInterestRecalculation_WITH_REST_WEEKLY_INTEREST_COMPOUND_INTEREST_FEE_STRATEGY_REDUCE_NEXT_INSTALLMENTS_PRE_CLOSE_INTEREST(
|
||||
preCloseInterestStrategy, preCloseAmount);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoanScheduleWithInterestRecalculation_WITH_REST_WEEKLY_INTEREST_COMPOUND_INTEREST_FEE_STRATEGY_REDUCE_NEXT_INSTALLMENTS_PRE_CLOSE_INTEREST_REST_DATE() {
|
||||
String preCloseInterestStrategy = LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_REST_DATE;
|
||||
String preCloseAmount = "7771.71";
|
||||
testLoanScheduleWithInterestRecalculation_WITH_REST_WEEKLY_INTEREST_COMPOUND_INTEREST_FEE_STRATEGY_REDUCE_NEXT_INSTALLMENTS_PRE_CLOSE_INTEREST(
|
||||
preCloseInterestStrategy, preCloseAmount);
|
||||
|
||||
}
|
||||
|
||||
private void testLoanScheduleWithInterestRecalculation_WITH_REST_WEEKLY_INTEREST_COMPOUND_INTEREST_FEE_STRATEGY_REDUCE_NEXT_INSTALLMENTS_PRE_CLOSE_INTEREST(
|
||||
String preCloseInterestStrategy, String preCloseAmount) {
|
||||
this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec);
|
||||
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy");
|
||||
|
||||
Calendar todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
todaysDate.add(Calendar.DAY_OF_MONTH, -16);
|
||||
final String LOAN_DISBURSEMENT_DATE = dateFormat.format(todaysDate.getTime());
|
||||
todaysDate.add(Calendar.DAY_OF_MONTH, -4);
|
||||
final String REST_START_DATE = dateFormat.format(todaysDate.getTime());
|
||||
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
todaysDate.add(Calendar.DAY_OF_MONTH, -16);
|
||||
todaysDate.add(Calendar.DAY_OF_MONTH, 2);
|
||||
final String LOAN_FLAT_CHARGE_DATE = dateFormat.format(todaysDate.getTime());
|
||||
todaysDate.add(Calendar.DAY_OF_MONTH, 14);
|
||||
final String LOAN_INTEREST_CHARGE_DATE = dateFormat.format(todaysDate.getTime());
|
||||
List<HashMap> charges = new ArrayList<>(2);
|
||||
Integer flat = ChargesHelper.createCharges(requestSpec, responseSpec,
|
||||
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, "100", false));
|
||||
Integer principalPercentage = ChargesHelper.createCharges(requestSpec, responseSpec,
|
||||
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_PERCENTAGE_AMOUNT, "2", false));
|
||||
|
||||
addCharges(charges, flat, "100", LOAN_FLAT_CHARGE_DATE);
|
||||
addCharges(charges, principalPercentage, "2", LOAN_INTEREST_CHARGE_DATE);
|
||||
|
||||
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
|
||||
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
|
||||
final Integer loanProductID = createLoanProductWithInterestRecalculation(LoanProductTestBuilder.MIFOS_STANDARD_STRATEGY,
|
||||
LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_INTEREST_AND_FEE,
|
||||
LoanProductTestBuilder.RECALCULATION_STRATEGY_RESCHEDULE_NEXT_REPAYMENTS,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_WEEKLY, "1", REST_START_DATE, preCloseInterestStrategy, null);
|
||||
|
||||
final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, LOAN_DISBURSEMENT_DATE,
|
||||
REST_START_DATE, LoanApplicationTestBuilder.MIFOS_STANDARD_STRATEGY, charges);
|
||||
|
||||
Assert.assertNotNull(loanID);
|
||||
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
|
||||
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
||||
|
||||
ArrayList<HashMap> loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
List<Map<String, Object>> expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -9, true, "2482.76", "46.15", "100.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2489.31", "39.6", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2500.78", "28.13", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2527.15", "16.61", "0.0", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
System.out.println("-----------------------------------APPROVE LOAN-----------------------------------------");
|
||||
loanStatusHashMap = this.loanTransactionHelper.approveLoan(LOAN_DISBURSEMENT_DATE, loanID);
|
||||
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
|
||||
LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap);
|
||||
|
||||
System.out.println("-------------------------------DISBURSE LOAN-------------------------------------------");
|
||||
loanStatusHashMap = this.loanTransactionHelper.disburseLoan(LOAN_DISBURSEMENT_DATE, loanID);
|
||||
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
|
||||
|
||||
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -9, true, "2482.76", "46.15", "100.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2482.37", "46.54", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2497.29", "31.62", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2537.58", "16.65", "0.0", "0.0");
|
||||
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
Calendar repaymentDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
repaymentDate.add(Calendar.DAY_OF_MONTH, -9);
|
||||
final String LOAN_FIRST_REPAYMENT_DATE = dateFormat.format(repaymentDate.getTime());
|
||||
Float totalDueForCurrentPeriod = (Float) loanSchedule.get(1).get("totalDueForPeriod");
|
||||
this.loanTransactionHelper.makeRepayment(LOAN_FIRST_REPAYMENT_DATE, totalDueForCurrentPeriod, loanID);
|
||||
|
||||
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -9, true, "2482.76", "46.15", "100.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2489.31", "39.6", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2500.78", "28.13", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2527.15", "16.61", "0.0", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
HashMap prepayDetail = this.loanTransactionHelper.getPrepayAmount(this.requestSpec, this.responseSpec, loanID);
|
||||
String prepayAmount = String.valueOf(prepayDetail.get("amount"));
|
||||
validateNumberForEqualWithMsg("verify pre-close amount", preCloseAmount, prepayAmount);
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
String LOAN_REPAYMENT_DATE = dateFormat.format(todaysDate.getTime());
|
||||
this.loanTransactionHelper.makeRepayment(LOAN_REPAYMENT_DATE, new Float(prepayAmount), loanID);
|
||||
loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
|
||||
LoanStatusChecker.verifyLoanAccountIsClosed(loanStatusHashMap);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoanScheduleWithInterestRecalculation_WITH_REST_DAILY_INTEREST_COMPOUND_INTEREST_FEE_STRATEGY_WITH_OVERDUE_CHARGE()
|
||||
throws InterruptedException {
|
||||
@@ -3584,7 +3790,8 @@ public class ClientLoanIntegrationTest {
|
||||
final Integer loanProductID = createLoanProductWithInterestRecalculation(LoanProductTestBuilder.MIFOS_STANDARD_STRATEGY,
|
||||
LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_INTEREST_AND_FEE,
|
||||
LoanProductTestBuilder.RECALCULATION_STRATEGY_RESCHEDULE_NEXT_REPAYMENTS,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_DAILY, "1", REST_START_DATE, null, overdueFeeChargeId.toString(), false);
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_DAILY, "1", REST_START_DATE,
|
||||
LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null, overdueFeeChargeId.toString(), false);
|
||||
|
||||
final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, LOAN_DISBURSEMENT_DATE,
|
||||
REST_START_DATE, LoanApplicationTestBuilder.MIFOS_STANDARD_STRATEGY, null);
|
||||
@@ -3596,10 +3803,10 @@ public class ClientLoanIntegrationTest {
|
||||
ArrayList<HashMap> loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
List<Map<String, Object>> expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -2, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2494.22", "34.69", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2505.73", "23.18", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2517.29", "11.62", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, -2, false, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2494.22", "34.69", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2505.73", "23.18", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2517.29", "11.62", "0.0", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
System.out.println("-----------------------------------APPROVE LOAN-----------------------------------------");
|
||||
@@ -3614,13 +3821,12 @@ public class ClientLoanIntegrationTest {
|
||||
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
|
||||
|
||||
addRepaymentValues(expectedvalues, todaysDate, -2, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2482.54", "46.37", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2482.33", "46.58", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2552.37", "11.78", "0.0", "0.0");
|
||||
|
||||
|
||||
addRepaymentValues(expectedvalues, todaysDate, -2, false, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2482.54", "46.37", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2482.33", "46.58", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2552.37", "11.78", "0.0", "0.0");
|
||||
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
String JobName = "Apply penalty to overdue loans";
|
||||
@@ -3629,10 +3835,10 @@ public class ClientLoanIntegrationTest {
|
||||
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -2, "2482.76", "46.15", "0.0", "252.89");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2481.38", "47.53", "0.0", "252.89");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2479.99", "48.92", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2555.87", "11.8", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, -2, false, "2482.76", "46.15", "0.0", "252.89");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2481.38", "47.53", "0.0", "252.89");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2479.99", "48.92", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2555.87", "11.8", "0.0", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
Calendar repaymentDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
@@ -3645,10 +3851,10 @@ public class ClientLoanIntegrationTest {
|
||||
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -2, "2482.76", "46.15", "0.0", "252.89");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2493.05", "35.86", "0.0", "252.89");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2491.72", "37.19", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2532.47", "11.69", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, -2, false, "2482.76", "46.15", "0.0", "252.89");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2493.05", "35.86", "0.0", "252.89");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2491.72", "37.19", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2532.47", "11.69", "0.0", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
repaymentDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
@@ -3660,10 +3866,10 @@ public class ClientLoanIntegrationTest {
|
||||
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -2, "2482.76", "46.15", "0.0", "252.89");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2493.05", "35.86", "0.0", "252.89");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2491.72", "37.19", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2532.47", "11.69", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, -2, false, "2482.76", "46.15", "0.0", "252.89");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2493.05", "35.86", "0.0", "252.89");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2497.22", "31.69", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2526.97", "11.66", "0.0", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
}
|
||||
@@ -3691,7 +3897,8 @@ public class ClientLoanIntegrationTest {
|
||||
final Integer loanProductID = createLoanProductWithInterestRecalculation(LoanProductTestBuilder.MIFOS_STANDARD_STRATEGY,
|
||||
LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_NONE,
|
||||
LoanProductTestBuilder.RECALCULATION_STRATEGY_REDUCE_EMI_AMOUN,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, "0", null, accounts);
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, "0", null,
|
||||
LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, accounts);
|
||||
|
||||
final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, LOAN_DISBURSEMENT_DATE, null,
|
||||
LoanApplicationTestBuilder.MIFOS_STANDARD_STRATEGY, new ArrayList<HashMap>(0));
|
||||
@@ -3703,10 +3910,10 @@ public class ClientLoanIntegrationTest {
|
||||
ArrayList<HashMap> loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
List<Map<String, Object>> expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2494.22", "34.69", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2505.73", "23.18", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2517.29", "11.62", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2494.22", "34.69", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2505.73", "23.18", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2517.29", "11.62", "0.0", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
System.out.println("-----------------------------------APPROVE LOAN-----------------------------------------");
|
||||
@@ -3721,10 +3928,10 @@ public class ClientLoanIntegrationTest {
|
||||
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2505.67", "23.24", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2528.81", "11.67", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2505.67", "23.24", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2528.81", "11.67", "0.0", "0.0");
|
||||
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
@@ -3746,10 +3953,10 @@ public class ClientLoanIntegrationTest {
|
||||
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2494.22", "34.69", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2505.73", "23.18", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2517.29", "11.62", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2494.22", "34.69", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2505.73", "23.18", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2517.29", "11.62", "0.0", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
this.loanTransactionHelper.checkAccrualTransactionForRepayment(Utils.getLocalDateOfTenant().minusDays(7), 46.15f, 0f, 0f, loanID);
|
||||
@@ -3783,7 +3990,8 @@ public class ClientLoanIntegrationTest {
|
||||
final Integer loanProductID = createLoanProductWithInterestRecalculation(LoanProductTestBuilder.RBI_INDIA_STRATEGY,
|
||||
LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_INTEREST,
|
||||
LoanProductTestBuilder.RECALCULATION_STRATEGY_RESCHEDULE_NEXT_REPAYMENTS,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_DAILY, "1", LOAN_DISBURSEMENT_DATE, null);
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_DAILY, "1", LOAN_DISBURSEMENT_DATE,
|
||||
LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null);
|
||||
|
||||
final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, LOAN_DISBURSEMENT_DATE,
|
||||
LOAN_DISBURSEMENT_DATE, LoanApplicationTestBuilder.RBI_INDIA_STRATEGY, new ArrayList<HashMap>(0));
|
||||
@@ -3795,10 +4003,10 @@ public class ClientLoanIntegrationTest {
|
||||
ArrayList<HashMap> loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
List<Map<String, Object>> expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2494.22", "34.69", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2505.73", "23.18", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2517.29", "11.62", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2494.22", "34.69", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2505.73", "23.18", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2517.29", "11.62", "0.0", "0.0");
|
||||
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
@@ -3814,10 +4022,10 @@ public class ClientLoanIntegrationTest {
|
||||
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2482.54", "46.37", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2505.67", "23.24", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2529.03", "11.67", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2482.54", "46.37", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2505.67", "23.24", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2529.03", "11.67", "0.0", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
@@ -3851,7 +4059,7 @@ public class ClientLoanIntegrationTest {
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy");
|
||||
|
||||
Calendar todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
System.out.println("----timeeeeeeeeeeeeee------>"+dateFormat.format(todaysDate.getTime()));
|
||||
System.out.println("----timeeeeeeeeeeeeee------>" + dateFormat.format(todaysDate.getTime()));
|
||||
todaysDate.add(Calendar.DAY_OF_MONTH, -14);
|
||||
final String LOAN_DISBURSEMENT_DATE = dateFormat.format(todaysDate.getTime());
|
||||
|
||||
@@ -3860,7 +4068,8 @@ public class ClientLoanIntegrationTest {
|
||||
final Integer loanProductID = createLoanProductWithInterestRecalculation(LoanProductTestBuilder.RBI_INDIA_STRATEGY,
|
||||
LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_INTEREST,
|
||||
LoanProductTestBuilder.RECALCULATION_STRATEGY_RESCHEDULE_NEXT_REPAYMENTS,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_DAILY, "1", LOAN_DISBURSEMENT_DATE, null, null, true);
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_DAILY, "1", LOAN_DISBURSEMENT_DATE,
|
||||
LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null, null, true);
|
||||
|
||||
final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, LOAN_DISBURSEMENT_DATE,
|
||||
LOAN_DISBURSEMENT_DATE, LoanApplicationTestBuilder.RBI_INDIA_STRATEGY, new ArrayList<HashMap>(0));
|
||||
@@ -3872,10 +4081,10 @@ public class ClientLoanIntegrationTest {
|
||||
ArrayList<HashMap> loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
List<Map<String, Object>> expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2494.22", "34.69", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2505.73", "23.18", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2517.29", "11.62", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2494.22", "34.69", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2505.73", "23.18", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2517.29", "11.62", "0.0", "0.0");
|
||||
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
@@ -3891,10 +4100,10 @@ public class ClientLoanIntegrationTest {
|
||||
loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID);
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2482.54", "46.37", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2505.67", "23.24", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, "2529.03", "11.67", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, -1, false, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2482.54", "46.37", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2505.67", "23.24", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2529.03", "11.67", "0.0", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
@@ -3919,10 +4128,14 @@ public class ClientLoanIntegrationTest {
|
||||
|
||||
}
|
||||
|
||||
private void addRepaymentValues(List<Map<String, Object>> expectedvalues, Calendar todaysDate, int addMonths, String principalDue,
|
||||
String interestDue, String feeChargesDue, String penaltyChargesDue) {
|
||||
private void addRepaymentValues(List<Map<String, Object>> expectedvalues, Calendar todaysDate, int addPeriod, boolean isAddDays,
|
||||
String principalDue, String interestDue, String feeChargesDue, String penaltyChargesDue) {
|
||||
Map<String, Object> values = new HashMap<>(3);
|
||||
values.put("dueDate", getDateAsArray(todaysDate, addMonths));
|
||||
if (isAddDays) {
|
||||
values.put("dueDate", getDateAsArray(todaysDate, addPeriod));
|
||||
} else {
|
||||
values.put("dueDate", getDateAsArray(todaysDate, addPeriod * 7));
|
||||
}
|
||||
values.put("principalDue", principalDue);
|
||||
values.put("interestDue", interestDue);
|
||||
values.put("feeChargesDue", feeChargesDue);
|
||||
@@ -3930,8 +4143,8 @@ public class ClientLoanIntegrationTest {
|
||||
expectedvalues.add(values);
|
||||
}
|
||||
|
||||
private List getDateAsArray(Calendar todaysDate, int addWeeks) {
|
||||
getDateAsArray(todaysDate, addWeeks * 7, Calendar.DAY_OF_MONTH);
|
||||
private List getDateAsArray(Calendar todaysDate, int addPeriod) {
|
||||
getDateAsArray(todaysDate, addPeriod, Calendar.DAY_OF_MONTH);
|
||||
return new ArrayList<>(Arrays.asList(todaysDate.get(Calendar.YEAR), todaysDate.get(Calendar.MONTH) + 1,
|
||||
todaysDate.get(Calendar.DAY_OF_MONTH)));
|
||||
}
|
||||
@@ -3945,17 +4158,17 @@ public class ClientLoanIntegrationTest {
|
||||
private Integer createLoanProductWithInterestRecalculation(final String repaymentStrategy,
|
||||
final String interestRecalculationCompoundingMethod, final String rescheduleStrategyMethod,
|
||||
final String recalculationRestFrequencyType, final String recalculationRestFrequencyInterval,
|
||||
final String recalculationRestFrequencyDate, final Account[] accounts) {
|
||||
final String recalculationRestFrequencyDate, final String preCloseInterestCalculationStrategy, final Account[] accounts) {
|
||||
return createLoanProductWithInterestRecalculation(repaymentStrategy, interestRecalculationCompoundingMethod,
|
||||
rescheduleStrategyMethod, recalculationRestFrequencyType, recalculationRestFrequencyInterval,
|
||||
recalculationRestFrequencyDate, accounts, null, false);
|
||||
recalculationRestFrequencyDate, preCloseInterestCalculationStrategy, accounts, null, false);
|
||||
}
|
||||
|
||||
private Integer createLoanProductWithInterestRecalculation(final String repaymentStrategy,
|
||||
final String interestRecalculationCompoundingMethod, final String rescheduleStrategyMethod,
|
||||
final String recalculationRestFrequencyType, final String recalculationRestFrequencyInterval,
|
||||
final String recalculationRestFrequencyDate, final Account[] accounts, final String chargeId,
|
||||
boolean isArrearsBasedOnOriginalSchedule) {
|
||||
final String recalculationRestFrequencyDate, final String preCloseInterestCalculationStrategy, final Account[] accounts,
|
||||
final String chargeId, boolean isArrearsBasedOnOriginalSchedule) {
|
||||
System.out.println("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------");
|
||||
LoanProductTestBuilder builder = new LoanProductTestBuilder()
|
||||
.withPrincipal("10000000.00")
|
||||
@@ -3967,7 +4180,8 @@ public class ClientLoanIntegrationTest {
|
||||
.withRepaymentStrategy(repaymentStrategy)
|
||||
.withAmortizationTypeAsEqualPrincipalPayment()
|
||||
.withInterestTypeAsDecliningBalance()
|
||||
.withInterestRecalculationDetails(interestRecalculationCompoundingMethod, rescheduleStrategyMethod)
|
||||
.withInterestRecalculationDetails(interestRecalculationCompoundingMethod, rescheduleStrategyMethod,
|
||||
preCloseInterestCalculationStrategy)
|
||||
.withInterestRecalculationRestFrequencyDetails(recalculationRestFrequencyType, recalculationRestFrequencyInterval,
|
||||
recalculationRestFrequencyDate);
|
||||
if (accounts != null) {
|
||||
|
||||
+7
-1
@@ -51,6 +51,9 @@ public class LoanProductTestBuilder {
|
||||
private static final String CASH_BASED = "2";
|
||||
private static final String ACCRUAL_PERIODIC = "3";
|
||||
private static final String ACCRUAL_UPFRONT = "4";
|
||||
|
||||
public static final String INTEREST_APPLICABLE_STRATEGY_REST_DATE = "2";
|
||||
public static final String INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE = "1";
|
||||
|
||||
private String digitsAfterDecimal = "2";
|
||||
private String inMultiplesOf = "0";
|
||||
@@ -83,6 +86,7 @@ public class LoanProductTestBuilder {
|
||||
private String daysInYearType = "1";
|
||||
private String daysInMonthType = "1";
|
||||
private String interestRecalculationCompoundingMethod = "0";
|
||||
private String preCloseInterestCalculationStrategy = INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE;
|
||||
private String rescheduleStrategyMethod = "1";
|
||||
private String recalculationRestFrequencyType = "1";
|
||||
private String recalculationRestFrequencyInterval = "0";
|
||||
@@ -149,6 +153,7 @@ public class LoanProductTestBuilder {
|
||||
map.put("recalculationRestFrequencyType", recalculationRestFrequencyType);
|
||||
map.put("recalculationRestFrequencyInterval", recalculationRestFrequencyInterval);
|
||||
map.put("recalculationRestFrequencyDate", recalculationRestFrequencyDate);
|
||||
map.put("preCloseInterestCalculationStrategy", preCloseInterestCalculationStrategy);
|
||||
if (isArrearsBasedOnOriginalSchedule != null) {
|
||||
map.put("isArrearsBasedOnOriginalSchedule", isArrearsBasedOnOriginalSchedule);
|
||||
}
|
||||
@@ -381,10 +386,11 @@ public class LoanProductTestBuilder {
|
||||
}
|
||||
|
||||
public LoanProductTestBuilder withInterestRecalculationDetails(final String interestRecalculationCompoundingMethod,
|
||||
final String rescheduleStrategyMethod) {
|
||||
final String rescheduleStrategyMethod, String preCloseInterestCalculationStrategy) {
|
||||
this.isInterestRecalculationEnabled = true;
|
||||
this.interestRecalculationCompoundingMethod = interestRecalculationCompoundingMethod;
|
||||
this.rescheduleStrategyMethod = rescheduleStrategyMethod;
|
||||
this.preCloseInterestCalculationStrategy = preCloseInterestCalculationStrategy;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
+21
-15
@@ -2375,13 +2375,15 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
.getInterestRecalculationCompoundingMethod());
|
||||
}
|
||||
|
||||
final LoanApplicationTerms loanApplicationTerms = LoanApplicationTerms.assembleFrom(scheduleGeneratorDTO.getApplicationCurrency(),
|
||||
loanTermFrequency, loanTermPeriodFrequencyType, nthDayType, dayOfWeekType, getDisbursementDate(),
|
||||
getExpectedFirstRepaymentOnDate(), scheduleGeneratorDTO.getCalculatedRepaymentsStartingFromDate(), getInArrearsTolerance(),
|
||||
this.loanRepaymentScheduleDetail, this.loanProduct.isMultiDisburseLoan(), this.fixedEmiAmount, disbursementData,
|
||||
this.maxOutstandingLoanBalance, loanVariationTermsData, getInterestChargedFromDate(),
|
||||
this.loanProduct.getPrincipalThresholdForLastInstallment(), this.loanProduct.getInstallmentAmountInMultiplesOf(),
|
||||
recalculationFrequencyType, restCalendarInstance, compoundingMethod);
|
||||
final LoanApplicationTerms loanApplicationTerms = LoanApplicationTerms
|
||||
.assembleFrom(scheduleGeneratorDTO.getApplicationCurrency(), loanTermFrequency, loanTermPeriodFrequencyType, nthDayType,
|
||||
dayOfWeekType, getDisbursementDate(), getExpectedFirstRepaymentOnDate(),
|
||||
scheduleGeneratorDTO.getCalculatedRepaymentsStartingFromDate(), getInArrearsTolerance(),
|
||||
this.loanRepaymentScheduleDetail, this.loanProduct.isMultiDisburseLoan(), this.fixedEmiAmount, disbursementData,
|
||||
this.maxOutstandingLoanBalance, loanVariationTermsData, getInterestChargedFromDate(),
|
||||
this.loanProduct.getPrincipalThresholdForLastInstallment(), this.loanProduct.getInstallmentAmountInMultiplesOf(),
|
||||
recalculationFrequencyType, restCalendarInstance, compoundingMethod,
|
||||
this.loanProduct.preCloseInterestCalculationStrategy());
|
||||
|
||||
final LoanScheduleModel loanSchedule = loanScheduleGenerator.generate(mc, loanApplicationTerms, charges(),
|
||||
scheduleGeneratorDTO.getHolidayDetailDTO());
|
||||
@@ -4729,7 +4731,8 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
this.loanProduct.isMultiDisburseLoan(), this.fixedEmiAmount, disbursementData, this.maxOutstandingLoanBalance,
|
||||
loanVariationTermsData, getInterestChargedFromDate(), this.loanInterestRecalculationDetails,
|
||||
calendarInstanceForInterestRecalculation, recalculationFrequencyType,
|
||||
this.loanProduct.getPrincipalThresholdForLastInstallment(), this.loanProduct.getInstallmentAmountInMultiplesOf());
|
||||
this.loanProduct.getPrincipalThresholdForLastInstallment(), this.loanProduct.getInstallmentAmountInMultiplesOf(),
|
||||
this.loanProduct.preCloseInterestCalculationStrategy());
|
||||
return loanApplicationTerms;
|
||||
}
|
||||
|
||||
@@ -4783,7 +4786,8 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
getInArrearsTolerance(), this.loanRepaymentScheduleDetail, this.loanProduct.isMultiDisburseLoan(), this.fixedEmiAmount,
|
||||
disbursementData, this.maxOutstandingLoanBalance, loanVariationTermsData, getInterestChargedFromDate(),
|
||||
this.loanProduct.getPrincipalThresholdForLastInstallment(), this.loanProduct.getInstallmentAmountInMultiplesOf(),
|
||||
recalculationFrequencyType, restCalendarInstance, compoundingMethod);
|
||||
recalculationFrequencyType, restCalendarInstance, compoundingMethod,
|
||||
this.loanProduct.preCloseInterestCalculationStrategy());
|
||||
|
||||
installment = loanScheduleGenerator.calculatePrepaymentAmount(this.repaymentScheduleInstallments, getCurrency(),
|
||||
DateUtils.getLocalDateOfTenant(), loanApplicationTerms, mc, charges(), holidayDetailDTO);
|
||||
@@ -4992,12 +4996,14 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
.getInterestRecalculationCompoundingMethod());
|
||||
}
|
||||
|
||||
return LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, nthDayType,
|
||||
dayOfWeekType, expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate,
|
||||
inArrearsToleranceMoney, this.loanRepaymentScheduleDetail, loanProduct.isMultiDisburseLoan(), emiAmount, disbursementData,
|
||||
maxOutstandingBalance, loanVariationTermsData, interestChargedFromDate,
|
||||
this.loanProduct.getPrincipalThresholdForLastInstallment(), this.loanProduct.getInstallmentAmountInMultiplesOf(),
|
||||
recalculationFrequencyType, restCalendarInstance, compoundingMethod);
|
||||
return LoanApplicationTerms
|
||||
.assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, nthDayType, dayOfWeekType,
|
||||
expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate,
|
||||
inArrearsToleranceMoney, this.loanRepaymentScheduleDetail, loanProduct.isMultiDisburseLoan(), emiAmount,
|
||||
disbursementData, maxOutstandingBalance, loanVariationTermsData, interestChargedFromDate,
|
||||
this.loanProduct.getPrincipalThresholdForLastInstallment(), this.loanProduct.getInstallmentAmountInMultiplesOf(),
|
||||
recalculationFrequencyType, restCalendarInstance, compoundingMethod,
|
||||
this.loanProduct.preCloseInterestCalculationStrategy());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+285
-140
@@ -144,6 +144,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
// interest calculation
|
||||
final Map<LocalDate, Money> latePaymentMap = new HashMap<>();
|
||||
final List<LoanRepaymentScheduleInstallment> installments = new ArrayList<>();
|
||||
LocalDate currentDate = DateUtils.getLocalDateOfTenant();
|
||||
while (!outstandingBalance.isZero() || !disburseDetailMap.isEmpty()) {
|
||||
|
||||
actualRepaymentDate = this.scheduledDateGenerator.generateNextRepaymentDate(actualRepaymentDate, loanApplicationTerms,
|
||||
@@ -202,126 +203,213 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
// transaction processor configuration
|
||||
// will be added only if there is a loan repayment between the
|
||||
// period for interest first repayment strategies
|
||||
if (isInterestRecalculationRequired(loanApplicationTerms, transactions) && loanRepaymentScheduleTransactionProcessor != null
|
||||
&& loanRepaymentScheduleTransactionProcessor.isInterestFirstRepaymentScheduleTransactionProcessor()) {
|
||||
Money earlyPaidAmount = Money.zero(currency);
|
||||
LoanScheduleModelPeriod lastInstallment = null;
|
||||
if (isInterestRecalculationRequired(loanApplicationTerms, transactions)) {
|
||||
boolean checkForOutstanding = true;
|
||||
List<RecalculationDetail> unprocessedTransactions = new ArrayList<>();
|
||||
LoanScheduleModelPeriod installment = null;
|
||||
for (RecalculationDetail detail : applicableTransactions) {
|
||||
if (detail.isProcessed()) {
|
||||
continue;
|
||||
}
|
||||
if (detail.getTransactionDate().isBefore(scheduledDueDate)) {
|
||||
List<LoanTransaction> currentTransactions = createCurrentTransactionList(detail);
|
||||
if (!detail.getTransactionDate().isEqual(periodStartDate)) {
|
||||
int periodDays = Days.daysBetween(periodStartDate, detail.getTransactionDate()).getDays();
|
||||
// calculates period start date for interest
|
||||
// calculation as per the configuration
|
||||
periodStartDateApplicableForInterest = calculateInterestStartDateForPeriod(loanApplicationTerms,
|
||||
periodStartDate, idealDisbursementDate, periodStartDateApplicableForInterest);
|
||||
if (loanRepaymentScheduleTransactionProcessor != null
|
||||
&& loanRepaymentScheduleTransactionProcessor.isInterestFirstRepaymentScheduleTransactionProcessor()) {
|
||||
List<LoanTransaction> currentTransactions = createCurrentTransactionList(detail);
|
||||
if (!detail.getTransactionDate().isEqual(periodStartDate)) {
|
||||
int periodDays = Days.daysBetween(periodStartDate, detail.getTransactionDate()).getDays();
|
||||
// calculates period start date for interest
|
||||
// calculation as per the configuration
|
||||
periodStartDateApplicableForInterest = calculateInterestStartDateForPeriod(loanApplicationTerms,
|
||||
periodStartDate, idealDisbursementDate, periodStartDateApplicableForInterest);
|
||||
|
||||
int daysInPeriodApplicable = Days
|
||||
.daysBetween(periodStartDateApplicableForInterest, detail.getTransactionDate()).getDays();
|
||||
Money interestForThisinstallment = Money.zero(currency);
|
||||
if (daysInPeriodApplicable > 0) {
|
||||
// 5 determine interest till the transaction
|
||||
// date
|
||||
PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(
|
||||
this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction,
|
||||
totalCumulativePrincipal.minus(reducePrincipal), totalCumulativeInterest,
|
||||
totalInterestChargedForFullLoanTerm, totalOutstandingInterestPaymentDueToGrace,
|
||||
outstandingBalanceAsPerRest, loanApplicationTerms, periodNumber, mc,
|
||||
mergeLateAndPaymentMaps(principalPortionMap, latePaymentMap, disburseDetailMap),
|
||||
periodStartDateApplicableForInterest, detail.getTransactionDate(),
|
||||
daysInPeriodApplicableForInterest);
|
||||
interestForThisinstallment = principalInterestForThisPeriod.interest();
|
||||
int daysInPeriodApplicable = Days.daysBetween(periodStartDateApplicableForInterest,
|
||||
detail.getTransactionDate()).getDays();
|
||||
Money interestForThisinstallment = Money.zero(currency);
|
||||
if (daysInPeriodApplicable > 0) {
|
||||
// 5 determine interest till the transaction
|
||||
// date
|
||||
PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(
|
||||
this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction,
|
||||
totalCumulativePrincipal.minus(reducePrincipal), totalCumulativeInterest,
|
||||
totalInterestChargedForFullLoanTerm, totalOutstandingInterestPaymentDueToGrace,
|
||||
outstandingBalanceAsPerRest, loanApplicationTerms, periodNumber, mc,
|
||||
mergeLateAndPaymentMaps(principalPortionMap, latePaymentMap, disburseDetailMap),
|
||||
periodStartDateApplicableForInterest, detail.getTransactionDate(),
|
||||
daysInPeriodApplicableForInterest);
|
||||
interestForThisinstallment = principalInterestForThisPeriod.interest();
|
||||
|
||||
totalOutstandingInterestPaymentDueToGrace = principalInterestForThisPeriod.interestPaymentDueToGrace();
|
||||
totalOutstandingInterestPaymentDueToGrace = principalInterestForThisPeriod.interestPaymentDueToGrace();
|
||||
|
||||
}
|
||||
|
||||
Money principalForThisPeriod = principalDisbursed.zero();
|
||||
|
||||
// applies all the applicable charges to the
|
||||
// newly
|
||||
// created installment
|
||||
PrincipalInterest principalInterest = new PrincipalInterest(principalForThisPeriod,
|
||||
interestForThisinstallment, null);
|
||||
Money feeChargesForInstallment = cumulativeFeeChargesDueWithin(periodStartDate,
|
||||
detail.getTransactionDate(), loanCharges, currency, principalInterest, principalDisbursed,
|
||||
totalCumulativeInterest, numberOfRepayments, true, lastTransactionDate);
|
||||
Money penaltyChargesForInstallment = cumulativePenaltyChargesDueWithin(periodStartDate,
|
||||
detail.getTransactionDate(), loanCharges, currency, principalInterest, principalDisbursed,
|
||||
totalCumulativeInterest, numberOfRepayments, true, lastTransactionDate);
|
||||
|
||||
// 8. sum up real totalInstallmentDue from
|
||||
// components
|
||||
final Money totalInstallmentDue = principalForThisPeriod.plus(interestForThisinstallment)
|
||||
.plus(feeChargesForInstallment).plus(penaltyChargesForInstallment);
|
||||
// 9. create repayment period from parts
|
||||
installment = LoanScheduleModelRepaymentPeriod.repayment(instalmentNumber, periodStartDate,
|
||||
detail.getTransactionDate(), principalForThisPeriod, outstandingBalance,
|
||||
interestForThisinstallment, feeChargesForInstallment, penaltyChargesForInstallment,
|
||||
totalInstallmentDue, true);
|
||||
periods.add(installment);
|
||||
|
||||
// update outstanding balance for interest
|
||||
// calculation as per the rest
|
||||
outstandingBalanceAsPerRest = updateBalanceForInterestCalculation(principalPortionMap,
|
||||
detail.getTransactionDate(), outstandingBalanceAsPerRest, false);
|
||||
outstandingBalanceAsPerRest = updateBalanceForInterestCalculation(disburseDetailMap,
|
||||
detail.getTransactionDate(), outstandingBalanceAsPerRest, true);
|
||||
|
||||
// handle cumulative fields
|
||||
loanTermInDays += periodDays;
|
||||
totalRepaymentExpected = totalRepaymentExpected.add(totalInstallmentDue.getAmount());
|
||||
totalCumulativeInterest = totalCumulativeInterest.plus(interestForThisinstallment);
|
||||
totalFeeChargesCharged = totalFeeChargesCharged.add(feeChargesForInstallment.getAmount());
|
||||
totalPenaltyChargesCharged = totalPenaltyChargesCharged.add(penaltyChargesForInstallment.getAmount());
|
||||
|
||||
periodStartDate = detail.getTransactionDate();
|
||||
periodStartDateApplicableForInterest = periodStartDate;
|
||||
instalmentNumber++;
|
||||
// creates and insert Loan repayment schedule
|
||||
// for
|
||||
// the period
|
||||
addLoanRepaymentScheduleInstallment(installments, installment);
|
||||
} else if (installment == null) {
|
||||
installment = ((List<LoanScheduleModelPeriod>) periods).get(periods.size() - 1);
|
||||
}
|
||||
// applies the transaction as per transaction
|
||||
// strategy
|
||||
// on scheduled installments to identify the
|
||||
// unprocessed(early payment ) amounts
|
||||
Money unprocessed = loanRepaymentScheduleTransactionProcessor.handleRepaymentSchedule(currentTransactions,
|
||||
currency, installments);
|
||||
if (unprocessed.isGreaterThanZero()) {
|
||||
|
||||
if (loanApplicationTerms.getPreCloseInterestCalculationStrategy().calculateTillRestFrequencyEnabled()) {
|
||||
LocalDate applicableDate = getNextRestScheduleDate(detail.getTransactionDate().minusDays(1),
|
||||
loanApplicationTerms, holidayDetailDTO);
|
||||
checkForOutstanding = detail.getTransactionDate().isEqual(applicableDate);
|
||||
|
||||
}
|
||||
// reduces actual outstanding balance
|
||||
outstandingBalance = outstandingBalance.minus(unprocessed);
|
||||
// if outstanding balance becomes less than zero
|
||||
// then adjusts the princiapal
|
||||
Money addToPrinciapal = Money.zero(currency);
|
||||
if (!outstandingBalance.isGreaterThanZero()) {
|
||||
addToPrinciapal = addToPrinciapal.plus(outstandingBalance);
|
||||
outstandingBalance = outstandingBalance.zero();
|
||||
lastInstallment = installment;
|
||||
}
|
||||
// updates principal portion map with the early
|
||||
// payment amounts and applicable date as per
|
||||
// rest
|
||||
updatePrincipalPaidPortionToMap(loanApplicationTerms, holidayDetailDTO, principalPortionMap, installment,
|
||||
detail, unprocessed.plus(addToPrinciapal), installments);
|
||||
totalRepaymentExpected = totalRepaymentExpected.add(unprocessed.plus(addToPrinciapal).getAmount());
|
||||
totalCumulativePrincipal = totalCumulativePrincipal.plus(unprocessed.plus(addToPrinciapal));
|
||||
|
||||
// method applies early payment strategy
|
||||
reducePrincipal = reducePrincipal.plus(unprocessed);
|
||||
reducePrincipal = applyEarlyPaymentStrategy(loanApplicationTerms, reducePrincipal);
|
||||
}
|
||||
// identify late payments and add compounding
|
||||
// details to
|
||||
// map for interest calculation
|
||||
if (!reducePrincipal.isZero() || !installment.periodDueDate().isBefore(currentDate)) {
|
||||
latePaymentMap.clear();
|
||||
} else {
|
||||
updateLatePaymentsToMap(loanApplicationTerms, holidayDetailDTO, currency, latePaymentMap, scheduledDueDate,
|
||||
installments, true);
|
||||
}
|
||||
} else if (loanRepaymentScheduleTransactionProcessor != null) {
|
||||
LocalDate applicableDate = getNextRestScheduleDate(detail.getTransactionDate().minusDays(1),
|
||||
loanApplicationTerms, holidayDetailDTO);
|
||||
if (applicableDate.isBefore(scheduledDueDate)) {
|
||||
List<LoanTransaction> currentTransactions = createCurrentTransactionList(detail);
|
||||
Money unprocessed = loanRepaymentScheduleTransactionProcessor.handleRepaymentSchedule(currentTransactions,
|
||||
currency, installments);
|
||||
Money arrears = detail.getTransaction().getAmount(currency);
|
||||
if (unprocessed.isGreaterThanZero()) {
|
||||
arrears = getTotalAmount(latePaymentMap, currency);
|
||||
updateMapWithAmount(principalPortionMap, unprocessed, applicableDate);
|
||||
earlyPaidAmount = earlyPaidAmount.plus(unprocessed);
|
||||
|
||||
// this check is to identify pre-closure and
|
||||
// apply interest calculation as per
|
||||
// configuration
|
||||
if (!outstandingBalance.isGreaterThan(unprocessed)
|
||||
&& !loanApplicationTerms.getPreCloseInterestCalculationStrategy()
|
||||
.calculateTillRestFrequencyEnabled()) {
|
||||
|
||||
LocalDate calculateTill = detail.getTransactionDate();
|
||||
PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(
|
||||
this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction,
|
||||
totalCumulativePrincipal.minus(reducePrincipal), totalCumulativeInterest,
|
||||
totalInterestChargedForFullLoanTerm, totalOutstandingInterestPaymentDueToGrace,
|
||||
outstandingBalanceAsPerRest, loanApplicationTerms, periodNumber, mc,
|
||||
mergeLateAndPaymentMaps(principalPortionMap, latePaymentMap, disburseDetailMap),
|
||||
periodStartDateApplicableForInterest, calculateTill, daysInPeriodApplicableForInterest);
|
||||
if (!principalInterestForThisPeriod.interest()
|
||||
.plus(principalInterestForThisPeriod.interestPaymentDueToGrace()).plus(outstandingBalance)
|
||||
.isGreaterThan(unprocessed)) {
|
||||
earlyPaidAmount = earlyPaidAmount.minus(unprocessed);
|
||||
updateMapWithAmount(principalPortionMap, unprocessed.negated(), applicableDate);
|
||||
LoanTransaction loanTransaction = LoanTransaction.repayment(null, unprocessed, null,
|
||||
detail.getTransactionDate(), null, DateUtils.getLocalDateTimeOfTenant(), null);
|
||||
RecalculationDetail recalculationDetail = new RecalculationDetail(detail.getTransactionDate(),
|
||||
loanTransaction);
|
||||
unprocessedTransactions.add(recalculationDetail);
|
||||
break;
|
||||
}
|
||||
}
|
||||
LoanTransaction loanTransaction = LoanTransaction.repayment(null, unprocessed, null, scheduledDueDate,
|
||||
null, DateUtils.getLocalDateTimeOfTenant(), null);
|
||||
RecalculationDetail recalculationDetail = new RecalculationDetail(scheduledDueDate, loanTransaction);
|
||||
unprocessedTransactions.add(recalculationDetail);
|
||||
checkForOutstanding = false;
|
||||
|
||||
outstandingBalance = outstandingBalance.minus(unprocessed);
|
||||
// if outstanding balance becomes less than
|
||||
// zero
|
||||
// then adjusts the princiapal
|
||||
Money addToPrinciapal = Money.zero(currency);
|
||||
if (outstandingBalance.isLessThanZero()) {
|
||||
addToPrinciapal = addToPrinciapal.plus(outstandingBalance);
|
||||
outstandingBalance = outstandingBalance.zero();
|
||||
updateMapWithAmount(principalPortionMap, addToPrinciapal, applicableDate);
|
||||
earlyPaidAmount = earlyPaidAmount.plus(addToPrinciapal);
|
||||
}
|
||||
|
||||
}
|
||||
if (arrears.isGreaterThanZero() && applicableDate.isBefore(currentDate)) {
|
||||
updateMapWithAmount(latePaymentMap, arrears.negated(), applicableDate);
|
||||
updateMapWithAmount(latePaymentMap, arrears, currentDate);
|
||||
}
|
||||
}
|
||||
|
||||
Money principalForThisPeriod = principalDisbursed.zero();
|
||||
|
||||
// applies all the applicable charges to the newly
|
||||
// created installment
|
||||
PrincipalInterest principalInterest = new PrincipalInterest(principalForThisPeriod, interestForThisinstallment,
|
||||
null);
|
||||
Money feeChargesForInstallment = cumulativeFeeChargesDueWithin(periodStartDate, detail.getTransactionDate(),
|
||||
loanCharges, currency, principalInterest, principalDisbursed, totalCumulativeInterest,
|
||||
numberOfRepayments, true, lastTransactionDate);
|
||||
Money penaltyChargesForInstallment = cumulativePenaltyChargesDueWithin(periodStartDate,
|
||||
detail.getTransactionDate(), loanCharges, currency, principalInterest, principalDisbursed,
|
||||
totalCumulativeInterest, numberOfRepayments, true, lastTransactionDate);
|
||||
|
||||
// 8. sum up real totalInstallmentDue from
|
||||
// components
|
||||
final Money totalInstallmentDue = principalForThisPeriod.plus(interestForThisinstallment)
|
||||
.plus(feeChargesForInstallment).plus(penaltyChargesForInstallment);
|
||||
// 9. create repayment period from parts
|
||||
installment = LoanScheduleModelRepaymentPeriod.repayment(instalmentNumber, periodStartDate,
|
||||
detail.getTransactionDate(), principalForThisPeriod, outstandingBalance, interestForThisinstallment,
|
||||
feeChargesForInstallment, penaltyChargesForInstallment, totalInstallmentDue, true);
|
||||
periods.add(installment);
|
||||
|
||||
// update outstanding balance for interest
|
||||
// calculation as per the rest
|
||||
outstandingBalanceAsPerRest = updateBalanceForInterestCalculation(principalPortionMap,
|
||||
detail.getTransactionDate(), outstandingBalanceAsPerRest, false);
|
||||
outstandingBalanceAsPerRest = updateBalanceForInterestCalculation(disburseDetailMap,
|
||||
detail.getTransactionDate(), outstandingBalanceAsPerRest, true);
|
||||
|
||||
// handle cumulative fields
|
||||
loanTermInDays += periodDays;
|
||||
totalRepaymentExpected = totalRepaymentExpected.add(totalInstallmentDue.getAmount());
|
||||
totalCumulativeInterest = totalCumulativeInterest.plus(interestForThisinstallment);
|
||||
totalFeeChargesCharged = totalFeeChargesCharged.add(feeChargesForInstallment.getAmount());
|
||||
totalPenaltyChargesCharged = totalPenaltyChargesCharged.add(penaltyChargesForInstallment.getAmount());
|
||||
|
||||
periodStartDate = detail.getTransactionDate();
|
||||
periodStartDateApplicableForInterest = periodStartDate;
|
||||
instalmentNumber++;
|
||||
// creates and insert Loan repayment schedule for
|
||||
// the period
|
||||
addLoanRepaymentScheduleInstallment(installments, installment);
|
||||
} else if (installment == null) {
|
||||
installment = ((List<LoanScheduleModelPeriod>) periods).get(periods.size() - 1);
|
||||
}
|
||||
// applies the transaction as per transaction strategy
|
||||
// on scheduled installments to identify the
|
||||
// unprocessed(early payment ) amounts
|
||||
Money unprocessed = loanRepaymentScheduleTransactionProcessor.handleRepaymentSchedule(currentTransactions,
|
||||
currency, installments);
|
||||
if (unprocessed.isGreaterThanZero()) {
|
||||
// reduces actual outstanding balance
|
||||
outstandingBalance = outstandingBalance.minus(unprocessed);
|
||||
// if outstanding balance becomes less than zero
|
||||
// then adjusts the princiapal
|
||||
Money addToPrinciapal = Money.zero(currency);
|
||||
if (outstandingBalance.isLessThanZero()) {
|
||||
addToPrinciapal = addToPrinciapal.plus(outstandingBalance);
|
||||
outstandingBalance = outstandingBalance.zero();
|
||||
}
|
||||
// updates principal portion map with the early
|
||||
// payment amounts and applicable date as per rest
|
||||
updatePrincipalPaidPortionToMap(loanApplicationTerms, holidayDetailDTO, principalPortionMap, installment,
|
||||
detail, unprocessed.plus(addToPrinciapal), installments);
|
||||
totalRepaymentExpected = totalRepaymentExpected.add(unprocessed.plus(addToPrinciapal).getAmount());
|
||||
totalCumulativePrincipal = totalCumulativePrincipal.plus(unprocessed.plus(addToPrinciapal));
|
||||
|
||||
// method applies early payment strategy
|
||||
reducePrincipal = reducePrincipal.plus(unprocessed);
|
||||
reducePrincipal = applyEarlyPaymentStrategy(loanApplicationTerms, reducePrincipal);
|
||||
}
|
||||
// identify late payments and add compounding details to
|
||||
// map for interest calculation
|
||||
if (!reducePrincipal.isZero() || !installment.periodDueDate().isBefore(DateUtils.getLocalDateOfTenant())) {
|
||||
latePaymentMap.clear();
|
||||
} else {
|
||||
updateLatePaymentsToMap(loanApplicationTerms, holidayDetailDTO, currency, latePaymentMap, scheduledDueDate,
|
||||
installments, true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (outstandingBalance.isZero() && disburseDetailMap.isEmpty()) {
|
||||
applicableTransactions.addAll(unprocessedTransactions);
|
||||
if (checkForOutstanding && outstandingBalance.isZero() && disburseDetailMap.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -364,9 +452,19 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
principalForThisPeriod = principalForThisPeriod.zero();
|
||||
}
|
||||
|
||||
// earlyPaidAmount is already subtracted from balancereducePrincipal
|
||||
// reducePrincipal.plus(unprocessed);
|
||||
Money reducedBalance = earlyPaidAmount;
|
||||
earlyPaidAmount = earlyPaidAmount.minus(principalForThisPeriod);
|
||||
if (earlyPaidAmount.isGreaterThanZero()) {
|
||||
reducePrincipal = reducePrincipal.plus(earlyPaidAmount);
|
||||
reducePrincipal = applyEarlyPaymentStrategy(loanApplicationTerms, reducePrincipal);
|
||||
principalForThisPeriod = principalForThisPeriod.plus(earlyPaidAmount);
|
||||
}
|
||||
|
||||
// 6. update outstandingLoanBlance using current period
|
||||
// 'principalDue'
|
||||
outstandingBalance = outstandingBalance.minus(principalForThisPeriod);
|
||||
outstandingBalance = outstandingBalance.minus(principalForThisPeriod.minus(reducedBalance));
|
||||
|
||||
if (outstandingBalance.isLessThanZero()) {
|
||||
principalForThisPeriod = principalForThisPeriod.plus(outstandingBalance);
|
||||
@@ -386,6 +484,13 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
final Money totalInstallmentDue = principalForThisPeriod.plus(interestForThisinstallment).plus(feeChargesForInstallment)
|
||||
.plus(penaltyChargesForInstallment);
|
||||
|
||||
// if previous installment is last then add interest to same
|
||||
// installment
|
||||
if (lastInstallment != null && principalForThisPeriod.isZero()) {
|
||||
lastInstallment.addInterestAmount(interestForThisinstallment);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 9. create repayment period from parts
|
||||
LoanScheduleModelPeriod installment = LoanScheduleModelRepaymentPeriod.repayment(instalmentNumber, periodStartDate,
|
||||
scheduledDueDate, principalForThisPeriod, outstandingBalance, interestForThisinstallment, feeChargesForInstallment,
|
||||
@@ -393,9 +498,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
|
||||
// apply loan transactions on installments to identify early/late
|
||||
// payments for interest recalculation
|
||||
if (isInterestRecalculationRequired(loanApplicationTerms, transactions)) {
|
||||
if (isInterestRecalculationRequired(loanApplicationTerms, transactions) && loanRepaymentScheduleTransactionProcessor != null) {
|
||||
addLoanRepaymentScheduleInstallment(installments, installment);
|
||||
|
||||
for (RecalculationDetail detail : applicableTransactions) {
|
||||
if (!detail.isProcessed()) {
|
||||
List<LoanTransaction> currentTransactions = new ArrayList<>(2);
|
||||
@@ -405,18 +509,23 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
// unprocessed(early payment ) amounts
|
||||
Money unprocessed = loanRepaymentScheduleTransactionProcessor.handleRepaymentSchedule(currentTransactions,
|
||||
currency, installments);
|
||||
|
||||
if (unprocessed.isGreaterThanZero()) {
|
||||
outstandingBalance = outstandingBalance.minus(unprocessed);
|
||||
// pre closure check and processing
|
||||
if (outstandingBalance.isLessThan(interestForThisinstallment)
|
||||
&& !scheduledDueDate.equals(detail.getTransactionDate())) {
|
||||
LocalDate calculateTill = detail.getTransactionDate();
|
||||
if (loanApplicationTerms.getPreCloseInterestCalculationStrategy().calculateTillRestFrequencyEnabled()) {
|
||||
calculateTill = getNextRestScheduleDate(calculateTill.minusDays(1), loanApplicationTerms,
|
||||
holidayDetailDTO);
|
||||
}
|
||||
PrincipalInterest interestTillDate = calculatePrincipalInterestComponentsForPeriod(
|
||||
this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction,
|
||||
totalCumulativePrincipal, totalCumulativeInterest, totalInterestChargedForFullLoanTerm,
|
||||
totalOutstandingInterestPaymentDueToGrace, outstandingBalanceAsPerRest, loanApplicationTerms,
|
||||
periodNumber, mc, mergeLateAndPaymentMaps(principalPortionMap, latePaymentMap, disburseDetailMap),
|
||||
periodStartDateApplicableForInterest, detail.getTransactionDate(),
|
||||
daysInPeriodApplicableForInterest);
|
||||
periodStartDateApplicableForInterest, calculateTill, daysInPeriodApplicableForInterest);
|
||||
Money diff = interestForThisinstallment.minus(interestTillDate.interest());
|
||||
if (!outstandingBalance.minus(diff).isGreaterThanZero()) {
|
||||
outstandingBalance = outstandingBalance.minus(diff);
|
||||
@@ -455,7 +564,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
}
|
||||
|
||||
// identify late payments and adds compounding details to map
|
||||
if (!reducePrincipal.isZero() || !installment.periodDueDate().isBefore(DateUtils.getLocalDateOfTenant())) {
|
||||
if (!reducePrincipal.isZero() || !installment.periodDueDate().isBefore(currentDate)) {
|
||||
latePaymentMap.clear();
|
||||
} else {
|
||||
updateLatePaymentsToMap(loanApplicationTerms, holidayDetailDTO, currency, latePaymentMap, scheduledDueDate,
|
||||
@@ -472,7 +581,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
amountApplicableDate = getNextRestScheduleDate(installment.periodDueDate().minusDays(1), loanApplicationTerms,
|
||||
holidayDetailDTO);
|
||||
}
|
||||
updateMapWithAmount(principalPortionMap, principalForThisPeriod, amountApplicableDate);
|
||||
updateMapWithAmount(principalPortionMap, principalForThisPeriod.minus(reducedBalance), amountApplicableDate);
|
||||
|
||||
// update outstanding balance for interest calculation
|
||||
outstandingBalanceAsPerRest = updateBalanceForInterestCalculation(principalPortionMap, scheduledDueDate,
|
||||
@@ -515,7 +624,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
|
||||
// this block is to add extra re-payment schedules with interest portion
|
||||
// if the loan not paid with in loan term
|
||||
LocalDate currentDate = DateUtils.getLocalDateOfTenant();
|
||||
|
||||
if (isInterestRecalculationRequired(loanApplicationTerms, transactions) && latePaymentMap.size() > 0
|
||||
&& currentDate.isAfter(periodStartDate)) {
|
||||
Money totalInterest = addInterestOnlyRepaymentScheduleForCurrentdate(mc, loanApplicationTerms, holidayDetailDTO, currency,
|
||||
@@ -743,9 +852,12 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
principalEffectiveDate = getNextRestScheduleDate(loanRepaymentScheduleInstallment.getDueDate().minusDays(1),
|
||||
loanApplicationTerms, holidayDetailDTO);
|
||||
}
|
||||
updateMapWithAmount(latePaymentMap, loanRepaymentScheduleInstallment.getPrincipalOutstanding(currency),
|
||||
principalEffectiveDate);
|
||||
totalCompoundingAmount = totalCompoundingAmount.plus(loanRepaymentScheduleInstallment.getPrincipalOutstanding(currency));
|
||||
if (principalEffectiveDate.isBefore(DateUtils.getLocalDateOfTenant())) {
|
||||
updateMapWithAmount(latePaymentMap, loanRepaymentScheduleInstallment.getPrincipalOutstanding(currency),
|
||||
principalEffectiveDate);
|
||||
totalCompoundingAmount = totalCompoundingAmount
|
||||
.plus(loanRepaymentScheduleInstallment.getPrincipalOutstanding(currency));
|
||||
}
|
||||
totalCompoundingAmount = updateMapWithCompoundingDetails(loanApplicationTerms, holidayDetailDTO, currency, latePaymentMap,
|
||||
totalCompoundingAmount, loanRepaymentScheduleInstallment);
|
||||
}
|
||||
@@ -762,25 +874,27 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
if (loanApplicationTerms.getInterestRecalculationCompoundingMethod().isCompoundingEnabled()) {
|
||||
LocalDate compoundingEffectiveDate = getNextCompoundScheduleDate(loanRepaymentScheduleInstallment.getDueDate().minusDays(1),
|
||||
loanApplicationTerms, holidayDetailDTO);
|
||||
Money amount = Money.zero(currency);
|
||||
switch (loanApplicationTerms.getInterestRecalculationCompoundingMethod()) {
|
||||
case INTEREST:
|
||||
amount = amount.plus(loanRepaymentScheduleInstallment.getInterestOutstanding(currency));
|
||||
break;
|
||||
case FEE:
|
||||
amount = amount.plus(loanRepaymentScheduleInstallment.getFeeChargesOutstanding(currency));
|
||||
amount = amount.plus(loanRepaymentScheduleInstallment.getPenaltyChargesOutstanding(currency));
|
||||
break;
|
||||
case INTEREST_AND_FEE:
|
||||
amount = amount.plus(loanRepaymentScheduleInstallment.getInterestOutstanding(currency));
|
||||
amount = amount.plus(loanRepaymentScheduleInstallment.getFeeChargesOutstanding(currency));
|
||||
amount = amount.plus(loanRepaymentScheduleInstallment.getPenaltyChargesOutstanding(currency));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
if (compoundingEffectiveDate.isBefore(DateUtils.getLocalDateOfTenant())) {
|
||||
Money amount = Money.zero(currency);
|
||||
switch (loanApplicationTerms.getInterestRecalculationCompoundingMethod()) {
|
||||
case INTEREST:
|
||||
amount = amount.plus(loanRepaymentScheduleInstallment.getInterestOutstanding(currency));
|
||||
break;
|
||||
case FEE:
|
||||
amount = amount.plus(loanRepaymentScheduleInstallment.getFeeChargesOutstanding(currency));
|
||||
amount = amount.plus(loanRepaymentScheduleInstallment.getPenaltyChargesOutstanding(currency));
|
||||
break;
|
||||
case INTEREST_AND_FEE:
|
||||
amount = amount.plus(loanRepaymentScheduleInstallment.getInterestOutstanding(currency));
|
||||
amount = amount.plus(loanRepaymentScheduleInstallment.getFeeChargesOutstanding(currency));
|
||||
amount = amount.plus(loanRepaymentScheduleInstallment.getPenaltyChargesOutstanding(currency));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
updateMapWithAmount(latePaymentMap, amount, compoundingEffectiveDate);
|
||||
totalCompoundingAmount = totalCompoundingAmount.plus(amount);
|
||||
}
|
||||
updateMapWithAmount(latePaymentMap, amount, compoundingEffectiveDate);
|
||||
totalCompoundingAmount = totalCompoundingAmount.plus(amount);
|
||||
}
|
||||
return totalCompoundingAmount;
|
||||
}
|
||||
@@ -852,6 +966,16 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
map.put(amountApplicableDate, principalPaid);
|
||||
}
|
||||
|
||||
private Money getTotalAmount(final Map<LocalDate, Money> map, final MonetaryCurrency currency) {
|
||||
Money total = Money.zero(currency);
|
||||
for (Map.Entry<LocalDate, Money> mapEntry : map.entrySet()) {
|
||||
if (mapEntry.getKey().isBefore(DateUtils.getLocalDateOfTenant())) {
|
||||
total = total.plus(mapEntry.getValue());
|
||||
}
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoanRescheduleModel reschedule(final MathContext mathContext, final LoanRescheduleRequest loanRescheduleRequest,
|
||||
final ApplicationCurrency applicationCurrency, final HolidayDetailDTO holidayDetailDTO,
|
||||
@@ -1381,16 +1505,20 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
Set<LoanCharge> charges, final HolidayDetailDTO holidayDetailDTO) {
|
||||
Money feeCharges = Money.zero(currency);
|
||||
Money penaltyCharges = Money.zero(currency);
|
||||
Money totalCompoundingAmount = Money.zero(currency);
|
||||
Money totalPrincipal = Money.zero(currency);
|
||||
Money totalInterest = Money.zero(currency);
|
||||
Money reducePrincipalAsperRest = Money.zero(currency);
|
||||
LocalDate reducePrincipalRestDate = onDate;
|
||||
LocalDate calculateInterestFrom = onDate;
|
||||
LocalDate periodStartDate = onDate;
|
||||
LocalDate currentDate = DateUtils.getLocalDateOfTenant();
|
||||
Money principalOutstanding = Money.zero(currency);
|
||||
Integer periodNumber = 1;
|
||||
// for multi disburse loan to identify all disbursed principal for
|
||||
// interest calculation
|
||||
Map<LocalDate, Money> differenceMap = new HashMap<>();
|
||||
Map<LocalDate, Money> disburseAmtMap = new HashMap<>();
|
||||
Map<LocalDate, Money> differenceMap = new TreeMap<>();
|
||||
Map<LocalDate, Money> disburseAmtMap = new TreeMap<>();
|
||||
if (loanApplicationTerms.isMultiDisburseLoan()) {
|
||||
for (DisbursementData disbursementData : loanApplicationTerms.getDisbursementDatas()) {
|
||||
if (disbursementData.isDisbursed()) {
|
||||
@@ -1412,10 +1540,17 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
feeCharges = feeCharges.plus(currentInstallment.getFeeChargesOutstanding(currency));
|
||||
penaltyCharges = penaltyCharges.plus(currentInstallment.getPenaltyChargesOutstanding(currency));
|
||||
principalOutstanding = principalOutstanding.minus(currentInstallment.getPrincipal(currency));
|
||||
LocalDate restDate = getNextRestScheduleDate(currentInstallment.getDueDate().minusDays(1), loanApplicationTerms,
|
||||
holidayDetailDTO);
|
||||
if (restDate.isAfter(currentDate)) {
|
||||
reducePrincipalRestDate = restDate;
|
||||
reducePrincipalAsperRest = reducePrincipalAsperRest.plus(currentInstallment.getPrincipalOutstanding(currency));
|
||||
}
|
||||
|
||||
updateMapWithAmount(differenceMap, currentInstallment.getPrincipalOutstanding(currency),
|
||||
currentInstallment.getDueDate());
|
||||
updateMapWithCompoundingDetails(loanApplicationTerms, holidayDetailDTO, currency, differenceMap, Money.zero(currency),
|
||||
currentInstallment);
|
||||
totalCompoundingAmount = updateMapWithCompoundingDetails(loanApplicationTerms, holidayDetailDTO, currency,
|
||||
differenceMap, totalCompoundingAmount, currentInstallment);
|
||||
} else {
|
||||
totalPrincipal = totalPrincipal.minus(currentInstallment.getPrincipalCompleted(currency));
|
||||
totalInterest = totalInterest.minus(currentInstallment.getInterestPaid(currency)).minus(
|
||||
@@ -1433,7 +1568,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
principalOutstanding = principalOutstanding.minus(currentInstallment.getPrincipal(currency));
|
||||
}
|
||||
}
|
||||
|
||||
Money arrears = totalPrincipal;
|
||||
totalPrincipal = totalPrincipal.plus(principalOutstanding);
|
||||
|
||||
for (Map.Entry<LocalDate, Money> disburseDetail : disburseAmtMap.entrySet()) {
|
||||
@@ -1467,12 +1602,22 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
if (calculateInterestFrom.isBefore(periodStartDateApplicableForInterest)) {
|
||||
calculateInterestFrom = periodStartDateApplicableForInterest;
|
||||
}
|
||||
LocalDate calculateTill = onDate;
|
||||
if (loanApplicationTerms.getPreCloseInterestCalculationStrategy().calculateTillRestFrequencyEnabled()) {
|
||||
LocalDate applicableDate = getNextRestScheduleDate(onDate.minusDays(1), loanApplicationTerms, holidayDetailDTO);
|
||||
calculateTill = applicableDate;
|
||||
}
|
||||
if (arrears.isGreaterThanZero()) {
|
||||
updateMapWithAmount(differenceMap, arrears.minus(reducePrincipalAsperRest).plus(totalCompoundingAmount).negated(),
|
||||
currentDate);
|
||||
updateMapWithAmount(differenceMap, reducePrincipalAsperRest.negated(), reducePrincipalRestDate);
|
||||
}
|
||||
if (calculateInterestFrom.isBefore(onDate)) {
|
||||
double interestCalculationGraceOnRepaymentPeriodFraction = Double.valueOf(0);
|
||||
PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(
|
||||
this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction, totalInterest.zero(),
|
||||
totalInterest.zero(), totalInterest.zero(), totalInterest.zero(), principalOutstanding, loanApplicationTerms,
|
||||
periodNumber, mc, differenceMap, calculateInterestFrom, onDate, daysInPeriodApplicableForInterest);
|
||||
periodNumber, mc, differenceMap, calculateInterestFrom, calculateTill, daysInPeriodApplicableForInterest);
|
||||
interest = interest.plus(principalInterestForThisPeriod.interest());
|
||||
|
||||
}
|
||||
|
||||
+21
-8
@@ -31,6 +31,7 @@ import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanPreCloseInterestCalculationStrategy;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanRescheduleStrategyMethod;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.RecalculationFrequencyType;
|
||||
@@ -137,6 +138,8 @@ public final class LoanApplicationTerms {
|
||||
private final BigDecimal principalThresholdForLastInstalment;
|
||||
private final Integer installmentAmountInMultiplesOf;
|
||||
|
||||
private final LoanPreCloseInterestCalculationStrategy preCloseInterestCalculationStrategy;
|
||||
|
||||
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency currency, final Integer loanTermFrequency,
|
||||
final PeriodFrequencyType loanTermPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery,
|
||||
final PeriodFrequencyType repaymentPeriodFrequencyType, Integer nthDay, DayOfWeekType weekDayType,
|
||||
@@ -151,7 +154,8 @@ public final class LoanApplicationTerms {
|
||||
final List<LoanTermVariationsData> emiAmountVariations, final Integer graceOnArrearsAgeing,
|
||||
final DaysInMonthType daysInMonthType, final DaysInYearType daysInYearType, final boolean isInterestRecalculationEnabled,
|
||||
final RecalculationFrequencyType recalculationFrequencyType, final CalendarInstance restCalendarInstance,
|
||||
final BigDecimal principalThresholdForLastInstalment, final Integer installmentAmountInMultiplesOf) {
|
||||
final BigDecimal principalThresholdForLastInstalment, final Integer installmentAmountInMultiplesOf,
|
||||
final LoanPreCloseInterestCalculationStrategy preCloseInterestCalculationStrategy) {
|
||||
|
||||
final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
|
||||
final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod = null;
|
||||
@@ -162,7 +166,8 @@ public final class LoanApplicationTerms {
|
||||
graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsTolerance, multiDisburseLoan, emiAmount,
|
||||
disbursementDatas, maxOutstandingBalance, emiAmountVariations, graceOnArrearsAgeing, daysInMonthType, daysInYearType,
|
||||
isInterestRecalculationEnabled, rescheduleStrategyMethod, interestRecalculationCompoundingMethod, restCalendarInstance,
|
||||
recalculationFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf);
|
||||
recalculationFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
|
||||
preCloseInterestCalculationStrategy);
|
||||
}
|
||||
|
||||
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
|
||||
@@ -174,7 +179,8 @@ public final class LoanApplicationTerms {
|
||||
final List<LoanTermVariationsData> emiAmountVariations, final LocalDate interestChargedFromDate,
|
||||
final BigDecimal principalThresholdForLastInstalment, final Integer installmentAmountInMultiplesOf,
|
||||
final RecalculationFrequencyType recalculationFrequencyType, final CalendarInstance restCalendarInstance,
|
||||
final InterestRecalculationCompoundingMethod compoundingMethod) {
|
||||
final InterestRecalculationCompoundingMethod compoundingMethod,
|
||||
final LoanPreCloseInterestCalculationStrategy loanPreCloseInterestCalculationStrategy) {
|
||||
|
||||
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
|
||||
final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
|
||||
@@ -207,7 +213,7 @@ public final class LoanApplicationTerms {
|
||||
multiDisburseLoan, emiAmount, disbursementDatas, maxOutstandingBalance, emiAmountVariations,
|
||||
loanProductRelatedDetail.getGraceOnDueDate(), daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
||||
rescheduleStrategyMethod, compoundingMethod, restCalendarInstance, recalculationFrequencyType,
|
||||
principalThresholdForLastInstalment, installmentAmountInMultiplesOf);
|
||||
principalThresholdForLastInstalment, installmentAmountInMultiplesOf, loanPreCloseInterestCalculationStrategy);
|
||||
}
|
||||
|
||||
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
|
||||
@@ -218,7 +224,7 @@ public final class LoanApplicationTerms {
|
||||
final List<LoanTermVariationsData> emiAmountVariations, final LocalDate interestChargedFromDate,
|
||||
final LoanInterestRecalculationDetails interestRecalculationDetails, final CalendarInstance restCalendarInstance,
|
||||
final RecalculationFrequencyType recalculationFrequencyType, final BigDecimal principalThresholdForLastInstalment,
|
||||
Integer installmentAmountInMultiplesOf) {
|
||||
Integer installmentAmountInMultiplesOf, final LoanPreCloseInterestCalculationStrategy loanPreCloseInterestCalculationStrategy) {
|
||||
|
||||
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
|
||||
final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
|
||||
@@ -256,7 +262,7 @@ public final class LoanApplicationTerms {
|
||||
disbursementDatas, maxOutstandingBalance, emiAmountVariations, loanProductRelatedDetail.getGraceOnDueDate(),
|
||||
daysInMonthType, daysInYearType, isInterestRecalculationEnabled, rescheduleStrategyMethod,
|
||||
interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType,
|
||||
principalThresholdForLastInstalment, installmentAmountInMultiplesOf);
|
||||
principalThresholdForLastInstalment, installmentAmountInMultiplesOf, loanPreCloseInterestCalculationStrategy);
|
||||
}
|
||||
|
||||
public static LoanApplicationTerms assembleFrom(final Integer repaymentEvery, final PeriodFrequencyType repaymentPeriodFrequencyType,
|
||||
@@ -275,7 +281,7 @@ public final class LoanApplicationTerms {
|
||||
applicationTerms.interestRecalculationEnabled, applicationTerms.rescheduleStrategyMethod,
|
||||
applicationTerms.interestRecalculationCompoundingMethod, applicationTerms.restCalendarInstance,
|
||||
applicationTerms.recalculationFrequencyType, applicationTerms.principalThresholdForLastInstalment,
|
||||
applicationTerms.installmentAmountInMultiplesOf);
|
||||
applicationTerms.installmentAmountInMultiplesOf, applicationTerms.preCloseInterestCalculationStrategy);
|
||||
}
|
||||
|
||||
private LoanApplicationTerms(final ApplicationCurrency currency, final Integer loanTermFrequency,
|
||||
@@ -293,7 +299,8 @@ public final class LoanApplicationTerms {
|
||||
final boolean isInterestRecalculationEnabled, final LoanRescheduleStrategyMethod rescheduleStrategyMethod,
|
||||
final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod,
|
||||
final CalendarInstance restCalendarInstance, final RecalculationFrequencyType recalculationFrequencyType,
|
||||
final BigDecimal principalThresholdForLastInstalment, final Integer installmentAmountInMultiplesOf) {
|
||||
final BigDecimal principalThresholdForLastInstalment, final Integer installmentAmountInMultiplesOf,
|
||||
final LoanPreCloseInterestCalculationStrategy preCloseInterestCalculationStrategy) {
|
||||
this.currency = currency;
|
||||
this.loanTermFrequency = loanTermFrequency;
|
||||
this.loanTermPeriodFrequencyType = loanTermPeriodFrequencyType;
|
||||
@@ -337,6 +344,7 @@ public final class LoanApplicationTerms {
|
||||
this.recalculationFrequencyType = recalculationFrequencyType;
|
||||
this.principalThresholdForLastInstalment = principalThresholdForLastInstalment;
|
||||
this.installmentAmountInMultiplesOf = installmentAmountInMultiplesOf;
|
||||
this.preCloseInterestCalculationStrategy = preCloseInterestCalculationStrategy;
|
||||
}
|
||||
|
||||
public Money adjustPrincipalIfLastRepaymentPeriod(final Money principalForPeriod, final Money totalCumulativePrincipalToDate,
|
||||
@@ -1170,4 +1178,9 @@ public final class LoanApplicationTerms {
|
||||
public InterestCalculationPeriodMethod getInterestCalculationPeriodMethod() {
|
||||
return this.interestCalculationPeriodMethod;
|
||||
}
|
||||
|
||||
|
||||
public LoanPreCloseInterestCalculationStrategy getPreCloseInterestCalculationStrategy() {
|
||||
return this.preCloseInterestCalculationStrategy;
|
||||
}
|
||||
}
|
||||
+5
@@ -104,4 +104,9 @@ public final class LoanScheduleModelDisbursementPeriod implements LoanScheduleMo
|
||||
public void addPrincipalAmount(@SuppressWarnings("unused") Money principalDue) {
|
||||
return;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInterestAmount(@SuppressWarnings("unused") Money principalDue) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
+2
@@ -36,4 +36,6 @@ public interface LoanScheduleModelPeriod {
|
||||
boolean isRecalculatedInterestComponent();
|
||||
|
||||
void addPrincipalAmount(Money principalDue);
|
||||
|
||||
void addInterestAmount(Money interestDue);
|
||||
}
|
||||
|
||||
+7
-1
@@ -22,7 +22,7 @@ public final class LoanScheduleModelRepaymentPeriod implements LoanScheduleModel
|
||||
private final LocalDate dueDate;
|
||||
private Money principalDue;
|
||||
private final Money outstandingLoanBalance;
|
||||
private final Money interestDue;
|
||||
private Money interestDue;
|
||||
private Money feeChargesDue;
|
||||
private Money penaltyChargesDue;
|
||||
private Money totalDue;
|
||||
@@ -135,4 +135,10 @@ public final class LoanScheduleModelRepaymentPeriod implements LoanScheduleModel
|
||||
public boolean isRecalculatedInterestComponent() {
|
||||
return this.recalculatedInterestComponent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addInterestAmount(Money interestDue) {
|
||||
this.interestDue = this.interestDue.plus(interestDue);
|
||||
this.totalDue = this.totalDue.plus(principalDue);
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -281,7 +281,8 @@ public class LoanScheduleAssembler {
|
||||
graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsToleranceMoney,
|
||||
loanProduct.isMultiDisburseLoan(), emiAmount, disbursementDatas, maxOutstandingBalance, loanVariationTermsData,
|
||||
graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, recalculationFrequencyType,
|
||||
restCalendarInstance, principalThresholdForLastInstalment, installmentAmountInMultiplesOf);
|
||||
restCalendarInstance, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
|
||||
loanProduct.preCloseInterestCalculationStrategy());
|
||||
}
|
||||
|
||||
private CalendarInstance createInterestRecalculationCalendarInstance(final LocalDate calendarStartDate,
|
||||
|
||||
+7
-8
@@ -132,6 +132,7 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
|
||||
|
||||
final Loan loan = this.loanAssembler.assembleFrom(loanId);
|
||||
|
||||
LocalDate today = DateUtils.getLocalDateOfTenant();
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = loanRepaymentScheduleTransactionProcessorFactory
|
||||
.determineProcessor(loan.transactionProcessingStrategy());
|
||||
|
||||
@@ -149,7 +150,7 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
|
||||
final List<LoanSchedulePeriodData> futureInstallments = new ArrayList<>();
|
||||
for (final LoanRepaymentScheduleInstallment currentInstallment : loan.fetchRepaymentScheduleInstallments()) {
|
||||
if (currentInstallment.isNotFullyPaidOff()) {
|
||||
if (!currentInstallment.getDueDate().isAfter(LocalDate.now())) {
|
||||
if (!currentInstallment.getDueDate().isAfter(today)) {
|
||||
totalPrincipal = totalPrincipal.plus(currentInstallment.getPrincipalOutstanding(currency));
|
||||
}
|
||||
}
|
||||
@@ -164,8 +165,7 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
|
||||
LoanApplicationTerms loanApplicationTerms = loan.constructLoanApplicationTerms(applicationCurrency,
|
||||
calculatedRepaymentsStartingFromDate, restCalendarInstance);
|
||||
LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = this.loanScheduleAssembler.calculatePrepaymentAmount(
|
||||
loan.fetchRepaymentScheduleInstallments(), currency, LocalDate.now(), loanApplicationTerms, loan.charges(),
|
||||
loan.getOfficeId());
|
||||
loan.fetchRepaymentScheduleInstallments(), currency, today, loanApplicationTerms, loan.charges(), loan.getOfficeId());
|
||||
Money totalAmount = totalPrincipal.plus(loanRepaymentScheduleInstallment.getFeeChargesOutstanding(currency)).plus(
|
||||
loanRepaymentScheduleInstallment.getPenaltyChargesOutstanding(currency));
|
||||
Money interestDue = Money.zero(currency);
|
||||
@@ -180,18 +180,17 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
|
||||
modifiedTransactions.add(LoanTransaction.copyTransactionProperties(loanTransaction));
|
||||
}
|
||||
if (isNewPaymentRequired) {
|
||||
LoanTransaction ondayPaymentTransaction = LoanTransaction.repayment(null, totalAmount, null, LocalDate.now(), null,
|
||||
LoanTransaction ondayPaymentTransaction = LoanTransaction.repayment(null, totalAmount, null, today, null,
|
||||
DateUtils.getLocalDateTimeOfTenant(), null);
|
||||
modifiedTransactions.add(ondayPaymentTransaction);
|
||||
}
|
||||
|
||||
LoanScheduleModel model = this.loanScheduleAssembler.assembleForInterestRecalculation(loanApplicationTerms, loan.getOfficeId(),
|
||||
modifiedTransactions, loan.charges(), loanRepaymentScheduleTransactionProcessor, LocalDate.now());
|
||||
modifiedTransactions, loan.charges(), loanRepaymentScheduleTransactionProcessor, today);
|
||||
LoanScheduleData scheduleDate = model.toData();
|
||||
Collection<LoanSchedulePeriodData> periodDatas = scheduleDate.getPeriods();
|
||||
for (LoanSchedulePeriodData periodData : periodDatas) {
|
||||
if ((periodData.periodDueDate().isEqual(LocalDate.now()) || periodData.periodDueDate().isAfter(LocalDate.now()))
|
||||
&& isNewPaymentRequired) {
|
||||
if ((periodData.periodDueDate().isEqual(today) || periodData.periodDueDate().isAfter(today)) && isNewPaymentRequired) {
|
||||
LoanSchedulePeriodData loanSchedulePeriodData = LoanSchedulePeriodData.repaymentOnlyPeriod(periodData.periodNumber(),
|
||||
periodData.periodFromDate(), periodData.periodDueDate(), totalPrincipal.getAmount(), periodData
|
||||
.principalLoanBalanceOutstanding(), interestDue.getAmount(), loanRepaymentScheduleInstallment
|
||||
@@ -199,7 +198,7 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
|
||||
loanRepaymentScheduleInstallment.getPenaltyChargesCharged(currency).getAmount(), totalAmount.getAmount());
|
||||
futureInstallments.add(loanSchedulePeriodData);
|
||||
isNewPaymentRequired = false;
|
||||
} else if (periodData.periodDueDate().isAfter(LocalDate.now())) {
|
||||
} else if (periodData.periodDueDate().isAfter(today)) {
|
||||
futureInstallments.add(periodData);
|
||||
}
|
||||
|
||||
|
||||
+1
@@ -75,6 +75,7 @@ public interface LoanProductConstants {
|
||||
public static final String recalculationRestFrequencyIntervalParameterName = "recalculationRestFrequencyInterval";
|
||||
public static final String recalculationRestFrequencyDateParamName = "recalculationRestFrequencyDate";
|
||||
public static final String isArrearsBasedOnOriginalScheduleParamName = "isArrearsBasedOnOriginalSchedule";
|
||||
public static final String preCloseInterestCalculationStrategyParamName = "preCloseInterestCalculationStrategy";
|
||||
|
||||
// Guarantee related
|
||||
public static final String holdGuaranteeFundsParamName = "holdGuaranteeFunds";
|
||||
|
||||
+4
-1
@@ -277,12 +277,15 @@ public class LoanProductsApiResource {
|
||||
final List<EnumOptionData> rescheduleStrategyTypeOptions = dropdownReadPlatformService.retrieveRescheduleStrategyTypeOptions();
|
||||
final List<EnumOptionData> interestRecalculationFrequencyTypeOptions = dropdownReadPlatformService
|
||||
.retrieveInterestRecalculationFrequencyTypeOptions();
|
||||
final List<EnumOptionData> preCloseInterestCalculationStrategyOptions = dropdownReadPlatformService
|
||||
.retrivePreCloseInterestCalculationStrategyOptions();
|
||||
|
||||
return new LoanProductData(productData, chargeOptions, penaltyOptions, paymentTypeOptions, currencyOptions,
|
||||
amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, repaymentFrequencyTypeOptions,
|
||||
interestRateFrequencyTypeOptions, fundOptions, transactionProcessingStrategyOptions, accountOptions,
|
||||
accountingRuleTypeOptions, loanCycleValueConditionTypeOptions, daysInMonthTypeOptions, daysInYearTypeOptions,
|
||||
interestRecalculationCompoundingTypeOptions, rescheduleStrategyTypeOptions, interestRecalculationFrequencyTypeOptions);
|
||||
interestRecalculationCompoundingTypeOptions, rescheduleStrategyTypeOptions, interestRecalculationFrequencyTypeOptions,
|
||||
preCloseInterestCalculationStrategyOptions);
|
||||
}
|
||||
|
||||
}
|
||||
+6
-1
@@ -129,6 +129,8 @@ public class LoanProductData {
|
||||
private final List<EnumOptionData> interestRecalculationCompoundingTypeOptions;
|
||||
@SuppressWarnings("unused")
|
||||
private final List<EnumOptionData> rescheduleStrategyTypeOptions;
|
||||
@SuppressWarnings("unused")
|
||||
private final List<EnumOptionData> preCloseInterestCalculationStrategyOptions;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final List<EnumOptionData> interestRecalculationFrequencyTypeOptions;
|
||||
@@ -479,6 +481,7 @@ public class LoanProductData {
|
||||
|
||||
this.canDefineInstallmentAmount = canDefineInstallmentAmount;
|
||||
this.installmentAmountInMultiplesOf = installmentAmountInMultiplesOf;
|
||||
this.preCloseInterestCalculationStrategyOptions = null;
|
||||
|
||||
}
|
||||
|
||||
@@ -491,7 +494,8 @@ public class LoanProductData {
|
||||
final Map<String, List<GLAccountData>> accountingMappingOptions, final List<EnumOptionData> accountingRuleOptions,
|
||||
final List<EnumOptionData> valueConditionTypeOptions, final List<EnumOptionData> daysInMonthTypeOptions,
|
||||
final List<EnumOptionData> daysInYearTypeOptions, final List<EnumOptionData> interestRecalculationCompoundingTypeOptions,
|
||||
final List<EnumOptionData> rescheduleStrategyTypeOptions, final List<EnumOptionData> interestRecalculationFrequencyTypeOptions) {
|
||||
final List<EnumOptionData> rescheduleStrategyTypeOptions, final List<EnumOptionData> interestRecalculationFrequencyTypeOptions,
|
||||
final List<EnumOptionData> preCloseInterestCalculationStrategyOptions) {
|
||||
this.id = productData.id;
|
||||
this.name = productData.name;
|
||||
this.shortName = productData.shortName;
|
||||
@@ -592,6 +596,7 @@ public class LoanProductData {
|
||||
|
||||
this.canDefineInstallmentAmount = productData.canDefineInstallmentAmount;
|
||||
this.installmentAmountInMultiplesOf = productData.installmentAmountInMultiplesOf;
|
||||
this.preCloseInterestCalculationStrategyOptions = preCloseInterestCalculationStrategyOptions;
|
||||
}
|
||||
|
||||
private Collection<ChargeData> nullIfEmpty(final Collection<ChargeData> charges) {
|
||||
|
||||
+9
-2
@@ -6,11 +6,13 @@
|
||||
package org.mifosplatform.portfolio.loanproduct.data;
|
||||
|
||||
import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.interestRecalculationCompoundingType;
|
||||
import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.preCloseInterestCalculationStrategy;
|
||||
import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.rescheduleStrategyType;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanPreCloseInterestCalculationStrategy;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanRescheduleStrategyMethod;
|
||||
|
||||
public class LoanProductInterestRecalculationData {
|
||||
@@ -26,11 +28,14 @@ public class LoanProductInterestRecalculationData {
|
||||
private final LocalDate recalculationRestFrequencyDate;
|
||||
@SuppressWarnings("unused")
|
||||
private final boolean isArrearsBasedOnOriginalSchedule;
|
||||
@SuppressWarnings("unused")
|
||||
private final EnumOptionData preCloseInterestCalculationStrategy;
|
||||
|
||||
public LoanProductInterestRecalculationData(final Long id, final Long productId,
|
||||
final EnumOptionData interestRecalculationCompoundingType, final EnumOptionData rescheduleStrategyType,
|
||||
final EnumOptionData recalculationRestFrequencyType, final Integer recalculationRestFrequencyInterval,
|
||||
final LocalDate recalculationRestFrequencyDate, boolean isArrearsBasedOnOriginalSchedule) {
|
||||
final LocalDate recalculationRestFrequencyDate, boolean isArrearsBasedOnOriginalSchedule,
|
||||
final EnumOptionData preCloseInterestCalculationStrategy) {
|
||||
this.id = id;
|
||||
this.productId = productId;
|
||||
this.interestRecalculationCompoundingType = interestRecalculationCompoundingType;
|
||||
@@ -39,6 +44,7 @@ public class LoanProductInterestRecalculationData {
|
||||
this.recalculationRestFrequencyInterval = recalculationRestFrequencyInterval;
|
||||
this.recalculationRestFrequencyDate = recalculationRestFrequencyDate;
|
||||
this.isArrearsBasedOnOriginalSchedule = isArrearsBasedOnOriginalSchedule;
|
||||
this.preCloseInterestCalculationStrategy = preCloseInterestCalculationStrategy;
|
||||
}
|
||||
|
||||
public static LoanProductInterestRecalculationData sensibleDefaultsForNewLoanProductCreation() {
|
||||
@@ -50,9 +56,10 @@ public class LoanProductInterestRecalculationData {
|
||||
final Integer recalculationRestFrequencyInterval = null;
|
||||
final LocalDate recalculationRestFrequencyDate = null;
|
||||
final boolean isArrearsBasedOnOriginalSchedule = false;
|
||||
final EnumOptionData preCloseInterestCalculationStrategy = preCloseInterestCalculationStrategy(LoanPreCloseInterestCalculationStrategy.TILL_PRE_CLOSURE_DATE);
|
||||
return new LoanProductInterestRecalculationData(id, productId, interestRecalculationCompoundingType, rescheduleStrategyType,
|
||||
recalculationRestFrequencyType, recalculationRestFrequencyInterval, recalculationRestFrequencyDate,
|
||||
isArrearsBasedOnOriginalSchedule);
|
||||
isArrearsBasedOnOriginalSchedule, preCloseInterestCalculationStrategy);
|
||||
}
|
||||
|
||||
public EnumOptionData getInterestRecalculationCompoundingType() {
|
||||
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.portfolio.loanproduct.domain;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public enum LoanPreCloseInterestCalculationStrategy {
|
||||
|
||||
NONE(0, "loanPreCloseInterestCalculationStrategy.none"), //
|
||||
TILL_PRE_CLOSURE_DATE(1, "loanPreCloseInterestCalculationStrategy.tillPreClosureDate"), //
|
||||
TILL_REST_FREQUENCY_DATE(2, "loanPreCloseInterestCalculationStrategy.tillRestFrequencyDate");
|
||||
|
||||
// REPAYMENT_PERIOD_DATE(3,
|
||||
// "loanPreCloseInterestCalculationStrategy.repaymentPeriodDate")
|
||||
|
||||
private Integer value;
|
||||
private String code;
|
||||
|
||||
private static final Map<Integer, LoanPreCloseInterestCalculationStrategy> intToEnumMap = new HashMap<>();
|
||||
private static int minValue;
|
||||
private static int maxValue;
|
||||
static {
|
||||
int i = 0;
|
||||
for (final LoanPreCloseInterestCalculationStrategy type : LoanPreCloseInterestCalculationStrategy.values()) {
|
||||
if (i == 0) {
|
||||
minValue = type.value;
|
||||
}
|
||||
intToEnumMap.put(type.value, type);
|
||||
if (minValue >= type.value) {
|
||||
minValue = type.value;
|
||||
}
|
||||
if (maxValue < type.value) {
|
||||
maxValue = type.value;
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
public static LoanPreCloseInterestCalculationStrategy fromInt(final Integer ruleTypeValue) {
|
||||
final LoanPreCloseInterestCalculationStrategy type = intToEnumMap.get(ruleTypeValue);
|
||||
return type;
|
||||
}
|
||||
|
||||
private LoanPreCloseInterestCalculationStrategy(final Integer value, final String code) {
|
||||
this.value = value;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return this.code;
|
||||
}
|
||||
|
||||
public static int getMinValue() {
|
||||
return minValue;
|
||||
}
|
||||
|
||||
public static int getMaxValue() {
|
||||
return maxValue;
|
||||
}
|
||||
|
||||
public boolean calculateTillRestFrequencyEnabled() {
|
||||
return this.getValue().equals(LoanPreCloseInterestCalculationStrategy.TILL_REST_FREQUENCY_DATE.getValue());
|
||||
}
|
||||
|
||||
public boolean calculateTillPreClosureDateEnabled() {
|
||||
return this.getValue().equals(LoanPreCloseInterestCalculationStrategy.TILL_PRE_CLOSURE_DATE.getValue());
|
||||
}
|
||||
}
|
||||
+8
@@ -1069,4 +1069,12 @@ public class LoanProduct extends AbstractPersistable<Long> {
|
||||
return this.installmentAmountInMultiplesOf;
|
||||
}
|
||||
|
||||
public LoanPreCloseInterestCalculationStrategy preCloseInterestCalculationStrategy() {
|
||||
LoanPreCloseInterestCalculationStrategy preCloseInterestCalculationStrategy = LoanPreCloseInterestCalculationStrategy.NONE;
|
||||
if (this.isInterestRecalculationEnabled()) {
|
||||
preCloseInterestCalculationStrategy = getProductInterestRecalculationDetails().preCloseInterestCalculationStrategy();
|
||||
}
|
||||
return preCloseInterestCalculationStrategy;
|
||||
}
|
||||
|
||||
}
|
||||
+28
-3
@@ -31,6 +31,7 @@ import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
@Table(name = "m_product_loan_recalculation_details")
|
||||
public class LoanProductInterestRecalculationDetails extends AbstractPersistable<Long> {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@OneToOne
|
||||
@JoinColumn(name = "product_id", nullable = false)
|
||||
private LoanProduct loanProduct;
|
||||
@@ -60,6 +61,9 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
|
||||
@Column(name = "arrears_based_on_original_schedule")
|
||||
private boolean isArrearsBasedOnOriginalSchedule;
|
||||
|
||||
@Column(name = "pre_close_interest_calculation_strategy")
|
||||
private Integer preCloseInterestCalculationStrategy;
|
||||
|
||||
protected LoanProductInterestRecalculationDetails() {
|
||||
//
|
||||
}
|
||||
@@ -91,19 +95,27 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
|
||||
recurrenceInterval = 0;
|
||||
}
|
||||
|
||||
Integer preCloseInterestCalculationStrategy = command
|
||||
.integerValueOfParameterNamed(LoanProductConstants.preCloseInterestCalculationStrategyParamName);
|
||||
if (preCloseInterestCalculationStrategy == null) {
|
||||
preCloseInterestCalculationStrategy = LoanPreCloseInterestCalculationStrategy.TILL_PRE_CLOSURE_DATE.getValue();
|
||||
}
|
||||
|
||||
return new LoanProductInterestRecalculationDetails(interestRecalculationCompoundingMethod, loanRescheduleStrategyMethod,
|
||||
recurrenceFrequency, recurrenceInterval, recurrenceOnDate, isArrearsBasedOnOriginalSchedule);
|
||||
recurrenceFrequency, recurrenceInterval, recurrenceOnDate, isArrearsBasedOnOriginalSchedule,
|
||||
preCloseInterestCalculationStrategy);
|
||||
}
|
||||
|
||||
private LoanProductInterestRecalculationDetails(final Integer interestRecalculationCompoundingMethod,
|
||||
final Integer rescheduleStrategyMethod, final Integer restFrequencyType, final Integer restInterval,
|
||||
final Date restFrequencyDate, final boolean isArrearsBasedOnOriginalSchedule) {
|
||||
final Date restFrequencyDate, final boolean isArrearsBasedOnOriginalSchedule, final Integer preCloseInterestCalculationStrategy) {
|
||||
this.interestRecalculationCompoundingMethod = interestRecalculationCompoundingMethod;
|
||||
this.rescheduleStrategyMethod = rescheduleStrategyMethod;
|
||||
this.restFrequencyType = restFrequencyType;
|
||||
this.restInterval = restInterval;
|
||||
this.restFrequencyDate = restFrequencyDate;
|
||||
this.isArrearsBasedOnOriginalSchedule = isArrearsBasedOnOriginalSchedule;
|
||||
this.preCloseInterestCalculationStrategy = preCloseInterestCalculationStrategy;
|
||||
}
|
||||
|
||||
public void updateProduct(final LoanProduct loanProduct) {
|
||||
@@ -183,6 +195,16 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
|
||||
this.isArrearsBasedOnOriginalSchedule = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.preCloseInterestCalculationStrategyParamName,
|
||||
this.preCloseInterestCalculationStrategy)) {
|
||||
Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.preCloseInterestCalculationStrategyParamName);
|
||||
if (newValue == null) {
|
||||
newValue = LoanPreCloseInterestCalculationStrategy.TILL_PRE_CLOSURE_DATE.getValue();
|
||||
}
|
||||
actualChanges.put(LoanProductConstants.preCloseInterestCalculationStrategyParamName, newValue);
|
||||
this.preCloseInterestCalculationStrategy = newValue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public LocalDate getRestFrequencyLocalDate() {
|
||||
@@ -201,8 +223,11 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
|
||||
return this.restInterval;
|
||||
}
|
||||
|
||||
|
||||
public boolean isArrearsBasedOnOriginalSchedule() {
|
||||
return this.isArrearsBasedOnOriginalSchedule;
|
||||
}
|
||||
|
||||
public LoanPreCloseInterestCalculationStrategy preCloseInterestCalculationStrategy() {
|
||||
return LoanPreCloseInterestCalculationStrategy.fromInt(this.preCloseInterestCalculationStrategy);
|
||||
}
|
||||
}
|
||||
|
||||
+51
-34
@@ -26,6 +26,7 @@ import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidation
|
||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.mifosplatform.portfolio.loanproduct.LoanProductConstants;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanPreCloseInterestCalculationStrategy;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductValueConditionType;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.RecalculationFrequencyType;
|
||||
@@ -43,40 +44,47 @@ public final class LoanProductDataValidator {
|
||||
/**
|
||||
* The parameters supported for this command.
|
||||
*/
|
||||
private final Set<String> supportedParameters = new HashSet<>(Arrays.asList("locale", "dateFormat", "name", "description", "fundId",
|
||||
"currencyCode", "digitsAfterDecimal", "inMultiplesOf", "principal", "minPrincipal", "maxPrincipal", "repaymentEvery",
|
||||
"numberOfRepayments", "minNumberOfRepayments", "maxNumberOfRepayments", "repaymentFrequencyType", "interestRatePerPeriod",
|
||||
"minInterestRatePerPeriod", "maxInterestRatePerPeriod", "interestRateFrequencyType", "amortizationType", "interestType",
|
||||
"interestCalculationPeriodType", "inArrearsTolerance", "transactionProcessingStrategyId", "graceOnPrincipalPayment",
|
||||
"graceOnInterestPayment", "graceOnInterestCharged", "charges", "accountingRule", "includeInBorrowerCycle", "startDate",
|
||||
"closeDate", "externalId", LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.OVERPAYMENT.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.FEE_INCOME_ACCOUNT_MAPPING.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_RECOVERY.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTY_INCOME_ACCOUNT_MAPPING.getValue(), LoanProductConstants.useBorrowerCycleParameterName,
|
||||
LoanProductConstants.principalVariationsForBorrowerCycleParameterName,
|
||||
LoanProductConstants.interestRateVariationsForBorrowerCycleParameterName,
|
||||
LoanProductConstants.numberOfRepaymentVariationsForBorrowerCycleParameterName, LoanProductConstants.shortName,
|
||||
LoanProductConstants.multiDisburseLoanParameterName, LoanProductConstants.outstandingLoanBalanceParameterName,
|
||||
LoanProductConstants.maxTrancheCountParameterName, LoanProductConstants.graceOnArrearsAgeingParameterName,
|
||||
LoanProductConstants.overdueDaysForNPAParameterName, LoanProductConstants.isInterestRecalculationEnabledParameterName,
|
||||
LoanProductConstants.daysInYearTypeParameterName, LoanProductConstants.daysInMonthTypeParameterName,
|
||||
LoanProductConstants.rescheduleStrategyMethodParameterName,
|
||||
LoanProductConstants.interestRecalculationCompoundingMethodParameterName,
|
||||
LoanProductConstants.recalculationRestFrequencyDateParamName,
|
||||
LoanProductConstants.recalculationRestFrequencyIntervalParameterName,
|
||||
LoanProductConstants.recalculationRestFrequencyTypeParameterName,
|
||||
LoanProductConstants.isArrearsBasedOnOriginalScheduleParamName,
|
||||
LoanProductConstants.minimumDaysBetweenDisbursalAndFirstRepayment, LoanProductConstants.mandatoryGuaranteeParamName,
|
||||
LoanProductConstants.holdGuaranteeFundsParamName, LoanProductConstants.minimumGuaranteeFromGuarantorParamName,
|
||||
LoanProductConstants.minimumGuaranteeFromOwnFundsParamName, LoanProductConstants.principalThresholdForLastInstallmentParamName,
|
||||
LoanProductConstants.accountMovesOutOfNPAOnlyOnArrearsCompletionParamName, LoanProductConstants.canDefineEmiAmountParamName,
|
||||
LoanProductConstants.installmentAmountInMultiplesOfParamName));
|
||||
private final Set<String> supportedParameters = new HashSet<>(
|
||||
Arrays.asList("locale", "dateFormat", "name", "description", "fundId", "currencyCode", "digitsAfterDecimal", "inMultiplesOf",
|
||||
"principal", "minPrincipal", "maxPrincipal", "repaymentEvery", "numberOfRepayments", "minNumberOfRepayments",
|
||||
"maxNumberOfRepayments", "repaymentFrequencyType", "interestRatePerPeriod", "minInterestRatePerPeriod",
|
||||
"maxInterestRatePerPeriod", "interestRateFrequencyType", "amortizationType", "interestType",
|
||||
"interestCalculationPeriodType", "inArrearsTolerance", "transactionProcessingStrategyId", "graceOnPrincipalPayment",
|
||||
"graceOnInterestPayment", "graceOnInterestCharged", "charges", "accountingRule", "includeInBorrowerCycle", "startDate",
|
||||
"closeDate", "externalId", LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.OVERPAYMENT.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.FEE_INCOME_ACCOUNT_MAPPING.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_RECOVERY.getValue(),
|
||||
LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTY_INCOME_ACCOUNT_MAPPING.getValue(),
|
||||
LoanProductConstants.useBorrowerCycleParameterName,
|
||||
LoanProductConstants.principalVariationsForBorrowerCycleParameterName,
|
||||
LoanProductConstants.interestRateVariationsForBorrowerCycleParameterName,
|
||||
LoanProductConstants.numberOfRepaymentVariationsForBorrowerCycleParameterName, LoanProductConstants.shortName,
|
||||
LoanProductConstants.multiDisburseLoanParameterName, LoanProductConstants.outstandingLoanBalanceParameterName,
|
||||
LoanProductConstants.maxTrancheCountParameterName, LoanProductConstants.graceOnArrearsAgeingParameterName,
|
||||
LoanProductConstants.overdueDaysForNPAParameterName, LoanProductConstants.isInterestRecalculationEnabledParameterName,
|
||||
LoanProductConstants.daysInYearTypeParameterName, LoanProductConstants.daysInMonthTypeParameterName,
|
||||
LoanProductConstants.rescheduleStrategyMethodParameterName,
|
||||
LoanProductConstants.interestRecalculationCompoundingMethodParameterName,
|
||||
LoanProductConstants.recalculationRestFrequencyDateParamName,
|
||||
LoanProductConstants.recalculationRestFrequencyIntervalParameterName,
|
||||
LoanProductConstants.recalculationRestFrequencyTypeParameterName,
|
||||
LoanProductConstants.isArrearsBasedOnOriginalScheduleParamName,
|
||||
LoanProductConstants.minimumDaysBetweenDisbursalAndFirstRepayment, LoanProductConstants.mandatoryGuaranteeParamName,
|
||||
LoanProductConstants.holdGuaranteeFundsParamName, LoanProductConstants.minimumGuaranteeFromGuarantorParamName,
|
||||
LoanProductConstants.minimumGuaranteeFromOwnFundsParamName,
|
||||
LoanProductConstants.principalThresholdForLastInstallmentParamName,
|
||||
LoanProductConstants.accountMovesOutOfNPAOnlyOnArrearsCompletionParamName,
|
||||
LoanProductConstants.canDefineEmiAmountParamName, LoanProductConstants.installmentAmountInMultiplesOfParamName,
|
||||
LoanProductConstants.preCloseInterestCalculationStrategyParamName));
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
|
||||
@@ -537,6 +545,15 @@ public final class LoanProductDataValidator {
|
||||
baseDataValidator.reset().parameter(LoanProductConstants.isArrearsBasedOnOriginalScheduleParamName)
|
||||
.value(isArrearsBasedOnOriginalSchedule).notNull().isOneOfTheseValues(true, false);
|
||||
}
|
||||
|
||||
final Integer preCloseInterestCalculationStrategy = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(
|
||||
LoanProductConstants.preCloseInterestCalculationStrategyParamName, element);
|
||||
baseDataValidator
|
||||
.reset()
|
||||
.parameter(LoanProductConstants.preCloseInterestCalculationStrategyParamName)
|
||||
.value(preCloseInterestCalculationStrategy)
|
||||
.ignoreIfNull()
|
||||
.inMinMaxRange(LoanPreCloseInterestCalculationStrategy.getMinValue(), LoanPreCloseInterestCalculationStrategy.getMaxValue());
|
||||
}
|
||||
|
||||
public void validateForUpdate(final String json, final LoanProduct loanProduct) {
|
||||
|
||||
+2
@@ -38,5 +38,7 @@ public interface LoanDropdownReadPlatformService {
|
||||
List<EnumOptionData> retrieveRescheduleStrategyTypeOptions();
|
||||
|
||||
List<EnumOptionData> retrieveInterestRecalculationFrequencyTypeOptions();
|
||||
|
||||
List<EnumOptionData> retrivePreCloseInterestCalculationStrategyOptions();
|
||||
|
||||
}
|
||||
+25
-14
@@ -17,7 +17,7 @@ import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.r
|
||||
import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.repaymentFrequencyNthDayType;
|
||||
import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.repaymentFrequencyType;
|
||||
import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.rescheduleStrategyType;
|
||||
|
||||
import static org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations.preCloseInterestCalculationStrategy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@@ -33,6 +33,7 @@ import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanPreCloseInterestCalculationStrategy;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductValueConditionType;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanRescheduleStrategyMethod;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy;
|
||||
@@ -93,21 +94,22 @@ public class LoanDropdownReadPlatformServiceImpl implements LoanDropdownReadPlat
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EnumOptionData> retrieveRepaymentFrequencyOptionsForNthDayOfMonth() {
|
||||
final List<EnumOptionData> repaymentFrequencyOptions = Arrays.asList(repaymentFrequencyNthDayType(NthDayType.ONE),
|
||||
repaymentFrequencyNthDayType(NthDayType.TWO), repaymentFrequencyNthDayType(NthDayType.THREE),
|
||||
repaymentFrequencyNthDayType(NthDayType.FOUR));
|
||||
return repaymentFrequencyOptions;
|
||||
public List<EnumOptionData> retrieveRepaymentFrequencyOptionsForNthDayOfMonth() {
|
||||
final List<EnumOptionData> repaymentFrequencyOptions = Arrays.asList(repaymentFrequencyNthDayType(NthDayType.ONE),
|
||||
repaymentFrequencyNthDayType(NthDayType.TWO), repaymentFrequencyNthDayType(NthDayType.THREE),
|
||||
repaymentFrequencyNthDayType(NthDayType.FOUR));
|
||||
return repaymentFrequencyOptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EnumOptionData> retrieveRepaymentFrequencyOptionsForDaysOfWeek() {
|
||||
|
||||
final List<EnumOptionData> repaymentFrequencyOptions = Arrays.asList(repaymentFrequencyDayOfWeekType(DayOfWeekType.SUNDAY),
|
||||
repaymentFrequencyDayOfWeekType(DayOfWeekType.MONDAY),repaymentFrequencyDayOfWeekType(DayOfWeekType.TUESDAY),repaymentFrequencyDayOfWeekType(DayOfWeekType.WEDNESDAY),
|
||||
repaymentFrequencyDayOfWeekType(DayOfWeekType.THURSDAY),repaymentFrequencyDayOfWeekType(DayOfWeekType.FRIDAY), repaymentFrequencyDayOfWeekType(DayOfWeekType.SATURDAY));
|
||||
return repaymentFrequencyOptions;
|
||||
}
|
||||
@Override
|
||||
public List<EnumOptionData> retrieveRepaymentFrequencyOptionsForDaysOfWeek() {
|
||||
|
||||
final List<EnumOptionData> repaymentFrequencyOptions = Arrays.asList(repaymentFrequencyDayOfWeekType(DayOfWeekType.SUNDAY),
|
||||
repaymentFrequencyDayOfWeekType(DayOfWeekType.MONDAY), repaymentFrequencyDayOfWeekType(DayOfWeekType.TUESDAY),
|
||||
repaymentFrequencyDayOfWeekType(DayOfWeekType.WEDNESDAY), repaymentFrequencyDayOfWeekType(DayOfWeekType.THURSDAY),
|
||||
repaymentFrequencyDayOfWeekType(DayOfWeekType.FRIDAY), repaymentFrequencyDayOfWeekType(DayOfWeekType.SATURDAY));
|
||||
return repaymentFrequencyOptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EnumOptionData> retrieveInterestRateFrequencyTypeOptions() {
|
||||
@@ -170,4 +172,13 @@ public class LoanDropdownReadPlatformServiceImpl implements LoanDropdownReadPlat
|
||||
interestRecalculationFrequencyType(RecalculationFrequencyType.MONTHLY));
|
||||
return interestRecalculationFrequencyTypeOptions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EnumOptionData> retrivePreCloseInterestCalculationStrategyOptions() {
|
||||
|
||||
final List<EnumOptionData> preCloseInterestCalculationStrategyOptions = Arrays.asList(
|
||||
preCloseInterestCalculationStrategy(LoanPreCloseInterestCalculationStrategy.TILL_PRE_CLOSURE_DATE),
|
||||
preCloseInterestCalculationStrategy(LoanPreCloseInterestCalculationStrategy.TILL_REST_FREQUENCY_DATE));
|
||||
return preCloseInterestCalculationStrategyOptions;
|
||||
}
|
||||
}
|
||||
+21
@@ -20,6 +20,7 @@ import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanPreCloseInterestCalculationStrategy;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductParamType;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductValueConditionType;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanRescheduleStrategyMethod;
|
||||
@@ -595,4 +596,24 @@ public class LoanEnumerations {
|
||||
}
|
||||
return optionData;
|
||||
}
|
||||
|
||||
public static EnumOptionData preCloseInterestCalculationStrategy(final int id) {
|
||||
return preCloseInterestCalculationStrategy(LoanPreCloseInterestCalculationStrategy.fromInt(id));
|
||||
}
|
||||
|
||||
public static EnumOptionData preCloseInterestCalculationStrategy(final LoanPreCloseInterestCalculationStrategy type) {
|
||||
EnumOptionData optionData = null;
|
||||
switch (type) {
|
||||
case TILL_PRE_CLOSURE_DATE:
|
||||
optionData = new EnumOptionData(LoanPreCloseInterestCalculationStrategy.TILL_PRE_CLOSURE_DATE.getValue().longValue(),
|
||||
LoanPreCloseInterestCalculationStrategy.TILL_PRE_CLOSURE_DATE.getCode(), "Till preclose Date");
|
||||
break;
|
||||
case TILL_REST_FREQUENCY_DATE:
|
||||
optionData = new EnumOptionData(LoanPreCloseInterestCalculationStrategy.TILL_REST_FREQUENCY_DATE.getValue().longValue(),
|
||||
LoanPreCloseInterestCalculationStrategy.TILL_REST_FREQUENCY_DATE.getCode(), "Till rest Frequency Date");
|
||||
break;
|
||||
}
|
||||
return optionData;
|
||||
}
|
||||
|
||||
}
|
||||
+7
-1
@@ -161,6 +161,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
||||
+ "lp.allow_multiple_disbursals as multiDisburseLoan, lp.max_disbursals as maxTrancheCount, lp.max_outstanding_loan_balance as outstandingLoanBalance, "
|
||||
+ "lp.days_in_month_enum as daysInMonth, lp.days_in_year_enum as daysInYear, lp.interest_recalculation_enabled as isInterestRecalculationEnabled, "
|
||||
+ "lp.can_define_fixed_emi_amount as canDefineInstallmentAmount, lp.instalment_amount_in_multiples_of as installmentAmountInMultiplesOf, "
|
||||
+ "lpr.pre_close_interest_calculation_strategy as preCloseInterestCalculationStrategy, "
|
||||
+ "lpr.id as lprId, lpr.product_id as productId, lpr.compound_type_enum as compoundType, lpr.reschedule_strategy_enum as rescheduleStrategy, "
|
||||
+ "lpr.rest_frequency_type_enum as restFrequencyEnum, lpr.rest_frequency_interval as restFrequencyInterval, "
|
||||
+ "lpr.rest_freqency_date as restFrequencyDate, lpr.arrears_based_on_original_schedule as isArrearsBasedOnOriginalSchedule, "
|
||||
@@ -281,6 +282,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
||||
final boolean canDefineInstallmentAmount = rs.getBoolean("canDefineInstallmentAmount");
|
||||
final boolean isInterestRecalculationEnabled = rs.getBoolean("isInterestRecalculationEnabled");
|
||||
|
||||
|
||||
LoanProductInterestRecalculationData interestRecalculationData = null;
|
||||
if (isInterestRecalculationEnabled) {
|
||||
|
||||
@@ -296,9 +298,13 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
||||
final int restFrequencyInterval = JdbcSupport.getInteger(rs, "restFrequencyInterval");
|
||||
final LocalDate restFrequencyDate = JdbcSupport.getLocalDate(rs, "restFrequencyDate");
|
||||
final boolean isArrearsBasedOnOriginalSchedule = rs.getBoolean("isArrearsBasedOnOriginalSchedule");
|
||||
final int preCloseInterestCalculationStrategyEnumValue = JdbcSupport.getInteger(rs, "preCloseInterestCalculationStrategy");
|
||||
final EnumOptionData preCloseInterestCalculationStrategy = LoanEnumerations
|
||||
.preCloseInterestCalculationStrategy(preCloseInterestCalculationStrategyEnumValue);
|
||||
|
||||
interestRecalculationData = new LoanProductInterestRecalculationData(lprId, productId,
|
||||
interestRecalculationCompoundingType, rescheduleStrategyType, restFrequencyType, restFrequencyInterval,
|
||||
restFrequencyDate, isArrearsBasedOnOriginalSchedule);
|
||||
restFrequencyDate, isArrearsBasedOnOriginalSchedule, preCloseInterestCalculationStrategy);
|
||||
}
|
||||
|
||||
final boolean holdGuaranteeFunds = rs.getBoolean("holdGuaranteeFunds");
|
||||
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE `m_product_loan_recalculation_details`
|
||||
ADD COLUMN `pre_close_interest_calculation_strategy` SMALLINT(3) NOT NULL DEFAULT '1';
|
||||
Reference in New Issue
Block a user