MIFOSX-1951 : compounding changes and recalculation fixes
This commit is contained in:
@@ -7474,6 +7474,13 @@ An enumeration that indicates the type of transaction processing strategy to be
|
||||
<td class=fielddesc>Specifies rest frequency start date for interest recalculation. This date must be before or equal to disbursement date
|
||||
</td>
|
||||
</tr>
|
||||
<tr class=alt>
|
||||
<td>recalculationCompoundingFrequencyDate</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class=fielddesc>Specifies compounding frequency start date for interest recalculation. This date must be equal to disbursement date
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@@ -7649,6 +7656,11 @@ GET https://DomainName/api/v1/loans/template?templateType=individual&clientId=1&
|
||||
"code": "interestRecalculationCompoundingMethod.fee",
|
||||
"value": "Fee"
|
||||
},
|
||||
"recalculationCompoundingFrequencyType": {
|
||||
"id":1,
|
||||
"code":"interestRecalculationFrequencyType.same.as.repayment.period",
|
||||
"value":"Same as repayment period"
|
||||
},
|
||||
"rescheduleStrategyType": {
|
||||
"id": 2,
|
||||
"code": "loanRescheduleStrategyMethod.reduce.number.of.installments",
|
||||
@@ -8608,6 +8620,14 @@ Request Body:
|
||||
<td>recalculationRestFrequencyDate</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class=matrixHeading>
|
||||
<tr class="matrixHeadingBG">
|
||||
<td><div class="mifosXHeading2">Additional Mandatory Fields if interest recalculation with interest/fee compounding is enabled for product and compounding frequency not same as repayment period</div></td>
|
||||
</tr>
|
||||
<tr class=alt>
|
||||
<td>recalculationCompoundingFrequencyDate</td>
|
||||
</tr>
|
||||
</table>
|
||||
<br/>
|
||||
<table class=matrixHeading>
|
||||
<tr class="matrixHeadingBG">
|
||||
@@ -11705,6 +11725,26 @@ An enumeration that indicates the type of transaction processing strategy to be
|
||||
<td class=fielddesc>Specifies what action should perform on loan repayment schedule for advance payments. <br>
|
||||
<span>Example Values:</span>1=Reschedule next repayments, 2=Reduce number of installments, 3=Reduce EMI amount</td>
|
||||
</tr>
|
||||
<tr class=alt>
|
||||
<td>recalculationCompoundingFrequencyType</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class=fielddesc>Specifies effective date from which the compounding of interest or fee amounts will be considered in recalculation on late payment.<br>
|
||||
<span>Example Values:</span>1=Same as repayment period, 2=Daily, 3=Weekly, 4=Monthly</td>
|
||||
</tr>
|
||||
<tr class=alt>
|
||||
<td>recalculationCompoundingFrequencyInterval</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class=fielddesc>Specifies compounding frequency interval for interest recalculation.<br>
|
||||
</tr>
|
||||
<tr class=alt>
|
||||
<td>recalculationCompoundingFrequencyDate</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class=fielddesc>Specifies compounding frequency start date for interest recalculation.<br>
|
||||
</tr>
|
||||
|
||||
<tr class=alt>
|
||||
<td>recalculationRestFrequencyType</td>
|
||||
</tr>
|
||||
@@ -11848,6 +11888,11 @@ GET https://DomainName/api/v1/loanproducts
|
||||
"code": "interestRecalculationCompoundingMethod.fee",
|
||||
"value": "Fee"
|
||||
},
|
||||
"recalculationCompoundingFrequencyType": {
|
||||
"id":1,
|
||||
"code":"interestRecalculationFrequencyType.same.as.repayment.period",
|
||||
"value":"Same as repayment period"
|
||||
},
|
||||
"rescheduleStrategyType": {
|
||||
"id": 2,
|
||||
"code": "loanRescheduleStrategyMethod.reduce.number.of.installments",
|
||||
@@ -13058,6 +13103,23 @@ GET https://DomainName/api/v1/loanproducts/{productId}
|
||||
<td>recalculationRestFrequencyInterval, recalculationRestFrequencyDate</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class=matrixHeading>
|
||||
<tr class="matrixHeadingBG">
|
||||
<td><div class="mifosXHeading2">Additional Optional Fields if interest recalculation is enabled(true) and interestRecalculationCompoundingMethod is enabled</div></td>
|
||||
</tr>
|
||||
<tr class=alt>
|
||||
<td>recalculationCompoundingFrequencyType</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class=matrixHeading>
|
||||
<tr class="matrixHeadingBG">
|
||||
<td><div class="mifosXHeading2">Additional Optional Fields if interest recalculation is enabled(true) and interestRecalculationCompoundingMethod is enabled and
|
||||
recalculationCompoundingFrequencyType is not same as repayment period</div></td>
|
||||
</tr>
|
||||
<tr class=alt>
|
||||
<td>recalculationCompoundingFrequencyInterval, recalculationCompoundingFrequencyDate</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table class=matrixHeading>
|
||||
<tr class="matrixHeadingBG">
|
||||
<td><div class="mifosXHeading2">Additional Mandatory Fields if Hold Guarantee funds is enabled(true)</div></td>
|
||||
|
||||
+73
-32
@@ -3262,7 +3262,7 @@ public class ClientLoanIntegrationTest {
|
||||
@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";
|
||||
String preCloseAmount = "7586.62";
|
||||
testLoanScheduleWithInterestRecalculation_WITH_REST_SAME_AS_REPAYMENT_INTEREST_COMPOUND_NONE_STRATEGY_REDUCE_EMI_PRE_CLOSE_INTEREST(
|
||||
preCloseInterestStrategy, preCloseAmount);
|
||||
}
|
||||
@@ -3314,8 +3314,8 @@ public class ClientLoanIntegrationTest {
|
||||
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");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2482.76", "46.15", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2551.72", "11.78", "0.0", "0.0");
|
||||
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
@@ -3330,8 +3330,8 @@ public class ClientLoanIntegrationTest {
|
||||
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");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2494.22", "34.69", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2528.8", "11.67", "0.0", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
HashMap prepayDetail = this.loanTransactionHelper.getPrepayAmount(this.requestSpec, this.responseSpec, loanID);
|
||||
@@ -3453,14 +3453,15 @@ public class ClientLoanIntegrationTest {
|
||||
|
||||
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
|
||||
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
|
||||
final Integer loanProductID = createLoanProductWithInterestRecalculation(LoanProductTestBuilder.RBI_INDIA_STRATEGY,
|
||||
LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_INTEREST,
|
||||
final Integer loanProductID = createLoanProductWithInterestRecalculationAndCompoundingDetails(
|
||||
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,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_WEEKLY, "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));
|
||||
LOAN_DISBURSEMENT_DATE, LOAN_DISBURSEMENT_DATE, LoanApplicationTestBuilder.RBI_INDIA_STRATEGY, new ArrayList<HashMap>(0));
|
||||
|
||||
Assert.assertNotNull(loanID);
|
||||
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
|
||||
@@ -3580,14 +3581,15 @@ public class ClientLoanIntegrationTest {
|
||||
|
||||
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,
|
||||
final Integer loanProductID = createLoanProductWithInterestRecalculationAndCompoundingDetails(
|
||||
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,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_WEEKLY, "1", LOAN_DISBURSEMENT_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);
|
||||
REST_START_DATE, LOAN_DISBURSEMENT_DATE, LoanApplicationTestBuilder.MIFOS_STANDARD_STRATEGY, charges);
|
||||
|
||||
Assert.assertNotNull(loanID);
|
||||
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
|
||||
@@ -3615,9 +3617,9 @@ public class ClientLoanIntegrationTest {
|
||||
expectedvalues = new ArrayList<>();
|
||||
todaysDate = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
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");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2482.08", "46.83", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2488.82", "40.09", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2546.34", "19.96", "0.0", "0.0");
|
||||
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
@@ -3664,7 +3666,7 @@ 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";
|
||||
String preCloseAmount = "7766.81";
|
||||
testLoanScheduleWithInterestRecalculation_WITH_REST_WEEKLY_INTEREST_COMPOUND_INTEREST_FEE_STRATEGY_REDUCE_NEXT_INSTALLMENTS_PRE_CLOSE_INTEREST(
|
||||
preCloseInterestStrategy, preCloseAmount);
|
||||
|
||||
@@ -3673,7 +3675,7 @@ public class ClientLoanIntegrationTest {
|
||||
@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";
|
||||
String preCloseAmount = "7771.79";
|
||||
testLoanScheduleWithInterestRecalculation_WITH_REST_WEEKLY_INTEREST_COMPOUND_INTEREST_FEE_STRATEGY_REDUCE_NEXT_INSTALLMENTS_PRE_CLOSE_INTEREST(
|
||||
preCloseInterestStrategy, preCloseAmount);
|
||||
|
||||
@@ -3709,10 +3711,11 @@ public class ClientLoanIntegrationTest {
|
||||
|
||||
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,
|
||||
final Integer loanProductID = createLoanProductWithInterestRecalculationAndCompoundingDetails(
|
||||
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);
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_WEEKLY, "1", REST_START_DATE,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, null, null, preCloseInterestStrategy, null);
|
||||
|
||||
final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, LOAN_DISBURSEMENT_DATE,
|
||||
REST_START_DATE, LoanApplicationTestBuilder.MIFOS_STANDARD_STRATEGY, charges);
|
||||
@@ -3743,9 +3746,9 @@ public class ClientLoanIntegrationTest {
|
||||
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");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2482.08", "46.83", "0.0", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2495.47", "33.44", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2539.69", "16.66", "0.0", "0.0");
|
||||
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
@@ -3760,8 +3763,8 @@ public class ClientLoanIntegrationTest {
|
||||
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");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2500.7", "28.21", "200", "0.0");
|
||||
addRepaymentValues(expectedvalues, todaysDate, 1, false, "2527.23", "16.61", "0.0", "0.0");
|
||||
verifyLoanRepaymentSchedule(loanSchedule, expectedvalues);
|
||||
|
||||
HashMap prepayDetail = this.loanTransactionHelper.getPrepayAmount(this.requestSpec, this.responseSpec, loanID);
|
||||
@@ -3797,11 +3800,15 @@ public class ClientLoanIntegrationTest {
|
||||
|
||||
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
|
||||
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
|
||||
final String recalculationCompoundingFrequencyInterval = null;
|
||||
final String recalculationCompoundingFrequencyDate = null;
|
||||
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,
|
||||
LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null, overdueFeeChargeId.toString(), false);
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, recalculationCompoundingFrequencyInterval,
|
||||
recalculationCompoundingFrequencyDate, 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);
|
||||
@@ -4001,10 +4008,11 @@ public class ClientLoanIntegrationTest {
|
||||
|
||||
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
|
||||
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
|
||||
final Integer loanProductID = createLoanProductWithInterestRecalculation(LoanProductTestBuilder.RBI_INDIA_STRATEGY,
|
||||
LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_INTEREST,
|
||||
final Integer loanProductID = createLoanProductWithInterestRecalculationAndCompoundingDetails(
|
||||
LoanProductTestBuilder.RBI_INDIA_STRATEGY, LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_INTEREST,
|
||||
LoanProductTestBuilder.RECALCULATION_STRATEGY_RESCHEDULE_NEXT_REPAYMENTS,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_DAILY, "1", LOAN_DISBURSEMENT_DATE,
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, "1", LOAN_DISBURSEMENT_DATE,
|
||||
LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null);
|
||||
|
||||
final Integer loanID = applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, LOAN_DISBURSEMENT_DATE,
|
||||
@@ -4080,11 +4088,15 @@ public class ClientLoanIntegrationTest {
|
||||
|
||||
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
|
||||
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
|
||||
final String recalculationCompoundingFrequencyInterval = null;
|
||||
final String recalculationCompoundingFrequencyDate = null;
|
||||
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,
|
||||
LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, null, null, true);
|
||||
LoanProductTestBuilder.RECALCULATION_FREQUENCY_TYPE_SAME_AS_REPAYMENT_PERIOD, recalculationCompoundingFrequencyInterval,
|
||||
recalculationCompoundingFrequencyDate, 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));
|
||||
@@ -4173,16 +4185,34 @@ public class ClientLoanIntegrationTest {
|
||||
final String interestRecalculationCompoundingMethod, final String rescheduleStrategyMethod,
|
||||
final String recalculationRestFrequencyType, final String recalculationRestFrequencyInterval,
|
||||
final String recalculationRestFrequencyDate, final String preCloseInterestCalculationStrategy, final Account[] accounts) {
|
||||
final String recalculationCompoundingFrequencyType = null;
|
||||
final String recalculationCompoundingFrequencyInterval = null;
|
||||
final String recalculationCompoundingFrequencyDate = null;
|
||||
return createLoanProductWithInterestRecalculation(repaymentStrategy, interestRecalculationCompoundingMethod,
|
||||
rescheduleStrategyMethod, recalculationRestFrequencyType, recalculationRestFrequencyInterval,
|
||||
recalculationRestFrequencyDate, preCloseInterestCalculationStrategy, accounts, null, false);
|
||||
recalculationRestFrequencyDate, recalculationCompoundingFrequencyType, recalculationCompoundingFrequencyInterval,
|
||||
recalculationCompoundingFrequencyDate, preCloseInterestCalculationStrategy, accounts, null, false);
|
||||
}
|
||||
|
||||
private Integer createLoanProductWithInterestRecalculationAndCompoundingDetails(final String repaymentStrategy,
|
||||
final String interestRecalculationCompoundingMethod, final String rescheduleStrategyMethod,
|
||||
final String recalculationRestFrequencyType, final String recalculationRestFrequencyInterval,
|
||||
final String recalculationRestFrequencyDate, final String recalculationCompoundingFrequencyType,
|
||||
final String recalculationCompoundingFrequencyInterval, final String recalculationCompoundingFrequencyDate,
|
||||
final String preCloseInterestCalculationStrategy, final Account[] accounts) {
|
||||
return createLoanProductWithInterestRecalculation(repaymentStrategy, interestRecalculationCompoundingMethod,
|
||||
rescheduleStrategyMethod, recalculationRestFrequencyType, recalculationRestFrequencyInterval,
|
||||
recalculationRestFrequencyDate, recalculationCompoundingFrequencyType, recalculationCompoundingFrequencyInterval,
|
||||
recalculationCompoundingFrequencyDate, 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 String preCloseInterestCalculationStrategy, final Account[] accounts,
|
||||
final String chargeId, boolean isArrearsBasedOnOriginalSchedule) {
|
||||
final String recalculationRestFrequencyDate, final String recalculationCompoundingFrequencyType,
|
||||
final String recalculationCompoundingFrequencyInterval, final String recalculationCompoundingFrequencyDate,
|
||||
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")
|
||||
@@ -4197,7 +4227,9 @@ public class ClientLoanIntegrationTest {
|
||||
.withInterestRecalculationDetails(interestRecalculationCompoundingMethod, rescheduleStrategyMethod,
|
||||
preCloseInterestCalculationStrategy)
|
||||
.withInterestRecalculationRestFrequencyDetails(recalculationRestFrequencyType, recalculationRestFrequencyInterval,
|
||||
recalculationRestFrequencyDate);
|
||||
recalculationRestFrequencyDate)
|
||||
.withInterestRecalculationCompoundingFrequencyDetails(recalculationCompoundingFrequencyType,
|
||||
recalculationCompoundingFrequencyInterval, recalculationCompoundingFrequencyDate);
|
||||
if (accounts != null) {
|
||||
builder = builder.withAccountingRulePeriodicAccrual(accounts);
|
||||
}
|
||||
@@ -4210,6 +4242,14 @@ public class ClientLoanIntegrationTest {
|
||||
|
||||
private Integer applyForLoanApplicationForInterestRecalculation(final Integer clientID, final Integer loanProductID,
|
||||
final String disbursementDate, final String restStartDate, final String repaymentStrategy, final List<HashMap> charges) {
|
||||
final String compoundingStartDate = null;
|
||||
return applyForLoanApplicationForInterestRecalculation(clientID, loanProductID, disbursementDate, restStartDate,
|
||||
compoundingStartDate, repaymentStrategy, charges);
|
||||
}
|
||||
|
||||
private Integer applyForLoanApplicationForInterestRecalculation(final Integer clientID, final Integer loanProductID,
|
||||
final String disbursementDate, final String restStartDate, final String compoundingStartDate, final String repaymentStrategy,
|
||||
final List<HashMap> charges) {
|
||||
System.out.println("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------");
|
||||
final String loanApplicationJSON = new LoanApplicationTestBuilder() //
|
||||
.withPrincipal("10000.00") //
|
||||
@@ -4225,6 +4265,7 @@ public class ClientLoanIntegrationTest {
|
||||
.withExpectedDisbursementDate(disbursementDate) //
|
||||
.withSubmittedOnDate(disbursementDate) //
|
||||
.withRestFrequencyDate(restStartDate)//
|
||||
.withCompoundingFrequencyDate(compoundingStartDate)//
|
||||
.withwithRepaymentStrategy(repaymentStrategy) //
|
||||
.withCharges(charges)//
|
||||
.build(clientID.toString(), loanProductID.toString(), null);
|
||||
|
||||
+11
-2
@@ -47,6 +47,7 @@ public class LoanApplicationTestBuilder {
|
||||
private List<HashMap> disbursementData = null;
|
||||
private List<HashMap> charges = new ArrayList<HashMap>();
|
||||
private String recalculationRestFrequencyDate = null;
|
||||
private String recalculationCompoundingFrequencyDate = null;
|
||||
private String repaymentsStartingFromDate = null;
|
||||
|
||||
public String build(final String ID, final String loanProductId, final String savingsID) {
|
||||
@@ -74,7 +75,7 @@ public class LoanApplicationTestBuilder {
|
||||
map.put("expectedDisbursementDate", this.expectedDisbursmentDate);
|
||||
map.put("submittedOnDate", this.submittedOnDate);
|
||||
map.put("loanType", this.loanType);
|
||||
if(repaymentsStartingFromDate != null){
|
||||
if (repaymentsStartingFromDate != null) {
|
||||
map.put("repaymentsStartingFromDate", this.repaymentsStartingFromDate);
|
||||
}
|
||||
if (charges != null) {
|
||||
@@ -101,6 +102,9 @@ public class LoanApplicationTestBuilder {
|
||||
if (recalculationRestFrequencyDate != null) {
|
||||
map.put("recalculationRestFrequencyDate", recalculationRestFrequencyDate);
|
||||
}
|
||||
if (recalculationCompoundingFrequencyDate != null) {
|
||||
map.put("recalculationCompoundingFrequencyDate", recalculationCompoundingFrequencyDate);
|
||||
}
|
||||
System.out.println("Loan Application request : " + map);
|
||||
return new Gson().toJson(map);
|
||||
}
|
||||
@@ -244,7 +248,12 @@ public class LoanApplicationTestBuilder {
|
||||
this.recalculationRestFrequencyDate = recalculationRestFrequencyDate;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public LoanApplicationTestBuilder withCompoundingFrequencyDate(final String recalculationCompoundingFrequencyDate) {
|
||||
this.recalculationCompoundingFrequencyDate = recalculationCompoundingFrequencyDate;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LoanApplicationTestBuilder withFirstRepaymentDate(final String firstRepaymentDate) {
|
||||
this.repaymentsStartingFromDate = firstRepaymentDate;
|
||||
return this;
|
||||
|
||||
+21
-4
@@ -92,6 +92,9 @@ public class LoanProductTestBuilder {
|
||||
private String recalculationRestFrequencyType = "1";
|
||||
private String recalculationRestFrequencyInterval = "0";
|
||||
private String recalculationRestFrequencyDate = null;
|
||||
private String recalculationCompoundingFrequencyType = null;
|
||||
private String recalculationCompoundingFrequencyInterval = null;
|
||||
private String recalculationCompoundingFrequencyDate = null;
|
||||
private String minimumDaysBetweenDisbursalAndFirstRepayment = null;
|
||||
private Boolean holdGuaranteeFunds = null;
|
||||
private String mandatoryGuarantee = null;
|
||||
@@ -101,7 +104,7 @@ public class LoanProductTestBuilder {
|
||||
private String graceOnPrincipalPayment = "1";
|
||||
private String graceOnInterestPayment = "1";
|
||||
private JsonObject allowAttributeOverrides = null;
|
||||
|
||||
|
||||
public String build(final String chargeId) {
|
||||
final HashMap<String, Object> map = new HashMap<>();
|
||||
|
||||
@@ -157,6 +160,11 @@ public class LoanProductTestBuilder {
|
||||
map.put("recalculationRestFrequencyType", recalculationRestFrequencyType);
|
||||
map.put("recalculationRestFrequencyInterval", recalculationRestFrequencyInterval);
|
||||
map.put("recalculationRestFrequencyDate", recalculationRestFrequencyDate);
|
||||
if (!RECALCULATION_COMPOUNDING_METHOD_NONE.equals(this.interestRecalculationCompoundingMethod)) {
|
||||
map.put("recalculationCompoundingFrequencyType", recalculationCompoundingFrequencyType);
|
||||
map.put("recalculationCompoundingFrequencyInterval", recalculationCompoundingFrequencyInterval);
|
||||
map.put("recalculationCompoundingFrequencyDate", recalculationCompoundingFrequencyDate);
|
||||
}
|
||||
map.put("preClosureInterestCalculationStrategy", preCloseInterestCalculationStrategy);
|
||||
if (isArrearsBasedOnOriginalSchedule != null) {
|
||||
map.put("isArrearsBasedOnOriginalSchedule", isArrearsBasedOnOriginalSchedule);
|
||||
@@ -172,8 +180,8 @@ public class LoanProductTestBuilder {
|
||||
}
|
||||
map.put("graceOnPrincipalPayment", graceOnPrincipalPayment);
|
||||
map.put("graceOnInterestPayment", graceOnInterestPayment);
|
||||
if(allowAttributeOverrides != null){
|
||||
map.put("allowAttributeOverrides", this.allowAttributeOverrides);
|
||||
if (allowAttributeOverrides != null) {
|
||||
map.put("allowAttributeOverrides", this.allowAttributeOverrides);
|
||||
}
|
||||
return new Gson().toJson(map);
|
||||
}
|
||||
@@ -411,6 +419,15 @@ public class LoanProductTestBuilder {
|
||||
this.recalculationRestFrequencyDate = recalculationRestFrequencyDate;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LoanProductTestBuilder withInterestRecalculationCompoundingFrequencyDetails(final String recalculationCompoundingFrequencyType,
|
||||
final String recalculationCompoundingFrequencyInterval, final String recalculationCompoundingFrequencyDate) {
|
||||
this.isInterestRecalculationEnabled = true;
|
||||
this.recalculationCompoundingFrequencyType = recalculationCompoundingFrequencyType;
|
||||
this.recalculationCompoundingFrequencyInterval = recalculationCompoundingFrequencyInterval;
|
||||
this.recalculationCompoundingFrequencyDate = recalculationCompoundingFrequencyDate;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LoanProductTestBuilder withMinimumDaysBetweenDisbursalAndFirstRepayment(final String minimumDaysBetweenDisbursalAndFirstRepayment) {
|
||||
this.minimumDaysBetweenDisbursalAndFirstRepayment = minimumDaysBetweenDisbursalAndFirstRepayment;
|
||||
@@ -440,5 +457,5 @@ public class LoanProductTestBuilder {
|
||||
public LoanProductTestBuilder withLoanProductConfiguration(JsonObject loanProductConfigurableAttributes) {
|
||||
this.allowAttributeOverrides = loanProductConfigurableAttributes;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+45
-8
@@ -129,8 +129,9 @@ public class DataValidatorBuilder {
|
||||
|
||||
/*** FIXME: Vishwas, why does this method have a parameter? Seems wrong ***/
|
||||
/*
|
||||
* This method is not meant for validation, if you have mandatory boolean param and
|
||||
* if it has invalid value or value not passed then call this method, this method is always used with input as false
|
||||
* This method is not meant for validation, if you have mandatory boolean
|
||||
* param and if it has invalid value or value not passed then call this
|
||||
* method, this method is always used with input as false
|
||||
*/
|
||||
public DataValidatorBuilder trueOrFalseRequired(final boolean trueOfFalseFieldProvided) {
|
||||
if (!trueOfFalseFieldProvided && !this.ignoreNullValue) {
|
||||
@@ -385,7 +386,7 @@ public class DataValidatorBuilder {
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public DataValidatorBuilder integerEqualToOrGreaterThanNumber(Integer number) {
|
||||
if (this.value == null && this.ignoreNullValue) { return this; }
|
||||
|
||||
@@ -394,8 +395,8 @@ public class DataValidatorBuilder {
|
||||
if (intValue < number) {
|
||||
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
|
||||
.append(this.parameter).append(".not.equal.to.or.greater.than.specified.number");
|
||||
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter).append(
|
||||
" must be equal to or greater than").append(number);
|
||||
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
|
||||
.append(" must be equal to or greater than").append(number);
|
||||
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
|
||||
defaultEnglishMessage.toString(), this.parameter, intValue, number);
|
||||
this.dataValidationErrors.add(error);
|
||||
@@ -403,7 +404,7 @@ public class DataValidatorBuilder {
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public DataValidatorBuilder integerSameAsNumber(Integer number) {
|
||||
if (this.value == null && this.ignoreNullValue) { return this; }
|
||||
|
||||
@@ -422,6 +423,24 @@ public class DataValidatorBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public DataValidatorBuilder integerInMultiplesOfNumber(Integer number) {
|
||||
if (this.value == null && this.ignoreNullValue) { return this; }
|
||||
|
||||
if (this.value != null) {
|
||||
final Integer intValue = Integer.valueOf(this.value.toString());
|
||||
if (intValue < number || intValue % number != 0) {
|
||||
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
|
||||
.append(this.parameter).append(".not.in.multiples.of.specified.number");
|
||||
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
|
||||
.append(" must be multiples of ").append(number);
|
||||
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
|
||||
defaultEnglishMessage.toString(), this.parameter, intValue, number);
|
||||
this.dataValidationErrors.add(error);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/*
|
||||
* should be used with .notNull() before it
|
||||
*/
|
||||
@@ -822,7 +841,7 @@ public class DataValidatorBuilder {
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public DataValidatorBuilder validateDateBefore(final LocalDate date) {
|
||||
if (this.value == null && this.ignoreNullValue) { return this; }
|
||||
|
||||
@@ -840,7 +859,7 @@ public class DataValidatorBuilder {
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public DataValidatorBuilder validateDateBeforeOrEqual(final LocalDate date) {
|
||||
if (this.value == null && this.ignoreNullValue) { return this; }
|
||||
|
||||
@@ -859,4 +878,22 @@ public class DataValidatorBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public DataValidatorBuilder validateDateForEqual(final LocalDate date) {
|
||||
if (this.value == null && this.ignoreNullValue) { return this; }
|
||||
|
||||
if (this.value != null && date != null) {
|
||||
final LocalDate dateVal = (LocalDate) this.value;
|
||||
if (!dateVal.isEqual(date)) {
|
||||
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
|
||||
.append(this.parameter).append(".is.not.equal.to.date");
|
||||
final StringBuilder defaultEnglishMessage = new StringBuilder("The ").append(this.parameter)
|
||||
.append(" must be equal to provided date").append(date);
|
||||
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
|
||||
defaultEnglishMessage.toString(), this.parameter, dateVal, date);
|
||||
this.dataValidationErrors.add(error);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -241,7 +241,7 @@ public class CalendarsApiResource {
|
||||
break;
|
||||
case INVALID:
|
||||
break;
|
||||
case LOAN_RECALCULATION_DETAIL:
|
||||
case LOAN_RECALCULATION_REST_DETAIL:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
+2
-1
@@ -16,7 +16,8 @@ public enum CalendarEntityType {
|
||||
LOANS(3, "calendarEntityType.loans"), //
|
||||
CENTERS(4, "calendarEntityType.centers"), //
|
||||
SAVINGS(5, "calendarEntityType.savings"), //
|
||||
LOAN_RECALCULATION_DETAIL(6, "calendarEntityType.loan.recalculation.detail");
|
||||
LOAN_RECALCULATION_REST_DETAIL(6, "calendarEntityType.loan.recalculation.rest.detail"), //
|
||||
LOAN_RECALCULATION_COMPOUNDING_DETAIL(7, "calendarEntityType.loan.recalculation.compounding.detail");
|
||||
|
||||
private final Integer value;
|
||||
private final String code;
|
||||
|
||||
+14
-5
@@ -226,8 +226,7 @@ public class LoansApiResource {
|
||||
public String template(@QueryParam("clientId") final Long clientId, @QueryParam("groupId") final Long groupId,
|
||||
@QueryParam("productId") final Long productId, @QueryParam("templateType") final String templateType,
|
||||
@DefaultValue("false") @QueryParam("staffInSelectedOfficeOnly") final boolean staffInSelectedOfficeOnly,
|
||||
@DefaultValue("false") @QueryParam("activeOnly") final boolean onlyActive,
|
||||
@Context final UriInfo uriInfo) {
|
||||
@DefaultValue("false") @QueryParam("activeOnly") final boolean onlyActive, @Context final UriInfo uriInfo) {
|
||||
|
||||
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
|
||||
|
||||
@@ -336,13 +335,23 @@ public class LoansApiResource {
|
||||
|
||||
LoanAccountData loanBasicDetails = this.loanReadPlatformService.retrieveOne(loanId);
|
||||
if (loanBasicDetails.isInterestRecalculationEnabled()) {
|
||||
Collection<CalendarData> interestRecalculationCalendarDatas = this.calendarReadPlatformService.retrieveCalendarsByEntity(
|
||||
loanBasicDetails.getInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue(), null);
|
||||
Collection<CalendarData> interestRecalculationCalendarDatas = this.calendarReadPlatformService
|
||||
.retrieveCalendarsByEntity(loanBasicDetails.getInterestRecalculationDetailId(),
|
||||
CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue(), null);
|
||||
CalendarData calendarData = null;
|
||||
if (!CollectionUtils.isEmpty(interestRecalculationCalendarDatas)) {
|
||||
calendarData = interestRecalculationCalendarDatas.iterator().next();
|
||||
}
|
||||
loanBasicDetails = LoanAccountData.withInterestRecalculationCalendarData(loanBasicDetails, calendarData);
|
||||
|
||||
Collection<CalendarData> interestRecalculationCompoundingCalendarDatas = this.calendarReadPlatformService
|
||||
.retrieveCalendarsByEntity(loanBasicDetails.getInterestRecalculationDetailId(),
|
||||
CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue(), null);
|
||||
CalendarData compoundingCalendarData = null;
|
||||
if (!CollectionUtils.isEmpty(interestRecalculationCompoundingCalendarDatas)) {
|
||||
compoundingCalendarData = interestRecalculationCompoundingCalendarDatas.iterator().next();
|
||||
}
|
||||
loanBasicDetails = LoanAccountData.withInterestRecalculationCalendarData(loanBasicDetails, calendarData,
|
||||
compoundingCalendarData);
|
||||
}
|
||||
|
||||
Collection<LoanTransactionData> loanRepayments = null;
|
||||
|
||||
+20
-19
@@ -565,10 +565,10 @@ public class LoanAccountData {
|
||||
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions,
|
||||
fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions,
|
||||
syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, accountLinkingOptions, linkedAccount,
|
||||
disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount, maxOutstandingBalance, emiAmountVariations,
|
||||
memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType, daysInYearType,
|
||||
isInterestRecalculationEnabled, interestRecalculationData, originalSchedule, createStandingInstructionAtDisbursement,
|
||||
paidInAdvance);
|
||||
disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount, maxOutstandingBalance,
|
||||
emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType,
|
||||
daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule,
|
||||
createStandingInstructionAtDisbursement, paidInAdvance);
|
||||
|
||||
}
|
||||
|
||||
@@ -595,7 +595,7 @@ public class LoanAccountData {
|
||||
acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType,
|
||||
acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule,
|
||||
acc.createStandingInstructionAtDisbursement, acc.paidInAdvance);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static LoanAccountData loanProductWithTemplateDefaults(final LoanProductData product,
|
||||
@@ -862,10 +862,10 @@ public class LoanAccountData {
|
||||
amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions,
|
||||
chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions,
|
||||
syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, accountLinkingOptions, linkedAccount,
|
||||
disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmont, outstandingLoanBalance, emiAmountVariations,
|
||||
memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType, daysInYearType,
|
||||
isInterestRecalculationEnabled, interestRecalculationData, originalSchedule, createStandingInstructionAtDisbursement,
|
||||
paidInAdvance);
|
||||
disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmont, outstandingLoanBalance,
|
||||
emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType,
|
||||
daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule,
|
||||
createStandingInstructionAtDisbursement, paidInAdvance);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -889,10 +889,10 @@ public class LoanAccountData {
|
||||
final PortfolioAccountData linkedAccount, final Collection<DisbursementData> disbursementDetails,
|
||||
final Collection<LoanTermVariationsData> emiAmountVariations, final Collection<ChargeData> overdueCharges,
|
||||
final PaidInAdvanceData paidInAdvance) {
|
||||
LoanProductConfigurableAttributes loanProductConfigurableAttributes = null;
|
||||
if (acc.product != null) {
|
||||
loanProductConfigurableAttributes = acc.product.getloanProductConfigurableAttributes();
|
||||
}
|
||||
LoanProductConfigurableAttributes loanProductConfigurableAttributes = null;
|
||||
if (acc.product != null) {
|
||||
loanProductConfigurableAttributes = acc.product.getloanProductConfigurableAttributes();
|
||||
}
|
||||
|
||||
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientName, acc.clientOfficeId,
|
||||
acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.fundId, acc.fundName,
|
||||
@@ -1014,10 +1014,11 @@ public class LoanAccountData {
|
||||
|
||||
}
|
||||
|
||||
public static LoanAccountData withInterestRecalculationCalendarData(final LoanAccountData acc, final CalendarData calendarData) {
|
||||
public static LoanAccountData withInterestRecalculationCalendarData(final LoanAccountData acc, final CalendarData calendarData,
|
||||
final CalendarData compoundingCalendarData) {
|
||||
|
||||
final LoanInterestRecalculationData interestRecalculationData = LoanInterestRecalculationData.withCalendarData(
|
||||
acc.interestRecalculationData, calendarData);
|
||||
acc.interestRecalculationData, calendarData, compoundingCalendarData);
|
||||
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientName, acc.clientOfficeId,
|
||||
acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.fundId, acc.fundName,
|
||||
acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal,
|
||||
@@ -1285,7 +1286,7 @@ public class LoanAccountData {
|
||||
this.originalSchedule = originalSchedule;
|
||||
this.createStandingInstructionAtDisbursement = createStandingInstructionAtDisbursement;
|
||||
this.paidInAdvance = paidInAdvance;
|
||||
if(this.product != null){
|
||||
if (this.product != null) {
|
||||
this.product.setloanProductConfigurableAttributes(product.getloanProductConfigurableAttributes());
|
||||
}
|
||||
}
|
||||
@@ -1357,10 +1358,10 @@ public class LoanAccountData {
|
||||
return this.product;
|
||||
}
|
||||
|
||||
public void setProduct(LoanProductData product){
|
||||
this.product = product;
|
||||
public void setProduct(LoanProductData product) {
|
||||
this.product = product;
|
||||
}
|
||||
|
||||
|
||||
public GroupGeneralData groupData() {
|
||||
return this.group;
|
||||
}
|
||||
|
||||
+16
-3
@@ -20,11 +20,18 @@ public class LoanInterestRecalculationData {
|
||||
private final EnumOptionData recalculationRestFrequencyType;
|
||||
private final Integer recalculationRestFrequencyInterval;
|
||||
private final LocalDate recalculationRestFrequencyDate;
|
||||
private final EnumOptionData recalculationCompoundingFrequencyType;
|
||||
private final Integer recalculationCompoundingFrequencyInterval;
|
||||
private final LocalDate recalculationCompoundingFrequencyDate;
|
||||
@SuppressWarnings("unused")
|
||||
private final CalendarData compoundingCalendarData;
|
||||
|
||||
public LoanInterestRecalculationData(final Long id, final Long loanId, final EnumOptionData interestRecalculationCompoundingType,
|
||||
final EnumOptionData rescheduleStrategyType, final CalendarData calendarData,
|
||||
final EnumOptionData recalculationRestFrequencyType, final Integer recalculationRestFrequencyInterval,
|
||||
final LocalDate recalculationRestFrequencyDate) {
|
||||
final LocalDate recalculationRestFrequencyDate, final CalendarData compoundingCalendarData,
|
||||
final EnumOptionData recalculationCompoundingFrequencyType, final Integer recalculationCompoundingFrequencyInterval,
|
||||
final LocalDate recalculationCompoundingFrequencyDate) {
|
||||
this.id = id;
|
||||
this.loanId = loanId;
|
||||
this.interestRecalculationCompoundingType = interestRecalculationCompoundingType;
|
||||
@@ -33,14 +40,20 @@ public class LoanInterestRecalculationData {
|
||||
this.recalculationRestFrequencyType = recalculationRestFrequencyType;
|
||||
this.recalculationRestFrequencyInterval = recalculationRestFrequencyInterval;
|
||||
this.recalculationRestFrequencyDate = recalculationRestFrequencyDate;
|
||||
this.recalculationCompoundingFrequencyType = recalculationCompoundingFrequencyType;
|
||||
this.recalculationCompoundingFrequencyInterval = recalculationCompoundingFrequencyInterval;
|
||||
this.recalculationCompoundingFrequencyDate = recalculationCompoundingFrequencyDate;
|
||||
this.compoundingCalendarData = compoundingCalendarData;
|
||||
}
|
||||
|
||||
public static LoanInterestRecalculationData withCalendarData(final LoanInterestRecalculationData recalculationData,
|
||||
final CalendarData calendarData) {
|
||||
final CalendarData calendarData, CalendarData compoundingCalendarData) {
|
||||
return new LoanInterestRecalculationData(recalculationData.id, recalculationData.loanId,
|
||||
recalculationData.interestRecalculationCompoundingType, recalculationData.rescheduleStrategyType, calendarData,
|
||||
recalculationData.recalculationRestFrequencyType, recalculationData.recalculationRestFrequencyInterval,
|
||||
recalculationData.recalculationRestFrequencyDate);
|
||||
recalculationData.recalculationRestFrequencyDate, compoundingCalendarData,
|
||||
recalculationData.recalculationCompoundingFrequencyType, recalculationData.recalculationCompoundingFrequencyInterval,
|
||||
recalculationData.recalculationCompoundingFrequencyDate);
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
|
||||
+8
-12
@@ -17,37 +17,37 @@ public class ScheduleGeneratorDTO {
|
||||
final LocalDate calculatedRepaymentsStartingFromDate;
|
||||
final HolidayDetailDTO holidayDetailDTO;
|
||||
final CalendarInstance calendarInstanceForInterestRecalculation;
|
||||
final CalendarInstance compoundingCalendarInstance;
|
||||
LocalDate recalculateFrom;
|
||||
final Long overdurPenaltyWaitPeriod;
|
||||
LocalDate lastTransactionDate;
|
||||
|
||||
public ScheduleGeneratorDTO(final LoanScheduleGeneratorFactory loanScheduleFactory, final ApplicationCurrency applicationCurrency,
|
||||
final LocalDate calculatedRepaymentsStartingFromDate, final HolidayDetailDTO holidayDetailDTO,
|
||||
final CalendarInstance calendarInstanceForInterestRecalculation) {
|
||||
final CalendarInstance calendarInstanceForInterestRecalculation, final CalendarInstance compoundingCalendarInstance) {
|
||||
|
||||
this.loanScheduleFactory = loanScheduleFactory;
|
||||
this.applicationCurrency = applicationCurrency;
|
||||
this.calculatedRepaymentsStartingFromDate = calculatedRepaymentsStartingFromDate;
|
||||
this.calendarInstanceForInterestRecalculation = calendarInstanceForInterestRecalculation;
|
||||
this.compoundingCalendarInstance = compoundingCalendarInstance;
|
||||
this.recalculateFrom = null;
|
||||
this.overdurPenaltyWaitPeriod = null;
|
||||
this.lastTransactionDate = null;
|
||||
this.holidayDetailDTO = holidayDetailDTO;
|
||||
|
||||
}
|
||||
|
||||
public ScheduleGeneratorDTO(final LoanScheduleGeneratorFactory loanScheduleFactory, final ApplicationCurrency applicationCurrency,
|
||||
final LocalDate calculatedRepaymentsStartingFromDate, final HolidayDetailDTO holidayDetailDTO,
|
||||
final CalendarInstance calendarInstanceForInterestRecalculation, final LocalDate recalculateFrom,
|
||||
final Long overdurPenaltyWaitPeriod, final LocalDate lastTransactionDate) {
|
||||
final CalendarInstance calendarInstanceForInterestRecalculation, final CalendarInstance compoundingCalendarInstance,
|
||||
final LocalDate recalculateFrom, final Long overdurPenaltyWaitPeriod) {
|
||||
|
||||
this.loanScheduleFactory = loanScheduleFactory;
|
||||
this.applicationCurrency = applicationCurrency;
|
||||
this.calculatedRepaymentsStartingFromDate = calculatedRepaymentsStartingFromDate;
|
||||
this.calendarInstanceForInterestRecalculation = calendarInstanceForInterestRecalculation;
|
||||
this.compoundingCalendarInstance = compoundingCalendarInstance;
|
||||
this.recalculateFrom = recalculateFrom;
|
||||
this.overdurPenaltyWaitPeriod = overdurPenaltyWaitPeriod;
|
||||
this.lastTransactionDate = lastTransactionDate;
|
||||
this.holidayDetailDTO = holidayDetailDTO;
|
||||
|
||||
}
|
||||
@@ -84,10 +84,6 @@ public class ScheduleGeneratorDTO {
|
||||
return penaltyWaitPeriod;
|
||||
}
|
||||
|
||||
public LocalDate getLastTransactionDate() {
|
||||
return this.lastTransactionDate;
|
||||
}
|
||||
|
||||
public HolidayDetailDTO getHolidayDetailDTO() {
|
||||
return this.holidayDetailDTO;
|
||||
}
|
||||
@@ -96,8 +92,8 @@ public class ScheduleGeneratorDTO {
|
||||
this.recalculateFrom = recalculateFrom;
|
||||
}
|
||||
|
||||
public void setLastTransactionDate(LocalDate lastTransactionDate) {
|
||||
this.lastTransactionDate = lastTransactionDate;
|
||||
public CalendarInstance getCompoundingCalendarInstance() {
|
||||
return this.compoundingCalendarInstance;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+99
-72
@@ -105,6 +105,7 @@ import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanRescheduleStrategyMethod;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanTransactionProcessingStrategy;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.RecalculationFrequencyType;
|
||||
import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations;
|
||||
@@ -557,8 +558,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
// store Id's of existing loan transactions and existing reversed loan
|
||||
// transactions
|
||||
final LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper();
|
||||
wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, charges(),
|
||||
getLastUserTransactionForChargeCalc());
|
||||
wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, charges());
|
||||
updateLoanSummaryDerivedFields();
|
||||
|
||||
}
|
||||
@@ -569,8 +569,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
.determineProcessor(this.transactionProcessingStrategy);
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
|
||||
allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments, charges(),
|
||||
getLastUserTransactionForChargeCalc());
|
||||
allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments, charges());
|
||||
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||
mapEntry.getValue().updateLoan(this);
|
||||
}
|
||||
@@ -707,8 +706,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
if (removed) {
|
||||
charge.setActive(false);
|
||||
final LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper();
|
||||
wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, charges(),
|
||||
getLastUserTransactionForChargeCalc());
|
||||
wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, charges());
|
||||
updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement());
|
||||
}
|
||||
|
||||
@@ -727,7 +725,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
***/
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||
loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement,
|
||||
getCurrency(), this.repaymentScheduleInstallments, charges(), getLastUserTransactionForChargeCalc());
|
||||
getCurrency(), this.repaymentScheduleInstallments, charges());
|
||||
}
|
||||
|
||||
updateLoanSummaryDerivedFields();
|
||||
@@ -785,12 +783,11 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
***/
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||
loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement,
|
||||
getCurrency(), this.repaymentScheduleInstallments, charges(), getLastUserTransactionForChargeCalc());
|
||||
getCurrency(), this.repaymentScheduleInstallments, charges());
|
||||
} else {
|
||||
// reprocess loan schedule based on charge been waived.
|
||||
final LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper();
|
||||
wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, charges(),
|
||||
getLastUserTransactionForChargeCalc());
|
||||
wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, charges());
|
||||
}
|
||||
|
||||
updateLoanSummaryDerivedFields();
|
||||
@@ -938,12 +935,11 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
***/
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||
loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(), allNonContraTransactionsPostDisbursement,
|
||||
getCurrency(), this.repaymentScheduleInstallments, charges(), getLastUserTransactionForChargeCalc());
|
||||
getCurrency(), this.repaymentScheduleInstallments, charges());
|
||||
} else {
|
||||
// reprocess loan schedule based on charge been waived.
|
||||
final LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper();
|
||||
wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, charges(),
|
||||
getLastUserTransactionForChargeCalc());
|
||||
wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, charges());
|
||||
}
|
||||
|
||||
updateLoanSummaryDerivedFields();
|
||||
@@ -1174,7 +1170,10 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
final String localeAsInput = command.locale();
|
||||
final LocalDate recalculationRestFrequencyDate = command
|
||||
.localDateValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyDateParamName);
|
||||
updateLoanInterestRecalculationSettings(recalculationRestFrequencyDate, command, actualChanges);
|
||||
final LocalDate recalculationCompoundingFrequencyDate = command
|
||||
.localDateValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyDateParamName);
|
||||
updateLoanInterestRecalculationSettings(recalculationRestFrequencyDate, recalculationCompoundingFrequencyDate, command,
|
||||
actualChanges);
|
||||
|
||||
final String accountNoParamName = "accountNo";
|
||||
if (command.isChangeInStringParameterNamed(accountNoParamName, this.accountNumber)) {
|
||||
@@ -1438,20 +1437,28 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
/**
|
||||
* Update interest recalculation settings if product configuration changes
|
||||
*/
|
||||
public void updateLoanInterestRecalculationSettings(final LocalDate recalculationRestFrequencyDate, final JsonCommand command,
|
||||
final Map<String, Object> actualChanges) {
|
||||
public void updateLoanInterestRecalculationSettings(final LocalDate recalculationRestFrequencyDate,
|
||||
final LocalDate recalculationCompoundingFrequencyDate, final JsonCommand command, final Map<String, Object> actualChanges) {
|
||||
|
||||
if (isInterestRecalculationEnabledForProduct()) {
|
||||
Date restFrequencyDate = null;
|
||||
if (recalculationRestFrequencyDate != null) {
|
||||
restFrequencyDate = recalculationRestFrequencyDate.toDate();
|
||||
}
|
||||
|
||||
Date compoundingFrequencyDate = null;
|
||||
if (recalculationCompoundingFrequencyDate != null) {
|
||||
compoundingFrequencyDate = recalculationCompoundingFrequencyDate.toDate();
|
||||
}
|
||||
if (this.loanInterestRecalculationDetails == null) {
|
||||
actualChanges.put(LoanProductConstants.isInterestRecalculationEnabledParameterName, true);
|
||||
this.loanInterestRecalculationDetails = LoanInterestRecalculationDetails.createFrom(this.loanProduct
|
||||
.getProductInterestRecalculationDetails().getInterestRecalculationCompoundingMethod(), this.loanProduct
|
||||
.getProductInterestRecalculationDetails().getRescheduleStrategyMethod(), this.loanProduct
|
||||
.getProductInterestRecalculationDetails().getRestFrequencyType().getValue(), this.loanProduct
|
||||
.getProductInterestRecalculationDetails().getRestInterval(), restFrequencyDate);
|
||||
.getProductInterestRecalculationDetails().getRestInterval(), restFrequencyDate, this.loanProduct
|
||||
.getProductInterestRecalculationDetails().getCompoundingFrequencyType().getValue(), this.loanProduct
|
||||
.getProductInterestRecalculationDetails().getCompoundingInterval(), compoundingFrequencyDate);
|
||||
this.loanInterestRecalculationDetails.updateLoan(this);
|
||||
} else {
|
||||
|
||||
@@ -1691,7 +1698,8 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
public void loanApplicationSubmittal(final AppUser currentUser, final LoanScheduleModel loanSchedule,
|
||||
final LoanApplicationTerms loanApplicationTerms, final LoanLifecycleStateMachine lifecycleStateMachine,
|
||||
final LocalDate submittedOn, final String externalId, final boolean allowTransactionsOnHoliday, final List<Holiday> holidays,
|
||||
final WorkingDays workingDays, final boolean allowTransactionsOnNonWorkingDay, final LocalDate recalculationRestFrequencyDate) {
|
||||
final WorkingDays workingDays, final boolean allowTransactionsOnNonWorkingDay, final LocalDate recalculationRestFrequencyDate,
|
||||
final LocalDate recalculationCompoundingFrequencyDate) {
|
||||
|
||||
updateLoanSchedule(loanSchedule, currentUser);
|
||||
|
||||
@@ -1767,11 +1775,18 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
if (recalculationRestFrequencyDate != null) {
|
||||
restFrequencyDate = recalculationRestFrequencyDate.toDate();
|
||||
}
|
||||
|
||||
Date compoundingFrequencyDate = null;
|
||||
if (recalculationCompoundingFrequencyDate != null) {
|
||||
compoundingFrequencyDate = recalculationCompoundingFrequencyDate.toDate();
|
||||
}
|
||||
this.loanInterestRecalculationDetails = LoanInterestRecalculationDetails.createFrom(this.loanProduct
|
||||
.getProductInterestRecalculationDetails().getInterestRecalculationCompoundingMethod(), this.loanProduct
|
||||
.getProductInterestRecalculationDetails().getRescheduleStrategyMethod(), this.loanProduct
|
||||
.getProductInterestRecalculationDetails().getRestFrequencyType().getValue(), this.loanProduct
|
||||
.getProductInterestRecalculationDetails().getRestInterval(), restFrequencyDate);
|
||||
.getProductInterestRecalculationDetails().getRestInterval(), restFrequencyDate, this.loanProduct
|
||||
.getProductInterestRecalculationDetails().getCompoundingFrequencyType().getValue(), this.loanProduct
|
||||
.getProductInterestRecalculationDetails().getCompoundingInterval(), compoundingFrequencyDate);
|
||||
this.loanInterestRecalculationDetails.updateLoan(this);
|
||||
}
|
||||
|
||||
@@ -2220,8 +2235,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
.determineProcessor(this.transactionProcessingStrategy);
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
|
||||
allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments, charges(),
|
||||
getLastUserTransactionForChargeCalc());
|
||||
allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments, charges());
|
||||
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||
mapEntry.getValue().updateLoan(this);
|
||||
}
|
||||
@@ -2374,24 +2388,28 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
CalendarInstance restCalendarInstance = null;
|
||||
CalendarInstance compoundingCalendarInstance = null;
|
||||
RecalculationFrequencyType recalculationFrequencyType = null;
|
||||
InterestRecalculationCompoundingMethod compoundingMethod = null;
|
||||
RecalculationFrequencyType compoundingFrequencyType = null;
|
||||
LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
|
||||
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
restCalendarInstance = scheduleGeneratorDTO.getCalendarInstanceForInterestRecalculation();
|
||||
recalculationFrequencyType = this.loanProduct.getProductInterestRecalculationDetails().getRestFrequencyType();
|
||||
compoundingMethod = InterestRecalculationCompoundingMethod.fromInt(this.loanProduct.getProductInterestRecalculationDetails()
|
||||
.getInterestRecalculationCompoundingMethod());
|
||||
compoundingCalendarInstance = scheduleGeneratorDTO.getCompoundingCalendarInstance();
|
||||
recalculationFrequencyType = this.loanInterestRecalculationDetails.getRestFrequencyType();
|
||||
compoundingMethod = this.loanInterestRecalculationDetails.getInterestRecalculationCompoundingMethod();
|
||||
compoundingFrequencyType = this.loanInterestRecalculationDetails.getCompoundingFrequencyType();
|
||||
rescheduleStrategyMethod = this.loanInterestRecalculationDetails.getRescheduleStrategyMethod();
|
||||
}
|
||||
|
||||
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 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, compoundingCalendarInstance, compoundingFrequencyType,
|
||||
this.loanProduct.preCloseInterestCalculationStrategy(), rescheduleStrategyMethod);
|
||||
|
||||
final LoanScheduleModel loanSchedule = loanScheduleGenerator.generate(mc, loanApplicationTerms, charges(),
|
||||
scheduleGeneratorDTO.getHolidayDetailDTO());
|
||||
@@ -2569,8 +2587,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
|
||||
this.loanTermVariations.clear();
|
||||
final LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper();
|
||||
wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, charges(),
|
||||
getLastUserTransactionForChargeCalc());
|
||||
wrapper.reprocess(getCurrency(), getDisbursementDate(), this.repaymentScheduleInstallments, charges());
|
||||
|
||||
updateLoanSummaryDerivedFields();
|
||||
}
|
||||
@@ -2790,8 +2807,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
}
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
|
||||
allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments, charges(),
|
||||
getLastUserTransactionForChargeCalc());
|
||||
allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments, charges());
|
||||
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||
mapEntry.getValue().updateLoan(this);
|
||||
}
|
||||
@@ -3110,7 +3126,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
}
|
||||
ChangedTransactionDetail changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(
|
||||
getDisbursementDate(), allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments,
|
||||
charges(), getLastUserTransactionForChargeCalc());
|
||||
charges());
|
||||
updateLoanSummaryDerivedFields();
|
||||
return changedTransactionDetail;
|
||||
}
|
||||
@@ -3249,8 +3265,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
}
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
|
||||
allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments, charges(),
|
||||
getLastUserTransactionForChargeCalc());
|
||||
allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments, charges());
|
||||
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||
mapEntry.getValue().updateLoan(this);
|
||||
this.loanTransactions.add(mapEntry.getValue());
|
||||
@@ -4527,7 +4542,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||
ChangedTransactionDetail changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(
|
||||
getDisbursementDate(), allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments,
|
||||
charges(), getLastUserTransactionForChargeCalc());
|
||||
charges());
|
||||
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||
mapEntry.getValue().updateLoan(this);
|
||||
this.loanTransactions.add(mapEntry.getValue());
|
||||
@@ -4631,7 +4646,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||
ChangedTransactionDetail changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(
|
||||
getDisbursementDate(), allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments,
|
||||
charges(), getLastUserTransactionForChargeCalc());
|
||||
charges());
|
||||
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||
mapEntry.getValue().updateLoan(this);
|
||||
}
|
||||
@@ -4652,7 +4667,6 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
public void regenerateRepaymentScheduleWithInterestRecalculation(final ScheduleGeneratorDTO generatorDTO, final AppUser currentUser) {
|
||||
|
||||
LocalDate lastTransactionDate = getLastUserTransactionDate();
|
||||
generatorDTO.setLastTransactionDate(lastTransactionDate);
|
||||
final LoanScheduleModel loanSchedule = getRecalculatedSchedule(generatorDTO);
|
||||
if (loanSchedule == null) { return; }
|
||||
updateLoanSchedule(loanSchedule, currentUser);
|
||||
@@ -4681,7 +4695,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
copyTransactions.add(LoanTransaction.copyTransactionProperties(loanTransaction));
|
||||
}
|
||||
loanRepaymentScheduleTransactionProcessor.populateDerivedFeildsWithoutReprocess(getDisbursementDate(), copyTransactions,
|
||||
getCurrency(), this.repaymentScheduleInstallments, charges(), getLastUserTransactionForChargeCalc());
|
||||
getCurrency(), this.repaymentScheduleInstallments, charges());
|
||||
|
||||
updateLoanSummaryDerivedFields();
|
||||
}
|
||||
@@ -4696,19 +4710,21 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
final MathContext mc = new MathContext(8, roundingMode);
|
||||
|
||||
final LoanApplicationTerms loanApplicationTerms = constructLoanApplicationTerms(generatorDTO.getApplicationCurrency(),
|
||||
generatorDTO.getCalculatedRepaymentsStartingFromDate(), generatorDTO.getCalendarInstanceForInterestRecalculation());
|
||||
generatorDTO.getCalculatedRepaymentsStartingFromDate(), generatorDTO.getCalendarInstanceForInterestRecalculation(),
|
||||
generatorDTO.getCompoundingCalendarInstance());
|
||||
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
||||
.determineProcessor(this.transactionProcessingStrategy);
|
||||
|
||||
final LoanScheduleModel loanSchedule = loanScheduleGenerator.rescheduleNextInstallments(mc, loanApplicationTerms, charges(),
|
||||
generatorDTO.getHolidayDetailDTO(), retreiveListOfTransactionsPostDisbursementExcludeAccruals(),
|
||||
loanRepaymentScheduleTransactionProcessor, generatorDTO.getLastTransactionDate());
|
||||
loanRepaymentScheduleTransactionProcessor);
|
||||
return loanSchedule;
|
||||
}
|
||||
|
||||
public LoanApplicationTerms constructLoanApplicationTerms(final ApplicationCurrency applicationCurrency,
|
||||
final LocalDate calculatedRepaymentsStartingFromDate, final CalendarInstance calendarInstanceForInterestRecalculation) {
|
||||
final LocalDate calculatedRepaymentsStartingFromDate, final CalendarInstance calendarInstanceForInterestRecalculation,
|
||||
final CalendarInstance compoundingCalendarInstance) {
|
||||
final Integer loanTermFrequency = this.termFrequency;
|
||||
final PeriodFrequencyType loanTermPeriodFrequencyType = PeriodFrequencyType.fromInt(this.termPeriodFrequencyType);
|
||||
final List<DisbursementData> disbursementData = new ArrayList<>();
|
||||
@@ -4732,20 +4748,22 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
RecalculationFrequencyType recalculationFrequencyType = this.loanInterestRecalculationDetails().getRestFrequencyType();
|
||||
RecalculationFrequencyType compoundingFrequencyType = this.loanInterestRecalculationDetails().getCompoundingFrequencyType();
|
||||
|
||||
final LoanApplicationTerms loanApplicationTerms = LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency,
|
||||
loanTermPeriodFrequencyType, getDisbursementDate(), getExpectedFirstRepaymentOnDate(),
|
||||
calculatedRepaymentsStartingFromDate, getInArrearsTolerance(), this.loanRepaymentScheduleDetail,
|
||||
this.loanProduct.isMultiDisburseLoan(), this.fixedEmiAmount, disbursementData, this.maxOutstandingLoanBalance,
|
||||
loanVariationTermsData, getInterestChargedFromDate(), this.loanInterestRecalculationDetails,
|
||||
calendarInstanceForInterestRecalculation, recalculationFrequencyType,
|
||||
this.loanProduct.getPrincipalThresholdForLastInstallment(), this.loanProduct.getInstallmentAmountInMultiplesOf(),
|
||||
this.loanProduct.preCloseInterestCalculationStrategy());
|
||||
calendarInstanceForInterestRecalculation, recalculationFrequencyType, compoundingCalendarInstance,
|
||||
compoundingFrequencyType, this.loanProduct.getPrincipalThresholdForLastInstallment(),
|
||||
this.loanProduct.getInstallmentAmountInMultiplesOf(), this.loanProduct.preCloseInterestCalculationStrategy());
|
||||
return loanApplicationTerms;
|
||||
}
|
||||
|
||||
public LoanRepaymentScheduleInstallment fetchPrepaymentDetail(final LoanScheduleGeneratorFactory loanScheduleFactory,
|
||||
CalendarInstance restCalendarInstance, HolidayDetailDTO holidayDetailDTO, LocalDate onDate) {
|
||||
final CalendarInstance restCalendarInstance, final CalendarInstance compoundingCalendarInstance,
|
||||
final HolidayDetailDTO holidayDetailDTO, final LocalDate onDate) {
|
||||
LoanRepaymentScheduleInstallment installment = null;
|
||||
|
||||
if (this.loanRepaymentScheduleDetail.isInterestRecalculationEnabled()) {
|
||||
@@ -4783,10 +4801,13 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
|
||||
RecalculationFrequencyType recalculationFrequencyType = null;
|
||||
InterestRecalculationCompoundingMethod compoundingMethod = null;
|
||||
RecalculationFrequencyType compoundingFrequencyType = null;
|
||||
LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
|
||||
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
recalculationFrequencyType = this.loanProduct.getProductInterestRecalculationDetails().getRestFrequencyType();
|
||||
compoundingMethod = InterestRecalculationCompoundingMethod.fromInt(this.loanProduct
|
||||
.getProductInterestRecalculationDetails().getInterestRecalculationCompoundingMethod());
|
||||
recalculationFrequencyType = this.loanInterestRecalculationDetails.getRestFrequencyType();
|
||||
compoundingMethod = this.loanInterestRecalculationDetails.getInterestRecalculationCompoundingMethod();
|
||||
compoundingFrequencyType = this.loanInterestRecalculationDetails.getCompoundingFrequencyType();
|
||||
rescheduleStrategyMethod = this.loanInterestRecalculationDetails.getRescheduleStrategyMethod();
|
||||
}
|
||||
|
||||
final LoanApplicationTerms loanApplicationTerms = LoanApplicationTerms.assembleFrom(null, loanTermFrequency,
|
||||
@@ -4794,11 +4815,13 @@ 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,
|
||||
this.loanProduct.preCloseInterestCalculationStrategy());
|
||||
|
||||
installment = loanScheduleGenerator.calculatePrepaymentAmount(this.repaymentScheduleInstallments, getCurrency(),
|
||||
onDate, loanApplicationTerms, mc, charges(), holidayDetailDTO);
|
||||
recalculationFrequencyType, restCalendarInstance, compoundingMethod, compoundingCalendarInstance,
|
||||
compoundingFrequencyType, this.loanProduct.preCloseInterestCalculationStrategy(), rescheduleStrategyMethod);
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
|
||||
.determineProcessor(this.transactionProcessingStrategy);
|
||||
installment = loanScheduleGenerator.calculatePrepaymentAmount(this.repaymentScheduleInstallments, getCurrency(), onDate,
|
||||
loanApplicationTerms, mc, charges(), holidayDetailDTO, retreiveListOfTransactionsPostDisbursementExcludeAccruals(),
|
||||
loanRepaymentScheduleTransactionProcessor);
|
||||
} else {
|
||||
installment = this.getTotalOutstandingOnLoan();
|
||||
}
|
||||
@@ -4937,13 +4960,15 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
/**
|
||||
* @param restCalendarInstance
|
||||
* TODO
|
||||
* @param compoundingCalendarInstance
|
||||
* TODO
|
||||
* @param loan
|
||||
* the Loan object
|
||||
* @return application terms of the Loan object
|
||||
**/
|
||||
@SuppressWarnings({ "unused" })
|
||||
public LoanApplicationTerms getLoanApplicationTerms(final ApplicationCurrency applicationCurrency,
|
||||
final CalendarInstance restCalendarInstance) {
|
||||
final CalendarInstance restCalendarInstance, CalendarInstance compoundingCalendarInstance) {
|
||||
LoanProduct loanProduct = loanProduct();
|
||||
// LoanProductRelatedDetail loanProductRelatedDetail =
|
||||
// getLoanRepaymentScheduleDetail();
|
||||
@@ -4998,20 +5023,22 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
|
||||
RecalculationFrequencyType recalculationFrequencyType = null;
|
||||
InterestRecalculationCompoundingMethod compoundingMethod = null;
|
||||
RecalculationFrequencyType compoundingFrequencyType = null;
|
||||
LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
|
||||
if (this.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
recalculationFrequencyType = this.loanProduct.getProductInterestRecalculationDetails().getRestFrequencyType();
|
||||
compoundingMethod = InterestRecalculationCompoundingMethod.fromInt(this.loanProduct.getProductInterestRecalculationDetails()
|
||||
.getInterestRecalculationCompoundingMethod());
|
||||
recalculationFrequencyType = this.loanInterestRecalculationDetails.getRestFrequencyType();
|
||||
compoundingMethod = this.loanInterestRecalculationDetails.getInterestRecalculationCompoundingMethod();
|
||||
compoundingFrequencyType = this.loanInterestRecalculationDetails.getCompoundingFrequencyType();
|
||||
rescheduleStrategyMethod = this.loanInterestRecalculationDetails.getRescheduleStrategyMethod();
|
||||
}
|
||||
|
||||
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());
|
||||
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, compoundingCalendarInstance, compoundingFrequencyType,
|
||||
this.loanProduct.preCloseInterestCalculationStrategy(), rescheduleStrategyMethod);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -5204,7 +5231,7 @@ public class Loan extends AbstractPersistable<Long> {
|
||||
} else {
|
||||
final List<LoanTransaction> allNonContraTransactionsPostDisbursement = retreiveListOfTransactionsPostDisbursement();
|
||||
changedTransactionDetail = loanRepaymentScheduleTransactionProcessor.handleTransaction(getDisbursementDate(),
|
||||
allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments, charges(), null);
|
||||
allNonContraTransactionsPostDisbursement, getCurrency(), this.repaymentScheduleInstallments, charges());
|
||||
for (final Map.Entry<Long, LoanTransaction> mapEntry : changedTransactionDetail.getNewTransactionMappings().entrySet()) {
|
||||
mapEntry.getValue().updateLoan(this);
|
||||
}
|
||||
|
||||
+11
-6
@@ -165,15 +165,17 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
final boolean allowTransactionsOnNonWorkingDay = this.configurationDomainService.allowTransactionsOnNonWorkingDayEnabled();
|
||||
|
||||
CalendarInstance restCalendarInstance = null;
|
||||
CalendarInstance compoundingCalendarInstance = null;
|
||||
ApplicationCurrency applicationCurrency = null;
|
||||
LocalDate calculatedRepaymentsStartingFromDate = null;
|
||||
boolean isHolidayEnabled = false;
|
||||
LocalDate recalculateFrom = null;
|
||||
Long overdurPenaltyWaitPeriod = null;
|
||||
LocalDate recalculateDueDateChargesFrom = null;
|
||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
|
||||
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
||||
CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
|
||||
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
||||
|
||||
final MonetaryCurrency currency = loan.getCurrency();
|
||||
applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
|
||||
@@ -188,8 +190,8 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays, allowTransactionsOnHoliday,
|
||||
allowTransactionsOnNonWorkingDay);
|
||||
final ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, recalculateFrom, overdurPenaltyWaitPeriod,
|
||||
recalculateDueDateChargesFrom);
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
||||
overdurPenaltyWaitPeriod);
|
||||
|
||||
final ChangedTransactionDetail changedTransactionDetail = loan.makeRepayment(newRepaymentTransaction,
|
||||
defaultLoanLifecycleStateMachine(), existingTransactionIds, existingReversedTransactionIds, isRecoveryRepayment,
|
||||
@@ -547,12 +549,15 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
|
||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays, allowTransactionsOnHoliday,
|
||||
allowTransactionsOnNonWorkingDay);
|
||||
CalendarInstance restCalendarInstance = null;
|
||||
CalendarInstance compoundingCalendarInstance = null;
|
||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
|
||||
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
||||
CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
|
||||
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
||||
}
|
||||
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance);
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance);
|
||||
|
||||
return scheduleGeneratorDTO;
|
||||
}
|
||||
|
||||
+60
-4
@@ -35,6 +35,7 @@ import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
@Table(name = "m_loan_recalculation_details")
|
||||
public class LoanInterestRecalculationDetails extends AbstractPersistable<Long> {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@OneToOne
|
||||
@JoinColumn(name = "loan_id", nullable = false)
|
||||
private Loan loan;
|
||||
@@ -61,24 +62,39 @@ public class LoanInterestRecalculationDetails extends AbstractPersistable<Long>
|
||||
@Column(name = "rest_freqency_date")
|
||||
private Date restFrequencyDate;
|
||||
|
||||
@Column(name = "compounding_frequency_type_enum", nullable = true)
|
||||
private Integer compoundingFrequencyType;
|
||||
|
||||
@Column(name = "compounding_frequency_interval", nullable = true)
|
||||
private Integer compoundingInterval;
|
||||
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Column(name = "compounding_freqency_date")
|
||||
private Date compoundingFrequencyDate;
|
||||
|
||||
protected LoanInterestRecalculationDetails() {
|
||||
// Default constructor for jpa repository
|
||||
}
|
||||
|
||||
private LoanInterestRecalculationDetails(final Integer interestRecalculationCompoundingMethod, final Integer rescheduleStrategyMethod,
|
||||
final Integer restFrequencyType, final Integer restInterval, final Date restFrequencyDate) {
|
||||
final Integer restFrequencyType, final Integer restInterval, final Date restFrequencyDate, Integer compoundingFrequencyType,
|
||||
Integer compoundingInterval, Date compoundingFrequencyDate) {
|
||||
this.interestRecalculationCompoundingMethod = interestRecalculationCompoundingMethod;
|
||||
this.rescheduleStrategyMethod = rescheduleStrategyMethod;
|
||||
this.restFrequencyDate = restFrequencyDate;
|
||||
this.restFrequencyType = restFrequencyType;
|
||||
this.restInterval = restInterval;
|
||||
this.compoundingFrequencyDate = compoundingFrequencyDate;
|
||||
this.compoundingFrequencyType = compoundingFrequencyType;
|
||||
this.compoundingInterval = compoundingInterval;
|
||||
}
|
||||
|
||||
public static LoanInterestRecalculationDetails createFrom(final Integer interestRecalculationCompoundingMethod,
|
||||
final Integer rescheduleStrategyMethod, final Integer restFrequencyType, final Integer restInterval,
|
||||
final Date restFrequencyDate) {
|
||||
final Date restFrequencyDate, final Integer compoundingFrequencyType, final Integer compoundingInterval,
|
||||
final Date compoundingFrequencyDate) {
|
||||
return new LoanInterestRecalculationDetails(interestRecalculationCompoundingMethod, rescheduleStrategyMethod, restFrequencyType,
|
||||
restInterval, restFrequencyDate);
|
||||
restInterval, restFrequencyDate, compoundingFrequencyType, compoundingInterval, compoundingFrequencyDate);
|
||||
}
|
||||
|
||||
public void updateLoan(final Loan loan) {
|
||||
@@ -96,7 +112,31 @@ public class LoanInterestRecalculationDetails extends AbstractPersistable<Long>
|
||||
actualChanges.put("locale", localeAsInput);
|
||||
|
||||
final LocalDate newValue = command.localDateValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyDateParamName);
|
||||
this.restFrequencyDate = newValue.toDate();
|
||||
if (newValue == null || getRestFrequencyType().isSameAsRepayment()) {
|
||||
this.restFrequencyDate = null;
|
||||
} else {
|
||||
this.restFrequencyDate = newValue.toDate();
|
||||
}
|
||||
}
|
||||
|
||||
if (command.isChangeInLocalDateParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyDateParamName,
|
||||
getCompoundingFrequencyLocalDate())) {
|
||||
final String dateFormatAsInput = command.dateFormat();
|
||||
final String localeAsInput = command.locale();
|
||||
final String valueAsInput = command
|
||||
.stringValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyDateParamName);
|
||||
actualChanges.put(LoanProductConstants.recalculationCompoundingFrequencyDateParamName, valueAsInput);
|
||||
actualChanges.put("dateFormat", dateFormatAsInput);
|
||||
actualChanges.put("locale", localeAsInput);
|
||||
|
||||
final LocalDate newValue = command
|
||||
.localDateValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyDateParamName);
|
||||
if (newValue == null || !getInterestRecalculationCompoundingMethod().isCompoundingEnabled()
|
||||
|| getCompoundingFrequencyType().isSameAsRepayment()) {
|
||||
this.compoundingFrequencyDate = null;
|
||||
} else {
|
||||
this.compoundingFrequencyDate = newValue.toDate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,4 +163,20 @@ public class LoanInterestRecalculationDetails extends AbstractPersistable<Long>
|
||||
public Integer getRestInterval() {
|
||||
return this.restInterval;
|
||||
}
|
||||
|
||||
public LocalDate getCompoundingFrequencyLocalDate() {
|
||||
LocalDate recurrenceOnLocalDate = null;
|
||||
if (this.compoundingFrequencyDate != null) {
|
||||
recurrenceOnLocalDate = new LocalDate(this.compoundingFrequencyDate);
|
||||
}
|
||||
return recurrenceOnLocalDate;
|
||||
}
|
||||
|
||||
public RecalculationFrequencyType getCompoundingFrequencyType() {
|
||||
return RecalculationFrequencyType.fromInt(this.compoundingFrequencyType);
|
||||
}
|
||||
|
||||
public Integer getCompoundingInterval() {
|
||||
return this.compoundingInterval;
|
||||
}
|
||||
}
|
||||
|
||||
+7
-14
@@ -20,8 +20,7 @@ import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
public class LoanRepaymentScheduleProcessingWrapper {
|
||||
|
||||
public void reprocess(final MonetaryCurrency currency, final LocalDate disbursementDate,
|
||||
final List<LoanRepaymentScheduleInstallment> repaymentPeriods, final Set<LoanCharge> loanCharges,
|
||||
final LocalDate lastTransactionDate) {
|
||||
final List<LoanRepaymentScheduleInstallment> repaymentPeriods, final Set<LoanCharge> loanCharges) {
|
||||
|
||||
Money totalInterest = Money.zero(currency);
|
||||
Money totalPrincipal = Money.zero(currency);
|
||||
@@ -33,16 +32,14 @@ public class LoanRepaymentScheduleProcessingWrapper {
|
||||
for (final LoanRepaymentScheduleInstallment period : repaymentPeriods) {
|
||||
|
||||
final Money feeChargesDueForRepaymentPeriod = cumulativeFeeChargesDueWithin(startDate, period.getDueDate(), loanCharges,
|
||||
currency, period, repaymentPeriods.size(), totalPrincipal, totalInterest, true,
|
||||
lastTransactionDate);
|
||||
currency, period, repaymentPeriods.size(), totalPrincipal, totalInterest, true);
|
||||
final Money feeChargesWaivedForRepaymentPeriod = cumulativeFeeChargesWaivedWithin(startDate, period.getDueDate(), loanCharges,
|
||||
currency, true);
|
||||
final Money feeChargesWrittenOffForRepaymentPeriod = cumulativeFeeChargesWrittenOffWithin(startDate, period.getDueDate(),
|
||||
loanCharges, currency, true);
|
||||
|
||||
final Money penaltyChargesDueForRepaymentPeriod = cumulativePenaltyChargesDueWithin(startDate, period.getDueDate(),
|
||||
loanCharges, currency, period, repaymentPeriods.size(), totalPrincipal, totalInterest,
|
||||
true, lastTransactionDate);
|
||||
loanCharges, currency, period, repaymentPeriods.size(), totalPrincipal, totalInterest, true);
|
||||
final Money penaltyChargesWaivedForRepaymentPeriod = cumulativePenaltyChargesWaivedWithin(startDate, period.getDueDate(),
|
||||
loanCharges, currency, true);
|
||||
final Money penaltyChargesWrittenOffForRepaymentPeriod = cumulativePenaltyChargesWrittenOffWithin(startDate,
|
||||
@@ -58,8 +55,7 @@ public class LoanRepaymentScheduleProcessingWrapper {
|
||||
|
||||
private Money cumulativeFeeChargesDueWithin(final LocalDate periodStart, final LocalDate periodEnd, final Set<LoanCharge> loanCharges,
|
||||
final MonetaryCurrency monetaryCurrency, LoanRepaymentScheduleInstallment period, int numberOfRepayments,
|
||||
final Money totalPrincipal, final Money totalInterest, boolean isInstallmentChargeApplicable,
|
||||
final LocalDate lastTransactionDate) {
|
||||
final Money totalPrincipal, final Money totalInterest, boolean isInstallmentChargeApplicable) {
|
||||
|
||||
Money cumulative = Money.zero(monetaryCurrency);
|
||||
|
||||
@@ -86,8 +82,7 @@ public class LoanRepaymentScheduleProcessingWrapper {
|
||||
&& loanCharge.getChargeCalculation().isPercentageBased()) {
|
||||
cumulative = cumulative.plus(loanCharge.chargeAmount());
|
||||
} else if (loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)
|
||||
&& loanCharge.getChargeCalculation().isPercentageBased()
|
||||
&& !lastTransactionDate.isAfter(loanCharge.getDueLocalDate())) {
|
||||
&& loanCharge.getChargeCalculation().isPercentageBased()) {
|
||||
BigDecimal amount = BigDecimal.ZERO;
|
||||
if (loanCharge.getChargeCalculation().isPercentageOfAmountAndInterest()) {
|
||||
amount = amount.add(totalPrincipal.getAmount()).add(totalInterest.getAmount());
|
||||
@@ -151,8 +146,7 @@ public class LoanRepaymentScheduleProcessingWrapper {
|
||||
|
||||
private Money cumulativePenaltyChargesDueWithin(final LocalDate periodStart, final LocalDate periodEnd,
|
||||
final Set<LoanCharge> loanCharges, final MonetaryCurrency currency, LoanRepaymentScheduleInstallment period,
|
||||
int numberOfRepayments, final Money totalPrincipal, final Money totalInterest, boolean isInstallmentChargeApplicable,
|
||||
final LocalDate lastTransactionDate) {
|
||||
int numberOfRepayments, final Money totalPrincipal, final Money totalInterest, boolean isInstallmentChargeApplicable) {
|
||||
|
||||
Money cumulative = Money.zero(currency);
|
||||
|
||||
@@ -179,8 +173,7 @@ public class LoanRepaymentScheduleProcessingWrapper {
|
||||
&& loanCharge.getChargeCalculation().isPercentageBased()) {
|
||||
cumulative = cumulative.plus(loanCharge.chargeAmount());
|
||||
} else if (loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)
|
||||
&& loanCharge.getChargeCalculation().isPercentageBased()
|
||||
&& !lastTransactionDate.isAfter(loanCharge.getDueLocalDate())) {
|
||||
&& loanCharge.getChargeCalculation().isPercentageBased()) {
|
||||
BigDecimal amount = BigDecimal.ZERO;
|
||||
if (loanCharge.getChargeCalculation().isPercentageOfAmountAndInterest()) {
|
||||
amount = amount.add(totalPrincipal.getAmount()).add(totalInterest.getAmount());
|
||||
|
||||
+14
-26
@@ -207,10 +207,8 @@ public final class LoanSummary {
|
||||
this.totalInterestWaived = summaryWrapper.calculateTotalInterestWaived(repaymentScheduleInstallments, currency).getAmount();
|
||||
this.totalInterestWrittenOff = summaryWrapper.calculateTotalInterestWrittenOff(repaymentScheduleInstallments, currency).getAmount();
|
||||
|
||||
if (totalInterestCharged.isGreaterThanZero()) {
|
||||
this.totalInterestOutstanding = totalInterestCharged.minus(this.totalInterestRepaid).minus(this.totalInterestWaived)
|
||||
.minus(this.totalInterestWrittenOff).getAmount();
|
||||
}
|
||||
this.totalInterestOutstanding = totalInterestCharged.minus(this.totalInterestRepaid).minus(this.totalInterestWaived)
|
||||
.minus(this.totalInterestWrittenOff).getAmount();
|
||||
|
||||
final Money totalFeeChargesCharged = summaryWrapper.calculateTotalFeeChargesCharged(repaymentScheduleInstallments, currency).plus(
|
||||
this.totalFeeChargesDueAtDisbursement);
|
||||
@@ -226,10 +224,8 @@ public final class LoanSummary {
|
||||
this.totalFeeChargesWrittenOff = summaryWrapper.calculateTotalFeeChargesWrittenOff(repaymentScheduleInstallments, currency)
|
||||
.getAmount();
|
||||
|
||||
if (totalFeeChargesCharged.isGreaterThanZero()) {
|
||||
this.totalFeeChargesOutstanding = totalFeeChargesCharged.minus(this.totalFeeChargesRepaid).minus(this.totalFeeChargesWaived)
|
||||
.minus(this.totalFeeChargesWrittenOff).getAmount();
|
||||
}
|
||||
this.totalFeeChargesOutstanding = totalFeeChargesCharged.minus(this.totalFeeChargesRepaid).minus(this.totalFeeChargesWaived)
|
||||
.minus(this.totalFeeChargesWrittenOff).getAmount();
|
||||
|
||||
final Money totalPenaltyChargesCharged = summaryWrapper
|
||||
.calculateTotalPenaltyChargesCharged(repaymentScheduleInstallments, currency);
|
||||
@@ -241,10 +237,8 @@ public final class LoanSummary {
|
||||
this.totalPenaltyChargesWrittenOff = summaryWrapper.calculateTotalPenaltyChargesWrittenOff(repaymentScheduleInstallments, currency)
|
||||
.getAmount();
|
||||
|
||||
if (totalPenaltyChargesCharged.isGreaterThanZero()) {
|
||||
this.totalPenaltyChargesOutstanding = totalPenaltyChargesCharged.minus(this.totalPenaltyChargesRepaid)
|
||||
.minus(this.totalPenaltyChargesWaived).minus(this.totalPenaltyChargesWrittenOff).getAmount();
|
||||
}
|
||||
this.totalPenaltyChargesOutstanding = totalPenaltyChargesCharged.minus(this.totalPenaltyChargesRepaid)
|
||||
.minus(this.totalPenaltyChargesWaived).minus(this.totalPenaltyChargesWrittenOff).getAmount();
|
||||
|
||||
final Money totalExpectedRepayment = Money.of(currency, this.totalPrincipalDisbursed).plus(this.totalInterestCharged)
|
||||
.plus(this.totalFeeChargesCharged).plus(this.totalPenaltyChargesCharged);
|
||||
@@ -286,48 +280,42 @@ public final class LoanSummary {
|
||||
public BigDecimal getTotalWrittenOff() {
|
||||
return this.totalWrittenOff;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return total interest repaid
|
||||
|
||||
/**
|
||||
* @return total interest repaid
|
||||
**/
|
||||
public BigDecimal getTotalInterestRepaid() {
|
||||
return this.totalInterestRepaid;
|
||||
return this.totalInterestRepaid;
|
||||
}
|
||||
|
||||
|
||||
public BigDecimal getTotalFeeChargesCharged() {
|
||||
return this.totalFeeChargesCharged;
|
||||
return this.totalFeeChargesCharged;
|
||||
}
|
||||
|
||||
|
||||
public BigDecimal getTotalPenaltyChargesCharged() {
|
||||
return this.totalPenaltyChargesCharged;
|
||||
return this.totalPenaltyChargesCharged;
|
||||
}
|
||||
|
||||
|
||||
public BigDecimal getTotalPrincipalWrittenOff() {
|
||||
return this.totalPrincipalWrittenOff;
|
||||
}
|
||||
|
||||
|
||||
public BigDecimal getTotalInterestWaived() {
|
||||
return this.totalInterestWaived;
|
||||
}
|
||||
|
||||
|
||||
public BigDecimal getTotalFeeChargesRepaid() {
|
||||
return this.totalFeeChargesRepaid;
|
||||
}
|
||||
|
||||
|
||||
public BigDecimal getTotalFeeChargesWaived() {
|
||||
return this.totalFeeChargesWaived;
|
||||
}
|
||||
|
||||
|
||||
public BigDecimal getTotalPenaltyChargesRepaid() {
|
||||
return this.totalPenaltyChargesRepaid;
|
||||
}
|
||||
|
||||
|
||||
public BigDecimal getTotalPenaltyChargesWaived() {
|
||||
return this.totalPenaltyChargesWaived;
|
||||
}
|
||||
|
||||
+9
-13
@@ -50,16 +50,14 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
@Override
|
||||
public ChangedTransactionDetail handleTransaction(final LocalDate disbursementDate,
|
||||
final List<LoanTransaction> transactionsPostDisbursement, final MonetaryCurrency currency,
|
||||
final List<LoanRepaymentScheduleInstallment> installments, final Set<LoanCharge> charges, final LocalDate recalculateChargesFrom) {
|
||||
final List<LoanRepaymentScheduleInstallment> installments, final Set<LoanCharge> charges) {
|
||||
final boolean reprocessCharges = true;
|
||||
return handleTransaction(disbursementDate, transactionsPostDisbursement, currency, installments, charges, recalculateChargesFrom,
|
||||
reprocessCharges);
|
||||
return handleTransaction(disbursementDate, transactionsPostDisbursement, currency, installments, charges, reprocessCharges);
|
||||
}
|
||||
|
||||
private ChangedTransactionDetail handleTransaction(final LocalDate disbursementDate,
|
||||
final List<LoanTransaction> transactionsPostDisbursement, final MonetaryCurrency currency,
|
||||
final List<LoanRepaymentScheduleInstallment> installments, final Set<LoanCharge> charges,
|
||||
final LocalDate recalculateChargesFrom, boolean reprocessCharges) {
|
||||
final List<LoanRepaymentScheduleInstallment> installments, final Set<LoanCharge> charges, boolean reprocessCharges) {
|
||||
|
||||
if (charges != null) {
|
||||
for (final LoanCharge loanCharge : charges) {
|
||||
@@ -78,7 +76,7 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
// loan charges)
|
||||
if (reprocessCharges) {
|
||||
final LoanRepaymentScheduleProcessingWrapper wrapper = new LoanRepaymentScheduleProcessingWrapper();
|
||||
wrapper.reprocess(currency, disbursementDate, installments, charges, recalculateChargesFrom);
|
||||
wrapper.reprocess(currency, disbursementDate, installments, charges);
|
||||
}
|
||||
|
||||
final ChangedTransactionDetail changedTransactionDetail = new ChangedTransactionDetail();
|
||||
@@ -473,11 +471,10 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
Money unProcessed = Money.zero(currency);
|
||||
for (final LoanTransaction loanTransaction : transactionsPostDisbursement) {
|
||||
Money amountToProcess = null;
|
||||
final LoanTransaction newLoanTransaction = LoanTransaction.copyTransactionProperties(loanTransaction);
|
||||
if (newLoanTransaction.isRepayment() || newLoanTransaction.isInterestWaiver() || newLoanTransaction.isRecoveryRepayment()) {
|
||||
newLoanTransaction.resetDerivedComponents();
|
||||
if (loanTransaction.isRepayment() || loanTransaction.isInterestWaiver() || loanTransaction.isRecoveryRepayment()) {
|
||||
loanTransaction.resetDerivedComponents();
|
||||
}
|
||||
unProcessed = processTransaction(newLoanTransaction, currency, installments, amountToProcess);
|
||||
unProcessed = processTransaction(loanTransaction, currency, installments, amountToProcess);
|
||||
}
|
||||
return unProcessed;
|
||||
}
|
||||
@@ -571,10 +568,9 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
@Override
|
||||
public ChangedTransactionDetail populateDerivedFeildsWithoutReprocess(final LocalDate disbursementDate,
|
||||
final List<LoanTransaction> transactionsPostDisbursement, final MonetaryCurrency currency,
|
||||
final List<LoanRepaymentScheduleInstallment> installments, final Set<LoanCharge> charges, final LocalDate recalculateChargesFrom) {
|
||||
final List<LoanRepaymentScheduleInstallment> installments, final Set<LoanCharge> charges) {
|
||||
final boolean reprocessCharges = false;
|
||||
return handleTransaction(disbursementDate, transactionsPostDisbursement, currency, installments, charges, recalculateChargesFrom,
|
||||
reprocessCharges);
|
||||
return handleTransaction(disbursementDate, transactionsPostDisbursement, currency, installments, charges, reprocessCharges);
|
||||
}
|
||||
|
||||
private LoanCharge findLatestPaidChargeFromUnOrderedSet(final Set<LoanCharge> charges, MonetaryCurrency currency) {
|
||||
|
||||
+2
-3
@@ -22,8 +22,7 @@ public interface LoanRepaymentScheduleTransactionProcessor {
|
||||
Set<LoanCharge> charges);
|
||||
|
||||
ChangedTransactionDetail handleTransaction(LocalDate disbursementDate, List<LoanTransaction> repaymentsOrWaivers,
|
||||
MonetaryCurrency currency, List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, Set<LoanCharge> charges,
|
||||
LocalDate recalculateChargesFrom);
|
||||
MonetaryCurrency currency, List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, Set<LoanCharge> charges);
|
||||
|
||||
void handleWriteOff(LoanTransaction loanTransaction, MonetaryCurrency loanCurrency,
|
||||
List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments);
|
||||
@@ -39,7 +38,7 @@ public interface LoanRepaymentScheduleTransactionProcessor {
|
||||
|
||||
ChangedTransactionDetail populateDerivedFeildsWithoutReprocess(LocalDate disbursementDate,
|
||||
List<LoanTransaction> transactionsPostDisbursement, MonetaryCurrency currency,
|
||||
List<LoanRepaymentScheduleInstallment> installments, Set<LoanCharge> charges, LocalDate recalculateChargesFrom);
|
||||
List<LoanRepaymentScheduleInstallment> installments, Set<LoanCharge> charges);
|
||||
|
||||
void handleRefund(LoanTransaction loanTransaction, MonetaryCurrency currency, List<LoanRepaymentScheduleInstallment> installments,
|
||||
final Set<LoanCharge> charges);
|
||||
|
||||
+347
-231
@@ -53,14 +53,14 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
final Set<LoanCharge> loanCharges, final HolidayDetailDTO holidayDetailDTO) {
|
||||
final Collection<RecalculationDetail> diffAmt = null;
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = null;
|
||||
final LocalDate lastTransactionDate = loanApplicationTerms.getExpectedDisbursementDate();
|
||||
return generate(mc, loanApplicationTerms, loanCharges, holidayDetailDTO, diffAmt, lastTransactionDate,
|
||||
loanRepaymentScheduleTransactionProcessor);
|
||||
final LocalDate scheduleTillDate = null;
|
||||
return generate(mc, loanApplicationTerms, loanCharges, holidayDetailDTO, diffAmt, loanRepaymentScheduleTransactionProcessor,
|
||||
scheduleTillDate);
|
||||
}
|
||||
|
||||
private LoanScheduleModel generate(final MathContext mc, final LoanApplicationTerms loanApplicationTerms,
|
||||
final Set<LoanCharge> loanCharges, final HolidayDetailDTO holidayDetailDTO, final Collection<RecalculationDetail> transactions,
|
||||
final LocalDate lastTransactionDate, final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor) {
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, final LocalDate scheduleTillDate) {
|
||||
|
||||
final ApplicationCurrency applicationCurrency = loanApplicationTerms.getApplicationCurrency();
|
||||
// 1. generate list of proposed schedule due dates
|
||||
@@ -138,13 +138,24 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
// from when these amounts will effect the outstanding balance for
|
||||
// interest calculation
|
||||
final Map<LocalDate, Money> principalPortionMap = new HashMap<>();
|
||||
// compounding(interest and fee) amounts will be added along with
|
||||
// compounding(principal) amounts will be added along with
|
||||
// date(after applying compounding frequency)
|
||||
// from when these amounts will effect the outstanding balance for
|
||||
// interest calculation
|
||||
final Map<LocalDate, Money> latePaymentMap = new HashMap<>();
|
||||
final List<LoanRepaymentScheduleInstallment> installments = new ArrayList<>();
|
||||
LocalDate currentDate = DateUtils.getLocalDateOfTenant();
|
||||
LocalDate lastRestDate = currentDate;
|
||||
if (loanApplicationTerms.getRestCalendarInstance() != null) {
|
||||
lastRestDate = getNextRestScheduleDate(currentDate.minusDays(1), loanApplicationTerms, holidayDetailDTO);
|
||||
}
|
||||
// compounding(interest/Fee) amounts will be added along with
|
||||
// date(after applying compounding frequency)
|
||||
// from when these amounts will effect the outstanding balance for
|
||||
// interest calculation
|
||||
final TreeMap<LocalDate, Money> compoundingMap = new TreeMap<>();
|
||||
final Map<LocalDate, TreeMap<LocalDate, Money>> compoundingDateVariations = new HashMap<>();
|
||||
boolean isNextRepaymentAvailable = true;
|
||||
while (!outstandingBalance.isZero() || !disburseDetailMap.isEmpty()) {
|
||||
|
||||
actualRepaymentDate = this.scheduledDateGenerator.generateNextRepaymentDate(actualRepaymentDate, loanApplicationTerms,
|
||||
@@ -153,11 +164,22 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
LocalDate scheduledDueDate = this.scheduledDateGenerator.adjustRepaymentDate(actualRepaymentDate, loanApplicationTerms,
|
||||
holidayDetailDTO);
|
||||
|
||||
if (!latePaymentMap.isEmpty()) {
|
||||
populateCompoundingDatesInPeriod(periodStartDate, scheduledDueDate, currentDate, loanApplicationTerms, holidayDetailDTO,
|
||||
compoundingMap, loanCharges, currency);
|
||||
compoundingDateVariations.put(periodStartDate, new TreeMap<>(compoundingMap));
|
||||
}
|
||||
|
||||
// calculated interest start date for the period
|
||||
periodStartDateApplicableForInterest = calculateInterestStartDateForPeriod(loanApplicationTerms, periodStartDate,
|
||||
idealDisbursementDate, periodStartDateApplicableForInterest);
|
||||
int daysInPeriodApplicableForInterest = Days.daysBetween(periodStartDateApplicableForInterest, scheduledDueDate).getDays();
|
||||
|
||||
if (scheduleTillDate != null && !scheduledDueDate.isBefore(scheduleTillDate)) {
|
||||
scheduledDueDate = scheduleTillDate;
|
||||
isNextRepaymentAvailable = false;
|
||||
}
|
||||
|
||||
// populates the collection with transactions till the due date of
|
||||
// the period for interest recalculation enabled loans
|
||||
Collection<RecalculationDetail> applicableTransactions = getApplicableTransactionsForPeriod(loanApplicationTerms,
|
||||
@@ -213,6 +235,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
if (detail.isProcessed()) {
|
||||
continue;
|
||||
}
|
||||
boolean updateLatePaymentMap = false;
|
||||
if (detail.getTransactionDate().isBefore(scheduledDueDate)) {
|
||||
if (loanRepaymentScheduleTransactionProcessor != null
|
||||
&& loanRepaymentScheduleTransactionProcessor.isInterestFirstRepaymentScheduleTransactionProcessor()) {
|
||||
@@ -230,18 +253,20 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
if (daysInPeriodApplicable > 0) {
|
||||
// 5 determine interest till the transaction
|
||||
// date
|
||||
if (!compoundingDateVariations.containsKey(periodStartDateApplicableForInterest)) {
|
||||
compoundingDateVariations.put(periodStartDateApplicableForInterest, new TreeMap<>(compoundingMap));
|
||||
}
|
||||
PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(
|
||||
this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction,
|
||||
totalCumulativePrincipal.minus(reducePrincipal), totalCumulativeInterest,
|
||||
totalInterestChargedForFullLoanTerm, totalOutstandingInterestPaymentDueToGrace,
|
||||
outstandingBalanceAsPerRest, loanApplicationTerms, periodNumber, mc,
|
||||
mergeLateAndPaymentMaps(principalPortionMap, latePaymentMap, disburseDetailMap),
|
||||
periodStartDateApplicableForInterest, detail.getTransactionDate(),
|
||||
mergeVariationsToMap(principalPortionMap, latePaymentMap, disburseDetailMap, compoundingMap),
|
||||
compoundingMap, periodStartDateApplicableForInterest, detail.getTransactionDate(),
|
||||
daysInPeriodApplicableForInterest);
|
||||
interestForThisinstallment = principalInterestForThisPeriod.interest();
|
||||
|
||||
totalOutstandingInterestPaymentDueToGrace = principalInterestForThisPeriod.interestPaymentDueToGrace();
|
||||
|
||||
}
|
||||
|
||||
Money principalForThisPeriod = principalDisbursed.zero();
|
||||
@@ -253,10 +278,10 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
interestForThisinstallment, null);
|
||||
Money feeChargesForInstallment = cumulativeFeeChargesDueWithin(periodStartDate,
|
||||
detail.getTransactionDate(), loanCharges, currency, principalInterest, principalDisbursed,
|
||||
totalCumulativeInterest, numberOfRepayments, true, lastTransactionDate);
|
||||
totalCumulativeInterest, numberOfRepayments, true);
|
||||
Money penaltyChargesForInstallment = cumulativePenaltyChargesDueWithin(periodStartDate,
|
||||
detail.getTransactionDate(), loanCharges, currency, principalInterest, principalDisbursed,
|
||||
totalCumulativeInterest, numberOfRepayments, true, lastTransactionDate);
|
||||
totalCumulativeInterest, numberOfRepayments, true);
|
||||
|
||||
// 8. sum up real totalInstallmentDue from
|
||||
// components
|
||||
@@ -285,6 +310,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
|
||||
periodStartDate = detail.getTransactionDate();
|
||||
periodStartDateApplicableForInterest = periodStartDate;
|
||||
updateLatePaymentMap = true;
|
||||
instalmentNumber++;
|
||||
// creates and insert Loan repayment schedule
|
||||
// for
|
||||
@@ -332,11 +358,12 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
// identify late payments and add compounding
|
||||
// details to
|
||||
// map for interest calculation
|
||||
if (!reducePrincipal.isZero() || !installment.periodDueDate().isBefore(currentDate)) {
|
||||
latePaymentMap.clear();
|
||||
} else {
|
||||
updateLatePaidAmountsToPrincipalMap(principalPortionMap, detail.getTransaction(), latePaymentMap,
|
||||
compoundingMap, loanApplicationTerms, currency, holidayDetailDTO, lastRestDate);
|
||||
compoundingDateVariations.put(periodStartDateApplicableForInterest, new TreeMap<>(compoundingMap));
|
||||
if (updateLatePaymentMap) {
|
||||
updateLatePaymentsToMap(loanApplicationTerms, holidayDetailDTO, currency, latePaymentMap, scheduledDueDate,
|
||||
installments, true);
|
||||
installments, true, lastRestDate, compoundingMap);
|
||||
}
|
||||
} else if (loanRepaymentScheduleTransactionProcessor != null) {
|
||||
LocalDate applicableDate = getNextRestScheduleDate(detail.getTransactionDate().minusDays(1),
|
||||
@@ -345,7 +372,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
List<LoanTransaction> currentTransactions = createCurrentTransactionList(detail);
|
||||
Money unprocessed = loanRepaymentScheduleTransactionProcessor.handleRepaymentSchedule(currentTransactions,
|
||||
currency, installments);
|
||||
Money arrears = detail.getTransaction().getAmount(currency);
|
||||
Money arrears = fetchCompoundedArrears(loanApplicationTerms, currency, detail.getTransaction());
|
||||
if (unprocessed.isGreaterThanZero()) {
|
||||
arrears = getTotalAmount(latePaymentMap, currency);
|
||||
updateMapWithAmount(principalPortionMap, unprocessed, applicableDate);
|
||||
@@ -359,13 +386,24 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
.calculateTillRestFrequencyEnabled()) {
|
||||
|
||||
LocalDate calculateTill = detail.getTransactionDate();
|
||||
if (!compoundingDateVariations.containsKey(periodStartDateApplicableForInterest)) {
|
||||
compoundingDateVariations.put(periodStartDateApplicableForInterest, new TreeMap<>(
|
||||
compoundingMap));
|
||||
}
|
||||
PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(
|
||||
this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction,
|
||||
totalCumulativePrincipal.minus(reducePrincipal), totalCumulativeInterest,
|
||||
totalInterestChargedForFullLoanTerm, totalOutstandingInterestPaymentDueToGrace,
|
||||
outstandingBalanceAsPerRest, loanApplicationTerms, periodNumber, mc,
|
||||
mergeLateAndPaymentMaps(principalPortionMap, latePaymentMap, disburseDetailMap),
|
||||
periodStartDateApplicableForInterest, calculateTill, daysInPeriodApplicableForInterest);
|
||||
this.paymentPeriodsInOneYearCalculator,
|
||||
interestCalculationGraceOnRepaymentPeriodFraction,
|
||||
totalCumulativePrincipal.minus(reducePrincipal),
|
||||
totalCumulativeInterest,
|
||||
totalInterestChargedForFullLoanTerm,
|
||||
totalOutstandingInterestPaymentDueToGrace,
|
||||
outstandingBalanceAsPerRest,
|
||||
loanApplicationTerms,
|
||||
periodNumber,
|
||||
mc,
|
||||
mergeVariationsToMap(principalPortionMap, latePaymentMap, disburseDetailMap, compoundingMap),
|
||||
compoundingMap, periodStartDateApplicableForInterest, calculateTill,
|
||||
daysInPeriodApplicableForInterest);
|
||||
if (!principalInterestForThisPeriod.interest()
|
||||
.plus(principalInterestForThisPeriod.interestPaymentDueToGrace()).plus(outstandingBalance)
|
||||
.isGreaterThan(unprocessed)) {
|
||||
@@ -398,9 +436,12 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
}
|
||||
|
||||
}
|
||||
if (arrears.isGreaterThanZero() && applicableDate.isBefore(currentDate)) {
|
||||
updateMapWithAmount(latePaymentMap, arrears.negated(), applicableDate);
|
||||
updateMapWithAmount(latePaymentMap, arrears, currentDate);
|
||||
LocalDate tillDate = getNextRestScheduleDate(currentDate.minusDays(1), loanApplicationTerms,
|
||||
holidayDetailDTO);
|
||||
if (arrears.isGreaterThanZero() && applicableDate.isBefore(tillDate)) {
|
||||
updateLatePaidAmountsToPrincipalMap(principalPortionMap, detail.getTransaction(), latePaymentMap,
|
||||
compoundingMap, loanApplicationTerms, currency, holidayDetailDTO, lastRestDate);
|
||||
compoundingDateVariations.put(periodStartDateApplicableForInterest, new TreeMap<>(compoundingMap));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,13 +459,20 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
periodStartDateApplicableForInterest = calculateInterestStartDateForPeriod(loanApplicationTerms, periodStartDate,
|
||||
idealDisbursementDate, periodStartDateApplicableForInterest);
|
||||
|
||||
// backup for pre-close transaction
|
||||
if (compoundingDateVariations.containsKey(periodStartDateApplicableForInterest)) {
|
||||
compoundingMap.clear();
|
||||
compoundingMap.putAll(compoundingDateVariations.get(periodStartDateApplicableForInterest));
|
||||
} else {
|
||||
compoundingDateVariations.put(periodStartDateApplicableForInterest, new TreeMap<>(compoundingMap));
|
||||
}
|
||||
// 5 determine principal,interest of repayment period
|
||||
PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(
|
||||
this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction,
|
||||
totalCumulativePrincipal.minus(reducePrincipal), totalCumulativeInterest, totalInterestChargedForFullLoanTerm,
|
||||
totalOutstandingInterestPaymentDueToGrace, outstandingBalanceAsPerRest, loanApplicationTerms, periodNumber, mc,
|
||||
mergeLateAndPaymentMaps(principalPortionMap, latePaymentMap, disburseDetailMap), periodStartDateApplicableForInterest,
|
||||
scheduledDueDate, daysInPeriodApplicableForInterest);
|
||||
mergeVariationsToMap(principalPortionMap, latePaymentMap, disburseDetailMap, compoundingMap), compoundingMap,
|
||||
periodStartDateApplicableForInterest, scheduledDueDate, daysInPeriodApplicableForInterest);
|
||||
|
||||
if (loanApplicationTerms.getFixedEmiAmount() != null
|
||||
&& loanApplicationTerms.getFixedEmiAmount().compareTo(principalInterestForThisPeriod.interest().getAmount()) != 1) {
|
||||
@@ -466,7 +514,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
// 'principalDue'
|
||||
outstandingBalance = outstandingBalance.minus(principalForThisPeriod.minus(reducedBalance));
|
||||
|
||||
if (outstandingBalance.isLessThanZero()) {
|
||||
if (outstandingBalance.isLessThanZero() || !isNextRepaymentAvailable) {
|
||||
principalForThisPeriod = principalForThisPeriod.plus(outstandingBalance);
|
||||
outstandingBalance = outstandingBalance.zero();
|
||||
}
|
||||
@@ -474,9 +522,9 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
// applies charges for the period
|
||||
PrincipalInterest principalInterest = new PrincipalInterest(principalForThisPeriod, interestForThisinstallment, null);
|
||||
Money feeChargesForInstallment = cumulativeFeeChargesDueWithin(periodStartDate, scheduledDueDate, loanCharges, currency,
|
||||
principalInterest, principalDisbursed, totalCumulativeInterest, numberOfRepayments, true, lastTransactionDate);
|
||||
principalInterest, principalDisbursed, totalCumulativeInterest, numberOfRepayments, true);
|
||||
Money penaltyChargesForInstallment = cumulativePenaltyChargesDueWithin(periodStartDate, scheduledDueDate, loanCharges,
|
||||
currency, principalInterest, principalDisbursed, totalCumulativeInterest, numberOfRepayments, true, lastTransactionDate);
|
||||
currency, principalInterest, principalDisbursed, totalCumulativeInterest, numberOfRepayments, true);
|
||||
totalFeeChargesCharged = totalFeeChargesCharged.add(feeChargesForInstallment.getAmount());
|
||||
totalPenaltyChargesCharged = totalPenaltyChargesCharged.add(penaltyChargesForInstallment.getAmount());
|
||||
|
||||
@@ -499,6 +547,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
// apply loan transactions on installments to identify early/late
|
||||
// payments for interest recalculation
|
||||
if (isInterestRecalculationRequired(loanApplicationTerms, transactions) && loanRepaymentScheduleTransactionProcessor != null) {
|
||||
Money principalProcessed = Money.zero(currency);
|
||||
addLoanRepaymentScheduleInstallment(installments, installment);
|
||||
for (RecalculationDetail detail : applicableTransactions) {
|
||||
if (!detail.isProcessed()) {
|
||||
@@ -520,12 +569,18 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
calculateTill = getNextRestScheduleDate(calculateTill.minusDays(1), loanApplicationTerms,
|
||||
holidayDetailDTO);
|
||||
}
|
||||
if (compoundingDateVariations.containsKey(periodStartDateApplicableForInterest)) {
|
||||
compoundingMap.clear();
|
||||
compoundingMap.putAll(compoundingDateVariations.get(periodStartDateApplicableForInterest));
|
||||
}
|
||||
PrincipalInterest interestTillDate = calculatePrincipalInterestComponentsForPeriod(
|
||||
this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction,
|
||||
totalCumulativePrincipal, totalCumulativeInterest, totalInterestChargedForFullLoanTerm,
|
||||
totalOutstandingInterestPaymentDueToGrace, outstandingBalanceAsPerRest, loanApplicationTerms,
|
||||
periodNumber, mc, mergeLateAndPaymentMaps(principalPortionMap, latePaymentMap, disburseDetailMap),
|
||||
periodStartDateApplicableForInterest, calculateTill, daysInPeriodApplicableForInterest);
|
||||
periodNumber, mc,
|
||||
mergeVariationsToMap(principalPortionMap, latePaymentMap, disburseDetailMap, compoundingMap),
|
||||
compoundingMap, periodStartDateApplicableForInterest, calculateTill,
|
||||
daysInPeriodApplicableForInterest);
|
||||
Money diff = interestForThisinstallment.minus(interestTillDate.interest());
|
||||
if (!outstandingBalance.minus(diff).isGreaterThanZero()) {
|
||||
outstandingBalance = outstandingBalance.minus(diff);
|
||||
@@ -557,19 +612,14 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
|
||||
reducePrincipal = reducePrincipal.plus(unprocessed);
|
||||
reducePrincipal = applyEarlyPaymentStrategy(loanApplicationTerms, reducePrincipal);
|
||||
|
||||
principalForThisPeriod = principalForThisPeriod.plus(unprocessed.plus(addToPrinciapal));
|
||||
principalProcessed = principalProcessed.plus(unprocessed.plus(addToPrinciapal));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// identify late payments and adds compounding details to map
|
||||
if (!reducePrincipal.isZero() || !installment.periodDueDate().isBefore(currentDate)) {
|
||||
latePaymentMap.clear();
|
||||
} else {
|
||||
updateLatePaymentsToMap(loanApplicationTerms, holidayDetailDTO, currency, latePaymentMap, scheduledDueDate,
|
||||
installments, true);
|
||||
}
|
||||
updateLatePaymentsToMap(loanApplicationTerms, holidayDetailDTO, currency, latePaymentMap, scheduledDueDate, installments,
|
||||
true, lastRestDate, compoundingMap);
|
||||
principalForThisPeriod = principalForThisPeriod.minus(principalProcessed);
|
||||
}
|
||||
|
||||
periods.add(installment);
|
||||
@@ -598,6 +648,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
periodStartDateApplicableForInterest = periodStartDate;
|
||||
instalmentNumber++;
|
||||
periodNumber++;
|
||||
compoundingDateVariations.clear();
|
||||
}
|
||||
|
||||
// 7. determine fees and penalties for charges which depends on total
|
||||
@@ -608,12 +659,10 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
Money.of(currency, loanScheduleModelPeriod.interestDue()), null);
|
||||
Money feeChargesForInstallment = cumulativeFeeChargesDueWithin(loanScheduleModelPeriod.periodFromDate(),
|
||||
loanScheduleModelPeriod.periodDueDate(), nonCompoundingCharges, currency, principalInterest, principalDisbursed,
|
||||
totalCumulativeInterest, numberOfRepayments, !loanScheduleModelPeriod.isRecalculatedInterestComponent(),
|
||||
lastTransactionDate);
|
||||
totalCumulativeInterest, numberOfRepayments, !loanScheduleModelPeriod.isRecalculatedInterestComponent());
|
||||
Money penaltyChargesForInstallment = cumulativePenaltyChargesDueWithin(loanScheduleModelPeriod.periodFromDate(),
|
||||
loanScheduleModelPeriod.periodDueDate(), nonCompoundingCharges, currency, principalInterest, principalDisbursed,
|
||||
totalCumulativeInterest, numberOfRepayments, !loanScheduleModelPeriod.isRecalculatedInterestComponent(),
|
||||
lastTransactionDate);
|
||||
totalCumulativeInterest, numberOfRepayments, !loanScheduleModelPeriod.isRecalculatedInterestComponent());
|
||||
totalFeeChargesCharged = totalFeeChargesCharged.add(feeChargesForInstallment.getAmount());
|
||||
totalPenaltyChargesCharged = totalPenaltyChargesCharged.add(penaltyChargesForInstallment.getAmount());
|
||||
totalRepaymentExpected = totalRepaymentExpected.add(feeChargesForInstallment.getAmount()).add(
|
||||
@@ -625,11 +674,14 @@ 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
|
||||
|
||||
if (scheduleTillDate != null) {
|
||||
currentDate = scheduleTillDate;
|
||||
}
|
||||
if (isInterestRecalculationRequired(loanApplicationTerms, transactions) && latePaymentMap.size() > 0
|
||||
&& currentDate.isAfter(periodStartDate)) {
|
||||
Money totalInterest = addInterestOnlyRepaymentScheduleForCurrentdate(mc, loanApplicationTerms, holidayDetailDTO, currency,
|
||||
periods, periodStartDate, actualRepaymentDate, instalmentNumber, latePaymentMap, currentDate,
|
||||
loanRepaymentScheduleTransactionProcessor, transactions, installments);
|
||||
loanRepaymentScheduleTransactionProcessor, principalPortionMap, compoundingMap, transactions, installments, loanCharges);
|
||||
totalCumulativeInterest = totalCumulativeInterest.plus(totalInterest);
|
||||
}
|
||||
|
||||
@@ -640,6 +692,19 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
totalPenaltyChargesCharged, totalRepaymentExpected, totalOutstanding);
|
||||
}
|
||||
|
||||
private Money fetchCompoundedArrears(final LoanApplicationTerms loanApplicationTerms, final MonetaryCurrency currency,
|
||||
final LoanTransaction transaction) {
|
||||
Money arrears = transaction.getPrincipalPortion(currency);
|
||||
if (loanApplicationTerms.getInterestRecalculationCompoundingMethod().isInterestCompoundingEnabled()) {
|
||||
arrears = arrears.plus(transaction.getInterestPortion(currency));
|
||||
}
|
||||
|
||||
if (loanApplicationTerms.getInterestRecalculationCompoundingMethod().isFeeCompoundingEnabled()) {
|
||||
arrears = arrears.plus(transaction.getFeeChargesPortion(currency)).plus(transaction.getPenaltyChargesPortion(currency));
|
||||
}
|
||||
return arrears;
|
||||
}
|
||||
|
||||
private boolean isInterestRecalculationRequired(final LoanApplicationTerms loanApplicationTerms,
|
||||
Collection<RecalculationDetail> transactions) {
|
||||
return loanApplicationTerms.isInterestRecalculationEnabled() && transactions != null;
|
||||
@@ -650,21 +715,30 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
* (if compounding is enabled) till current date and adds new repayment
|
||||
* schedule detail
|
||||
*
|
||||
* @param compoundingMap
|
||||
* TODO
|
||||
* @param loanCharges
|
||||
* TODO
|
||||
* @param principalPortioMap
|
||||
* TODO
|
||||
*
|
||||
*/
|
||||
private Money addInterestOnlyRepaymentScheduleForCurrentdate(final MathContext mc, final LoanApplicationTerms loanApplicationTerms,
|
||||
final HolidayDetailDTO holidayDetailDTO, final MonetaryCurrency currency, final Collection<LoanScheduleModelPeriod> periods,
|
||||
LocalDate periodStartDate, LocalDate actualRepaymentDate, int instalmentNumber, Map<LocalDate, Money> latePaymentMap,
|
||||
LocalDate currentDate, LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor,
|
||||
final Collection<RecalculationDetail> transactions, List<LoanRepaymentScheduleInstallment> installments) {
|
||||
final LocalDate currentDate, LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor,
|
||||
final Map<LocalDate, Money> principalPortionMap, TreeMap<LocalDate, Money> compoundingMap,
|
||||
final Collection<RecalculationDetail> transactions, final List<LoanRepaymentScheduleInstallment> installments,
|
||||
Set<LoanCharge> loanCharges) {
|
||||
boolean isFirstRepayment = false;
|
||||
LocalDate startDate = periodStartDate;
|
||||
updateLatePaymentsToMap(loanApplicationTerms, holidayDetailDTO, currency, latePaymentMap, currentDate, installments, false);
|
||||
Money outstanding = Money.zero(currency);
|
||||
Money totalInterest = Money.zero(currency);
|
||||
Money totalCumulativeInterest = Money.zero(currency);
|
||||
Map<LocalDate, Money> retainEntries = new HashMap<>();
|
||||
Map<LocalDate, Money> disburseDetailsMap = new HashMap<>();
|
||||
double interestCalculationGraceOnRepaymentPeriodFraction = Double.valueOf(0);
|
||||
int periodNumberTemp = 1;
|
||||
LocalDate lastRestDate = getNextRestScheduleDate(currentDate.minusDays(1), loanApplicationTerms, holidayDetailDTO);
|
||||
do {
|
||||
|
||||
actualRepaymentDate = this.scheduledDateGenerator.generateNextRepaymentDate(actualRepaymentDate, loanApplicationTerms,
|
||||
@@ -673,11 +747,16 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
if (actualRepaymentDate.isAfter(currentDate)) {
|
||||
actualRepaymentDate = currentDate;
|
||||
}
|
||||
outstanding = updateOutstandingFromLatePayment(periodStartDate, latePaymentMap, outstanding, retainEntries);
|
||||
outstanding = updateOutstandingFromLatePayment(periodStartDate, latePaymentMap, outstanding);
|
||||
|
||||
Collection<RecalculationDetail> applicableTransactions = getApplicableTransactionsForPeriod(loanApplicationTerms,
|
||||
actualRepaymentDate, transactions);
|
||||
|
||||
if (!latePaymentMap.isEmpty()) {
|
||||
populateCompoundingDatesInPeriod(periodStartDate, actualRepaymentDate, currentDate, loanApplicationTerms, holidayDetailDTO,
|
||||
compoundingMap, loanCharges, currency);
|
||||
}
|
||||
|
||||
for (RecalculationDetail detail : applicableTransactions) {
|
||||
if (detail.isProcessed()) {
|
||||
continue;
|
||||
@@ -688,8 +767,9 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(
|
||||
this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction,
|
||||
totalInterest.zero(), totalInterest.zero(), totalInterest.zero(), totalInterest.zero(), outstanding,
|
||||
loanApplicationTerms, periodNumberTemp, mc, latePaymentMap, periodStartDate, detail.getTransactionDate(),
|
||||
daysInPeriod);
|
||||
loanApplicationTerms, periodNumberTemp, mc,
|
||||
mergeVariationsToMap(principalPortionMap, latePaymentMap, disburseDetailsMap, compoundingMap), compoundingMap,
|
||||
periodStartDate, detail.getTransactionDate(), daysInPeriod);
|
||||
|
||||
Money interest = principalInterestForThisPeriod.interest();
|
||||
totalInterest = totalInterest.plus(interest);
|
||||
@@ -705,9 +785,11 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
startDate = detail.getTransactionDate();
|
||||
}
|
||||
loanRepaymentScheduleTransactionProcessor.handleRepaymentSchedule(currentTransactions, currency, installments);
|
||||
updateLatePaymentsToMap(loanApplicationTerms, holidayDetailDTO, currency, latePaymentMap, currentDate, installments, false);
|
||||
updateLatePaymentsToMap(loanApplicationTerms, holidayDetailDTO, currency, latePaymentMap, currentDate, installments, false,
|
||||
lastRestDate, compoundingMap);
|
||||
outstanding = outstanding.zero();
|
||||
outstanding = updateOutstandingFromLatePayment(periodStartDate, latePaymentMap, outstanding, retainEntries);
|
||||
outstanding = updateOutstandingFromLatePayment(periodStartDate, latePaymentMap, outstanding);
|
||||
outstanding = updateBalanceForInterestCalculation(principalPortionMap, periodStartDate, outstanding, false);
|
||||
if (latePaymentMap.isEmpty() && !outstanding.isGreaterThanZero()) {
|
||||
break;
|
||||
}
|
||||
@@ -717,7 +799,9 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
PrincipalInterest principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(
|
||||
this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction, totalInterest.zero(),
|
||||
totalInterest.zero(), totalInterest.zero(), totalInterest.zero(), outstanding, loanApplicationTerms,
|
||||
periodNumberTemp, mc, latePaymentMap, periodStartDate, actualRepaymentDate, daysInPeriod);
|
||||
periodNumberTemp, mc,
|
||||
mergeVariationsToMap(principalPortionMap, latePaymentMap, disburseDetailsMap, compoundingMap), compoundingMap,
|
||||
periodStartDate, actualRepaymentDate, daysInPeriod);
|
||||
Money interest = principalInterestForThisPeriod.interest();
|
||||
totalInterest = totalInterest.plus(interest);
|
||||
if (loanApplicationTerms.getInterestRecalculationCompoundingMethod().isInterestCompoundingEnabled()) {
|
||||
@@ -761,8 +845,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
return currentTransactions;
|
||||
}
|
||||
|
||||
private Money updateOutstandingFromLatePayment(LocalDate periodStartDate, Map<LocalDate, Money> latePaymentMap, Money outstanding,
|
||||
Map<LocalDate, Money> retainEntries) {
|
||||
private Money updateOutstandingFromLatePayment(LocalDate periodStartDate, Map<LocalDate, Money> latePaymentMap, Money outstanding) {
|
||||
Map<LocalDate, Money> retainEntries = new HashMap<>();
|
||||
for (Map.Entry<LocalDate, Money> mapEntry : latePaymentMap.entrySet()) {
|
||||
if (!mapEntry.getKey().isAfter(periodStartDate)) {
|
||||
outstanding = outstanding.plus(mapEntry.getValue());
|
||||
@@ -832,17 +916,83 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
return outstandingBalance;
|
||||
}
|
||||
|
||||
// this is to make sure even paid late payments(principal and compounded
|
||||
// interest/fee) should be reduced as per rest date
|
||||
private void updateLatePaidAmountsToPrincipalMap(final Map<LocalDate, Money> principalVariationMap,
|
||||
final LoanTransaction loanTransaction, final Map<LocalDate, Money> latePaymentsMap, final Map<LocalDate, Money> compoundingMap,
|
||||
final LoanApplicationTerms applicationTerms, final MonetaryCurrency currency, final HolidayDetailDTO holidayDetailDTO,
|
||||
final LocalDate lastRestDate) {
|
||||
LocalDate applicableDate = getNextRestScheduleDate(loanTransaction.getTransactionDate().minusDays(1), applicationTerms,
|
||||
holidayDetailDTO);
|
||||
|
||||
Money principalPortion = loanTransaction.getPrincipalPortion(currency);
|
||||
Money compoundedLatePayments = Money.zero(currency);
|
||||
if (applicationTerms.getInterestRecalculationCompoundingMethod().isInterestCompoundingEnabled()) {
|
||||
compoundedLatePayments = compoundedLatePayments.plus(loanTransaction.getInterestPortion(currency));
|
||||
}
|
||||
if (applicationTerms.getInterestRecalculationCompoundingMethod().isFeeCompoundingEnabled()) {
|
||||
compoundedLatePayments = compoundedLatePayments.plus(loanTransaction.getFeeChargesPortion(currency)).plus(
|
||||
loanTransaction.getPenaltyChargesPortion(currency));
|
||||
}
|
||||
|
||||
updateCompoundingAmount(principalVariationMap, latePaymentsMap, currency, lastRestDate, principalPortion, applicableDate);
|
||||
updateCompoundingAmount(principalVariationMap, compoundingMap, currency, lastRestDate, compoundedLatePayments, applicableDate);
|
||||
}
|
||||
|
||||
private void updateCompoundingAmount(final Map<LocalDate, Money> principalVariationMap,
|
||||
final Map<LocalDate, Money> latePaymentCompoundingMap, final MonetaryCurrency currency, final LocalDate lastRestDate,
|
||||
Money compoundedPortion, final LocalDate applicableDate) {
|
||||
Money appliedOnPrincipalVariationMap = Money.zero(currency);
|
||||
Map<LocalDate, Money> temp = new HashMap<>();
|
||||
for (LocalDate date : latePaymentCompoundingMap.keySet()) {
|
||||
if (date.isBefore(lastRestDate)) {
|
||||
Money money = latePaymentCompoundingMap.get(date);
|
||||
appliedOnPrincipalVariationMap = appliedOnPrincipalVariationMap.plus(money);
|
||||
if (appliedOnPrincipalVariationMap.isLessThan(compoundedPortion)) {
|
||||
if (date.isBefore(applicableDate)) {
|
||||
updateMapWithAmount(principalVariationMap, money.negated(), date);
|
||||
updateMapWithAmount(principalVariationMap, money, applicableDate);
|
||||
}
|
||||
} else if (temp.isEmpty()) {
|
||||
Money diff = money.minus(appliedOnPrincipalVariationMap.minus(compoundedPortion));
|
||||
updateMapWithAmount(principalVariationMap, diff.negated(), date);
|
||||
updateMapWithAmount(principalVariationMap, diff, applicableDate);
|
||||
updateMapWithAmount(temp, money.minus(diff), date);
|
||||
updateMapWithAmount(temp, money.minus(diff).negated(), lastRestDate);
|
||||
} else {
|
||||
updateMapWithAmount(temp, money, date);
|
||||
updateMapWithAmount(temp, money.negated(), lastRestDate);
|
||||
}
|
||||
}
|
||||
}
|
||||
latePaymentCompoundingMap.clear();
|
||||
latePaymentCompoundingMap.putAll(temp);
|
||||
}
|
||||
|
||||
/**
|
||||
* this Method updates late/ not paid installment components to Map with
|
||||
* effective date as per REST(for principal portion ) and compounding
|
||||
* (interest or fee or interest and fee portions) frequency
|
||||
*
|
||||
* @param lastRestDate
|
||||
* TODO
|
||||
* @param compoundingMap
|
||||
* TODO
|
||||
*
|
||||
*/
|
||||
private void updateLatePaymentsToMap(final LoanApplicationTerms loanApplicationTerms, final HolidayDetailDTO holidayDetailDTO,
|
||||
final MonetaryCurrency currency, final Map<LocalDate, Money> latePaymentMap, final LocalDate scheduledDueDate,
|
||||
List<LoanRepaymentScheduleInstallment> installments, boolean applyRestFrequencyForPrincipal) {
|
||||
List<LoanRepaymentScheduleInstallment> installments, boolean applyRestFrequencyForPrincipal, final LocalDate lastRestDate,
|
||||
final TreeMap<LocalDate, Money> compoundingMap) {
|
||||
latePaymentMap.clear();
|
||||
LocalDate currentDate = DateUtils.getLocalDateOfTenant();
|
||||
|
||||
Money totalCompoundingAmount = Money.zero(currency);
|
||||
Money compoundedMoney = Money.zero(currency);
|
||||
if (!compoundingMap.isEmpty()) {
|
||||
compoundedMoney = compoundingMap.get(lastRestDate);
|
||||
}
|
||||
boolean clearCompoundingMap = true;
|
||||
for (LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : installments) {
|
||||
if (loanRepaymentScheduleInstallment.isNotFullyPaidOff()
|
||||
&& !loanRepaymentScheduleInstallment.getDueDate().isAfter(scheduledDueDate)
|
||||
@@ -852,28 +1002,38 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
principalEffectiveDate = getNextRestScheduleDate(loanRepaymentScheduleInstallment.getDueDate().minusDays(1),
|
||||
loanApplicationTerms, holidayDetailDTO);
|
||||
}
|
||||
if (principalEffectiveDate.isBefore(DateUtils.getLocalDateOfTenant())) {
|
||||
if (principalEffectiveDate.isBefore(currentDate)) {
|
||||
updateMapWithAmount(latePaymentMap, loanRepaymentScheduleInstallment.getPrincipalOutstanding(currency),
|
||||
principalEffectiveDate);
|
||||
totalCompoundingAmount = totalCompoundingAmount
|
||||
.plus(loanRepaymentScheduleInstallment.getPrincipalOutstanding(currency));
|
||||
}
|
||||
totalCompoundingAmount = updateMapWithCompoundingDetails(loanApplicationTerms, holidayDetailDTO, currency, latePaymentMap,
|
||||
totalCompoundingAmount, loanRepaymentScheduleInstallment);
|
||||
|
||||
final Money changedCompoundedMoney = updateMapWithCompoundingDetails(loanApplicationTerms, holidayDetailDTO, currency,
|
||||
compoundingMap, loanRepaymentScheduleInstallment, lastRestDate, compoundedMoney, scheduledDueDate);
|
||||
if (compoundedMoney.isZero() || !compoundedMoney.isEqualTo(changedCompoundedMoney)) {
|
||||
compoundedMoney = changedCompoundedMoney;
|
||||
clearCompoundingMap = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (totalCompoundingAmount.isGreaterThanZero()) {
|
||||
updateMapWithAmount(latePaymentMap, totalCompoundingAmount.negated(), DateUtils.getLocalDateOfTenant());
|
||||
updateMapWithAmount(latePaymentMap, totalCompoundingAmount.negated(), lastRestDate);
|
||||
}
|
||||
if (clearCompoundingMap) {
|
||||
compoundingMap.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private Money updateMapWithCompoundingDetails(final LoanApplicationTerms loanApplicationTerms, final HolidayDetailDTO holidayDetailDTO,
|
||||
final MonetaryCurrency currency, final Map<LocalDate, Money> latePaymentMap, Money totalCompoundingAmount,
|
||||
LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment) {
|
||||
final MonetaryCurrency currency, final TreeMap<LocalDate, Money> compoundingMap,
|
||||
final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment, final LocalDate lastRestDate,
|
||||
final Money compoundedMoney, final LocalDate scheduledDueDate) {
|
||||
Money ignoreMoney = compoundedMoney;
|
||||
if (loanApplicationTerms.getInterestRecalculationCompoundingMethod().isCompoundingEnabled()) {
|
||||
LocalDate compoundingEffectiveDate = getNextCompoundScheduleDate(loanRepaymentScheduleInstallment.getDueDate().minusDays(1),
|
||||
loanApplicationTerms, holidayDetailDTO);
|
||||
|
||||
if (compoundingEffectiveDate.isBefore(DateUtils.getLocalDateOfTenant())) {
|
||||
Money amount = Money.zero(currency);
|
||||
switch (loanApplicationTerms.getInterestRecalculationCompoundingMethod()) {
|
||||
@@ -892,11 +1052,61 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
default:
|
||||
break;
|
||||
}
|
||||
updateMapWithAmount(latePaymentMap, amount, compoundingEffectiveDate);
|
||||
totalCompoundingAmount = totalCompoundingAmount.plus(amount);
|
||||
if (compoundingEffectiveDate.isBefore(scheduledDueDate)) {
|
||||
ignoreMoney = ignoreMoney.plus(amount);
|
||||
if (ignoreMoney.isGreaterThanZero()) {
|
||||
updateMapWithAmount(compoundingMap, ignoreMoney, compoundingEffectiveDate);
|
||||
updateMapWithAmount(compoundingMap, ignoreMoney.negated(), lastRestDate);
|
||||
ignoreMoney = ignoreMoney.zero();
|
||||
}
|
||||
} else {
|
||||
if (ignoreMoney.isLessThanZero()) {
|
||||
LocalDate firstKey = compoundingMap.firstKey();
|
||||
updateMapWithAmount(compoundingMap, ignoreMoney, firstKey);
|
||||
updateMapWithAmount(compoundingMap, ignoreMoney.negated(), lastRestDate);
|
||||
ignoreMoney = ignoreMoney.zero();
|
||||
}
|
||||
updateMapWithAmount(compoundingMap, amount, compoundingEffectiveDate);
|
||||
updateMapWithAmount(compoundingMap, amount.negated(), lastRestDate);
|
||||
}
|
||||
}
|
||||
}
|
||||
return totalCompoundingAmount;
|
||||
return ignoreMoney;
|
||||
}
|
||||
|
||||
private void populateCompoundingDatesInPeriod(final LocalDate startDate, final LocalDate endDate, final LocalDate currentDate,
|
||||
final LoanApplicationTerms loanApplicationTerms, final HolidayDetailDTO holidayDetailDTO,
|
||||
final Map<LocalDate, Money> compoundingMap, final Set<LoanCharge> charges, MonetaryCurrency currency) {
|
||||
if (loanApplicationTerms.getInterestRecalculationCompoundingMethod().isCompoundingEnabled()) {
|
||||
LocalDate lastCompoundingDate = startDate;
|
||||
LocalDate compoundingDate = startDate;
|
||||
while (compoundingDate.isBefore(endDate) && compoundingDate.isBefore(currentDate)) {
|
||||
compoundingDate = getNextCompoundScheduleDate(compoundingDate, loanApplicationTerms, holidayDetailDTO);
|
||||
if (!compoundingDate.isBefore(currentDate)) {
|
||||
break;
|
||||
} else if (compoundingDate.isAfter(endDate)) {
|
||||
updateMapWithAmount(compoundingMap, Money.zero(currency), compoundingDate);
|
||||
} else {
|
||||
Money feeChargesForInstallment = cumulativeFeeChargesDueWithin(lastCompoundingDate, compoundingDate, charges, currency,
|
||||
null, loanApplicationTerms.getPrincipal(), null, loanApplicationTerms.getNumberOfRepayments(), false);
|
||||
Money penaltyChargesForInstallment = cumulativePenaltyChargesDueWithin(lastCompoundingDate, compoundingDate, charges,
|
||||
currency, null, loanApplicationTerms.getPrincipal(), null, loanApplicationTerms.getNumberOfRepayments(), false);
|
||||
updateMapWithAmount(compoundingMap, feeChargesForInstallment.plus(penaltyChargesForInstallment), compoundingDate);
|
||||
}
|
||||
lastCompoundingDate = compoundingDate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void clearMapDetails(final LocalDate startDate, final Map<LocalDate, Money> compoundingMap) {
|
||||
Map<LocalDate, Money> temp = new HashMap<>();
|
||||
for (LocalDate date : compoundingMap.keySet()) {
|
||||
if (!date.isBefore(startDate)) {
|
||||
temp.put(date, compoundingMap.get(date));
|
||||
}
|
||||
}
|
||||
compoundingMap.clear();
|
||||
compoundingMap.putAll(temp);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -916,13 +1126,17 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
}
|
||||
|
||||
/**
|
||||
* merges all the applicable amounts(disbursements, late payment compounding
|
||||
* and principal change as per rest) changes to single map for interest
|
||||
* calculation
|
||||
* merges all the applicable amounts(compounding dates, disbursements, late
|
||||
* payment compounding and principal change as per rest) changes to single
|
||||
* map for interest calculation
|
||||
*
|
||||
* @param compoundingDates
|
||||
* TODO
|
||||
*/
|
||||
private Map<LocalDate, Money> mergeLateAndPaymentMaps(final Map<LocalDate, Money> princiaplPaidMap,
|
||||
final Map<LocalDate, Money> latePaymentMap, Map<LocalDate, Money> disburseDetailsMap) {
|
||||
Map<LocalDate, Money> map = new TreeMap<>();
|
||||
private TreeMap<LocalDate, Money> mergeVariationsToMap(final Map<LocalDate, Money> princiaplPaidMap,
|
||||
final Map<LocalDate, Money> latePaymentMap, final Map<LocalDate, Money> disburseDetailsMap,
|
||||
final Map<LocalDate, Money> compoundingDates) {
|
||||
TreeMap<LocalDate, Money> map = new TreeMap<>();
|
||||
map.putAll(latePaymentMap);
|
||||
|
||||
for (Map.Entry<LocalDate, Money> mapEntry : disburseDetailsMap.entrySet()) {
|
||||
@@ -940,6 +1154,14 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
}
|
||||
map.put(mapEntry.getKey(), value);
|
||||
}
|
||||
|
||||
for (Map.Entry<LocalDate, Money> mapEntry : compoundingDates.entrySet()) {
|
||||
Money value = mapEntry.getValue();
|
||||
if (!map.containsKey(mapEntry.getKey())) {
|
||||
map.put(mapEntry.getKey(), value.zero());
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
@@ -979,7 +1201,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
@Override
|
||||
public LoanRescheduleModel reschedule(final MathContext mathContext, final LoanRescheduleRequest loanRescheduleRequest,
|
||||
final ApplicationCurrency applicationCurrency, final HolidayDetailDTO holidayDetailDTO,
|
||||
final CalendarInstance restCalendarInstance) {
|
||||
final CalendarInstance restCalendarInstance, final CalendarInstance compoundingCalendarInstance) {
|
||||
|
||||
final Loan loan = loanRescheduleRequest.getLoan();
|
||||
final LoanSummary loanSummary = loan.getSummary();
|
||||
@@ -1120,7 +1342,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
}
|
||||
|
||||
// get the loan application terms from the Loan object
|
||||
final LoanApplicationTerms loanApplicationTerms = loan.getLoanApplicationTerms(applicationCurrency, restCalendarInstance);
|
||||
final LoanApplicationTerms loanApplicationTerms = loan.getLoanApplicationTerms(applicationCurrency, restCalendarInstance,
|
||||
compoundingCalendarInstance);
|
||||
|
||||
// update the number of repayments
|
||||
loanApplicationTerms.updateNumberOfRepayments(numberOfRepayments);
|
||||
@@ -1194,7 +1417,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
this.paymentPeriodsInOneYearCalculator, interestCalculationGraceOnRepaymentPeriodFraction,
|
||||
totalCumulativePrincipal, totalCumulativeInterest, totalInterestChargedForFullLoanTerm,
|
||||
totalOutstandingInterestPaymentDueToGrace, outstandingBalance, loanApplicationTerms, periodNumber, mathContext,
|
||||
null, installmentFromDate, adjustedInstallmentDueDate, daysInInstallment);
|
||||
null, null, installmentFromDate, adjustedInstallmentDueDate, daysInInstallment);
|
||||
|
||||
// update the interest due for the period
|
||||
period.updateInterestDue(principalInterestForThisPeriod.interest());
|
||||
@@ -1212,7 +1435,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
principalInterestForThisPeriod = calculatePrincipalInterestComponentsForPeriod(this.paymentPeriodsInOneYearCalculator,
|
||||
interestCalculationGraceOnRepaymentPeriodFraction, totalCumulativePrincipal, totalCumulativeInterest,
|
||||
totalInterestChargedForFullLoanTerm, totalOutstandingInterestPaymentDueToGrace, outstandingBalance,
|
||||
loanApplicationTerms, periodNumber, mathContext, null, installmentFromDate, adjustedInstallmentDueDate,
|
||||
loanApplicationTerms, periodNumber, mathContext, null, null, installmentFromDate, adjustedInstallmentDueDate,
|
||||
daysInInstallment);
|
||||
|
||||
period.updatePrincipalDue(principalInterestForThisPeriod.principal());
|
||||
@@ -1279,8 +1502,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
public abstract PrincipalInterest calculatePrincipalInterestComponentsForPeriod(PaymentPeriodsInOneYearCalculator calculator,
|
||||
double interestCalculationGraceOnRepaymentPeriodFraction, Money totalCumulativePrincipal, Money totalCumulativeInterest,
|
||||
Money totalInterestDueForLoan, Money cumulatingInterestPaymentDueToGrace, Money outstandingBalance,
|
||||
LoanApplicationTerms loanApplicationTerms, int periodNumber, MathContext mc, Map<LocalDate, Money> principalVariation,
|
||||
LocalDate periodStartDate, LocalDate periodEndDate, int daysForInterestInFullPeriod);
|
||||
LoanApplicationTerms loanApplicationTerms, int periodNumber, MathContext mc, TreeMap<LocalDate, Money> principalVariation,
|
||||
Map<LocalDate, Money> compoundingMap, LocalDate periodStartDate, LocalDate periodEndDate, int daysForInterestInFullPeriod);
|
||||
|
||||
protected final boolean isLastRepaymentPeriod(final int numberOfRepayments, final int periodNumber) {
|
||||
return periodNumber == numberOfRepayments;
|
||||
@@ -1347,7 +1570,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
private Money cumulativeFeeChargesDueWithin(final LocalDate periodStart, final LocalDate periodEnd, final Set<LoanCharge> loanCharges,
|
||||
final MonetaryCurrency monetaryCurrency, final PrincipalInterest principalInterestForThisPeriod,
|
||||
final Money principalDisbursed, final Money totalInterestChargedForFullLoanTerm, int numberOfRepayments,
|
||||
boolean isInstallmentChargeApplicable, final LocalDate lastTransactionDate) {
|
||||
boolean isInstallmentChargeApplicable) {
|
||||
|
||||
Money cumulative = Money.zero(monetaryCurrency);
|
||||
|
||||
@@ -1360,8 +1583,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
&& loanCharge.getChargeCalculation().isPercentageBased()) {
|
||||
cumulative = cumulative.plus(loanCharge.chargeAmount());
|
||||
} else if (loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)
|
||||
&& loanCharge.getChargeCalculation().isPercentageBased()
|
||||
&& !lastTransactionDate.isAfter(loanCharge.getDueLocalDate())) {
|
||||
&& loanCharge.getChargeCalculation().isPercentageBased()) {
|
||||
cumulative = calculateSpecificDueDateChargeWithPercentage(principalDisbursed, totalInterestChargedForFullLoanTerm,
|
||||
cumulative, loanCharge);
|
||||
} else if (loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)) {
|
||||
@@ -1411,8 +1633,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
private Money cumulativePenaltyChargesDueWithin(final LocalDate periodStart, final LocalDate periodEnd,
|
||||
final Set<LoanCharge> loanCharges, final MonetaryCurrency monetaryCurrency,
|
||||
final PrincipalInterest principalInterestForThisPeriod, final Money principalDisbursed,
|
||||
final Money totalInterestChargedForFullLoanTerm, int numberOfRepayments, boolean isInstallmentChargeApplicable,
|
||||
final LocalDate lastTransactionDate) {
|
||||
final Money totalInterestChargedForFullLoanTerm, int numberOfRepayments, boolean isInstallmentChargeApplicable) {
|
||||
|
||||
Money cumulative = Money.zero(monetaryCurrency);
|
||||
|
||||
@@ -1425,8 +1646,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
&& loanCharge.getChargeCalculation().isPercentageBased()) {
|
||||
cumulative = cumulative.plus(loanCharge.chargeAmount());
|
||||
} else if (loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)
|
||||
&& loanCharge.getChargeCalculation().isPercentageBased()
|
||||
&& !lastTransactionDate.isAfter(loanCharge.getDueLocalDate())) {
|
||||
&& loanCharge.getChargeCalculation().isPercentageBased()) {
|
||||
cumulative = calculateSpecificDueDateChargeWithPercentage(principalDisbursed, totalInterestChargedForFullLoanTerm,
|
||||
cumulative, loanCharge);
|
||||
} else if (loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStart, periodEnd)) {
|
||||
@@ -1446,14 +1666,24 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
@Override
|
||||
public LoanScheduleModel rescheduleNextInstallments(final MathContext mc, final LoanApplicationTerms loanApplicationTerms,
|
||||
final Set<LoanCharge> loanCharges, final HolidayDetailDTO holidayDetailDTO, final List<LoanTransaction> transactions,
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor, final LocalDate lastTransactionDate) {
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor) {
|
||||
|
||||
Collection<RecalculationDetail> recalculationDetails = new ArrayList<>();
|
||||
for (LoanTransaction loanTransaction : transactions) {
|
||||
recalculationDetails.add(new RecalculationDetail(loanTransaction.getTransactionDate(), loanTransaction));
|
||||
recalculationDetails.add(new RecalculationDetail(loanTransaction.getTransactionDate(), LoanTransaction
|
||||
.copyTransactionProperties(loanTransaction)));
|
||||
}
|
||||
return generate(mc, loanApplicationTerms, loanCharges, holidayDetailDTO, recalculationDetails, lastTransactionDate,
|
||||
loanRepaymentScheduleTransactionProcessor);
|
||||
final LocalDate scheduleTillDate = null;
|
||||
return generate(mc, loanApplicationTerms, loanCharges, holidayDetailDTO, recalculationDetails,
|
||||
loanRepaymentScheduleTransactionProcessor, scheduleTillDate);
|
||||
}
|
||||
|
||||
private List<LoanRepaymentScheduleInstallment> fetchInstallmentsFromScheduleModel(final LoanScheduleModel loanScheduleModel) {
|
||||
final List<LoanRepaymentScheduleInstallment> installments = new ArrayList<>();
|
||||
for (LoanScheduleModelPeriod loanScheduleModelPeriod : loanScheduleModel.getPeriods()) {
|
||||
addLoanRepaymentScheduleInstallment(installments, loanScheduleModelPeriod);
|
||||
}
|
||||
return installments;
|
||||
}
|
||||
|
||||
private void addLoanRepaymentScheduleInstallment(final List<LoanRepaymentScheduleInstallment> installments,
|
||||
@@ -1485,11 +1715,12 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
private LocalDate getNextCompoundScheduleDate(LocalDate startDate, LoanApplicationTerms loanApplicationTerms,
|
||||
final HolidayDetailDTO holidayDetailDTO) {
|
||||
LocalDate nextScheduleDate = null;
|
||||
if (loanApplicationTerms.getRecalculationFrequencyType().isSameAsRepayment()) {
|
||||
if (!loanApplicationTerms.getInterestRecalculationCompoundingMethod().isCompoundingEnabled()) { return null; }
|
||||
if (loanApplicationTerms.getCompoundingFrequencyType().isSameAsRepayment()) {
|
||||
nextScheduleDate = this.scheduledDateGenerator.generateNextScheduleDateStartingFromDisburseDate(startDate,
|
||||
loanApplicationTerms, holidayDetailDTO);
|
||||
} else {
|
||||
CalendarInstance calendarInstance = loanApplicationTerms.getRestCalendarInstance();
|
||||
CalendarInstance calendarInstance = loanApplicationTerms.getCompoundingCalendarInstance();
|
||||
nextScheduleDate = CalendarUtils.getNextScheduleDate(calendarInstance.getCalendar(), startDate);
|
||||
}
|
||||
|
||||
@@ -1500,150 +1731,35 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|
||||
* Method returns the amount payable to close the loan account as of today.
|
||||
*/
|
||||
@Override
|
||||
public LoanRepaymentScheduleInstallment calculatePrepaymentAmount(final List<LoanRepaymentScheduleInstallment> installments,
|
||||
public LoanRepaymentScheduleInstallment calculatePrepaymentAmount(List<LoanRepaymentScheduleInstallment> installments,
|
||||
MonetaryCurrency currency, final LocalDate onDate, LoanApplicationTerms loanApplicationTerms, MathContext mc,
|
||||
Set<LoanCharge> charges, final HolidayDetailDTO holidayDetailDTO) {
|
||||
Set<LoanCharge> charges, final HolidayDetailDTO holidayDetailDTO, final List<LoanTransaction> loanTransactions,
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor) {
|
||||
|
||||
LocalDate calculateTill = onDate;
|
||||
if (loanApplicationTerms.getPreClosureInterestCalculationStrategy().calculateTillRestFrequencyEnabled()) {
|
||||
calculateTill = getNextRestScheduleDate(onDate.minusDays(1), loanApplicationTerms, holidayDetailDTO);
|
||||
}
|
||||
Collection<RecalculationDetail> recalculationDetails = new ArrayList<>();
|
||||
for (LoanTransaction loanTransaction : loanTransactions) {
|
||||
recalculationDetails.add(new RecalculationDetail(loanTransaction.getTransactionDate(), LoanTransaction
|
||||
.copyTransactionProperties(loanTransaction)));
|
||||
}
|
||||
LoanScheduleModel loanScheduleModel = generate(mc, loanApplicationTerms, charges, holidayDetailDTO, recalculationDetails,
|
||||
loanRepaymentScheduleTransactionProcessor, calculateTill);
|
||||
installments = fetchInstallmentsFromScheduleModel(loanScheduleModel);
|
||||
loanRepaymentScheduleTransactionProcessor.handleTransaction(loanApplicationTerms.getExpectedDisbursementDate(), loanTransactions,
|
||||
currency, installments, charges);
|
||||
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 TreeMap<>();
|
||||
Map<LocalDate, Money> disburseAmtMap = new TreeMap<>();
|
||||
if (loanApplicationTerms.isMultiDisburseLoan()) {
|
||||
for (DisbursementData disbursementData : loanApplicationTerms.getDisbursementDatas()) {
|
||||
if (disbursementData.isDisbursed()) {
|
||||
principalOutstanding = principalOutstanding.plus(disbursementData.amount());
|
||||
disburseAmtMap.put(disbursementData.disbursementDate(), Money.of(currency, disbursementData.amount()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
principalOutstanding = loanApplicationTerms.getPrincipal();
|
||||
}
|
||||
|
||||
// adds all the unpaid principal till date and identifies the total
|
||||
// outstanding for interest calculation
|
||||
for (final LoanRepaymentScheduleInstallment currentInstallment : installments) {
|
||||
if (currentInstallment.isNotFullyPaidOff()) {
|
||||
if (!currentInstallment.getDueDate().isAfter(onDate)) {
|
||||
totalPrincipal = totalPrincipal.plus(currentInstallment.getPrincipalOutstanding(currency));
|
||||
totalInterest = totalInterest.plus(currentInstallment.getInterestOutstanding(currency));
|
||||
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());
|
||||
totalCompoundingAmount = updateMapWithCompoundingDetails(loanApplicationTerms, holidayDetailDTO, currency,
|
||||
differenceMap, totalCompoundingAmount, currentInstallment);
|
||||
} else {
|
||||
totalPrincipal = totalPrincipal.minus(currentInstallment.getPrincipalCompleted(currency));
|
||||
totalInterest = totalInterest.minus(currentInstallment.getInterestPaid(currency)).minus(
|
||||
currentInstallment.getInterestWaived(currency));
|
||||
if (!currentInstallment.getFromDate().isAfter(periodStartDate)) {
|
||||
if (!currentInstallment.isRecalculatedInterestComponent()) {
|
||||
periodStartDate = currentInstallment.getFromDate();
|
||||
}
|
||||
calculateInterestFrom = currentInstallment.getFromDate();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
principalOutstanding = principalOutstanding.minus(currentInstallment.getPrincipal(currency));
|
||||
}
|
||||
}
|
||||
Money arrears = totalPrincipal;
|
||||
totalPrincipal = totalPrincipal.plus(principalOutstanding);
|
||||
|
||||
for (Map.Entry<LocalDate, Money> disburseDetail : disburseAmtMap.entrySet()) {
|
||||
if (disburseDetail.getKey().isAfter(periodStartDate)) {
|
||||
differenceMap.put(disburseDetail.getKey(), disburseDetail.getValue());
|
||||
principalOutstanding = principalOutstanding.minus(disburseDetail.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
// interest calculation on outstanding amount till on date from the
|
||||
// period start of installment where on date falls
|
||||
Money interest = Money.zero(currency);
|
||||
LocalDate firstRepaymentdate = this.scheduledDateGenerator.generateNextRepaymentDate(
|
||||
loanApplicationTerms.getExpectedDisbursementDate(), loanApplicationTerms, true);
|
||||
final LocalDate idealDisbursementDate = this.scheduledDateGenerator.idealDisbursementDateBasedOnFirstRepaymentDate(
|
||||
loanApplicationTerms.getLoanTermPeriodFrequencyType(), loanApplicationTerms.getRepaymentEvery(), firstRepaymentdate);
|
||||
if (calculateInterestFrom.isBefore(onDate) && !periodStartDate.isBefore(idealDisbursementDate)) {
|
||||
|
||||
boolean isFirstRepayment = false;
|
||||
if (periodStartDate.isBefore(firstRepaymentdate)) {
|
||||
isFirstRepayment = true;
|
||||
}
|
||||
LocalDate scheduledDueDate = this.scheduledDateGenerator.generateNextRepaymentDate(periodStartDate, loanApplicationTerms,
|
||||
isFirstRepayment);
|
||||
isFirstRepayment = false;
|
||||
|
||||
LocalDate periodStartDateApplicableForInterest = calculateInterestStartDateForPeriod(loanApplicationTerms, periodStartDate,
|
||||
idealDisbursementDate, periodStartDate);
|
||||
int daysInPeriodApplicableForInterest = Days.daysBetween(periodStartDateApplicableForInterest, scheduledDueDate).getDays();
|
||||
|
||||
if (calculateInterestFrom.isBefore(periodStartDateApplicableForInterest)) {
|
||||
calculateInterestFrom = periodStartDateApplicableForInterest;
|
||||
}
|
||||
LocalDate calculateTill = onDate;
|
||||
if (loanApplicationTerms.getPreClosureInterestCalculationStrategy().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, calculateTill, daysInPeriodApplicableForInterest);
|
||||
interest = interest.plus(principalInterestForThisPeriod.interest());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
totalInterest = totalInterest.plus(interest);
|
||||
PrincipalInterest principalInterest = new PrincipalInterest(principalOutstanding, interest, null);
|
||||
|
||||
// apply changes applicable in the period
|
||||
for (LoanCharge loanCharge : charges) {
|
||||
if (loanCharge.isActive() && loanCharge.isNotFullyPaid() && !loanCharge.isWaived()
|
||||
&& loanCharge.isDueForCollectionFromAndUpToAndIncluding(periodStartDate, onDate)) {
|
||||
if (loanCharge.isFeeCharge()) {
|
||||
feeCharges = feeCharges.plus(loanCharge.amountOutstanding());
|
||||
} else {
|
||||
penaltyCharges = penaltyCharges.plus(loanCharge.amountOutstanding());
|
||||
|
||||
}
|
||||
} else if (loanCharge.isActive() && interest.isGreaterThanZero() && loanCharge.isInstalmentFee()) {
|
||||
if (loanCharge.isFeeCharge()) {
|
||||
feeCharges = feeCharges.plus(calculateInstallmentCharge(principalInterest,
|
||||
loanApplicationTerms.getNumberOfRepayments(), feeCharges.zero(), loanCharge));
|
||||
} else {
|
||||
penaltyCharges = penaltyCharges.plus(calculateInstallmentCharge(principalInterest,
|
||||
loanApplicationTerms.getNumberOfRepayments(), feeCharges.zero(), loanCharge));
|
||||
}
|
||||
totalPrincipal = totalPrincipal.plus(currentInstallment.getPrincipalOutstanding(currency));
|
||||
totalInterest = totalInterest.plus(currentInstallment.getInterestOutstanding(currency));
|
||||
feeCharges = feeCharges.plus(currentInstallment.getFeeChargesOutstanding(currency));
|
||||
penaltyCharges = penaltyCharges.plus(currentInstallment.getPenaltyChargesOutstanding(currency));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+37
-3
@@ -7,9 +7,11 @@ package org.mifosplatform.portfolio.loanaccount.loanschedule.domain;
|
||||
|
||||
import java.math.MathContext;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.joda.time.Days;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.AmortizationMethod;
|
||||
|
||||
@@ -46,16 +48,27 @@ public class DecliningBalanceInterestLoanScheduleGenerator extends AbstractLoanS
|
||||
@SuppressWarnings("unused") final Money totalCumulativeInterest,
|
||||
@SuppressWarnings("unused") final Money totalInterestDueForLoan, final Money cumulatingInterestPaymentDueToGrace,
|
||||
final Money outstandingBalance, final LoanApplicationTerms loanApplicationTerms, final int periodNumber, final MathContext mc,
|
||||
final Map<LocalDate, Money> principalVariation, final LocalDate periodStartDate, final LocalDate periodEndDate,
|
||||
final int daysForInterestInFullPeriod) {
|
||||
final TreeMap<LocalDate, Money> principalVariation, final Map<LocalDate, Money> compoundingMap,
|
||||
final LocalDate periodStartDate, final LocalDate periodEndDate, final int daysForInterestInFullPeriod) {
|
||||
|
||||
LocalDate interestStartDate = periodStartDate;
|
||||
Money interestForThisInstallment = totalCumulativePrincipal.zero();
|
||||
Money compoundedMoney = totalCumulativePrincipal.zero();
|
||||
Money compoundedInterest = totalCumulativePrincipal.zero();
|
||||
Money balanceForInterestCalculation = outstandingBalance;
|
||||
Money cumulatingInterestDueToGrace = cumulatingInterestPaymentDueToGrace;
|
||||
final int daysInPeriodApplicableForInterest = Days.daysBetween(periodStartDate, periodEndDate).getDays();
|
||||
if (principalVariation != null) {
|
||||
// identifies rest date after current date for reducing all
|
||||
// compounding
|
||||
// values
|
||||
LocalDate compoundingEndDate = principalVariation.ceilingKey(DateUtils.getLocalDateOfTenant());
|
||||
if (compoundingEndDate == null) {
|
||||
compoundingEndDate = DateUtils.getLocalDateOfTenant();
|
||||
}
|
||||
|
||||
for (Map.Entry<LocalDate, Money> principal : principalVariation.entrySet()) {
|
||||
|
||||
if (!principal.getKey().isAfter(periodEndDate)) {
|
||||
int interestForDays = Days.daysBetween(interestStartDate, principal.getKey()).getDays();
|
||||
if (interestForDays > 0) {
|
||||
@@ -71,10 +84,31 @@ public class DecliningBalanceInterestLoanScheduleGenerator extends AbstractLoanS
|
||||
cumulatingInterestDueToGrace = result.interestPaymentDueToGrace();
|
||||
interestStartDate = principal.getKey();
|
||||
}
|
||||
balanceForInterestCalculation = balanceForInterestCalculation.plus(principal.getValue());
|
||||
Money compoundFee = totalCumulativePrincipal.zero();
|
||||
if (compoundingMap.containsKey(principal.getKey())) {
|
||||
Money interestToBeCompounded = totalCumulativePrincipal.zero();
|
||||
// for interest compounding
|
||||
if (loanApplicationTerms.getInterestRecalculationCompoundingMethod().isInterestCompoundingEnabled()) {
|
||||
interestToBeCompounded = interestForThisInstallment.minus(compoundedInterest);
|
||||
balanceForInterestCalculation = balanceForInterestCalculation.plus(interestToBeCompounded);
|
||||
compoundedInterest = interestForThisInstallment;
|
||||
}
|
||||
// fee compounding will be done after calculation
|
||||
compoundFee = compoundingMap.get(principal.getKey());
|
||||
compoundedMoney = compoundedMoney.plus(interestToBeCompounded).plus(compoundFee);
|
||||
}
|
||||
balanceForInterestCalculation = balanceForInterestCalculation.plus(principal.getValue()).plus(compoundFee);
|
||||
}
|
||||
|
||||
}
|
||||
if (!periodEndDate.isBefore(compoundingEndDate)) {
|
||||
balanceForInterestCalculation = balanceForInterestCalculation.minus(compoundedMoney);
|
||||
compoundingMap.clear();
|
||||
} else if (compoundedMoney.isGreaterThanZero()) {
|
||||
compoundingMap.put(periodEndDate, compoundedMoney);
|
||||
compoundingMap.put(compoundingEndDate, compoundedMoney.negated());
|
||||
clearMapDetails(periodEndDate, compoundingMap);
|
||||
}
|
||||
}
|
||||
int interestForDays = Days.daysBetween(interestStartDate, periodEndDate).getDays();
|
||||
|
||||
|
||||
+3
-1
@@ -7,6 +7,7 @@ package org.mifosplatform.portfolio.loanaccount.loanschedule.domain;
|
||||
|
||||
import java.math.MathContext;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.joda.time.Days;
|
||||
import org.joda.time.LocalDate;
|
||||
@@ -19,7 +20,8 @@ public class FlatInterestLoanScheduleGenerator extends AbstractLoanScheduleGener
|
||||
final double interestCalculationGraceOnRepaymentPeriodFraction, final Money totalCumulativePrincipal,
|
||||
final Money totalCumulativeInterest, final Money totalInterestDueForLoan, final Money cumulatingInterestPaymentDueToGrace,
|
||||
final Money outstandingBalance, final LoanApplicationTerms loanApplicationTerms, final int periodNumber, final MathContext mc,
|
||||
@SuppressWarnings("unused") Map<LocalDate, Money> principalVariation, LocalDate periodStartDate, LocalDate periodEndDate,
|
||||
@SuppressWarnings("unused") TreeMap<LocalDate, Money> principalVariation,
|
||||
@SuppressWarnings("unused") Map<LocalDate, Money> compoundingMap, LocalDate periodStartDate, LocalDate periodEndDate,
|
||||
@SuppressWarnings("unused") int daysForInterestInFullPeriod) {
|
||||
final int daysInPeriodApplicableForInterest = Days.daysBetween(periodStartDate, periodEndDate).getDays();
|
||||
Money principalForThisInstallment = loanApplicationTerms.calculateTotalPrincipalForPeriod(calculator,
|
||||
|
||||
+33
-12
@@ -135,6 +135,10 @@ public final class LoanApplicationTerms {
|
||||
|
||||
private final RecalculationFrequencyType recalculationFrequencyType;
|
||||
|
||||
private final CalendarInstance compoundingCalendarInstance;
|
||||
|
||||
private final RecalculationFrequencyType compoundingFrequencyType;
|
||||
|
||||
private final BigDecimal principalThresholdForLastInstalment;
|
||||
private final Integer installmentAmountInMultiplesOf;
|
||||
|
||||
@@ -154,6 +158,7 @@ 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 CalendarInstance compoundingCalendarInstance, final RecalculationFrequencyType compoundingFrequencyType,
|
||||
final BigDecimal principalThresholdForLastInstalment, final Integer installmentAmountInMultiplesOf,
|
||||
final LoanPreClosureInterestCalculationStrategy preClosureInterestCalculationStrategy) {
|
||||
|
||||
@@ -166,8 +171,8 @@ public final class LoanApplicationTerms {
|
||||
graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsTolerance, multiDisburseLoan, emiAmount,
|
||||
disbursementDatas, maxOutstandingBalance, emiAmountVariations, graceOnArrearsAgeing, daysInMonthType, daysInYearType,
|
||||
isInterestRecalculationEnabled, rescheduleStrategyMethod, interestRecalculationCompoundingMethod, restCalendarInstance,
|
||||
recalculationFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
|
||||
preClosureInterestCalculationStrategy);
|
||||
recalculationFrequencyType, compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment,
|
||||
installmentAmountInMultiplesOf, preClosureInterestCalculationStrategy);
|
||||
}
|
||||
|
||||
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
|
||||
@@ -179,8 +184,10 @@ 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 LoanPreClosureInterestCalculationStrategy loanPreClosureInterestCalculationStrategy) {
|
||||
final InterestRecalculationCompoundingMethod compoundingMethod, final CalendarInstance compoundingCalendarInstance,
|
||||
final RecalculationFrequencyType compoundingFrequencyType,
|
||||
final LoanPreClosureInterestCalculationStrategy loanPreClosureInterestCalculationStrategy,
|
||||
final LoanRescheduleStrategyMethod rescheduleStrategyMethod) {
|
||||
|
||||
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
|
||||
final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery();
|
||||
@@ -203,7 +210,6 @@ public final class LoanApplicationTerms {
|
||||
final DaysInMonthType daysInMonthType = loanProductRelatedDetail.fetchDaysInMonthType();
|
||||
final DaysInYearType daysInYearType = loanProductRelatedDetail.fetchDaysInYearType();
|
||||
final boolean isInterestRecalculationEnabled = loanProductRelatedDetail.isInterestRecalculationEnabled();
|
||||
final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null;
|
||||
|
||||
return new LoanApplicationTerms(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments,
|
||||
repaymentEvery, repaymentPeriodFrequencyType, nthDay.getValue(), dayOfWeek, amortizationMethod, interestMethod,
|
||||
@@ -212,8 +218,9 @@ public final class LoanApplicationTerms {
|
||||
graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsTolerance,
|
||||
multiDisburseLoan, emiAmount, disbursementDatas, maxOutstandingBalance, emiAmountVariations,
|
||||
loanProductRelatedDetail.getGraceOnDueDate(), daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
|
||||
rescheduleStrategyMethod, compoundingMethod, restCalendarInstance, recalculationFrequencyType,
|
||||
principalThresholdForLastInstalment, installmentAmountInMultiplesOf, loanPreClosureInterestCalculationStrategy);
|
||||
rescheduleStrategyMethod, compoundingMethod, restCalendarInstance, recalculationFrequencyType, compoundingCalendarInstance,
|
||||
compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
|
||||
loanPreClosureInterestCalculationStrategy);
|
||||
}
|
||||
|
||||
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
|
||||
@@ -223,8 +230,9 @@ public final class LoanApplicationTerms {
|
||||
final BigDecimal emiAmount, final List<DisbursementData> disbursementDatas, final BigDecimal maxOutstandingBalance,
|
||||
final List<LoanTermVariationsData> emiAmountVariations, final LocalDate interestChargedFromDate,
|
||||
final LoanInterestRecalculationDetails interestRecalculationDetails, final CalendarInstance restCalendarInstance,
|
||||
final RecalculationFrequencyType recalculationFrequencyType, final BigDecimal principalThresholdForLastInstalment,
|
||||
Integer installmentAmountInMultiplesOf,
|
||||
final RecalculationFrequencyType recalculationFrequencyType, final CalendarInstance compoundingCalendarInstance,
|
||||
final RecalculationFrequencyType compoundingFrequencyType, final BigDecimal principalThresholdForLastInstalment,
|
||||
final Integer installmentAmountInMultiplesOf,
|
||||
final LoanPreClosureInterestCalculationStrategy loanPreClosureInterestCalculationStrategy) {
|
||||
|
||||
final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments();
|
||||
@@ -262,8 +270,9 @@ public final class LoanApplicationTerms {
|
||||
graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsTolerance, multiDisburseLoan, emiAmount,
|
||||
disbursementDatas, maxOutstandingBalance, emiAmountVariations, loanProductRelatedDetail.getGraceOnDueDate(),
|
||||
daysInMonthType, daysInYearType, isInterestRecalculationEnabled, rescheduleStrategyMethod,
|
||||
interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType,
|
||||
principalThresholdForLastInstalment, installmentAmountInMultiplesOf, loanPreClosureInterestCalculationStrategy);
|
||||
interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType, compoundingCalendarInstance,
|
||||
compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
|
||||
loanPreClosureInterestCalculationStrategy);
|
||||
}
|
||||
|
||||
public static LoanApplicationTerms assembleFrom(final Integer repaymentEvery, final PeriodFrequencyType repaymentPeriodFrequencyType,
|
||||
@@ -281,7 +290,8 @@ public final class LoanApplicationTerms {
|
||||
applicationTerms.graceOnArrearsAgeing, applicationTerms.daysInMonthType, applicationTerms.daysInYearType,
|
||||
applicationTerms.interestRecalculationEnabled, applicationTerms.rescheduleStrategyMethod,
|
||||
applicationTerms.interestRecalculationCompoundingMethod, applicationTerms.restCalendarInstance,
|
||||
applicationTerms.recalculationFrequencyType, applicationTerms.principalThresholdForLastInstalment,
|
||||
applicationTerms.recalculationFrequencyType, applicationTerms.compoundingCalendarInstance,
|
||||
applicationTerms.compoundingFrequencyType, applicationTerms.principalThresholdForLastInstalment,
|
||||
applicationTerms.installmentAmountInMultiplesOf, applicationTerms.preClosureInterestCalculationStrategy);
|
||||
}
|
||||
|
||||
@@ -300,6 +310,7 @@ public final class LoanApplicationTerms {
|
||||
final boolean isInterestRecalculationEnabled, final LoanRescheduleStrategyMethod rescheduleStrategyMethod,
|
||||
final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod,
|
||||
final CalendarInstance restCalendarInstance, final RecalculationFrequencyType recalculationFrequencyType,
|
||||
final CalendarInstance compoundingCalendarInstance, final RecalculationFrequencyType compoundingFrequencyType,
|
||||
final BigDecimal principalThresholdForLastInstalment, final Integer installmentAmountInMultiplesOf,
|
||||
final LoanPreClosureInterestCalculationStrategy preClosureInterestCalculationStrategy) {
|
||||
this.currency = currency;
|
||||
@@ -342,7 +353,9 @@ public final class LoanApplicationTerms {
|
||||
this.rescheduleStrategyMethod = rescheduleStrategyMethod;
|
||||
this.interestRecalculationCompoundingMethod = interestRecalculationCompoundingMethod;
|
||||
this.restCalendarInstance = restCalendarInstance;
|
||||
this.compoundingCalendarInstance = compoundingCalendarInstance;
|
||||
this.recalculationFrequencyType = recalculationFrequencyType;
|
||||
this.compoundingFrequencyType = compoundingFrequencyType;
|
||||
this.principalThresholdForLastInstalment = principalThresholdForLastInstalment;
|
||||
this.installmentAmountInMultiplesOf = installmentAmountInMultiplesOf;
|
||||
this.preClosureInterestCalculationStrategy = preClosureInterestCalculationStrategy;
|
||||
@@ -1183,4 +1196,12 @@ public final class LoanApplicationTerms {
|
||||
public LoanPreClosureInterestCalculationStrategy getPreClosureInterestCalculationStrategy() {
|
||||
return this.preClosureInterestCalculationStrategy;
|
||||
}
|
||||
|
||||
public CalendarInstance getCompoundingCalendarInstance() {
|
||||
return this.compoundingCalendarInstance;
|
||||
}
|
||||
|
||||
public RecalculationFrequencyType getCompoundingFrequencyType() {
|
||||
return this.compoundingFrequencyType;
|
||||
}
|
||||
}
|
||||
+3
-4
@@ -28,13 +28,12 @@ public interface LoanScheduleGenerator {
|
||||
|
||||
LoanScheduleModel rescheduleNextInstallments(MathContext mc, LoanApplicationTerms loanApplicationTerms, Set<LoanCharge> loanCharges,
|
||||
final HolidayDetailDTO holidayDetailDTO, List<LoanTransaction> transactions,
|
||||
LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor,
|
||||
LocalDate lastTransactionDate);
|
||||
LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor);
|
||||
|
||||
LoanRepaymentScheduleInstallment calculatePrepaymentAmount(List<LoanRepaymentScheduleInstallment> installments,
|
||||
MonetaryCurrency currency, LocalDate onDate, LoanApplicationTerms loanApplicationTerms, MathContext mc,
|
||||
Set<LoanCharge> charges, HolidayDetailDTO holidayDetailDTO);
|
||||
Set<LoanCharge> charges, HolidayDetailDTO holidayDetailDTO, List<LoanTransaction> loanTransactions, LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor);
|
||||
|
||||
LoanRescheduleModel reschedule(final MathContext mathContext, final LoanRescheduleRequest loanRescheduleRequest,
|
||||
final ApplicationCurrency applicationCurrency, final HolidayDetailDTO holidayDetailDTO, CalendarInstance restCalendarInstance);
|
||||
final ApplicationCurrency applicationCurrency, final HolidayDetailDTO holidayDetailDTO, CalendarInstance restCalendarInstance, CalendarInstance compoundingCalendarInstance);
|
||||
}
|
||||
+31
-11
@@ -67,7 +67,9 @@ import org.mifosplatform.portfolio.loanproduct.LoanProductConstants;
|
||||
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.LoanProduct;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductInterestRecalculationDetails;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductRepository;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.RecalculationFrequencyType;
|
||||
@@ -256,9 +258,12 @@ public class LoanScheduleAssembler {
|
||||
final boolean isInterestRecalculationEnabled = loanProduct.isInterestRecalculationEnabled();
|
||||
RecalculationFrequencyType recalculationFrequencyType = null;
|
||||
CalendarInstance restCalendarInstance = null;
|
||||
|
||||
RecalculationFrequencyType compoundingFrequencyType = null;
|
||||
CalendarInstance compoundingCalendarInstance = null;
|
||||
if (isInterestRecalculationEnabled) {
|
||||
recalculationFrequencyType = loanProduct.getProductInterestRecalculationDetails().getRestFrequencyType();
|
||||
LoanProductInterestRecalculationDetails loanProductInterestRecalculationDetails = loanProduct
|
||||
.getProductInterestRecalculationDetails();
|
||||
recalculationFrequencyType = loanProductInterestRecalculationDetails.getRestFrequencyType();
|
||||
if (!recalculationFrequencyType.isSameAsRepayment()) {
|
||||
LocalDate calendarStartDate = this.fromApiJsonHelper.extractLocalDateNamed(
|
||||
LoanProductConstants.recalculationRestFrequencyDateParamName, element);
|
||||
@@ -266,7 +271,22 @@ public class LoanScheduleAssembler {
|
||||
calendarStartDate = expectedDisbursementDate;
|
||||
}
|
||||
restCalendarInstance = createInterestRecalculationCalendarInstance(calendarStartDate, recalculationFrequencyType,
|
||||
loanProduct.getProductInterestRecalculationDetails().getRestInterval());
|
||||
loanProductInterestRecalculationDetails.getRestInterval());
|
||||
}
|
||||
InterestRecalculationCompoundingMethod compoundingMethod = InterestRecalculationCompoundingMethod
|
||||
.fromInt(loanProductInterestRecalculationDetails.getInterestRecalculationCompoundingMethod());
|
||||
if (compoundingMethod.isCompoundingEnabled()) {
|
||||
compoundingFrequencyType = loanProductInterestRecalculationDetails.getCompoundingFrequencyType();
|
||||
if (!compoundingFrequencyType.isSameAsRepayment()) {
|
||||
LocalDate calendarStartDate = this.fromApiJsonHelper.extractLocalDateNamed(
|
||||
LoanProductConstants.recalculationCompoundingFrequencyDateParamName, element);
|
||||
if (calendarStartDate == null) {
|
||||
calendarStartDate = expectedDisbursementDate;
|
||||
}
|
||||
compoundingCalendarInstance = createInterestRecalculationCalendarInstance(calendarStartDate, compoundingFrequencyType,
|
||||
loanProductInterestRecalculationDetails.getCompoundingInterval());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,8 +301,8 @@ public class LoanScheduleAssembler {
|
||||
graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsToleranceMoney,
|
||||
loanProduct.isMultiDisburseLoan(), emiAmount, disbursementDatas, maxOutstandingBalance, loanVariationTermsData,
|
||||
graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, recalculationFrequencyType,
|
||||
restCalendarInstance, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
|
||||
loanProduct.preCloseInterestCalculationStrategy());
|
||||
restCalendarInstance, compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment,
|
||||
installmentAmountInMultiplesOf, loanProduct.preCloseInterestCalculationStrategy());
|
||||
}
|
||||
|
||||
private CalendarInstance createInterestRecalculationCalendarInstance(final LocalDate calendarStartDate,
|
||||
@@ -307,7 +327,7 @@ public class LoanScheduleAssembler {
|
||||
final String title = "loan_recalculation_detail";
|
||||
final Calendar calendar = Calendar.createRepeatingCalendar(title, calendarStartDate, CalendarType.COLLECTION.getValue(),
|
||||
calendarFrequencyType, frequency, repeatsOnDay);
|
||||
return CalendarInstance.from(calendar, null, CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
||||
return CalendarInstance.from(calendar, null, CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
|
||||
}
|
||||
|
||||
private List<DisbursementData> fetchDisbursementData(final JsonObject command) {
|
||||
@@ -434,8 +454,7 @@ public class LoanScheduleAssembler {
|
||||
|
||||
public LoanScheduleModel assembleForInterestRecalculation(final LoanApplicationTerms loanApplicationTerms, final Long officeId,
|
||||
List<LoanTransaction> transactions, final Set<LoanCharge> loanCharges,
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor,
|
||||
LocalDate recalculateDueDateChargesFrom) {
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor) {
|
||||
final RoundingMode roundingMode = RoundingMode.HALF_EVEN;
|
||||
final MathContext mc = new MathContext(8, roundingMode);
|
||||
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
|
||||
@@ -447,12 +466,13 @@ public class LoanScheduleAssembler {
|
||||
final LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(loanApplicationTerms.getInterestMethod());
|
||||
HolidayDetailDTO detailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
||||
return loanScheduleGenerator.rescheduleNextInstallments(mc, loanApplicationTerms, loanCharges, detailDTO, transactions,
|
||||
loanRepaymentScheduleTransactionProcessor, recalculateDueDateChargesFrom);
|
||||
loanRepaymentScheduleTransactionProcessor);
|
||||
}
|
||||
|
||||
public LoanRepaymentScheduleInstallment calculatePrepaymentAmount(List<LoanRepaymentScheduleInstallment> installments,
|
||||
MonetaryCurrency currency, LocalDate onDate, LoanApplicationTerms loanApplicationTerms, final Set<LoanCharge> loanCharges,
|
||||
final Long officeId) {
|
||||
final Long officeId, List<LoanTransaction> loanTransactions,
|
||||
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor) {
|
||||
final LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(loanApplicationTerms.getInterestMethod());
|
||||
final RoundingMode roundingMode = RoundingMode.HALF_EVEN;
|
||||
final MathContext mc = new MathContext(8, roundingMode);
|
||||
@@ -464,7 +484,7 @@ public class LoanScheduleAssembler {
|
||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
||||
|
||||
return loanScheduleGenerator.calculatePrepaymentAmount(installments, currency, onDate, loanApplicationTerms, mc, loanCharges,
|
||||
holidayDetailDTO);
|
||||
holidayDetailDTO, loanTransactions, loanRepaymentScheduleTransactionProcessor);
|
||||
|
||||
}
|
||||
|
||||
|
||||
+7
-4
@@ -159,13 +159,16 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
|
||||
final CalendarInstance calendarInstance = this.calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(),
|
||||
CalendarEntityType.LOANS.getValue());
|
||||
final CalendarInstance restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
|
||||
final CalendarInstance compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
||||
LocalDate calculatedRepaymentsStartingFromDate = accountDomainService.getCalculatedRepaymentsStartingFromDate(
|
||||
loan.getDisbursementDate(), loan, calendarInstance);
|
||||
LoanApplicationTerms loanApplicationTerms = loan.constructLoanApplicationTerms(applicationCurrency,
|
||||
calculatedRepaymentsStartingFromDate, restCalendarInstance);
|
||||
calculatedRepaymentsStartingFromDate, restCalendarInstance, compoundingCalendarInstance);
|
||||
LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = this.loanScheduleAssembler.calculatePrepaymentAmount(
|
||||
loan.fetchRepaymentScheduleInstallments(), currency, today, loanApplicationTerms, loan.charges(), loan.getOfficeId());
|
||||
loan.fetchRepaymentScheduleInstallments(), currency, today, loanApplicationTerms, loan.charges(), loan.getOfficeId(),
|
||||
loan.retreiveListOfTransactionsPostDisbursementExcludeAccruals(), loanRepaymentScheduleTransactionProcessor);
|
||||
Money totalAmount = totalPrincipal.plus(loanRepaymentScheduleInstallment.getFeeChargesOutstanding(currency)).plus(
|
||||
loanRepaymentScheduleInstallment.getPenaltyChargesOutstanding(currency));
|
||||
Money interestDue = Money.zero(currency);
|
||||
@@ -186,7 +189,7 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC
|
||||
}
|
||||
|
||||
LoanScheduleModel model = this.loanScheduleAssembler.assembleForInterestRecalculation(loanApplicationTerms, loan.getOfficeId(),
|
||||
modifiedTransactions, loan.charges(), loanRepaymentScheduleTransactionProcessor, today);
|
||||
modifiedTransactions, loan.charges(), loanRepaymentScheduleTransactionProcessor);
|
||||
LoanScheduleData scheduleDate = model.toData();
|
||||
Collection<LoanSchedulePeriodData> periodDatas = scheduleDate.getPeriods();
|
||||
for (LoanSchedulePeriodData periodData : periodDatas) {
|
||||
|
||||
+4
-3
@@ -19,19 +19,20 @@ public class DefaultLoanReschedulerFactory implements LoanReschedulerFactory {
|
||||
@Override
|
||||
public LoanRescheduleModel reschedule(final MathContext mathContext, final InterestMethod interestMethod,
|
||||
final LoanRescheduleRequest loanRescheduleRequest, final ApplicationCurrency applicationCurrency,
|
||||
final HolidayDetailDTO holidayDetailDTO,final CalendarInstance restCalendarInstance) {
|
||||
final HolidayDetailDTO holidayDetailDTO, final CalendarInstance restCalendarInstance,
|
||||
final CalendarInstance compoundingCalendarInstance) {
|
||||
|
||||
LoanRescheduleModel loanRescheduleModel = null;
|
||||
|
||||
switch (interestMethod) {
|
||||
case DECLINING_BALANCE:
|
||||
loanRescheduleModel = new DecliningBalanceInterestLoanScheduleGenerator().reschedule(mathContext, loanRescheduleRequest,
|
||||
applicationCurrency, holidayDetailDTO, restCalendarInstance);
|
||||
applicationCurrency, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance);
|
||||
break;
|
||||
|
||||
case FLAT:
|
||||
loanRescheduleModel = new FlatInterestLoanScheduleGenerator().reschedule(mathContext, loanRescheduleRequest,
|
||||
applicationCurrency, holidayDetailDTO, restCalendarInstance);
|
||||
applicationCurrency, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance);
|
||||
break;
|
||||
|
||||
case INVALID:
|
||||
|
||||
+1
-1
@@ -16,5 +16,5 @@ public interface LoanReschedulerFactory {
|
||||
|
||||
public LoanRescheduleModel reschedule(final MathContext mathContext, final InterestMethod interestMethod,
|
||||
final LoanRescheduleRequest loanRescheduleRequest, final ApplicationCurrency applicationCurrency,
|
||||
final HolidayDetailDTO holidayDetailDTO, CalendarInstance restCalendarInstance);
|
||||
final HolidayDetailDTO holidayDetailDTO, CalendarInstance restCalendarInstance, CalendarInstance compoundingCalendarInstance);
|
||||
}
|
||||
|
||||
+5
-2
@@ -85,13 +85,16 @@ public class LoanReschedulePreviewPlatformServiceImpl implements LoanRescheduleP
|
||||
loan.getRepaymentScheduleInstallments(), loan, loanRescheduleRequest);
|
||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
||||
CalendarInstance restCalendarInstance = null;
|
||||
CalendarInstance compoundingCalendarInstance = null;
|
||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
|
||||
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
||||
CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
|
||||
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
||||
}
|
||||
|
||||
LoanRescheduleModel loanRescheduleModel = new DefaultLoanReschedulerFactory().reschedule(mathContext, interestMethod,
|
||||
loanRescheduleRequest, applicationCurrency, holidayDetailDTO, restCalendarInstance);
|
||||
loanRescheduleRequest, applicationCurrency, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance);
|
||||
LoanRescheduleModel loanRescheduleModelWithOldPeriods = LoanRescheduleModel.createWithSchedulehistory(loanRescheduleModel,
|
||||
oldPeriods);
|
||||
return loanRescheduleModelWithOldPeriods;
|
||||
|
||||
+11
-6
@@ -322,12 +322,15 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
|
||||
|
||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
||||
CalendarInstance restCalendarInstance = null;
|
||||
CalendarInstance compoundingCalendarInstance = null;
|
||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
|
||||
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
||||
}
|
||||
LoanRescheduleModel loanRescheduleModel = new DefaultLoanReschedulerFactory().reschedule(mathContext, interestMethod,
|
||||
loanRescheduleRequest, applicationCurrency, holidayDetailDTO, restCalendarInstance);
|
||||
loanRescheduleRequest, applicationCurrency, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance);
|
||||
|
||||
final Collection<LoanRescheduleModelRepaymentPeriod> periods = loanRescheduleModel.getPeriods();
|
||||
List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments = loan.getRepaymentScheduleInstallments();
|
||||
@@ -450,6 +453,7 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
|
||||
final List<Long> existingTransactionIds = new ArrayList<>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<>();
|
||||
CalendarInstance restCalendarInstance = null;
|
||||
CalendarInstance compoundingCalendarInstance = null;
|
||||
ApplicationCurrency applicationCurrency = null;
|
||||
LocalDate calculatedRepaymentsStartingFromDate = null;
|
||||
List<Holiday> holidays = null;
|
||||
@@ -460,8 +464,9 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
|
||||
Long overdurPenaltyWaitPeriod = null;
|
||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
||||
|
||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
|
||||
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
||||
final MonetaryCurrency currency = loan.getCurrency();
|
||||
applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
|
||||
final CalendarInstance calendarInstance = this.calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(),
|
||||
@@ -478,8 +483,8 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
|
||||
|
||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
||||
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, recalculateFrom,
|
||||
overdurPenaltyWaitPeriod, lastTransactionDate);
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance,
|
||||
recalculateFrom, overdurPenaltyWaitPeriod);
|
||||
|
||||
Money accruedCharge = Money.zero(loan.getCurrency());
|
||||
if (loan.isPeriodicAccrualAccountingEnabledOnLoanProduct()) {
|
||||
|
||||
+39
-11
@@ -27,6 +27,7 @@ import org.mifosplatform.portfolio.accountdetails.domain.AccountType;
|
||||
import org.mifosplatform.portfolio.loanaccount.api.LoanApiConstants;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanInterestRecalculationDetails;
|
||||
import org.mifosplatform.portfolio.loanproduct.LoanProductConstants;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
|
||||
@@ -47,9 +48,15 @@ public final class LoanApplicationCommandFromApiJsonHelper {
|
||||
*/
|
||||
final Set<String> supportedParameters = new HashSet<>(Arrays.asList("dateFormat", "locale", "id", "clientId", "groupId", "loanType",
|
||||
"productId", "principal", "loanTermFrequency", "loanTermFrequencyType", "numberOfRepayments", "repaymentEvery",
|
||||
"repaymentFrequencyType", "repaymentFrequencyNthDayType", "repaymentFrequencyDayOfWeekType", "interestRatePerPeriod",
|
||||
"amortizationType", "interestType", "interestCalculationPeriodType", "expectedDisbursementDate", "repaymentsStartingFromDate",
|
||||
"graceOnPrincipalPayment", "graceOnInterestPayment",
|
||||
"repaymentFrequencyType", "repaymentFrequencyNthDayType", "repaymentFrequencyDayOfWeekType",
|
||||
"interestRatePerPeriod",
|
||||
"amortizationType",
|
||||
"interestType",
|
||||
"interestCalculationPeriodType",
|
||||
"expectedDisbursementDate",
|
||||
"repaymentsStartingFromDate",
|
||||
"graceOnPrincipalPayment",
|
||||
"graceOnInterestPayment",
|
||||
"graceOnInterestCharged",
|
||||
"interestChargedFromDate", //
|
||||
"submittedOnDate",
|
||||
@@ -67,7 +74,8 @@ public final class LoanApplicationCommandFromApiJsonHelper {
|
||||
"syncDisbursementWithMeeting",// optional
|
||||
"linkAccountId", LoanApiConstants.disbursementDataParameterName, LoanApiConstants.emiAmountParameterName,
|
||||
LoanApiConstants.maxOutstandingBalanceParameterName, LoanProductConstants.graceOnArrearsAgeingParameterName,
|
||||
LoanProductConstants.recalculationRestFrequencyDateParamName, "createStandingInstructionAtDisbursement"));
|
||||
LoanProductConstants.recalculationRestFrequencyDateParamName,
|
||||
LoanProductConstants.recalculationCompoundingFrequencyDateParamName, "createStandingInstructionAtDisbursement"));
|
||||
|
||||
private final FromJsonHelper fromApiJsonHelper;
|
||||
private final CalculateLoanScheduleQueryFromApiJsonHelper apiJsonHelper;
|
||||
@@ -933,11 +941,11 @@ public final class LoanApplicationCommandFromApiJsonHelper {
|
||||
}
|
||||
|
||||
public void validateRecalcuationFrequency(final LocalDate recalculationFrequencyDate, final LocalDate expectedDisbursementDate,
|
||||
final List<ApiParameterError> dataValidationErrors) {
|
||||
final List<ApiParameterError> dataValidationErrors, final String paramName) {
|
||||
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan");
|
||||
baseDataValidator.reset().parameter(LoanProductConstants.recalculationRestFrequencyDateParamName).value(recalculationFrequencyDate)
|
||||
.notNull().validateDateBeforeOrEqual(expectedDisbursementDate);
|
||||
baseDataValidator.reset().parameter(paramName).value(recalculationFrequencyDate).notNull()
|
||||
.validateDateBeforeOrEqual(expectedDisbursementDate);
|
||||
}
|
||||
|
||||
public void validateLoanCharges(final Set<LoanCharge> charges, final List<ApiParameterError> dataValidationErrors) {
|
||||
@@ -974,12 +982,32 @@ public final class LoanApplicationCommandFromApiJsonHelper {
|
||||
}
|
||||
}
|
||||
|
||||
public void validateLoanForInterestRecalculation(final LocalDate recalculationFrequencyDate, final LocalDate expectedDisbursementDate,
|
||||
final Set<LoanCharge> charges) {
|
||||
public void validateLoanForInterestRecalculation(final Loan loan) {
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
validateRecalcuationFrequency(recalculationFrequencyDate, expectedDisbursementDate, dataValidationErrors);
|
||||
validateLoanCharges(charges, dataValidationErrors);
|
||||
LoanInterestRecalculationDetails interestRecalculationDetails = loan.loanInterestRecalculationDetails();
|
||||
if (!interestRecalculationDetails.getRestFrequencyType().isSameAsRepayment()) {
|
||||
String paramName = LoanProductConstants.recalculationRestFrequencyDateParamName;
|
||||
validateRecalcuationFrequency(interestRecalculationDetails.getRestFrequencyLocalDate(), loan.getExpectedDisbursedOnLocalDate(),
|
||||
dataValidationErrors, paramName);
|
||||
}
|
||||
|
||||
if (interestRecalculationDetails.getInterestRecalculationCompoundingMethod().isCompoundingEnabled()
|
||||
&& !interestRecalculationDetails.getCompoundingFrequencyType().isSameAsRepayment()) {
|
||||
String paramName = LoanProductConstants.recalculationCompoundingFrequencyDateParamName;
|
||||
validateCompoundingFrequency(interestRecalculationDetails.getCompoundingFrequencyLocalDate(),
|
||||
loan.getExpectedDisbursedOnLocalDate(), dataValidationErrors, paramName);
|
||||
}
|
||||
|
||||
validateLoanCharges(loan.charges(), dataValidationErrors);
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
public void validateCompoundingFrequency(final LocalDate recalculationFrequencyDate, final LocalDate expectedDisbursementDate,
|
||||
final List<ApiParameterError> dataValidationErrors, final String paramName) {
|
||||
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan");
|
||||
baseDataValidator.reset().parameter(paramName).value(recalculationFrequencyDate).notNull()
|
||||
.validateDateForEqual(expectedDisbursementDate);
|
||||
}
|
||||
|
||||
}
|
||||
+119
-81
@@ -232,11 +232,11 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
validateSubmittedOnDate(newLoanApplication);
|
||||
|
||||
final LoanProductRelatedDetail productRelatedDetail = newLoanApplication.repaymentScheduleDetail();
|
||||
|
||||
if(loanProduct.getLoanProductConfigurableAttributes() != null){
|
||||
updateProductRelatedDetails(productRelatedDetail,newLoanApplication);
|
||||
}
|
||||
|
||||
|
||||
if (loanProduct.getLoanProductConfigurableAttributes() != null) {
|
||||
updateProductRelatedDetails(productRelatedDetail, newLoanApplication);
|
||||
}
|
||||
|
||||
this.fromApiJsonDeserializer.validateLoanTermAndRepaidEveryValues(newLoanApplication.getTermFrequency(),
|
||||
newLoanApplication.getTermPeriodFrequencyType(), productRelatedDetail.getNumberOfRepayments(),
|
||||
productRelatedDetail.getRepayEvery(), productRelatedDetail.getRepaymentPeriodFrequencyType().getValue(),
|
||||
@@ -245,13 +245,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
this.loanRepository.save(newLoanApplication);
|
||||
|
||||
if (loanProduct.isInterestRecalculationEnabled()) {
|
||||
|
||||
final LocalDate recalculationFrequencyDate = this.fromJsonHelper.extractLocalDateNamed(
|
||||
LoanProductConstants.recalculationRestFrequencyDateParamName, command.parsedJson());
|
||||
if (!newLoanApplication.loanInterestRecalculationDetails().getRestFrequencyType().isSameAsRepayment()) {
|
||||
this.fromApiJsonDeserializer.validateLoanForInterestRecalculation(recalculationFrequencyDate,
|
||||
newLoanApplication.getExpectedDisbursedOnLocalDate(), newLoanApplication.charges());
|
||||
}
|
||||
this.fromApiJsonDeserializer.validateLoanForInterestRecalculation(newLoanApplication);
|
||||
createAndPersistCalendarInstanceForInterestRecalculation(newLoanApplication);
|
||||
}
|
||||
|
||||
@@ -306,43 +300,46 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
}
|
||||
}
|
||||
|
||||
private void updateProductRelatedDetails(LoanProductRelatedDetail productRelatedDetail,
|
||||
Loan loan){
|
||||
final Boolean amortization = loan.loanProduct().getLoanProductConfigurableAttributes().getAmortizationBoolean();
|
||||
private void updateProductRelatedDetails(LoanProductRelatedDetail productRelatedDetail, Loan loan) {
|
||||
final Boolean amortization = loan.loanProduct().getLoanProductConfigurableAttributes().getAmortizationBoolean();
|
||||
final Boolean arrearsTolerance = loan.loanProduct().getLoanProductConfigurableAttributes().getArrearsToleranceBoolean();
|
||||
final Boolean graceOnArrearsAging = loan.loanProduct().getLoanProductConfigurableAttributes().getGraceOnArrearsAgingBoolean();
|
||||
final Boolean interestCalcPeriod = loan.loanProduct().getLoanProductConfigurableAttributes().getInterestCalcPeriodBoolean();
|
||||
final Boolean interestMethod = loan.loanProduct().getLoanProductConfigurableAttributes().getInterestMethodBoolean();
|
||||
final Boolean graceOnPrincipalAndInterestPayment = loan.loanProduct().getLoanProductConfigurableAttributes().getGraceOnPrincipalAndInterestPaymentBoolean();
|
||||
final Boolean repaymentEvery = loan.loanProduct().getLoanProductConfigurableAttributes().getRepaymentEveryBoolean();
|
||||
final Boolean transactionProcessingStrategy = loan.loanProduct().getLoanProductConfigurableAttributes().getTransactionProcessingStrategyBoolean();
|
||||
|
||||
if(!amortization){
|
||||
productRelatedDetail.setAmortizationMethod(loan.loanProduct().getLoanProductRelatedDetail().getAmortizationMethod());
|
||||
}
|
||||
if(!arrearsTolerance){
|
||||
productRelatedDetail.setInArrearsTolerance(loan.loanProduct().getLoanProductRelatedDetail().getArrearsTolerance());
|
||||
}
|
||||
if(!graceOnArrearsAging){
|
||||
productRelatedDetail.setGraceOnArrearsAgeing(loan.loanProduct().getLoanProductRelatedDetail().getGraceOnArrearsAgeing());
|
||||
}
|
||||
if(!interestCalcPeriod){
|
||||
productRelatedDetail.setInterestCalculationPeriodMethod(loan.loanProduct().getLoanProductRelatedDetail().getInterestCalculationPeriodMethod());
|
||||
}
|
||||
if(!interestMethod){
|
||||
productRelatedDetail.setInterestMethod(loan.loanProduct().getLoanProductRelatedDetail().getInterestMethod());
|
||||
}
|
||||
if(!graceOnPrincipalAndInterestPayment){
|
||||
productRelatedDetail.setGraceOnInterestPayment(loan.loanProduct().getLoanProductRelatedDetail().getGraceOnInterestPayment());
|
||||
productRelatedDetail.setGraceOnPrincipalPayment(loan.loanProduct().getLoanProductRelatedDetail().getGraceOnPrincipalPayment());
|
||||
}
|
||||
if(!repaymentEvery){
|
||||
productRelatedDetail.setRepayEvery(loan.loanProduct().getLoanProductRelatedDetail().getRepayEvery());
|
||||
}
|
||||
if(!transactionProcessingStrategy){
|
||||
loan.updateTransactionProcessingStrategy(loan.loanProduct().getRepaymentStrategy());
|
||||
}
|
||||
final Boolean interestCalcPeriod = loan.loanProduct().getLoanProductConfigurableAttributes().getInterestCalcPeriodBoolean();
|
||||
final Boolean interestMethod = loan.loanProduct().getLoanProductConfigurableAttributes().getInterestMethodBoolean();
|
||||
final Boolean graceOnPrincipalAndInterestPayment = loan.loanProduct().getLoanProductConfigurableAttributes()
|
||||
.getGraceOnPrincipalAndInterestPaymentBoolean();
|
||||
final Boolean repaymentEvery = loan.loanProduct().getLoanProductConfigurableAttributes().getRepaymentEveryBoolean();
|
||||
final Boolean transactionProcessingStrategy = loan.loanProduct().getLoanProductConfigurableAttributes()
|
||||
.getTransactionProcessingStrategyBoolean();
|
||||
|
||||
if (!amortization) {
|
||||
productRelatedDetail.setAmortizationMethod(loan.loanProduct().getLoanProductRelatedDetail().getAmortizationMethod());
|
||||
}
|
||||
if (!arrearsTolerance) {
|
||||
productRelatedDetail.setInArrearsTolerance(loan.loanProduct().getLoanProductRelatedDetail().getArrearsTolerance());
|
||||
}
|
||||
if (!graceOnArrearsAging) {
|
||||
productRelatedDetail.setGraceOnArrearsAgeing(loan.loanProduct().getLoanProductRelatedDetail().getGraceOnArrearsAgeing());
|
||||
}
|
||||
if (!interestCalcPeriod) {
|
||||
productRelatedDetail.setInterestCalculationPeriodMethod(loan.loanProduct().getLoanProductRelatedDetail()
|
||||
.getInterestCalculationPeriodMethod());
|
||||
}
|
||||
if (!interestMethod) {
|
||||
productRelatedDetail.setInterestMethod(loan.loanProduct().getLoanProductRelatedDetail().getInterestMethod());
|
||||
}
|
||||
if (!graceOnPrincipalAndInterestPayment) {
|
||||
productRelatedDetail.setGraceOnInterestPayment(loan.loanProduct().getLoanProductRelatedDetail().getGraceOnInterestPayment());
|
||||
productRelatedDetail.setGraceOnPrincipalPayment(loan.loanProduct().getLoanProductRelatedDetail().getGraceOnPrincipalPayment());
|
||||
}
|
||||
if (!repaymentEvery) {
|
||||
productRelatedDetail.setRepayEvery(loan.loanProduct().getLoanProductRelatedDetail().getRepayEvery());
|
||||
}
|
||||
if (!transactionProcessingStrategy) {
|
||||
loan.updateTransactionProcessingStrategy(loan.loanProduct().getRepaymentStrategy());
|
||||
}
|
||||
}
|
||||
|
||||
private void createAndPersistCalendarInstanceForInterestRecalculation(final Loan loan) {
|
||||
|
||||
LocalDate calendarStartDate = loan.loanInterestRecalculationDetails().getRestFrequencyLocalDate();
|
||||
@@ -353,6 +350,34 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
final RecalculationFrequencyType recalculationFrequencyType = loan.loanInterestRecalculationDetails().getRestFrequencyType();
|
||||
|
||||
Integer frequency = loan.loanInterestRecalculationDetails().getRestInterval();
|
||||
CalendarEntityType calendarEntityType = CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL;
|
||||
final String title = "loan_recalculation_detail_" + loan.loanInterestRecalculationDetails().getId();
|
||||
|
||||
createCalendar(loan, calendarStartDate, repeatsOnDay, recalculationFrequencyType, frequency, calendarEntityType, title);
|
||||
|
||||
if (loan.loanInterestRecalculationDetails().getInterestRecalculationCompoundingMethod().isCompoundingEnabled()) {
|
||||
LocalDate compoundingStartDate = loan.loanInterestRecalculationDetails().getCompoundingFrequencyLocalDate();
|
||||
if (compoundingStartDate == null) {
|
||||
compoundingStartDate = loan.getExpectedDisbursedOnLocalDate();
|
||||
}
|
||||
final Integer compoundingRepeatsOnDay = compoundingStartDate.getDayOfWeek();
|
||||
final RecalculationFrequencyType recalculationCompoundingFrequencyType = loan.loanInterestRecalculationDetails()
|
||||
.getCompoundingFrequencyType();
|
||||
|
||||
Integer compoundingFrequency = loan.loanInterestRecalculationDetails().getCompoundingInterval();
|
||||
CalendarEntityType compoundingCalendarEntityType = CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL;
|
||||
final String compoundingCalendarTitle = "loan_recalculation_detail_compounding_frequency"
|
||||
+ loan.loanInterestRecalculationDetails().getId();
|
||||
|
||||
createCalendar(loan, compoundingStartDate, compoundingRepeatsOnDay, recalculationCompoundingFrequencyType,
|
||||
compoundingFrequency, compoundingCalendarEntityType, compoundingCalendarTitle);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void createCalendar(final Loan loan, LocalDate calendarStartDate, final Integer repeatsOnDay,
|
||||
final RecalculationFrequencyType recalculationFrequencyType, Integer frequency, CalendarEntityType calendarEntityType,
|
||||
final String title) {
|
||||
CalendarFrequencyType calendarFrequencyType = CalendarFrequencyType.INVALID;
|
||||
switch (recalculationFrequencyType) {
|
||||
case DAILY:
|
||||
@@ -373,16 +398,14 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
break;
|
||||
}
|
||||
|
||||
final String title = "loan_recalculation_detail_" + loan.loanInterestRecalculationDetails().getId();
|
||||
final Calendar calendar = Calendar.createRepeatingCalendar(title, calendarStartDate, CalendarType.COLLECTION.getValue(),
|
||||
calendarFrequencyType, frequency, repeatsOnDay);
|
||||
final CalendarInstance calendarInstance = CalendarInstance.from(calendar, loan.loanInterestRecalculationDetails().getId(),
|
||||
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
||||
calendarEntityType.getValue());
|
||||
this.calendarInstanceRepository.save(calendarInstance);
|
||||
|
||||
}
|
||||
|
||||
private void updateCalendarDetailsForInterestRecalculation(final CalendarInstance calendarInstance, final Loan loan) {
|
||||
private void updateRestCalendarDetailsForInterestRecalculation(final CalendarInstance calendarInstance, final Loan loan) {
|
||||
|
||||
Calendar interestRecalculationRecurrings = calendarInstance.getCalendar();
|
||||
LocalDate calendarStartDate = loan.loanInterestRecalculationDetails().getRestFrequencyLocalDate();
|
||||
@@ -393,6 +416,29 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
final RecalculationFrequencyType recalculationFrequencyType = loan.loanInterestRecalculationDetails().getRestFrequencyType();
|
||||
|
||||
Integer frequency = loan.loanInterestRecalculationDetails().getRestInterval();
|
||||
|
||||
updateCalendar(loan, interestRecalculationRecurrings, calendarStartDate, repeatsOnDay, recalculationFrequencyType, frequency);
|
||||
|
||||
}
|
||||
|
||||
private void updateCompoundingCalendarDetailsForInterestRecalculation(final CalendarInstance calendarInstance, final Loan loan) {
|
||||
|
||||
Calendar interestRecalculationRecurrings = calendarInstance.getCalendar();
|
||||
LocalDate calendarStartDate = loan.loanInterestRecalculationDetails().getCompoundingFrequencyLocalDate();
|
||||
if (calendarStartDate == null) {
|
||||
calendarStartDate = loan.getExpectedDisbursedOnLocalDate();
|
||||
}
|
||||
final Integer repeatsOnDay = calendarStartDate.getDayOfWeek();
|
||||
final RecalculationFrequencyType recalculationFrequencyType = loan.loanInterestRecalculationDetails().getCompoundingFrequencyType();
|
||||
|
||||
Integer frequency = loan.loanInterestRecalculationDetails().getCompoundingInterval();
|
||||
|
||||
updateCalendar(loan, interestRecalculationRecurrings, calendarStartDate, repeatsOnDay, recalculationFrequencyType, frequency);
|
||||
|
||||
}
|
||||
|
||||
private void updateCalendar(final Loan loan, Calendar interestRecalculationRecurrings, LocalDate calendarStartDate,
|
||||
final Integer repeatsOnDay, final RecalculationFrequencyType recalculationFrequencyType, Integer frequency) {
|
||||
CalendarFrequencyType calendarFrequencyType = CalendarFrequencyType.INVALID;
|
||||
switch (recalculationFrequencyType) {
|
||||
case DAILY:
|
||||
@@ -416,7 +462,6 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
|
||||
interestRecalculationRecurrings.updateRepeatingCalendar(calendarStartDate, calendarFrequencyType, frequency, repeatsOnDay);
|
||||
this.calendarRepository.save(interestRecalculationRecurrings);
|
||||
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@@ -503,10 +548,10 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
}
|
||||
|
||||
final String productIdParamName = "productId";
|
||||
if (changes.containsKey(productIdParamName)) {
|
||||
final Long productId = command.longValueOfParameterNamed(productIdParamName);
|
||||
final LoanProduct loanProduct = this.loanProductRepository.findOne(productId);
|
||||
if (loanProduct == null) { throw new LoanProductNotFoundException(productId); }
|
||||
if (changes.containsKey(productIdParamName)) {
|
||||
final Long productId = command.longValueOfParameterNamed(productIdParamName);
|
||||
final LoanProduct loanProduct = this.loanProductRepository.findOne(productId);
|
||||
if (loanProduct == null) { throw new LoanProductNotFoundException(productId); }
|
||||
|
||||
existingLoanApplication.updateLoanProduct(loanProduct);
|
||||
if (!changes.containsKey("interestRateFrequencyType")) {
|
||||
@@ -537,10 +582,10 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
validateSubmittedOnDate(existingLoanApplication);
|
||||
|
||||
final LoanProductRelatedDetail productRelatedDetail = existingLoanApplication.repaymentScheduleDetail();
|
||||
if(existingLoanApplication.loanProduct().getLoanProductConfigurableAttributes() != null){
|
||||
updateProductRelatedDetails(productRelatedDetail,existingLoanApplication);
|
||||
}
|
||||
|
||||
if (existingLoanApplication.loanProduct().getLoanProductConfigurableAttributes() != null) {
|
||||
updateProductRelatedDetails(productRelatedDetail, existingLoanApplication);
|
||||
}
|
||||
|
||||
final String fundIdParamName = "fundId";
|
||||
if (changes.containsKey(fundIdParamName)) {
|
||||
final Long fundId = command.longValueOfParameterNamed(fundIdParamName);
|
||||
@@ -693,30 +738,23 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa
|
||||
this.loanRepository.save(existingLoanApplication);
|
||||
|
||||
if (productRelatedDetail.isInterestRecalculationEnabled()) {
|
||||
LocalDate recalculationFrequencyDate = existingLoanApplication.loanInterestRecalculationDetails()
|
||||
.getRestFrequencyLocalDate();
|
||||
if (recalculationFrequencyDate == null) {
|
||||
recalculationFrequencyDate = existingLoanApplication.loanProduct().getProductInterestRecalculationDetails()
|
||||
.getRestFrequencyLocalDate();
|
||||
}
|
||||
if (this.fromJsonHelper.parameterExists(LoanProductConstants.recalculationRestFrequencyDateParamName, command.parsedJson())) {
|
||||
recalculationFrequencyDate = this.fromJsonHelper.extractLocalDateNamed(
|
||||
LoanProductConstants.recalculationRestFrequencyDateParamName, command.parsedJson());
|
||||
if (!existingLoanApplication.loanInterestRecalculationDetails().getRestFrequencyType().isSameAsRepayment()) {
|
||||
this.fromApiJsonDeserializer.validateLoanForInterestRecalculation(recalculationFrequencyDate,
|
||||
existingLoanApplication.getExpectedDisbursedOnLocalDate(), existingLoanApplication.charges());
|
||||
}
|
||||
}
|
||||
|
||||
CalendarInstance calendarInstance = this.calendarInstanceRepository.findByEntityIdAndEntityTypeIdAndCalendarTypeId(
|
||||
existingLoanApplication.loanInterestRecalculationDetailId(),
|
||||
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue(), CalendarType.COLLECTION.getValue());
|
||||
|
||||
if (calendarInstance == null) {
|
||||
this.fromApiJsonDeserializer.validateLoanForInterestRecalculation(existingLoanApplication);
|
||||
if (changes.containsKey(LoanProductConstants.isInterestRecalculationEnabledParameterName)) {
|
||||
createAndPersistCalendarInstanceForInterestRecalculation(existingLoanApplication);
|
||||
|
||||
} else {
|
||||
updateCalendarDetailsForInterestRecalculation(calendarInstance, existingLoanApplication);
|
||||
if (changes.containsKey(LoanProductConstants.recalculationRestFrequencyDateParamName)) {
|
||||
|
||||
CalendarInstance calendarInstance = this.calendarInstanceRepository.findByEntityIdAndEntityTypeIdAndCalendarTypeId(
|
||||
existingLoanApplication.loanInterestRecalculationDetailId(),
|
||||
CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue(), CalendarType.COLLECTION.getValue());
|
||||
updateRestCalendarDetailsForInterestRecalculation(calendarInstance, existingLoanApplication);
|
||||
}
|
||||
if (changes.containsKey(LoanProductConstants.recalculationCompoundingFrequencyDateParamName)) {
|
||||
CalendarInstance calendarInstance = this.calendarInstanceRepository.findByEntityIdAndEntityTypeIdAndCalendarTypeId(
|
||||
existingLoanApplication.loanInterestRecalculationDetailId(),
|
||||
CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue(), CalendarType.COLLECTION.getValue());
|
||||
updateCompoundingCalendarDetailsForInterestRecalculation(calendarInstance, existingLoanApplication);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-2
@@ -270,6 +270,8 @@ public class LoanAssembler {
|
||||
|
||||
final LocalDate recalculationRestFrequencyDate = this.fromApiJsonHelper.extractLocalDateNamed(
|
||||
LoanProductConstants.recalculationRestFrequencyDateParamName, element);
|
||||
final LocalDate recalculationCompoundingFrequencyDate = this.fromApiJsonHelper.extractLocalDateNamed(
|
||||
LoanProductConstants.recalculationCompoundingFrequencyDateParamName, element);
|
||||
|
||||
final LoanApplicationTerms loanApplicationTerms = this.loanScheduleAssembler.assembleLoanTerms(element);
|
||||
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
|
||||
@@ -282,7 +284,7 @@ public class LoanAssembler {
|
||||
isHolidayEnabled, holidays, workingDays, element);
|
||||
loanApplication.loanApplicationSubmittal(currentUser, loanScheduleModel, loanApplicationTerms, defaultLoanLifecycleStateMachine(),
|
||||
submittedOnDate, externalId, allowTransactionsOnHoliday, holidays, workingDays, allowTransactionsOnNonWorkingDay,
|
||||
recalculationRestFrequencyDate);
|
||||
recalculationRestFrequencyDate, recalculationCompoundingFrequencyDate);
|
||||
|
||||
return loanApplication;
|
||||
}
|
||||
@@ -313,7 +315,7 @@ public class LoanAssembler {
|
||||
&& StringUtils.isNotBlank((jsonObject.get(LoanApiConstants.disbursementPrincipalParameterName).getAsString()))) {
|
||||
principal = jsonObject.getAsJsonPrimitive(LoanApiConstants.disbursementPrincipalParameterName).getAsBigDecimal();
|
||||
}
|
||||
|
||||
|
||||
disbursementDatas.add(new LoanDisbursementDetails(expectedDisbursementDate, actualDisbursementDate, principal));
|
||||
i++;
|
||||
} while (i < disbursementDataArray.size());
|
||||
|
||||
+23
-4
@@ -82,6 +82,7 @@ import org.mifosplatform.portfolio.loanaccount.data.PaidInAdvanceData;
|
||||
import org.mifosplatform.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanStatus;
|
||||
import org.mifosplatform.portfolio.loanaccount.domain.LoanTermVariationType;
|
||||
@@ -140,6 +141,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
private final ConfigurationDomainService configurationDomainService;
|
||||
private final WorkingDaysRepositoryWrapper workingDaysRepository;
|
||||
private final PaymentTypeReadPlatformService paymentTypeReadPlatformService;
|
||||
private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
|
||||
|
||||
@Autowired
|
||||
public LoanReadPlatformServiceImpl(final PlatformSecurityContext context, final LoanRepository loanRepository,
|
||||
@@ -152,7 +154,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
final CalendarReadPlatformService calendarReadPlatformService, final StaffReadPlatformService staffReadPlatformService,
|
||||
final LoanScheduleGeneratorFactory loanScheduleFactory, final CalendarInstanceRepository calendarInstanceRepository,
|
||||
final HolidayRepository holidayRepository, final ConfigurationDomainService configurationDomainService,
|
||||
final WorkingDaysRepositoryWrapper workingDaysRepository, PaymentTypeReadPlatformService paymentTypeReadPlatformService) {
|
||||
final WorkingDaysRepositoryWrapper workingDaysRepository, PaymentTypeReadPlatformService paymentTypeReadPlatformService,
|
||||
final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory) {
|
||||
this.context = context;
|
||||
this.loanRepository = loanRepository;
|
||||
this.loanTransactionRepository = loanTransactionRepository;
|
||||
@@ -174,6 +177,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
this.configurationDomainService = configurationDomainService;
|
||||
this.workingDaysRepository = workingDaysRepository;
|
||||
this.paymentTypeReadPlatformService = paymentTypeReadPlatformService;
|
||||
this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -404,6 +408,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
|
||||
final Loan loan = this.loanRepository.findOne(loanId);
|
||||
if (loan == null) { throw new LoanNotFoundException(loanId); }
|
||||
loan.setHelpers(null, null, loanRepaymentScheduleTransactionProcessorFactory);
|
||||
|
||||
final MonetaryCurrency currency = loan.getCurrency();
|
||||
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
|
||||
@@ -413,10 +418,13 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
final LocalDate earliestUnpaidInstallmentDate = LocalDate.now();
|
||||
|
||||
CalendarInstance restCalendarInstance = null;
|
||||
CalendarInstance compoundingCalendarInstance = null;
|
||||
HolidayDetailDTO holidayDetailDTO = null;
|
||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
|
||||
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
||||
CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
|
||||
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
||||
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
|
||||
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), loan
|
||||
.getDisbursementDate().toDate(), HolidayStatusType.ACTIVE.getValue());
|
||||
@@ -425,7 +433,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
}
|
||||
|
||||
final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment = loan.fetchPrepaymentDetail(this.loanScheduleFactory,
|
||||
restCalendarInstance, holidayDetailDTO, onDate);
|
||||
restCalendarInstance, compoundingCalendarInstance, holidayDetailDTO, onDate);
|
||||
final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.REPAYMENT);
|
||||
final Collection<PaymentTypeData> paymentOptions = this.paymentTypeReadPlatformService.retrieveAllPaymentTypes();
|
||||
final BigDecimal outstandingLoanBalance = loanRepaymentScheduleInstallment.getPrincipalOutstanding(currency).getAmount();
|
||||
@@ -600,6 +608,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
+ " lir.id as lirId, lir.loan_id as loanId, lir.compound_type_enum as compoundType, lir.reschedule_strategy_enum as rescheduleStrategy, "
|
||||
+ " lir.rest_frequency_type_enum as restFrequencyEnum, lir.rest_frequency_interval as restFrequencyInterval, "
|
||||
+ " lir.rest_freqency_date as restFrequencyDate, "
|
||||
+ " lir.compounding_frequency_type_enum as compoundingFrequencyEnum, lir.compounding_frequency_interval as compoundingInterval, "
|
||||
+ " lir.compounding_freqency_date as compoundingFrequencyDate, "
|
||||
+ " l.create_standing_instruction_at_disbursement as createStandingInstructionAtDisbursement "
|
||||
+ " from m_loan l" //
|
||||
+ " join m_product_loan lp on lp.id = l.product_id" //
|
||||
@@ -857,9 +867,18 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
|
||||
final EnumOptionData restFrequencyType = LoanEnumerations.interestRecalculationFrequencyType(restFrequencyEnumValue);
|
||||
final int restFrequencyInterval = JdbcSupport.getInteger(rs, "restFrequencyInterval");
|
||||
final LocalDate restFrequencyDate = JdbcSupport.getLocalDate(rs, "restFrequencyDate");
|
||||
final CalendarData compoundingCalendarData = null;
|
||||
final Integer compoundingFrequencyEnumValue = JdbcSupport.getInteger(rs, "compoundingFrequencyEnum");
|
||||
EnumOptionData compoundingFrequencyType = null;
|
||||
if (compoundingFrequencyEnumValue != null) {
|
||||
compoundingFrequencyType = LoanEnumerations.interestRecalculationFrequencyType(compoundingFrequencyEnumValue);
|
||||
}
|
||||
final Integer compoundingInterval = JdbcSupport.getInteger(rs, "compoundingInterval");
|
||||
final LocalDate compoundingFrequencyDate = JdbcSupport.getLocalDate(rs, "compoundingFrequencyDate");
|
||||
|
||||
interestRecalculationData = new LoanInterestRecalculationData(lprId, productId, interestRecalculationCompoundingType,
|
||||
rescheduleStrategyType, calendarData, restFrequencyType, restFrequencyInterval, restFrequencyDate);
|
||||
rescheduleStrategyType, calendarData, restFrequencyType, restFrequencyInterval, restFrequencyDate,
|
||||
compoundingCalendarData, compoundingFrequencyType, compoundingInterval, compoundingFrequencyDate);
|
||||
}
|
||||
|
||||
return LoanAccountData.basicLoanDetails(id, accountNo, status, externalId, clientId, clientName, clientOfficeId, groupData,
|
||||
|
||||
+76
-50
@@ -340,19 +340,21 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
}
|
||||
|
||||
CalendarInstance restCalendarInstance = null;
|
||||
CalendarInstance compoundingCalendarInstance = null;
|
||||
LocalDate recalculateFrom = null;
|
||||
Long overdurPenaltyWaitPeriod = null;
|
||||
LocalDate lastTransactionDate = null;
|
||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
|
||||
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
||||
CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
|
||||
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
||||
overdurPenaltyWaitPeriod = this.configurationDomainService.retrievePenaltyWaitPeriod();
|
||||
}
|
||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays, allowTransactionsOnHoliday,
|
||||
allowTransactionsOnNonWorkingDay);
|
||||
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, recalculateFrom,
|
||||
overdurPenaltyWaitPeriod, lastTransactionDate);
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance,
|
||||
recalculateFrom, overdurPenaltyWaitPeriod);
|
||||
|
||||
regenerateScheduleOnDisbursement(command, loan, recalculateSchedule, scheduleGeneratorDTO);
|
||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
@@ -472,7 +474,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
&& loan.loanInterestRecalculationDetails().getRestFrequencyType().isSameAsRepayment() && !loan.isDisbursed()) {
|
||||
final CalendarInstance calendarInstanceForInterestRecalculation = this.calendarInstanceRepository
|
||||
.findByEntityIdAndEntityTypeIdAndCalendarTypeId(loan.loanInterestRecalculationDetailId(),
|
||||
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue(), CalendarType.COLLECTION.getValue());
|
||||
CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue(), CalendarType.COLLECTION.getValue());
|
||||
|
||||
Calendar calendarForInterestRecalculation = calendarInstanceForInterestRecalculation.getCalendar();
|
||||
calendarForInterestRecalculation.updateStartAndEndDate(loan.getDisbursementDate(), loan.getMaturityDate());
|
||||
@@ -595,19 +597,21 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
loan.getLoanTransactions().add(disbursementTransaction);
|
||||
}
|
||||
CalendarInstance restCalendarInstance = null;
|
||||
CalendarInstance compoundingCalendarInstance = null;
|
||||
LocalDate recalculateFrom = null;
|
||||
Long overdurPenaltyWaitPeriod = null;
|
||||
LocalDate lastTransactionDate = null;
|
||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
|
||||
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
||||
overdurPenaltyWaitPeriod = this.configurationDomainService.retrievePenaltyWaitPeriod();
|
||||
}
|
||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays,
|
||||
allowTransactionsOnHoliday, allowTransactionsOnNonWorkingDay);
|
||||
final ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
||||
firstRepaymentOnDate, holidayDetailDTO, restCalendarInstance, recalculateFrom, overdurPenaltyWaitPeriod,
|
||||
lastTransactionDate);
|
||||
firstRepaymentOnDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
||||
overdurPenaltyWaitPeriod);
|
||||
regenerateScheduleOnDisbursement(command, loan, recalculateSchedule, scheduleGeneratorDTO);
|
||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
this.loanScheduleHistoryWritePlatformService.createAndSaveLoanScheduleArchive(
|
||||
@@ -697,13 +701,16 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
||||
CalendarInstance restCalendarInstance = null;
|
||||
CalendarInstance compoundingCalendarInstance = null;
|
||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
|
||||
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
||||
CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
|
||||
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
||||
}
|
||||
|
||||
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(this.loanScheduleFactory, applicationCurrency,
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance);
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance);
|
||||
|
||||
final Map<String, Object> changes = loan.undoDisbursal(scheduleGeneratorDTO, existingTransactionIds,
|
||||
existingReversedTransactionIds, currentUser);
|
||||
@@ -860,16 +867,18 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final boolean allowTransactionsOnNonWorkingDay = this.configurationDomainService.allowTransactionsOnNonWorkingDayEnabled();
|
||||
|
||||
CalendarInstance restCalendarInstance = null;
|
||||
CalendarInstance compoundingCalendarInstance = null;
|
||||
ApplicationCurrency applicationCurrency = null;
|
||||
LocalDate calculatedRepaymentsStartingFromDate = null;
|
||||
boolean isHolidayEnabled = false;
|
||||
LocalDate recalculateFrom = null;
|
||||
Long overdurPenaltyWaitPeriod = null;
|
||||
LocalDate lastTransactionDate = null;
|
||||
|
||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
|
||||
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
||||
CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
|
||||
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
||||
|
||||
final MonetaryCurrency currency = loan.getCurrency();
|
||||
applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
|
||||
@@ -885,8 +894,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays, allowTransactionsOnHoliday,
|
||||
allowTransactionsOnNonWorkingDay);
|
||||
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, recalculateFrom, overdurPenaltyWaitPeriod,
|
||||
lastTransactionDate);
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
||||
overdurPenaltyWaitPeriod);
|
||||
|
||||
final ChangedTransactionDetail changedTransactionDetail = loan.adjustExistingTransaction(newTransactionDetail,
|
||||
defaultLoanLifecycleStateMachine(), transactionToAdjust, existingTransactionIds, existingReversedTransactionIds,
|
||||
@@ -990,6 +999,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.LOAN_WAIVE_INTEREST,
|
||||
constructEntityMap(BUSINESS_ENTITY.LOAN_TRANSACTION, waiveInterestTransaction));
|
||||
CalendarInstance restCalendarInstance = null;
|
||||
CalendarInstance compoundingCalendarInstance = null;
|
||||
ApplicationCurrency applicationCurrency = null;
|
||||
LocalDate calculatedRepaymentsStartingFromDate = null;
|
||||
List<Holiday> holidays = null;
|
||||
@@ -997,10 +1007,11 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
WorkingDays workingDays = null;
|
||||
LocalDate recalculateFrom = null;
|
||||
Long overdurPenaltyWaitPeriod = null;
|
||||
LocalDate lastTransactionDate = null;
|
||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
|
||||
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
||||
CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
|
||||
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
||||
|
||||
final MonetaryCurrency currency = loan.getCurrency();
|
||||
applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
|
||||
@@ -1017,8 +1028,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
||||
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, recalculateFrom, overdurPenaltyWaitPeriod,
|
||||
lastTransactionDate);
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
||||
overdurPenaltyWaitPeriod);
|
||||
final ChangedTransactionDetail changedTransactionDetail = loan.waiveInterest(waiveInterestTransaction,
|
||||
defaultLoanLifecycleStateMachine(), existingTransactionIds, existingReversedTransactionIds, scheduleGeneratorDTO,
|
||||
currentUser);
|
||||
@@ -1099,18 +1110,20 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
|
||||
|
||||
CalendarInstance restCalendarInstance = null;
|
||||
CalendarInstance compoundingCalendarInstance = null;
|
||||
LocalDate recalculateFrom = null;
|
||||
Long overdurPenaltyWaitPeriod = null;
|
||||
LocalDate lastTransactionDate = null;
|
||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
|
||||
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
||||
CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
|
||||
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
||||
overdurPenaltyWaitPeriod = this.configurationDomainService.retrievePenaltyWaitPeriod();
|
||||
}
|
||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
||||
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, recalculateFrom, overdurPenaltyWaitPeriod,
|
||||
lastTransactionDate);
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
||||
overdurPenaltyWaitPeriod);
|
||||
|
||||
final ChangedTransactionDetail changedTransactionDetail = loan.closeAsWrittenOff(command, defaultLoanLifecycleStateMachine(),
|
||||
changes, existingTransactionIds, existingReversedTransactionIds, currentUser, scheduleGeneratorDTO);
|
||||
@@ -1178,20 +1191,22 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
|
||||
|
||||
CalendarInstance restCalendarInstance = null;
|
||||
CalendarInstance compoundingCalendarInstance = null;
|
||||
LocalDate recalculateFrom = null;
|
||||
Long overdurPenaltyWaitPeriod = null;
|
||||
LocalDate lastTransactionDate = null;
|
||||
|
||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
|
||||
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
||||
CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
|
||||
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
||||
overdurPenaltyWaitPeriod = this.configurationDomainService.retrievePenaltyWaitPeriod();
|
||||
}
|
||||
|
||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
||||
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(this.loanScheduleFactory, applicationCurrency,
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, recalculateFrom, overdurPenaltyWaitPeriod,
|
||||
lastTransactionDate);
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
||||
overdurPenaltyWaitPeriod);
|
||||
ChangedTransactionDetail changedTransactionDetail = loan.close(command, defaultLoanLifecycleStateMachine(), changes,
|
||||
existingTransactionIds, existingReversedTransactionIds, scheduleGeneratorDTO, currentUser);
|
||||
final LoanTransaction possibleClosingTransaction = changedTransactionDetail.getNewTransactionMappings().remove(0L);
|
||||
@@ -1376,7 +1391,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
AppUser currentUser = getAppUserIfPresent();
|
||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
CalendarInstance restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
|
||||
CalendarInstance compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
||||
|
||||
final MonetaryCurrency currency = loan.getCurrency();
|
||||
ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
|
||||
@@ -1392,12 +1409,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final Long overdurPenaltyWaitPeriod = this.configurationDomainService.retrievePenaltyWaitPeriod();
|
||||
|
||||
LocalDate recalculateFrom = null;
|
||||
LocalDate lastTransactionDate = null;
|
||||
|
||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
||||
ScheduleGeneratorDTO generatorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, recalculateFrom,
|
||||
overdurPenaltyWaitPeriod, lastTransactionDate);
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance,
|
||||
recalculateFrom, overdurPenaltyWaitPeriod);
|
||||
ChangedTransactionDetail changedTransactionDetail = loan.handleRegenerateRepaymentScheduleWithInterestRecalculation(
|
||||
generatorDTO, currentUser);
|
||||
saveLoanWithDataIntegrityViolationChecks(loan);
|
||||
@@ -1431,13 +1446,16 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
||||
CalendarInstance restCalendarInstance = null;
|
||||
CalendarInstance compoundingCalendarInstance = null;
|
||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
|
||||
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
||||
CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
|
||||
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
||||
}
|
||||
|
||||
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance);
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance);
|
||||
createLoanScheduleArchive(loan, scheduleGeneratorDTO);
|
||||
}
|
||||
|
||||
@@ -1564,17 +1582,19 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final List<Long> existingTransactionIds = new ArrayList<>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<>();
|
||||
CalendarInstance restCalendarInstance = null;
|
||||
CalendarInstance compoundingCalendarInstance = null;
|
||||
ApplicationCurrency applicationCurrency = null;
|
||||
LocalDate calculatedRepaymentsStartingFromDate = null;
|
||||
List<Holiday> holidays = null;
|
||||
boolean isHolidayEnabled = false;
|
||||
WorkingDays workingDays = null;
|
||||
LocalDate recalculateFrom = null;
|
||||
LocalDate lastTransactionDate = null;
|
||||
Long overdurPenaltyWaitPeriod = null;
|
||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
|
||||
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
||||
CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
|
||||
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
||||
|
||||
final MonetaryCurrency currency = loan.getCurrency();
|
||||
applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
|
||||
@@ -1591,8 +1611,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
||||
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, recalculateFrom, overdurPenaltyWaitPeriod,
|
||||
lastTransactionDate);
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
||||
overdurPenaltyWaitPeriod);
|
||||
|
||||
Money accruedCharge = Money.zero(loan.getCurrency());
|
||||
if (loan.isPeriodicAccrualAccountingEnabledOnLoanProduct()) {
|
||||
@@ -2510,6 +2530,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
"error.msg.loan.status.not.written.off.update.not.allowed", "Loan :" + loanId
|
||||
+ " update not allowed as loan status is not written off", loanId); }
|
||||
CalendarInstance restCalendarInstance = null;
|
||||
CalendarInstance compoundingCalendarInstance = null;
|
||||
ApplicationCurrency applicationCurrency = null;
|
||||
LocalDate calculatedRepaymentsStartingFromDate = null;
|
||||
List<Holiday> holidays = null;
|
||||
@@ -2517,13 +2538,14 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
WorkingDays workingDays = null;
|
||||
LocalDate recalculateFrom = null;
|
||||
Long overdurPenaltyWaitPeriod = null;
|
||||
LocalDate lastTransactionDate = null;
|
||||
LoanTransaction writeOffTransaction = loan.findWriteOffTransaction();
|
||||
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.LOAN_UNDO_WRITTEN_OFF,
|
||||
constructEntityMap(BUSINESS_ENTITY.LOAN_TRANSACTION, writeOffTransaction));
|
||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
|
||||
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
||||
CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
|
||||
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
||||
|
||||
final MonetaryCurrency currency = loan.getCurrency();
|
||||
applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
|
||||
@@ -2540,8 +2562,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
||||
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, recalculateFrom, overdurPenaltyWaitPeriod,
|
||||
lastTransactionDate);
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
||||
overdurPenaltyWaitPeriod);
|
||||
|
||||
ChangedTransactionDetail changedTransactionDetail = loan.undoWrittenOff(existingTransactionIds, existingReversedTransactionIds,
|
||||
scheduleGeneratorDTO, currentUser);
|
||||
@@ -2655,19 +2677,21 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<>();
|
||||
final Map<String, Object> changes = new LinkedHashMap<>();
|
||||
CalendarInstance restCalendarInstance = null;
|
||||
CalendarInstance compoundingCalendarInstance = null;
|
||||
LocalDate recalculateFrom = null;
|
||||
Long overdurPenaltyWaitPeriod = null;
|
||||
LocalDate lastTransactionDate = null;
|
||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
|
||||
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
||||
CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
|
||||
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
||||
overdurPenaltyWaitPeriod = this.configurationDomainService.retrievePenaltyWaitPeriod();
|
||||
}
|
||||
|
||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
||||
ScheduleGeneratorDTO scheduleGeneratorDTO = new ScheduleGeneratorDTO(this.loanScheduleFactory, applicationCurrency,
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, recalculateFrom, overdurPenaltyWaitPeriod,
|
||||
lastTransactionDate);
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
||||
overdurPenaltyWaitPeriod);
|
||||
|
||||
ChangedTransactionDetail changedTransactionDetail = null;
|
||||
AppUser currentUser = getAppUserIfPresent();
|
||||
@@ -2815,6 +2839,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.LOAN_INTEREST_RECALCULATION,
|
||||
constructEntityMap(BUSINESS_ENTITY.LOAN, loan));
|
||||
CalendarInstance restCalendarInstance = null;
|
||||
CalendarInstance compoundingCalendarInstance = null;
|
||||
ApplicationCurrency applicationCurrency = null;
|
||||
LocalDate calculatedRepaymentsStartingFromDate = null;
|
||||
List<Holiday> holidays = null;
|
||||
@@ -2822,12 +2847,13 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
WorkingDays workingDays = null;
|
||||
LocalDate recalculateFrom = null;
|
||||
Long overdurPenaltyWaitPeriod = null;
|
||||
LocalDate lastTransactionDate = null;
|
||||
final List<Long> existingTransactionIds = new ArrayList<>();
|
||||
final List<Long> existingReversedTransactionIds = new ArrayList<>();
|
||||
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
|
||||
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
|
||||
CalendarEntityType.LOAN_RECALCULATION_DETAIL.getValue());
|
||||
CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
|
||||
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
|
||||
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
|
||||
|
||||
final MonetaryCurrency currency = loan.getCurrency();
|
||||
applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
|
||||
@@ -2843,8 +2869,8 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
}
|
||||
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
||||
ScheduleGeneratorDTO generatorDTO = new ScheduleGeneratorDTO(loanScheduleFactory, applicationCurrency,
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, recalculateFrom, overdurPenaltyWaitPeriod,
|
||||
lastTransactionDate);
|
||||
calculatedRepaymentsStartingFromDate, holidayDetailDTO, restCalendarInstance, compoundingCalendarInstance, recalculateFrom,
|
||||
overdurPenaltyWaitPeriod);
|
||||
|
||||
ChangedTransactionDetail changedTransactionDetail = loan.recalculateScheduleFromLastTransaction(generatorDTO,
|
||||
existingTransactionIds, existingReversedTransactionIds, currentUser);
|
||||
|
||||
+3
@@ -76,6 +76,9 @@ public interface LoanProductConstants {
|
||||
public static final String recalculationRestFrequencyDateParamName = "recalculationRestFrequencyDate";
|
||||
public static final String isArrearsBasedOnOriginalScheduleParamName = "isArrearsBasedOnOriginalSchedule";
|
||||
public static final String preClosureInterestCalculationStrategyParamName = "preClosureInterestCalculationStrategy";
|
||||
public static final String recalculationCompoundingFrequencyTypeParameterName = "recalculationCompoundingFrequencyType";
|
||||
public static final String recalculationCompoundingFrequencyIntervalParameterName = "recalculationCompoundingFrequencyInterval";
|
||||
public static final String recalculationCompoundingFrequencyDateParamName = "recalculationCompoundingFrequencyDate";
|
||||
|
||||
// Guarantee related
|
||||
public static final String holdGuaranteeFundsParamName = "holdGuaranteeFunds";
|
||||
|
||||
+23
-5
@@ -370,7 +370,8 @@ public class LoanProductData {
|
||||
multiDisburseLoan, maxTrancheCount, outstandingLoanBalance, graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType,
|
||||
daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment,
|
||||
holdGuaranteeFunds, productGuaranteeData, principalThresholdForLastInstallment,
|
||||
accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount, installmentAmountInMultiplesOf, loanProductConfigurableAttributes);
|
||||
accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount, installmentAmountInMultiplesOf,
|
||||
loanProductConfigurableAttributes);
|
||||
|
||||
}
|
||||
|
||||
@@ -827,9 +828,11 @@ public class LoanProductData {
|
||||
final Long id = null;
|
||||
final Long loanId = null;
|
||||
final CalendarData calendarData = null;
|
||||
final CalendarData compoundingCalendarData = null;
|
||||
return new LoanInterestRecalculationData(id, loanId, getInterestRecalculationCompoundingType(), getRescheduleStrategyType(),
|
||||
calendarData, getRecalculationRestFrequencyType(), getRecalculationRestFrequencyInterval(),
|
||||
getRecalculationRestFrequencyDate());
|
||||
getRecalculationRestFrequencyDate(), compoundingCalendarData, getRecalculationCompoundingFrequencyType(),
|
||||
getRecalculationCompoundingFrequencyInterval(), getRecalculationCompoundingFrequencyDate());
|
||||
}
|
||||
|
||||
private EnumOptionData getRescheduleStrategyType() {
|
||||
@@ -847,20 +850,35 @@ public class LoanProductData {
|
||||
return null;
|
||||
}
|
||||
|
||||
public EnumOptionData getRecalculationRestFrequencyType() {
|
||||
private EnumOptionData getRecalculationRestFrequencyType() {
|
||||
if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.getRecalculationRestFrequencyType(); }
|
||||
return null;
|
||||
}
|
||||
|
||||
public Integer getRecalculationRestFrequencyInterval() {
|
||||
private Integer getRecalculationRestFrequencyInterval() {
|
||||
if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.getRecalculationRestFrequencyInterval(); }
|
||||
return null;
|
||||
}
|
||||
|
||||
private LocalDate getRecalculationCompoundingFrequencyDate() {
|
||||
if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.getRecalculationCompoundingFrequencyDate(); }
|
||||
return null;
|
||||
}
|
||||
|
||||
private EnumOptionData getRecalculationCompoundingFrequencyType() {
|
||||
if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.getRecalculationCompoundingFrequencyType(); }
|
||||
return null;
|
||||
}
|
||||
|
||||
private Integer getRecalculationCompoundingFrequencyInterval() {
|
||||
if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.getRecalculationCompoundingFrequencyInterval(); }
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean canDefineInstallmentAmount() {
|
||||
return this.canDefineInstallmentAmount;
|
||||
}
|
||||
|
||||
|
||||
public LoanProductConfigurableAttributes getloanProductConfigurableAttributes() {
|
||||
return this.allowAttributeOverrides;
|
||||
}
|
||||
|
||||
+25
-2
@@ -26,6 +26,9 @@ public class LoanProductInterestRecalculationData {
|
||||
private final EnumOptionData recalculationRestFrequencyType;
|
||||
private final Integer recalculationRestFrequencyInterval;
|
||||
private final LocalDate recalculationRestFrequencyDate;
|
||||
private final EnumOptionData recalculationCompoundingFrequencyType;
|
||||
private final Integer recalculationCompoundingFrequencyInterval;
|
||||
private final LocalDate recalculationCompoundingFrequencyDate;
|
||||
@SuppressWarnings("unused")
|
||||
private final boolean isArrearsBasedOnOriginalSchedule;
|
||||
@SuppressWarnings("unused")
|
||||
@@ -34,8 +37,9 @@ public class LoanProductInterestRecalculationData {
|
||||
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 EnumOptionData preCloseInterestCalculationStrategy) {
|
||||
final LocalDate recalculationRestFrequencyDate, final EnumOptionData recalculationCompoundingFrequencyType,
|
||||
final Integer recalculationCompoundingFrequencyInterval, final LocalDate recalculationCompoundingFrequencyDate,
|
||||
final boolean isArrearsBasedOnOriginalSchedule, final EnumOptionData preCloseInterestCalculationStrategy) {
|
||||
this.id = id;
|
||||
this.productId = productId;
|
||||
this.interestRecalculationCompoundingType = interestRecalculationCompoundingType;
|
||||
@@ -43,6 +47,9 @@ public class LoanProductInterestRecalculationData {
|
||||
this.recalculationRestFrequencyType = recalculationRestFrequencyType;
|
||||
this.recalculationRestFrequencyInterval = recalculationRestFrequencyInterval;
|
||||
this.recalculationRestFrequencyDate = recalculationRestFrequencyDate;
|
||||
this.recalculationCompoundingFrequencyType = recalculationCompoundingFrequencyType;
|
||||
this.recalculationCompoundingFrequencyInterval = recalculationCompoundingFrequencyInterval;
|
||||
this.recalculationCompoundingFrequencyDate = recalculationCompoundingFrequencyDate;
|
||||
this.isArrearsBasedOnOriginalSchedule = isArrearsBasedOnOriginalSchedule;
|
||||
this.preClosureInterestCalculationStrategy = preCloseInterestCalculationStrategy;
|
||||
}
|
||||
@@ -55,10 +62,14 @@ public class LoanProductInterestRecalculationData {
|
||||
final EnumOptionData recalculationRestFrequencyType = null;
|
||||
final Integer recalculationRestFrequencyInterval = null;
|
||||
final LocalDate recalculationRestFrequencyDate = null;
|
||||
final EnumOptionData recalculationCompoundingFrequencyType = null;
|
||||
final Integer recalculationCompoundingFrequencyInterval = null;
|
||||
final LocalDate recalculationCompoundingFrequencyDate = null;
|
||||
final boolean isArrearsBasedOnOriginalSchedule = false;
|
||||
final EnumOptionData preCloseInterestCalculationStrategy = preCloseInterestCalculationStrategy(LoanPreClosureInterestCalculationStrategy.TILL_PRE_CLOSURE_DATE);
|
||||
return new LoanProductInterestRecalculationData(id, productId, interestRecalculationCompoundingType, rescheduleStrategyType,
|
||||
recalculationRestFrequencyType, recalculationRestFrequencyInterval, recalculationRestFrequencyDate,
|
||||
recalculationCompoundingFrequencyType, recalculationCompoundingFrequencyInterval, recalculationCompoundingFrequencyDate,
|
||||
isArrearsBasedOnOriginalSchedule, preCloseInterestCalculationStrategy);
|
||||
}
|
||||
|
||||
@@ -82,4 +93,16 @@ public class LoanProductInterestRecalculationData {
|
||||
return this.recalculationRestFrequencyInterval;
|
||||
}
|
||||
|
||||
public EnumOptionData getRecalculationCompoundingFrequencyType() {
|
||||
return this.recalculationCompoundingFrequencyType;
|
||||
}
|
||||
|
||||
public Integer getRecalculationCompoundingFrequencyInterval() {
|
||||
return this.recalculationCompoundingFrequencyInterval;
|
||||
}
|
||||
|
||||
public LocalDate getRecalculationCompoundingFrequencyDate() {
|
||||
return this.recalculationCompoundingFrequencyDate;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+101
-9
@@ -58,6 +58,16 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
|
||||
@Column(name = "rest_freqency_date")
|
||||
private Date restFrequencyDate;
|
||||
|
||||
@Column(name = "compounding_frequency_type_enum", nullable = true)
|
||||
private Integer compoundingFrequencyType;
|
||||
|
||||
@Column(name = "compounding_frequency_interval", nullable = true)
|
||||
private Integer compoundingInterval;
|
||||
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Column(name = "compounding_freqency_date")
|
||||
private Date compoundingFrequencyDate;
|
||||
|
||||
@Column(name = "arrears_based_on_original_schedule")
|
||||
private boolean isArrearsBasedOnOriginalSchedule;
|
||||
|
||||
@@ -95,6 +105,30 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
|
||||
recurrenceInterval = 0;
|
||||
}
|
||||
|
||||
InterestRecalculationCompoundingMethod compoundingMethod = InterestRecalculationCompoundingMethod
|
||||
.fromInt(interestRecalculationCompoundingMethod);
|
||||
Integer compoundingRecurrenceFrequency = null;
|
||||
Integer compoundingInterval = null;
|
||||
Date recurrenceOnCompoundingDate = null;
|
||||
if (compoundingMethod.isCompoundingEnabled()) {
|
||||
compoundingRecurrenceFrequency = command
|
||||
.integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyTypeParameterName);
|
||||
compoundingInterval = command
|
||||
.integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyIntervalParameterName);
|
||||
RecalculationFrequencyType compoundingFrequencyType = RecalculationFrequencyType.fromInt(compoundingRecurrenceFrequency);
|
||||
if (compoundingFrequencyType.isSameAsRepayment()) {
|
||||
recurrenceInterval = 0;
|
||||
}
|
||||
final LocalDate compoundingRecurrenceOnLocalDate = command
|
||||
.localDateValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyDateParamName);
|
||||
|
||||
if (compoundingRecurrenceOnLocalDate != null) {
|
||||
if (!compoundingFrequencyType.isSameAsRepayment()) {
|
||||
recurrenceOnCompoundingDate = compoundingRecurrenceOnLocalDate.toDate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Integer preCloseInterestCalculationStrategy = command
|
||||
.integerValueOfParameterNamed(LoanProductConstants.preClosureInterestCalculationStrategyParamName);
|
||||
if (preCloseInterestCalculationStrategy == null) {
|
||||
@@ -102,18 +136,22 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
|
||||
}
|
||||
|
||||
return new LoanProductInterestRecalculationDetails(interestRecalculationCompoundingMethod, loanRescheduleStrategyMethod,
|
||||
recurrenceFrequency, recurrenceInterval, recurrenceOnDate, isArrearsBasedOnOriginalSchedule,
|
||||
preCloseInterestCalculationStrategy);
|
||||
recurrenceFrequency, recurrenceInterval, recurrenceOnDate, compoundingRecurrenceFrequency, compoundingInterval,
|
||||
recurrenceOnCompoundingDate, isArrearsBasedOnOriginalSchedule, preCloseInterestCalculationStrategy);
|
||||
}
|
||||
|
||||
private LoanProductInterestRecalculationDetails(final Integer interestRecalculationCompoundingMethod,
|
||||
final Integer rescheduleStrategyMethod, final Integer restFrequencyType, final Integer restInterval,
|
||||
final Date restFrequencyDate, final boolean isArrearsBasedOnOriginalSchedule, final Integer preCloseInterestCalculationStrategy) {
|
||||
final Date restFrequencyDate, Integer compoundingFrequencyType, Integer compoundingInterval, Date compoundingFrequencyDate,
|
||||
final boolean isArrearsBasedOnOriginalSchedule, final Integer preCloseInterestCalculationStrategy) {
|
||||
this.interestRecalculationCompoundingMethod = interestRecalculationCompoundingMethod;
|
||||
this.rescheduleStrategyMethod = rescheduleStrategyMethod;
|
||||
this.restFrequencyType = restFrequencyType;
|
||||
this.restInterval = restInterval;
|
||||
this.restFrequencyDate = restFrequencyDate;
|
||||
this.compoundingFrequencyDate = compoundingFrequencyDate;
|
||||
this.compoundingFrequencyType = compoundingFrequencyType;
|
||||
this.compoundingInterval = compoundingInterval;
|
||||
this.isArrearsBasedOnOriginalSchedule = isArrearsBasedOnOriginalSchedule;
|
||||
this.preClosureInterestCalculationStrategy = preCloseInterestCalculationStrategy;
|
||||
}
|
||||
@@ -165,9 +203,6 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
|
||||
this.restInterval)) {
|
||||
Integer newValue = command
|
||||
.integerValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyIntervalParameterName);
|
||||
if (frequencyType.isSameAsRepayment()) {
|
||||
newValue = 0;
|
||||
}
|
||||
actualChanges.put(LoanProductConstants.recalculationRestFrequencyIntervalParameterName, newValue);
|
||||
actualChanges.put("locale", localeAsInput);
|
||||
this.restInterval = newValue;
|
||||
@@ -179,14 +214,55 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
|
||||
.localDateValueOfParameterNamed(LoanProductConstants.recalculationRestFrequencyDateParamName);
|
||||
Date recurrenceOnDate = null;
|
||||
if (newValue != null) {
|
||||
if (!frequencyType.isSameAsRepayment()) {
|
||||
recurrenceOnDate = newValue.toDate();
|
||||
}
|
||||
recurrenceOnDate = newValue.toDate();
|
||||
}
|
||||
actualChanges.put(LoanProductConstants.recalculationRestFrequencyDateParamName, newValue);
|
||||
this.restFrequencyDate = recurrenceOnDate;
|
||||
}
|
||||
}
|
||||
|
||||
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyTypeParameterName,
|
||||
this.compoundingFrequencyType)) {
|
||||
final Integer newValue = command
|
||||
.integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyTypeParameterName);
|
||||
actualChanges.put(LoanProductConstants.recalculationCompoundingFrequencyTypeParameterName, newValue);
|
||||
this.compoundingFrequencyType = RecalculationFrequencyType.fromInt(newValue).getValue();
|
||||
}
|
||||
|
||||
InterestRecalculationCompoundingMethod compoundingMethod = InterestRecalculationCompoundingMethod
|
||||
.fromInt(this.interestRecalculationCompoundingMethod);
|
||||
if (compoundingMethod.isCompoundingEnabled()) {
|
||||
RecalculationFrequencyType compoundingfrequencyType = RecalculationFrequencyType.fromInt(this.compoundingFrequencyType);
|
||||
if (compoundingfrequencyType.isSameAsRepayment()) {
|
||||
this.compoundingInterval = null;
|
||||
this.compoundingFrequencyDate = null;
|
||||
} else {
|
||||
if (command.isChangeInIntegerParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyIntervalParameterName,
|
||||
this.compoundingInterval)) {
|
||||
Integer newValue = command
|
||||
.integerValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyIntervalParameterName);
|
||||
actualChanges.put(LoanProductConstants.recalculationCompoundingFrequencyIntervalParameterName, newValue);
|
||||
this.compoundingInterval = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInLocalDateParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyDateParamName,
|
||||
getCompoundingFrequencyLocalDate())) {
|
||||
final LocalDate newValue = command
|
||||
.localDateValueOfParameterNamed(LoanProductConstants.recalculationCompoundingFrequencyDateParamName);
|
||||
Date recurrenceOnDate = null;
|
||||
if (newValue != null) {
|
||||
recurrenceOnDate = newValue.toDate();
|
||||
}
|
||||
actualChanges.put(LoanProductConstants.recalculationCompoundingFrequencyDateParamName, newValue);
|
||||
this.compoundingFrequencyDate = recurrenceOnDate;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.compoundingFrequencyType = null;
|
||||
this.compoundingInterval = null;
|
||||
this.compoundingFrequencyDate = null;
|
||||
}
|
||||
|
||||
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.isArrearsBasedOnOriginalScheduleParamName,
|
||||
this.isArrearsBasedOnOriginalSchedule)) {
|
||||
final boolean newValue = command
|
||||
@@ -223,6 +299,22 @@ public class LoanProductInterestRecalculationDetails extends AbstractPersistable
|
||||
return this.restInterval;
|
||||
}
|
||||
|
||||
public LocalDate getCompoundingFrequencyLocalDate() {
|
||||
LocalDate recurrenceOnLocalDate = null;
|
||||
if (this.compoundingFrequencyDate != null) {
|
||||
recurrenceOnLocalDate = new LocalDate(this.compoundingFrequencyDate);
|
||||
}
|
||||
return recurrenceOnLocalDate;
|
||||
}
|
||||
|
||||
public RecalculationFrequencyType getCompoundingFrequencyType() {
|
||||
return RecalculationFrequencyType.fromInt(this.compoundingFrequencyType);
|
||||
}
|
||||
|
||||
public Integer getCompoundingInterval() {
|
||||
return this.compoundingInterval;
|
||||
}
|
||||
|
||||
public boolean isArrearsBasedOnOriginalSchedule() {
|
||||
return this.isArrearsBasedOnOriginalSchedule;
|
||||
}
|
||||
|
||||
+21
@@ -8,6 +8,8 @@ package org.mifosplatform.portfolio.loanproduct.domain;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
|
||||
|
||||
public enum RecalculationFrequencyType {
|
||||
INVALID(0, "interestRecalculationFrequencyType.invalid"), //
|
||||
SAME_AS_REPAYMENT_PERIOD(1, "interestRecalculationFrequencyType.same.as.repayment.period"), //
|
||||
@@ -59,4 +61,23 @@ public enum RecalculationFrequencyType {
|
||||
public boolean isMonthly() {
|
||||
return this.value.equals(RecalculationFrequencyType.MONTHLY.getValue());
|
||||
}
|
||||
|
||||
public boolean isSameFrequency(final PeriodFrequencyType frequencyType) {
|
||||
boolean isSameFre = false;
|
||||
switch (this) {
|
||||
case DAILY:
|
||||
isSameFre = frequencyType.isDaily();
|
||||
break;
|
||||
case MONTHLY:
|
||||
isSameFre = frequencyType.isMonthly();
|
||||
break;
|
||||
case WEEKLY:
|
||||
isSameFre = frequencyType.isWeekly();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return isSameFre;
|
||||
}
|
||||
}
|
||||
|
||||
+87
-1
@@ -25,8 +25,10 @@ import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||
import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
|
||||
import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
|
||||
import org.mifosplatform.portfolio.loanproduct.LoanProductConstants;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanPreClosureInterestCalculationStrategy;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
|
||||
import org.mifosplatform.portfolio.loanproduct.domain.LoanProductConfigurableAttributes;
|
||||
@@ -74,6 +76,9 @@ public final class LoanProductDataValidator {
|
||||
LoanProductConstants.recalculationRestFrequencyDateParamName,
|
||||
LoanProductConstants.recalculationRestFrequencyIntervalParameterName,
|
||||
LoanProductConstants.recalculationRestFrequencyTypeParameterName,
|
||||
LoanProductConstants.recalculationCompoundingFrequencyDateParamName,
|
||||
LoanProductConstants.recalculationCompoundingFrequencyIntervalParameterName,
|
||||
LoanProductConstants.recalculationCompoundingFrequencyTypeParameterName,
|
||||
LoanProductConstants.isArrearsBasedOnOriginalScheduleParamName,
|
||||
LoanProductConstants.minimumDaysBetweenDisbursalAndFirstRepayment, LoanProductConstants.mandatoryGuaranteeParamName,
|
||||
LoanProductConstants.holdGuaranteeFundsParamName, LoanProductConstants.minimumGuaranteeFromGuarantorParamName,
|
||||
@@ -510,6 +515,8 @@ public final class LoanProductDataValidator {
|
||||
/**
|
||||
* { @link InterestRecalculationCompoundingMethod }
|
||||
*/
|
||||
InterestRecalculationCompoundingMethod compoundingMethod = null;
|
||||
|
||||
if (loanProduct == null
|
||||
|| this.fromApiJsonHelper
|
||||
.parameterExists(LoanProductConstants.interestRecalculationCompoundingMethodParameterName, element)) {
|
||||
@@ -517,7 +524,20 @@ public final class LoanProductDataValidator {
|
||||
LoanProductConstants.interestRecalculationCompoundingMethodParameterName, element, Locale.getDefault());
|
||||
baseDataValidator.reset().parameter(LoanProductConstants.interestRecalculationCompoundingMethodParameterName)
|
||||
.value(interestRecalculationCompoundingMethod).notNull().inMinMaxRange(0, 3);
|
||||
if (interestRecalculationCompoundingMethod != null) {
|
||||
compoundingMethod = InterestRecalculationCompoundingMethod.fromInt(interestRecalculationCompoundingMethod);
|
||||
}
|
||||
}
|
||||
|
||||
if (compoundingMethod == null) {
|
||||
if (loanProduct == null) {
|
||||
compoundingMethod = InterestRecalculationCompoundingMethod.NONE;
|
||||
} else {
|
||||
compoundingMethod = InterestRecalculationCompoundingMethod.fromInt(loanProduct.getProductInterestRecalculationDetails()
|
||||
.getInterestRecalculationCompoundingMethod());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* { @link LoanRescheduleStrategyMethod }
|
||||
*/
|
||||
@@ -537,7 +557,9 @@ public final class LoanProductDataValidator {
|
||||
LoanProductConstants.recalculationRestFrequencyTypeParameterName, element, Locale.getDefault());
|
||||
baseDataValidator.reset().parameter(LoanProductConstants.recalculationRestFrequencyTypeParameterName)
|
||||
.value(recalculationRestFrequencyType).notNull().inMinMaxRange(1, 4);
|
||||
frequencyType = RecalculationFrequencyType.fromInt(recalculationRestFrequencyType);
|
||||
if (recalculationRestFrequencyType != null) {
|
||||
frequencyType = RecalculationFrequencyType.fromInt(recalculationRestFrequencyType);
|
||||
}
|
||||
}
|
||||
|
||||
if (frequencyType == null) {
|
||||
@@ -566,6 +588,70 @@ public final class LoanProductDataValidator {
|
||||
}
|
||||
}
|
||||
|
||||
if (compoundingMethod.isCompoundingEnabled()) {
|
||||
RecalculationFrequencyType compoundingfrequencyType = null;
|
||||
|
||||
if (loanProduct == null
|
||||
|| this.fromApiJsonHelper.parameterExists(LoanProductConstants.recalculationCompoundingFrequencyTypeParameterName,
|
||||
element)) {
|
||||
final Integer recalculationCompoundingFrequencyType = this.fromApiJsonHelper.extractIntegerNamed(
|
||||
LoanProductConstants.recalculationCompoundingFrequencyTypeParameterName, element, Locale.getDefault());
|
||||
baseDataValidator.reset().parameter(LoanProductConstants.recalculationCompoundingFrequencyTypeParameterName)
|
||||
.value(recalculationCompoundingFrequencyType).notNull().inMinMaxRange(1, 4);
|
||||
if (recalculationCompoundingFrequencyType != null) {
|
||||
compoundingfrequencyType = RecalculationFrequencyType.fromInt(recalculationCompoundingFrequencyType);
|
||||
if (!compoundingfrequencyType.isSameAsRepayment()) {
|
||||
PeriodFrequencyType repaymentFrequencyType = null;
|
||||
if (loanProduct == null) {
|
||||
Integer repaymentFrequencyTypeVal = this.fromApiJsonHelper.extractIntegerNamed("repaymentFrequencyType",
|
||||
element, Locale.getDefault());
|
||||
repaymentFrequencyType = PeriodFrequencyType.fromInt(repaymentFrequencyTypeVal);
|
||||
} else {
|
||||
repaymentFrequencyType = loanProduct.getLoanProductRelatedDetail().getRepaymentPeriodFrequencyType();
|
||||
}
|
||||
if (!compoundingfrequencyType.isSameFrequency(repaymentFrequencyType)) {
|
||||
baseDataValidator.reset().parameter(LoanProductConstants.recalculationCompoundingFrequencyTypeParameterName)
|
||||
.value(recalculationCompoundingFrequencyType).failWithCode("must.be.same.as.repayment.frequency");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (compoundingfrequencyType == null) {
|
||||
if (loanProduct == null) {
|
||||
compoundingfrequencyType = RecalculationFrequencyType.INVALID;
|
||||
} else {
|
||||
compoundingfrequencyType = loanProduct.getProductInterestRecalculationDetails().getCompoundingFrequencyType();
|
||||
}
|
||||
}
|
||||
|
||||
if (!compoundingfrequencyType.isSameAsRepayment()) {
|
||||
if (loanProduct == null
|
||||
|| this.fromApiJsonHelper.parameterExists(LoanProductConstants.recalculationCompoundingFrequencyDateParamName,
|
||||
element)) {
|
||||
final LocalDate recurrenceOnLocalDate = this.fromApiJsonHelper.extractLocalDateNamed(
|
||||
LoanProductConstants.recalculationCompoundingFrequencyDateParamName, element);
|
||||
baseDataValidator.reset().parameter(LoanProductConstants.recalculationCompoundingFrequencyDateParamName)
|
||||
.value(recurrenceOnLocalDate).notNull();
|
||||
}
|
||||
if (loanProduct == null
|
||||
|| this.fromApiJsonHelper.parameterExists(
|
||||
LoanProductConstants.recalculationCompoundingFrequencyIntervalParameterName, element)) {
|
||||
final Integer recurrenceInterval = this.fromApiJsonHelper.extractIntegerNamed(
|
||||
LoanProductConstants.recalculationCompoundingFrequencyIntervalParameterName, element, Locale.getDefault());
|
||||
Integer repaymentEvery = null;
|
||||
if (loanProduct == null) {
|
||||
repaymentEvery = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("repaymentEvery", element);
|
||||
} else {
|
||||
repaymentEvery = loanProduct.getLoanProductRelatedDetail().getRepayEvery();
|
||||
}
|
||||
|
||||
baseDataValidator.reset().parameter(LoanProductConstants.recalculationCompoundingFrequencyIntervalParameterName)
|
||||
.value(recurrenceInterval).notNull().integerInMultiplesOfNumber(repaymentEvery);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.isArrearsBasedOnOriginalScheduleParamName, element)) {
|
||||
final Boolean isArrearsBasedOnOriginalSchedule = this.fromApiJsonHelper.extractBooleanNamed(
|
||||
LoanProductConstants.isArrearsBasedOnOriginalScheduleParamName, element);
|
||||
|
||||
+13
-3
@@ -77,7 +77,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
||||
final String sql = "select " + rm.schema() + " where bc.loan_product_id=? order by bc.borrower_cycle_number,bc.value_condition";
|
||||
return this.jdbcTemplate.query(sql, rm, new Object[] { loanProductId });
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Collection<LoanProductData> retrieveAllLoanProducts() {
|
||||
|
||||
@@ -166,6 +166,8 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
||||
+ "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, "
|
||||
+ "lpr.compounding_frequency_type_enum as compoundingFrequencyTypeEnum, lpr.compounding_frequency_interval as compoundingInterval, "
|
||||
+ "lpr.compounding_freqency_date as compoundingFrequencyDate, "
|
||||
+ "lp.hold_guarantee_funds as holdGuaranteeFunds, "
|
||||
+ "lp.principal_threshold_for_last_installment as principalThresholdForLastInstallment, "
|
||||
+ "lpg.id as lpgId, lpg.mandatory_guarantee as mandatoryGuarantee, "
|
||||
@@ -287,7 +289,6 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
||||
final boolean canDefineInstallmentAmount = rs.getBoolean("canDefineInstallmentAmount");
|
||||
final boolean isInterestRecalculationEnabled = rs.getBoolean("isInterestRecalculationEnabled");
|
||||
|
||||
|
||||
LoanProductInterestRecalculationData interestRecalculationData = null;
|
||||
if (isInterestRecalculationEnabled) {
|
||||
|
||||
@@ -302,6 +303,14 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
||||
final EnumOptionData restFrequencyType = LoanEnumerations.interestRecalculationFrequencyType(restFrequencyEnumValue);
|
||||
final int restFrequencyInterval = JdbcSupport.getInteger(rs, "restFrequencyInterval");
|
||||
final LocalDate restFrequencyDate = JdbcSupport.getLocalDate(rs, "restFrequencyDate");
|
||||
final Integer compoundingFrequencyEnumValue = JdbcSupport.getInteger(rs, "compoundingFrequencyTypeEnum");
|
||||
EnumOptionData compoundingFrequencyType = null;
|
||||
if (compoundingFrequencyEnumValue != null) {
|
||||
compoundingFrequencyType = LoanEnumerations
|
||||
.interestRecalculationFrequencyType(compoundingFrequencyEnumValue);
|
||||
}
|
||||
final Integer compoundingInterval = JdbcSupport.getInteger(rs, "compoundingInterval");
|
||||
final LocalDate compoundingFrequencyDate = JdbcSupport.getLocalDate(rs, "compoundingFrequencyDate");
|
||||
final boolean isArrearsBasedOnOriginalSchedule = rs.getBoolean("isArrearsBasedOnOriginalSchedule");
|
||||
final int preCloseInterestCalculationStrategyEnumValue = JdbcSupport.getInteger(rs, "preCloseInterestCalculationStrategy");
|
||||
final EnumOptionData preCloseInterestCalculationStrategy = LoanEnumerations
|
||||
@@ -309,7 +318,8 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
|
||||
|
||||
interestRecalculationData = new LoanProductInterestRecalculationData(lprId, productId,
|
||||
interestRecalculationCompoundingType, rescheduleStrategyType, restFrequencyType, restFrequencyInterval,
|
||||
restFrequencyDate, isArrearsBasedOnOriginalSchedule, preCloseInterestCalculationStrategy);
|
||||
restFrequencyDate, compoundingFrequencyType, compoundingInterval, compoundingFrequencyDate,
|
||||
isArrearsBasedOnOriginalSchedule, preCloseInterestCalculationStrategy);
|
||||
}
|
||||
|
||||
final boolean amortization = rs.getBoolean("amortizationBoolean");
|
||||
|
||||
+1
-1
@@ -252,7 +252,7 @@ public class MeetingsApiResource {
|
||||
break;
|
||||
case INVALID:
|
||||
break;
|
||||
case LOAN_RECALCULATION_DETAIL:
|
||||
case LOAN_RECALCULATION_REST_DETAIL:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
ALTER TABLE `m_product_loan_recalculation_details`
|
||||
ADD COLUMN `compounding_frequency_type_enum` SMALLINT(1) NULL DEFAULT NULL,
|
||||
ADD COLUMN `compounding_frequency_interval` SMALLINT(3) NULL DEFAULT NULL,
|
||||
ADD COLUMN `compounding_freqency_date` DATE NULL DEFAULT NULL;
|
||||
|
||||
|
||||
ALTER TABLE `m_loan_recalculation_details`
|
||||
ADD COLUMN `compounding_frequency_type_enum` SMALLINT(1) NULL DEFAULT NULL,
|
||||
ADD COLUMN `compounding_frequency_interval` SMALLINT(3) NULL DEFAULT NULL,
|
||||
ADD COLUMN `compounding_freqency_date` DATE NULL DEFAULT NULL;
|
||||
Reference in New Issue
Block a user