Merge pull request #1585 from pramodn02/variableinstalmentchanges

Partial periods interest calculation & variable installment junits
This commit is contained in:
Shaik Nazeer Hussain
2016-01-11 16:17:28 +05:30
31 changed files with 1763 additions and 523 deletions
+18 -2
View File
@@ -8003,6 +8003,14 @@ GET https://DomainName/mifosng-provider/api/v1/groups?paged=true
<tr> <tr>
<td class=fielddesc><span>Example Values:</span> 0=Daily, 1=Same as repayment period</td> <td class=fielddesc><span>Example Values:</span> 0=Daily, 1=Same as repayment period</td>
</tr> </tr>
<tr class=alt>
<td>allowPartialPeriodInterestCalcualtion</td>
</tr>
<tr>
<td class=fielddesc>This value will be supported along with interestCalculationPeriodType as Same as repayment period to calculate interest for partial periods.
<span>Example:</span> Interest charged from is 5th of April , Principal is 10000 and interest is 1% per month then the interest will be (10000 * 1%)* (25/30) , it calculates for the month first then calculates exact periods between start date and end date(can be a decimal)
</td>
</tr>
<tr class=alt> <tr class=alt>
<td>inArrearsTolerance</td> <td>inArrearsTolerance</td>
</tr> </tr>
@@ -9219,7 +9227,7 @@ Request Body:
<td><div class="mifosXHeading2">Optional Fields</div></td> <td><div class="mifosXHeading2">Optional Fields</div></td>
</tr> </tr>
<tr class=alt> <tr class=alt>
<td>graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, linkAccountId, <td>graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, linkAccountId, allowPartialPeriodInterestCalcualtion,
fixedEmiAmount, maxOutstandingLoanBalance, disbursementData, graceOnArrearsAgeing, createStandingInstructionAtDisbursement (requires linkedAccountId if set to true) fixedEmiAmount, maxOutstandingLoanBalance, disbursementData, graceOnArrearsAgeing, createStandingInstructionAtDisbursement (requires linkedAccountId if set to true)
</td> </td>
</tr> </tr>
@@ -12759,6 +12767,14 @@ Request Body:
<tr> <tr>
<td class=fielddesc><span>Example Values:</span> 0=Daily, 1=Same as repayment period</td> <td class=fielddesc><span>Example Values:</span> 0=Daily, 1=Same as repayment period</td>
</tr> </tr>
<tr class=alt>
<td>allowPartialPeriodInterestCalcualtion</td>
</tr>
<tr>
<td class=fielddesc>This value will be supported along with interestCalculationPeriodType as Same as repayment period to calculate interest for partial periods.
<span>Example:</span> Interest charged from is 5th of April , Principal is 10000 and interest is 1% per month then the interest will be (10000 * 1%)* (25/30) , it calculates for the month first then calculates exact periods between start date and end date(can be a decimal)
</td>
</tr>
<tr class=alt> <tr class=alt>
<td>inArrearsTolerance</td> <td>inArrearsTolerance</td>
</tr> </tr>
@@ -14236,7 +14252,7 @@ GET https://DomainName/api/v1/loanproducts/{productId}
numberOfRepaymentVariationsForBorrowerCycle, numberOfRepaymentVariationsForBorrowerCycle,
interestRateVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle,
multiDisburseLoan,maxTrancheCount, multiDisburseLoan,maxTrancheCount,
outstandingLoanBalance,overdueDaysForNPA,holdGuaranteeFunds, principalThresholdForLastInstalment, accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount, installmentAmountInMultiplesOf, allowAttributeOverrides outstandingLoanBalance,overdueDaysForNPA,holdGuaranteeFunds, principalThresholdForLastInstalment, accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount, installmentAmountInMultiplesOf, allowAttributeOverrides, allowPartialPeriodInterestCalcualtion
</td> </td>
</tr> </tr>
</table> </table>
@@ -868,7 +868,7 @@ public class ClientLoanIntegrationTest {
private Integer createLoanProduct(final boolean multiDisburseLoan, final String accountingRule, final Account... accounts) { private Integer createLoanProduct(final boolean multiDisburseLoan, final String accountingRule, final Account... accounts) {
System.out.println("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------"); System.out.println("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------");
final String loanProductJSON = new LoanProductTestBuilder() // LoanProductTestBuilder builder = new LoanProductTestBuilder() //
.withPrincipal("12,000.00") // .withPrincipal("12,000.00") //
.withNumberOfRepayments("4") // .withNumberOfRepayments("4") //
.withRepaymentAfterEvery("1") // .withRepaymentAfterEvery("1") //
@@ -878,7 +878,11 @@ public class ClientLoanIntegrationTest {
.withAmortizationTypeAsEqualInstallments() // .withAmortizationTypeAsEqualInstallments() //
.withInterestTypeAsDecliningBalance() // .withInterestTypeAsDecliningBalance() //
.withTranches(multiDisburseLoan) // .withTranches(multiDisburseLoan) //
.withAccounting(accountingRule, accounts).build(null); .withAccounting(accountingRule, accounts);
if (multiDisburseLoan) {
builder = builder.withInterestCalculationPeriodTypeAsRepaymentPeriod(true);
}
final String loanProductJSON = builder.build(null);
return this.loanTransactionHelper.getLoanProductId(loanProductJSON); return this.loanTransactionHelper.getLoanProductId(loanProductJSON);
} }
@@ -4173,7 +4177,6 @@ public class ClientLoanIntegrationTest {
LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_REST_DATE, "10046.15"); LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_REST_DATE, "10046.15");
} }
private void testLoanScheduleWithInterestRecalculation_FOR_PRE_CLOSE_WITH_MORATORIUM(final String preCloseStrategy, private void testLoanScheduleWithInterestRecalculation_FOR_PRE_CLOSE_WITH_MORATORIUM(final String preCloseStrategy,
final String preCloseAmount) { final String preCloseAmount) {
this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec); this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec);
@@ -4307,6 +4310,7 @@ public class ClientLoanIntegrationTest {
.withInterestRateFrequencyTypeAsMonths() .withInterestRateFrequencyTypeAsMonths()
.withRepaymentStrategy(repaymentStrategy) .withRepaymentStrategy(repaymentStrategy)
.withAmortizationTypeAsEqualPrincipalPayment() .withAmortizationTypeAsEqualPrincipalPayment()
.withInterestCalculationPeriodTypeAsRepaymentPeriod(true)
.withInterestTypeAsDecliningBalance() .withInterestTypeAsDecliningBalance()
.withInterestRecalculationDetails(interestRecalculationCompoundingMethod, rescheduleStrategyMethod, .withInterestRecalculationDetails(interestRecalculationCompoundingMethod, rescheduleStrategyMethod,
preCloseInterestCalculationStrategy) preCloseInterestCalculationStrategy)
@@ -80,7 +80,7 @@ public class ConcurrencyIntegrationTest {
private Integer createLoanProduct(final boolean multiDisburseLoan, final String accountingRule, final Account... accounts) { private Integer createLoanProduct(final boolean multiDisburseLoan, final String accountingRule, final Account... accounts) {
System.out.println("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------"); System.out.println("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------");
final String loanProductJSON = new LoanProductTestBuilder() // LoanProductTestBuilder builder = new LoanProductTestBuilder() //
.withPrincipal("12,000.00") // .withPrincipal("12,000.00") //
.withNumberOfRepayments("4") // .withNumberOfRepayments("4") //
.withRepaymentAfterEvery("1") // .withRepaymentAfterEvery("1") //
@@ -90,7 +90,12 @@ public class ConcurrencyIntegrationTest {
.withAmortizationTypeAsEqualInstallments() // .withAmortizationTypeAsEqualInstallments() //
.withInterestTypeAsDecliningBalance() // .withInterestTypeAsDecliningBalance() //
.withTranches(multiDisburseLoan) // .withTranches(multiDisburseLoan) //
.withAccounting(accountingRule, accounts).build(null); .withAccounting(accountingRule, accounts);
if (multiDisburseLoan) {
builder = builder.withInterestCalculationPeriodTypeAsRepaymentPeriod(true);
}
final String loanProductJSON = builder.build(null);
return this.loanTransactionHelper.getLoanProductId(loanProductJSON); return this.loanTransactionHelper.getLoanProductId(loanProductJSON);
} }
@@ -121,7 +121,8 @@ public class LoanApplicationApprovalTest {
+ clientID); + clientID);
final Integer loanProductID = this.loanTransactionHelper.getLoanProductId(new LoanProductTestBuilder() final Integer loanProductID = this.loanTransactionHelper.getLoanProductId(new LoanProductTestBuilder()
.withInterestTypeAsDecliningBalance().withTranches(true).build(null)); .withInterestTypeAsDecliningBalance().withTranches(true).withInterestCalculationPeriodTypeAsRepaymentPeriod(true)
.build(null));
System.out.println("----------------------------------LOAN PRODUCT CREATED WITH ID-------------------------------------------" System.out.println("----------------------------------LOAN PRODUCT CREATED WITH ID-------------------------------------------"
+ loanProductID); + loanProductID);
@@ -11,7 +11,6 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@@ -32,7 +31,7 @@ import org.mifosplatform.integrationtests.LoanApplicationApprovalTest;
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
public class LoanApplicationUndoLastTrancheTest { public class LoanApplicationUndoLastTrancheTest {
private ResponseSpecification responseSpec; private ResponseSpecification responseSpec;
private RequestSpecification requestSpec; private RequestSpecification requestSpec;
private LoanTransactionHelper loanTransactionHelper; private LoanTransactionHelper loanTransactionHelper;
private LoanApplicationApprovalTest loanApplicationApprovalTest; private LoanApplicationApprovalTest loanApplicationApprovalTest;
@@ -48,22 +47,23 @@ public class LoanApplicationUndoLastTrancheTest {
} }
@Test @Test
public void LoanApplicationUndoLastTranche(){ public void LoanApplicationUndoLastTranche() {
final String proposedAmount = "5000"; final String proposedAmount = "5000";
final String approvalAmount = "2000"; final String approvalAmount = "2000";
final String approveDate = "1 March 2014"; final String approveDate = "1 March 2014";
final String expectedDisbursementDate = "1 March 2014"; final String expectedDisbursementDate = "1 March 2014";
final String disbursalDate = "1 March 2014"; final String disbursalDate = "1 March 2014";
// CREATE CLIENT // CREATE CLIENT
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2014"); final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2014");
System.out.println("---------------------------------CLIENT CREATED WITH ID---------------------------------------------------" System.out.println("---------------------------------CLIENT CREATED WITH ID---------------------------------------------------"
+ clientID); + clientID);
// CREATE LOAN MULTIDISBURSAL PRODUCT // CREATE LOAN MULTIDISBURSAL PRODUCT
final Integer loanProductID = this.loanTransactionHelper.getLoanProductId(new LoanProductTestBuilder() final Integer loanProductID = this.loanTransactionHelper.getLoanProductId(new LoanProductTestBuilder()
.withInterestTypeAsDecliningBalance().withTranches(true).build(null)); .withInterestTypeAsDecliningBalance().withTranches(true).withInterestCalculationPeriodTypeAsRepaymentPeriod(true)
.build(null));
System.out.println("----------------------------------LOAN PRODUCT CREATED WITH ID-------------------------------------------" System.out.println("----------------------------------LOAN PRODUCT CREATED WITH ID-------------------------------------------"
+ loanProductID); + loanProductID);
@@ -114,12 +114,12 @@ public class LoanApplicationUndoLastTrancheTest {
validateDisbursedAmount(disbursedAmount); validateDisbursedAmount(disbursedAmount);
} }
private void validateDisbursedAmount(Float disbursedAmount) { private void validateDisbursedAmount(Float disbursedAmount) {
Assert.assertEquals(Float.valueOf("1000.0"), disbursedAmount); Assert.assertEquals(Float.valueOf("1000.0"), disbursedAmount);
} }
public Integer applyForLoanApplicationWithTranches(final Integer clientID, final Integer loanProductID, String principal, public Integer applyForLoanApplicationWithTranches(final Integer clientID, final Integer loanProductID, String principal,
List<HashMap> tranches) { List<HashMap> tranches) {
System.out.println("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------"); System.out.println("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------");
final String loanApplicationJSON = new LoanApplicationTestBuilder() final String loanApplicationJSON = new LoanApplicationTestBuilder()
@@ -141,5 +141,4 @@ public class LoanApplicationUndoLastTrancheTest {
return this.loanTransactionHelper.getLoanId(loanApplicationJSON); return this.loanTransactionHelper.getLoanId(loanApplicationJSON);
} }
} }
@@ -64,12 +64,12 @@ public class LoanDisbursementDetailsIntegrationTest {
createTranches.add(this.loanTransactionHelper.createTrancheDetail(id, "01 Sep 2015", "5000")); createTranches.add(this.loanTransactionHelper.createTrancheDetail(id, "01 Sep 2015", "5000"));
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2014"); final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2014");
System.out.println( System.out.println("---------------------------------CLIENT CREATED WITH ID---------------------------------------------------"
"---------------------------------CLIENT CREATED WITH ID---------------------------------------------------" + clientID); + clientID);
final Integer loanProductID = this.loanTransactionHelper final Integer loanProductID = this.loanTransactionHelper.getLoanProductId(new LoanProductTestBuilder()
.getLoanProductId(new LoanProductTestBuilder().withInterestTypeAsDecliningBalance().withMoratorium("", "") .withInterestTypeAsDecliningBalance().withMoratorium("", "").withAmortizationTypeAsEqualInstallments().withTranches(true)
.withAmortizationTypeAsEqualInstallments().withTranches(true).build(null)); .withInterestCalculationPeriodTypeAsRepaymentPeriod(true).build(null));
System.out.println("----------------------------------LOAN PRODUCT CREATED WITH ID-------------------------------------------" System.out.println("----------------------------------LOAN PRODUCT CREATED WITH ID-------------------------------------------"
+ loanProductID); + loanProductID);
@@ -96,8 +96,8 @@ public class LoanDisbursementDetailsIntegrationTest {
createTranches); createTranches);
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap); LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap); LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap);
System.out.println( System.out
"-----------------------------------MULTI DISBURSAL LOAN WITH EMI APPROVED SUCCESSFULLY---------------------------------------"); .println("-----------------------------------MULTI DISBURSAL LOAN WITH EMI APPROVED SUCCESSFULLY---------------------------------------");
final Integer loanIDWithoutEmi = applyForLoanApplicationWithEmiAmount(clientID, loanProductID, proposedAmount, createTranches, final Integer loanIDWithoutEmi = applyForLoanApplicationWithEmiAmount(clientID, loanProductID, proposedAmount, createTranches,
withoutInstallmentAmount); withoutInstallmentAmount);
@@ -108,8 +108,8 @@ public class LoanDisbursementDetailsIntegrationTest {
ArrayList<HashMap> periods1 = (ArrayList<HashMap>) repaymentScheduleWithEmi.get("periods"); ArrayList<HashMap> periods1 = (ArrayList<HashMap>) repaymentScheduleWithEmi.get("periods");
assertEquals(periods1.size(), 15); assertEquals(periods1.size(), 15);
System.out.println( System.out
"-----------------------------------LOAN CREATED WITHOUT EMI LOANID-------------------------------------------------" .println("-----------------------------------LOAN CREATED WITHOUT EMI LOANID-------------------------------------------------"
+ loanIDWithoutEmi); + loanIDWithoutEmi);
/* To be uncommented once issue MIFOSX-2006 is closed. */ /* To be uncommented once issue MIFOSX-2006 is closed. */
@@ -123,8 +123,8 @@ public class LoanDisbursementDetailsIntegrationTest {
loanIDWithoutEmi, createTranches); loanIDWithoutEmi, createTranches);
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap); LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap); LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap);
System.out.println( System.out
"-----------------------------------MULTI DISBURSAL LOAN WITHOUT EMI APPROVED SUCCESSFULLY---------------------------------------"); .println("-----------------------------------MULTI DISBURSAL LOAN WITHOUT EMI APPROVED SUCCESSFULLY---------------------------------------");
} }
@@ -201,8 +201,8 @@ public class LoanDisbursementDetailsIntegrationTest {
assertEquals(period.get("dueDate").toString(), expectedRepaymentSchedule.getDueDate()); assertEquals(period.get("dueDate").toString(), expectedRepaymentSchedule.getDueDate());
assertEquals(period.get("principalLoanBalanceOutstanding"), expectedRepaymentSchedule.getPrincipalLoanBalanceOutstanding()); assertEquals(period.get("principalLoanBalanceOutstanding"), expectedRepaymentSchedule.getPrincipalLoanBalanceOutstanding());
System.out.println(period.get("totalOriginalDueForPeriod").toString()); System.out.println(period.get("totalOriginalDueForPeriod").toString());
assertEquals(new Float(period.get("totalOriginalDueForPeriod").toString()), assertEquals(new Float(period.get("totalOriginalDueForPeriod").toString()), expectedRepaymentSchedule
expectedRepaymentSchedule.getTotalOriginalDueForPeriod().floatValue(), 0.0f); .getTotalOriginalDueForPeriod().floatValue(), 0.0f);
assertEquals(new Float(period.get("totalOutstandingForPeriod").toString()).floatValue(), assertEquals(new Float(period.get("totalOutstandingForPeriod").toString()).floatValue(),
expectedRepaymentSchedule.getTotalOutstandingForPeriod(), 0.0f); expectedRepaymentSchedule.getTotalOutstandingForPeriod(), 0.0f);
@@ -335,7 +335,7 @@ public class LoanDisbursementDetailsIntegrationTest {
System.out.println("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------"); System.out.println("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------");
final String loanApplicationJSON = new LoanApplicationTestBuilder() final String loanApplicationJSON = new LoanApplicationTestBuilder()
// //
.withPrincipal(proposedAmount) .withPrincipal(proposedAmount)
// //
.withLoanTermFrequency("12") .withLoanTermFrequency("12")
@@ -364,17 +364,18 @@ public class LoanDisbursementDetailsIntegrationTest {
createTranches.add(this.loanTransactionHelper.createTrancheDetail(id, "01 March 2014", "1000")); createTranches.add(this.loanTransactionHelper.createTrancheDetail(id, "01 March 2014", "1000"));
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2014"); final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2014");
System.out.println( System.out.println("---------------------------------CLIENT CREATED WITH ID---------------------------------------------------"
"---------------------------------CLIENT CREATED WITH ID---------------------------------------------------" + clientID); + clientID);
final Integer loanProductID = this.loanTransactionHelper final Integer loanProductID = this.loanTransactionHelper.getLoanProductId(new LoanProductTestBuilder()
.getLoanProductId(new LoanProductTestBuilder().withInterestTypeAsDecliningBalance().withTranches(true).build(null)); .withInterestTypeAsDecliningBalance().withTranches(true).withInterestCalculationPeriodTypeAsRepaymentPeriod(true)
.build(null));
System.out.println("----------------------------------LOAN PRODUCT CREATED WITH ID-------------------------------------------" System.out.println("----------------------------------LOAN PRODUCT CREATED WITH ID-------------------------------------------"
+ loanProductID); + loanProductID);
this.loanID = applyForLoanApplicationWithTranches(clientID, loanProductID, proposedAmount, createTranches); this.loanID = applyForLoanApplicationWithTranches(clientID, loanProductID, proposedAmount, createTranches);
System.out.println( System.out.println("-----------------------------------LOAN CREATED WITH LOANID-------------------------------------------------"
"-----------------------------------LOAN CREATED WITH LOANID-------------------------------------------------" + loanID); + loanID);
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID); HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap); LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
@@ -384,8 +385,8 @@ public class LoanDisbursementDetailsIntegrationTest {
loanID, createTranches); loanID, createTranches);
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap); LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap); LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap);
System.out.println( System.out
"-----------------------------------MULTI DISBURSAL LOAN APPROVED SUCCESSFULLY---------------------------------------"); .println("-----------------------------------MULTI DISBURSAL LOAN APPROVED SUCCESSFULLY---------------------------------------");
ArrayList<HashMap> disbursementDetails = (ArrayList<HashMap>) this.loanTransactionHelper.getLoanDetail(this.requestSpec, ArrayList<HashMap> disbursementDetails = (ArrayList<HashMap>) this.loanTransactionHelper.getLoanDetail(this.requestSpec,
this.responseSpec, this.loanID, "disbursementDetails"); this.responseSpec, this.loanID, "disbursementDetails");
this.disbursementId = (Integer) disbursementDetails.get(0).get("id"); this.disbursementId = (Integer) disbursementDetails.get(0).get("id");
@@ -466,7 +467,7 @@ public class LoanDisbursementDetailsIntegrationTest {
List<HashMap> tranches) { List<HashMap> tranches) {
System.out.println("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------"); System.out.println("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------");
final String loanApplicationJSON = new LoanApplicationTestBuilder() final String loanApplicationJSON = new LoanApplicationTestBuilder()
// //
.withPrincipal(principal) .withPrincipal(principal)
// //
.withLoanTermFrequency("5") .withLoanTermFrequency("5")
@@ -161,7 +161,7 @@ public class ProvisioningIntegrationTest {
private Integer createLoanProduct(final boolean multiDisburseLoan, final String accountingRule, final Account... accounts) { private Integer createLoanProduct(final boolean multiDisburseLoan, final String accountingRule, final Account... accounts) {
System.out.println("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------"); System.out.println("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------");
final String loanProductJSON = new LoanProductTestBuilder() // LoanProductTestBuilder builder = new LoanProductTestBuilder() //
.withPrincipal("1,00,000.00") // .withPrincipal("1,00,000.00") //
.withNumberOfRepayments("4") // .withNumberOfRepayments("4") //
.withRepaymentAfterEvery("1") // .withRepaymentAfterEvery("1") //
@@ -171,7 +171,12 @@ public class ProvisioningIntegrationTest {
.withAmortizationTypeAsEqualInstallments() // .withAmortizationTypeAsEqualInstallments() //
.withInterestTypeAsDecliningBalance() // .withInterestTypeAsDecliningBalance() //
.withTranches(multiDisburseLoan) // .withTranches(multiDisburseLoan) //
.withAccounting(accountingRule, accounts).build(null); .withAccounting(accountingRule, accounts);
if (multiDisburseLoan) {
builder = builder.withInterestCalculationPeriodTypeAsRepaymentPeriod(true);
}
final String loanProductJSON = builder.build(null);
return this.loanTransactionHelper.getLoanProductId(loanProductJSON); return this.loanTransactionHelper.getLoanProductId(loanProductJSON);
} }
@@ -104,6 +104,11 @@ public class LoanProductTestBuilder {
private String graceOnPrincipalPayment = "1"; private String graceOnPrincipalPayment = "1";
private String graceOnInterestPayment = "1"; private String graceOnInterestPayment = "1";
private JsonObject allowAttributeOverrides = null; private JsonObject allowAttributeOverrides = null;
private Boolean allowPartialPeriodInterestCalcualtion = false;
private Boolean allowVariableInstallments = Boolean.FALSE;
private Integer minimumGap;
private Integer maximumGap;
public String build(final String chargeId) { public String build(final String chargeId) {
final HashMap<String, Object> map = new HashMap<>(); final HashMap<String, Object> map = new HashMap<>();
@@ -183,6 +188,12 @@ public class LoanProductTestBuilder {
if (allowAttributeOverrides != null) { if (allowAttributeOverrides != null) {
map.put("allowAttributeOverrides", this.allowAttributeOverrides); map.put("allowAttributeOverrides", this.allowAttributeOverrides);
} }
map.put("allowPartialPeriodInterestCalcualtion", this.allowPartialPeriodInterestCalcualtion);
map.put("allowVariableInstallments", allowVariableInstallments) ;
if(allowVariableInstallments) {
map.put("minimumGap", minimumGap) ;
map.put("maximumGap", maximumGap) ;
}
return new Gson().toJson(map); return new Gson().toJson(map);
} }
@@ -276,8 +287,9 @@ public class LoanProductTestBuilder {
return this; return this;
} }
public LoanProductTestBuilder withInterestCalculationPeriodTypeAsRepaymentPeriod() { public LoanProductTestBuilder withInterestCalculationPeriodTypeAsRepaymentPeriod(final Boolean allowPartialPeriodInterestCalcualtion) {
this.interestCalculationPeriodType = CALCULATION_PERIOD_SAME_AS_REPAYMENT_PERIOD; this.interestCalculationPeriodType = CALCULATION_PERIOD_SAME_AS_REPAYMENT_PERIOD;
this.allowPartialPeriodInterestCalcualtion = allowPartialPeriodInterestCalcualtion;
return this; return this;
} }
@@ -458,4 +470,11 @@ public class LoanProductTestBuilder {
this.allowAttributeOverrides = loanProductConfigurableAttributes; this.allowAttributeOverrides = loanProductConfigurableAttributes;
return this; return this;
} }
public LoanProductTestBuilder withVariableInstallmentsConfig(Boolean allowVariableInstallments, Integer minimumGap, Integer maximumGap) {
this.allowVariableInstallments = allowVariableInstallments ;
this.minimumGap = minimumGap;
this.maximumGap = maximumGap;
return this ;
}
} }
@@ -0,0 +1,298 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.integrationtests.variableinstallments;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.mifosplatform.integrationtests.common.accounting.Account;
import org.mifosplatform.integrationtests.common.loans.LoanApplicationTestBuilder;
import org.mifosplatform.integrationtests.common.loans.LoanProductTestBuilder;
import com.google.gson.Gson;
@SuppressWarnings({"rawtypes", "unchecked"})
public class VariableInstallmentsDecliningBalanceHelper {
public static String createLoanProductWithoutVaribleConfig(final boolean multiDisburseLoan, final String accountingRule, final Account... accounts) {
System.out.println("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------");
final String loanProductJSON = new LoanProductTestBuilder() //
.withPrincipal("1,00,000.00") //
.withNumberOfRepayments("4") //
.withRepaymentAfterEvery("1") //
.withRepaymentTypeAsMonth() //
.withinterestRatePerPeriod("1") //
.withInterestRateFrequencyTypeAsMonths() //
.withAmortizationTypeAsEqualInstallments() //
.withInterestTypeAsDecliningBalance() //
.withTranches(multiDisburseLoan) //
.withAccounting(accountingRule, accounts).build(null);
return loanProductJSON ;
}
public static String createLoanProductWithVaribleConfig(final boolean multiDisburseLoan, final String accountingRule, final Account... accounts) {
System.out.println("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------");
final String loanProductJSON = new LoanProductTestBuilder() //
.withPrincipal("1,00,000.00") //
.withNumberOfRepayments("4") //
.withRepaymentAfterEvery("1") //
.withRepaymentTypeAsMonth() //
.withinterestRatePerPeriod("1") //
.withInterestRateFrequencyTypeAsMonths() //
.withAmortizationTypeAsEqualInstallments() //
.withInterestTypeAsDecliningBalance() //
.withTranches(multiDisburseLoan) //
.withInterestCalculationPeriodTypeAsRepaymentPeriod(true)//
.withVariableInstallmentsConfig(Boolean.TRUE, new Integer(5), new Integer(90))//
.withAccounting(accountingRule, accounts).build(null);
return loanProductJSON ;
}
public static String createLoanProductWithVaribleConfigwithEqualPrincipal(final boolean multiDisburseLoan, final String accountingRule, final Account... accounts) {
System.out.println("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------");
final String loanProductJSON = new LoanProductTestBuilder() //
.withPrincipal("1,00,000.00") //
.withNumberOfRepayments("4") //
.withRepaymentAfterEvery("1") //
.withRepaymentTypeAsMonth() //
.withinterestRatePerPeriod("1") //
.withInterestRateFrequencyTypeAsMonths() //
.withAmortizationTypeAsEqualPrincipalPayment() //
.withInterestTypeAsDecliningBalance() //
.withTranches(multiDisburseLoan) //
.withInterestCalculationPeriodTypeAsRepaymentPeriod(true)//
.withVariableInstallmentsConfig(Boolean.TRUE, new Integer(5), new Integer(90))//
.withAccounting(accountingRule, accounts).build(null);
return loanProductJSON ;
}
public static String applyForLoanApplication(final Integer clientID, final Integer loanProductID, List<HashMap> charges,
final String savingsId, String principal) {
System.out.println("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------");
final String loanApplicationJSON = new LoanApplicationTestBuilder() //
.withPrincipal(principal) //
.withLoanTermFrequency("4") //
.withLoanTermFrequencyAsMonths() //
.withNumberOfRepayments("4") //
.withRepaymentEveryAfter("1") //
.withRepaymentFrequencyTypeAsMonths() //
.withInterestRatePerPeriod("2") //
.withAmortizationTypeAsEqualInstallments() //
.withInterestTypeAsDecliningBalance() //
.withInterestCalculationPeriodTypeSameAsRepaymentPeriod() //
.withExpectedDisbursementDate("20 September 2011") //
.withSubmittedOnDate("20 September 2011") //
.withCharges(charges).build(clientID.toString(), loanProductID.toString(), savingsId);
return loanApplicationJSON ;
}
public static String applyForLoanApplicationWithEqualPrincipal(final Integer clientID, final Integer loanProductID, List<HashMap> charges,
final String savingsId, String principal) {
System.out.println("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------");
final String loanApplicationJSON = new LoanApplicationTestBuilder() //
.withPrincipal(principal) //
.withLoanTermFrequency("4") //
.withLoanTermFrequencyAsMonths() //
.withNumberOfRepayments("4") //
.withRepaymentEveryAfter("1") //
.withRepaymentFrequencyTypeAsMonths() //
.withInterestRatePerPeriod("2") //
.withAmortizationTypeAsEqualPrincipalPayments() //
.withInterestTypeAsDecliningBalance() //
.withInterestCalculationPeriodTypeSameAsRepaymentPeriod() //
.withExpectedDisbursementDate("20 September 2011") //
.withSubmittedOnDate("20 September 2011") //
.withCharges(charges).build(clientID.toString(), loanProductID.toString(), savingsId);
return loanApplicationJSON ;
}
public static String createDeleteVariations(ArrayList<Map> deletedInstallments) {
Map<String, Object> toReturn = new HashMap<>();
toReturn.put("locale", "en");
toReturn.put("dateFormat", "dd MMMM yyyy");
Map exceptions = new HashMap<>();
exceptions.put("deletedinstallments", createDeletedMap(deletedInstallments));
toReturn.put("exceptions", exceptions);
String json = new Gson().toJson(toReturn);
return json;
}
private static ArrayList createDeletedMap(ArrayList<Map> deletedItems) {
ArrayList toReturn = new ArrayList<>();
for (Map map : deletedItems) {
ArrayList dueDate = (ArrayList) map.get("dueDate");
Map tosend = new HashMap();
tosend.put("dueDate", formatDate(dueDate));
toReturn.add(tosend);
}
return toReturn;
}
public static String createAddVariations() {
Map<String, Object> toReturn = new HashMap<>();
toReturn.put("locale", "en");
toReturn.put("dateFormat", "dd MMMM yyyy");
Map exceptions = new HashMap<>();
exceptions.put("newinstallments", createNewInstallments());
toReturn.put("exceptions", exceptions);
String json = new Gson().toJson(toReturn);
return json;
}
private static ArrayList createNewInstallments() {
ArrayList toReturn = new ArrayList<>();
Map tosend = new HashMap();
tosend.put("dueDate", "31 October 2011");
tosend.put("installmentAmount", "5000");
toReturn.add(tosend);
return toReturn;
}
public static String createModifiyVariations(Map firstSchedule) {
Map<String, Object> toReturn = new HashMap<>();
toReturn.put("locale", "en");
toReturn.put("dateFormat", "dd MMMM yyyy");
Map exceptions = new HashMap<>();
exceptions.put("modifiedinstallments", createModifyMap(firstSchedule));
toReturn.put("exceptions", exceptions);
String json = new Gson().toJson(toReturn);
return json;
}
private static ArrayList createNewInstallments(String date) {
ArrayList toReturn = new ArrayList<>();
Map tosend = new HashMap();
tosend.put("dueDate", date);
tosend.put("installmentAmount", "5000");
toReturn.add(tosend);
return toReturn;
}
private static ArrayList createModifyMap(Map firstSchedule) {
ArrayList toReturn = new ArrayList<>();
ArrayList dueDate = (ArrayList) firstSchedule.get("dueDate");
Map tosend = new HashMap();
tosend.put("dueDate", formatDate(dueDate));
tosend.put("installmentAmount", 30000) ;
toReturn.add(tosend);
return toReturn;
}
public static String createAllVariations() {
Map<String, Object> toReturn = new HashMap<>();
toReturn.put("locale", "en");
toReturn.put("dateFormat", "dd MMMM yyyy");
Map exceptions = new HashMap<>();
exceptions.put("modifiedinstallments", createModifyMap("20 November 2011"));
exceptions.put("newinstallments", createNewInstallments("25 December 2011"));
exceptions.put("deletedinstallments", createDeletedMap("20 December 2011"));
toReturn.put("exceptions", exceptions);
String json = new Gson().toJson(toReturn);
return json;
}
public static String createAllVariationsWithEqualPrincipal() {
Map<String, Object> toReturn = new HashMap<>();
toReturn.put("locale", "en");
toReturn.put("dateFormat", "dd MMMM yyyy");
Map exceptions = new HashMap<>();
exceptions.put("modifiedinstallments", createModifyMapWithPrinciapl("20 November 2011"));
exceptions.put("newinstallments", createNewInstallmentsWithPrincipal("25 December 2011"));
exceptions.put("deletedinstallments", createDeletedMap("20 December 2011"));
toReturn.put("exceptions", exceptions);
String json = new Gson().toJson(toReturn);
return json;
}
private static ArrayList createNewInstallmentsWithPrincipal(String date) {
ArrayList toReturn = new ArrayList<>();
Map tosend = new HashMap();
tosend.put("dueDate", date);
tosend.put("principal", "5000");
toReturn.add(tosend);
return toReturn;
}
private static ArrayList createModifyMapWithPrinciapl(String date) {
ArrayList toReturn = new ArrayList<>();
Map tosend = new HashMap();
tosend.put("dueDate", date);
tosend.put("principal", 30000) ;
toReturn.add(tosend);
return toReturn;
}
private static ArrayList createDeletedMap(String date) {
ArrayList toReturn = new ArrayList<>();
Map tosend = new HashMap();
tosend.put("dueDate", date);
toReturn.add(tosend);
return toReturn;
}
private static ArrayList createModifyMap(String date) {
ArrayList toReturn = new ArrayList<>();
Map tosend = new HashMap();
tosend.put("dueDate", date);
tosend.put("installmentAmount", 30000) ;
toReturn.add(tosend);
return toReturn;
}
public static String createModifiyDateVariations(String[] date, String[] newdate, String[] principal) {
Map<String, Object> toReturn = new HashMap<>();
toReturn.put("locale", "en");
toReturn.put("dateFormat", "dd MMMM yyyy");
Map exceptions = new HashMap<>();
exceptions.put("modifiedinstallments", createDateModifyMap(date, newdate, principal));
toReturn.put("exceptions", exceptions);
String json = new Gson().toJson(toReturn);
return json;
}
private static ArrayList createDateModifyMap(String[] date, String[] newdate, String[] installments) {
ArrayList toReturn = new ArrayList<>();
for(int i = 0 ; i < date.length; i++) {
Map tosend = new HashMap();
tosend.put("dueDate", date[i]);
tosend.put("modifiedDueDate", newdate[i]) ;
if(i < installments.length) {
tosend.put("installmentAmount", installments[i]) ;
}
toReturn.add(tosend);
}
return toReturn;
}
public static String formatDate(ArrayList list) {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, (int) list.get(0));
cal.set(Calendar.MONTH, (int) list.get(1) - 1);
cal.set(Calendar.DAY_OF_MONTH, (int) list.get(2));
Date date = cal.getTime();
DateFormat requiredFormat = new SimpleDateFormat("dd MMMM YYYY");
return requiredFormat.format(date);
}
public Map<String, Object> createModifyVarations() {
return null;
}
public static ArrayList<Map> constructVerifyData(String[] dates, String[] installments) {
ArrayList<Map> toReturn = new ArrayList<>();
for (int i = 0; i < dates.length; i++) {
Map<String, String> map = new HashMap<>();
map.put("dueDate", dates[i]);
map.put("installmentAmount", installments[i]);
toReturn.add(map);
}
return toReturn;
}
}
@@ -0,0 +1,217 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.integrationtests.variableinstallments;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.mifosplatform.integrationtests.common.accounting.Account;
import org.mifosplatform.integrationtests.common.loans.LoanApplicationTestBuilder;
import org.mifosplatform.integrationtests.common.loans.LoanProductTestBuilder;
import com.google.gson.Gson;
@SuppressWarnings({"rawtypes", "unchecked"})
public class VariableInstallmentsFlatHelper {
public static String createLoanProductWithVaribleConfig(final boolean multiDisburseLoan, final String accountingRule, final Account... accounts) {
System.out.println("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------");
final String loanProductJSON = new LoanProductTestBuilder() //
.withPrincipal("1,00,000.00") //
.withNumberOfRepayments("4") //
.withRepaymentAfterEvery("1") //
.withRepaymentTypeAsMonth() //
.withinterestRatePerPeriod("1") //
.withAmortizationTypeAsEqualPrincipalPayment()
.withInterestTypeAsFlat() //
.withTranches(multiDisburseLoan) //
.withInterestCalculationPeriodTypeAsRepaymentPeriod(true)//
.withVariableInstallmentsConfig(Boolean.TRUE, new Integer(5), new Integer(90))//
.withAccounting(accountingRule, accounts).build(null);
return loanProductJSON ;
}
public static String applyForLoanApplication(final Integer clientID, final Integer loanProductID, List<HashMap> charges,
final String savingsId, String principal) {
System.out.println("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------");
final String loanApplicationJSON = new LoanApplicationTestBuilder() //
.withPrincipal(principal) //
.withLoanTermFrequency("4") //
.withLoanTermFrequencyAsMonths() //
.withNumberOfRepayments("4") //
.withRepaymentEveryAfter("1") //
.withRepaymentFrequencyTypeAsMonths() //
.withInterestRatePerPeriod("2") //
.withAmortizationTypeAsEqualPrincipalPayments() //
.withInterestTypeAsFlatBalance() //
.withInterestCalculationPeriodTypeSameAsRepaymentPeriod() //
.withExpectedDisbursementDate("20 September 2011") //
.withSubmittedOnDate("20 September 2011") //
.withCharges(charges).build(clientID.toString(), loanProductID.toString(), savingsId);
return loanApplicationJSON ;
}
public static String createDeleteVariations(ArrayList<Map> deletedInstallments) {
Map<String, Object> toReturn = new HashMap<>();
toReturn.put("locale", "en");
toReturn.put("dateFormat", "dd MMMM yyyy");
Map exceptions = new HashMap<>();
exceptions.put("deletedinstallments", createDeletedMap(deletedInstallments));
toReturn.put("exceptions", exceptions);
String json = new Gson().toJson(toReturn);
return json;
}
private static ArrayList createDeletedMap(ArrayList<Map> deletedItems) {
ArrayList toReturn = new ArrayList<>();
for (Map map : deletedItems) {
ArrayList dueDate = (ArrayList) map.get("dueDate");
Map tosend = new HashMap();
tosend.put("dueDate", formatDate(dueDate));
toReturn.add(tosend);
}
return toReturn;
}
public static String createAddVariations() {
Map<String, Object> toReturn = new HashMap<>();
toReturn.put("locale", "en");
toReturn.put("dateFormat", "dd MMMM yyyy");
Map exceptions = new HashMap<>();
exceptions.put("newinstallments", createNewInstallments());
toReturn.put("exceptions", exceptions);
String json = new Gson().toJson(toReturn);
return json;
}
private static ArrayList createNewInstallments() {
ArrayList toReturn = new ArrayList<>();
Map tosend = new HashMap();
tosend.put("dueDate", "31 October 2011");
tosend.put("principal", "5000");
toReturn.add(tosend);
return toReturn;
}
public static String createModifiyVariations(Map firstSchedule) {
Map<String, Object> toReturn = new HashMap<>();
toReturn.put("locale", "en");
toReturn.put("dateFormat", "dd MMMM yyyy");
Map exceptions = new HashMap<>();
exceptions.put("modifiedinstallments", createModifyMap(firstSchedule));
toReturn.put("exceptions", exceptions);
String json = new Gson().toJson(toReturn);
return json;
}
private static ArrayList createNewInstallments(String date) {
ArrayList toReturn = new ArrayList<>();
Map tosend = new HashMap();
tosend.put("dueDate", date);
tosend.put("principal", "5000");
toReturn.add(tosend);
return toReturn;
}
public static String createModifiyDateVariations(String[] date, String[] newdate, String[] principal) {
Map<String, Object> toReturn = new HashMap<>();
toReturn.put("locale", "en");
toReturn.put("dateFormat", "dd MMMM yyyy");
Map exceptions = new HashMap<>();
exceptions.put("modifiedinstallments", createDateModifyMap(date, newdate, principal));
toReturn.put("exceptions", exceptions);
String json = new Gson().toJson(toReturn);
return json;
}
private static ArrayList createDateModifyMap(String[] date, String[] newdate, String[] principal) {
ArrayList toReturn = new ArrayList<>();
for(int i = 0 ; i < date.length; i++) {
Map tosend = new HashMap();
tosend.put("dueDate", date[i]);
tosend.put("modifiedDueDate", newdate[i]) ;
if(i < principal.length) {
tosend.put("principal", principal[i]) ;
}
toReturn.add(tosend);
}
return toReturn;
}
private static ArrayList createModifyMap(Map firstSchedule) {
ArrayList toReturn = new ArrayList<>();
ArrayList dueDate = (ArrayList) firstSchedule.get("dueDate");
Map tosend = new HashMap();
tosend.put("dueDate", formatDate(dueDate));
tosend.put("principal", 30000) ;
toReturn.add(tosend);
return toReturn;
}
public static String createAllVariations() {
Map<String, Object> toReturn = new HashMap<>();
toReturn.put("locale", "en");
toReturn.put("dateFormat", "dd MMMM yyyy");
Map exceptions = new HashMap<>();
exceptions.put("modifiedinstallments", createModifyMap("20 November 2011"));
exceptions.put("newinstallments", createNewInstallments("25 December 2011"));
exceptions.put("deletedinstallments", createDeletedMap("20 December 2011"));
toReturn.put("exceptions", exceptions);
String json = new Gson().toJson(toReturn);
return json;
}
private static ArrayList createDeletedMap(String date) {
ArrayList toReturn = new ArrayList<>();
Map tosend = new HashMap();
tosend.put("dueDate", date);
toReturn.add(tosend);
return toReturn;
}
private static ArrayList createModifyMap(String date) {
ArrayList toReturn = new ArrayList<>();
Map tosend = new HashMap();
tosend.put("dueDate", date);
tosend.put("principal", 30000) ;
toReturn.add(tosend);
return toReturn;
}
public static String formatDate(ArrayList list) {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, (int) list.get(0));
cal.set(Calendar.MONTH, (int) list.get(1) - 1);
cal.set(Calendar.DAY_OF_MONTH, (int) list.get(2));
Date date = cal.getTime();
DateFormat requiredFormat = new SimpleDateFormat("dd MMMM YYYY");
return requiredFormat.format(date);
}
public Map<String, Object> createModifyVarations() {
return null;
}
public static ArrayList<Map> constructVerifyData(String[] dates, String[] installments) {
ArrayList<Map> toReturn = new ArrayList<>();
for (int i = 0; i < dates.length; i++) {
Map<String, String> map = new HashMap<>();
map.put("dueDate", dates[i]);
map.put("installmentAmount", installments[i]);
toReturn.add(map);
}
return toReturn;
}
}
@@ -0,0 +1,427 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.integrationtests.variableinstallments;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mifosplatform.integrationtests.common.ClientHelper;
import org.mifosplatform.integrationtests.common.Utils;
import org.mifosplatform.integrationtests.common.loans.LoanStatusChecker;
import org.mifosplatform.integrationtests.common.loans.LoanTransactionHelper;
import com.jayway.restassured.builder.RequestSpecBuilder;
import com.jayway.restassured.builder.ResponseSpecBuilder;
import com.jayway.restassured.http.ContentType;
import com.jayway.restassured.specification.RequestSpecification;
import com.jayway.restassured.specification.ResponseSpecification;
@SuppressWarnings({"rawtypes", "unchecked"})
public class VariableInstallmentsIntegrationTest {
private static final String NONE = "1";
private RequestSpecification requestSpec;
private ResponseSpecification responseSpec;
private LoanTransactionHelper loanTransactionHelper;
@Before
public void setup() {
Utils.initializeRESTAssured();
this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec);
}
@Test
public void testVariableLoanProductCreation() {
final String json = VariableInstallmentsDecliningBalanceHelper.createLoanProductWithVaribleConfig(false, NONE);
final Integer loanProductID = this.loanTransactionHelper.getLoanProductId(json);
System.out.println("------------------------------RETRIEVING CREATED LOAN PRODUCT DETAILS ---------------------------------------");
Map loanProduct = (Map)loanTransactionHelper.getLoanProductDetail(requestSpec, responseSpec, loanProductID, "") ;
Assert.assertTrue((Boolean)loanProduct.get("allowVariableInstallments")) ;
Assert.assertEquals(new Integer(5), loanProduct.get("minimumGap")) ;
Assert.assertEquals(new Integer(90), loanProduct.get("maximumGap")) ;
}
@Test
public void testLoanProductCreation() {
final String josn = VariableInstallmentsDecliningBalanceHelper.createLoanProductWithoutVaribleConfig(false, NONE);
Integer loanProductID = this.loanTransactionHelper.getLoanProductId(josn);
System.out.println("------------------------------RETRIEVING CREATED LOAN PRODUCT DETAILS ---------------------------------------");
Map loanProduct = (Map)loanTransactionHelper.getLoanProductDetail(requestSpec, responseSpec, loanProductID, "") ;
Assert.assertTrue(!(Boolean)loanProduct.get("allowVariableInstallments")) ;
}
@Test
public void testDeleteInstallmentsWithDecliningBalanceEqualInstallments() {
VariableIntallmentsTransactionHelper transactionHelper = new VariableIntallmentsTransactionHelper(requestSpec, responseSpec) ;
final String loanProductJson = VariableInstallmentsDecliningBalanceHelper.createLoanProductWithVaribleConfig(false, NONE);
Integer loanProductID = this.loanTransactionHelper.getLoanProductId(loanProductJson);
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
final String json = VariableInstallmentsDecliningBalanceHelper.applyForLoanApplication(clientID, loanProductID, null, null, "1,00,000.00");
final Integer loanID = this.loanTransactionHelper.getLoanId(json);
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
//Integer loanID = 49 ;
Map list = transactionHelper.retrieveSchedule(loanID) ;
Map repaymentSchedule = (Map)list.get("repaymentSchedule") ;
ArrayList periods = (ArrayList)repaymentSchedule.get("periods") ;
ArrayList toDelete = new ArrayList<>() ;
toDelete.add(periods.get(1)) ;
String toDeletedata = VariableInstallmentsDecliningBalanceHelper.createDeleteVariations(toDelete) ;
HashMap modifiedReschdule = transactionHelper.validateVariations(toDeletedata, loanID) ;
ArrayList newperiods = (ArrayList) modifiedReschdule.get("periods") ;
ArrayList toVerifyData = VariableInstallmentsDecliningBalanceHelper.constructVerifyData(new String[] {"20 November 2011", "20 December 2011", "20 January 2012"},
new String[] {"34675.47", "34675.47", "36756.26"}) ;
assertAfterSubmit(newperiods, toVerifyData) ;
transactionHelper.submitVariations(toDeletedata, loanID) ;
list = transactionHelper.retrieveSchedule(loanID) ;
repaymentSchedule = (Map)list.get("repaymentSchedule") ;
periods = (ArrayList)repaymentSchedule.get("periods") ;
periods.remove(0) ; //Repayments Schedule includes disbursement also. So remove this.
assertAfterSubmit(periods, toVerifyData) ;
}
private void assertAfterSubmit(ArrayList<Map> serverData, ArrayList<Map> expectedData) {
Assert.assertTrue(serverData.size() == expectedData.size()) ;
for(int i = 0 ; i < serverData.size(); i++) {
Map<String, Object> serverMap = serverData.get(i) ;
Map<String, Object> expectedMap = expectedData.get(i) ;
Assert.assertTrue(VariableInstallmentsDecliningBalanceHelper.formatDate((ArrayList)serverMap.get("dueDate")).equals(expectedMap.get("dueDate"))) ;
Assert.assertTrue(serverMap.get("totalOutstandingForPeriod").toString().equals(expectedMap.get("installmentAmount"))) ;
}
}
@Test
public void testAddInstallmentsWithDecliningBalanceEqualInstallments() {
//31 October 2011 - 5000
//Result: 20 October 2011 - 21,215.84, 31 October 2011 - 5000, 20 November 2011 26,477.31, 20 December 2011 26,477.31, 20 January 2012 25,947.7
VariableIntallmentsTransactionHelper transactionHelper = new VariableIntallmentsTransactionHelper(requestSpec, responseSpec) ;
final String loanProductJson = VariableInstallmentsDecliningBalanceHelper.createLoanProductWithVaribleConfig(false, NONE);
Integer loanProductID = this.loanTransactionHelper.getLoanProductId(loanProductJson);
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
final String json = VariableInstallmentsDecliningBalanceHelper.applyForLoanApplication(clientID, loanProductID, null, null, "1,00,000.00");
final Integer loanID = this.loanTransactionHelper.getLoanId(json);
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
// Integer loanID = 57 ;
Map list = transactionHelper.retrieveSchedule(loanID) ;
Map repaymentSchedule = (Map)list.get("repaymentSchedule") ;
ArrayList periods = (ArrayList)repaymentSchedule.get("periods") ;
String addVariationsjsondata = VariableInstallmentsDecliningBalanceHelper.createAddVariations() ;
HashMap modifiedReschdule = transactionHelper.validateVariations(addVariationsjsondata, loanID) ;
ArrayList newperiods = (ArrayList) modifiedReschdule.get("periods") ;
ArrayList toVerifyData = VariableInstallmentsDecliningBalanceHelper.constructVerifyData(new String[] {"20 October 2011", "31 October 2011", "20 November 2011", "20 December 2011", "20 January 2012"},
new String[] {"21215.84", "5000.0", "26477.31", "26477.31", "25947.7"}) ;
assertAfterSubmit(newperiods, toVerifyData) ;
transactionHelper.submitVariations(addVariationsjsondata, loanID) ;
list = transactionHelper.retrieveSchedule(loanID) ;
repaymentSchedule = (Map)list.get("repaymentSchedule") ;
periods = (ArrayList)repaymentSchedule.get("periods") ;
periods.remove(0) ; //Repayments Schedule includes disbursement also. So remove this.
assertAfterSubmit(periods, toVerifyData) ;
}
@Test
public void testModifyInstallmentWithDecliningBalanceEqualInstallments() {
//20 October 2011 - 30000 modify
//Result 20 October 2011 - 30000.0, 20 November 2011 - 24,966.34, 20 December 2011 - 24,966.34, 20 January 2012 - 24,966.33
VariableIntallmentsTransactionHelper transactionHelper = new VariableIntallmentsTransactionHelper(requestSpec, responseSpec) ;
final String loanProductJson = VariableInstallmentsDecliningBalanceHelper.createLoanProductWithVaribleConfig(false, NONE);
Integer loanProductID = this.loanTransactionHelper.getLoanProductId(loanProductJson);
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
final String json = VariableInstallmentsDecliningBalanceHelper.applyForLoanApplication(clientID, loanProductID, null, null, "1,00,000.00");
final Integer loanID = this.loanTransactionHelper.getLoanId(json);
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
//Integer loanID = 57 ;
Map list = transactionHelper.retrieveSchedule(loanID) ;
Map repaymentSchedule = (Map)list.get("repaymentSchedule") ;
ArrayList periods = (ArrayList)repaymentSchedule.get("periods") ;
String addVariationsjsondata = VariableInstallmentsDecliningBalanceHelper.createModifiyVariations((Map)periods.get(1)) ; //0th position will have disbursement
HashMap modifiedReschdule = transactionHelper.validateVariations(addVariationsjsondata, loanID) ;
ArrayList newperiods = (ArrayList) modifiedReschdule.get("periods") ;
ArrayList toVerifyData = VariableInstallmentsDecliningBalanceHelper.constructVerifyData(new String[] {"20 October 2011", "20 November 2011", "20 December 2011", "20 January 2012"},
new String[] {"30000.0", "24966.34", "24966.34", "24966.33"}) ;
assertAfterSubmit(newperiods, toVerifyData) ;
transactionHelper.submitVariations(addVariationsjsondata, loanID) ;
list = transactionHelper.retrieveSchedule(loanID) ;
repaymentSchedule = (Map)list.get("repaymentSchedule") ;
periods = (ArrayList)repaymentSchedule.get("periods") ;
periods.remove(0) ; //Repayments Schedule includes disbursement also. So remove this.
assertAfterSubmit(periods, toVerifyData) ;
}
@Test
public void testAllVariationsDecliningBalancewithEqualInstallments() {
// Request: Delete 20 December 2011 26,262.38, Modify 20 November 2011 from 26,262.38 to 30000, Add 25 December 2011 5000
// Result: 20 October 2011 - 26262.38, 20 November 2011 - 30000, 25 December 2011 - 5000, 20 January 2012 - 44077
VariableIntallmentsTransactionHelper transactionHelper = new VariableIntallmentsTransactionHelper(requestSpec, responseSpec) ;
final String loanProductJson = VariableInstallmentsDecliningBalanceHelper.createLoanProductWithVaribleConfig(false, NONE);
Integer loanProductID = this.loanTransactionHelper.getLoanProductId(loanProductJson);
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
final String json = VariableInstallmentsDecliningBalanceHelper.applyForLoanApplication(clientID, loanProductID, null, null, "1,00,000.00");
final Integer loanID = this.loanTransactionHelper.getLoanId(json);
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
//Integer loanID = 57 ;
Map list = transactionHelper.retrieveSchedule(loanID) ;
Map repaymentSchedule = (Map)list.get("repaymentSchedule") ;
ArrayList periods = (ArrayList)repaymentSchedule.get("periods") ;
String addVariationsjsondata = VariableInstallmentsDecliningBalanceHelper.createAllVariations() ; //0th position will have disbursement
HashMap modifiedReschdule = transactionHelper.validateVariations(addVariationsjsondata, loanID) ;
ArrayList newperiods = (ArrayList) modifiedReschdule.get("periods") ;
ArrayList toVerifyData = VariableInstallmentsDecliningBalanceHelper.constructVerifyData(new String[] {"20 October 2011", "20 November 2011", "25 December 2011", "20 January 2012"},
new String[] {"26262.38", "30000.0", "5000.0", "44077.0"}) ;
assertAfterSubmit(newperiods, toVerifyData) ;
transactionHelper.submitVariations(addVariationsjsondata, loanID) ;
list = transactionHelper.retrieveSchedule(loanID) ;
repaymentSchedule = (Map)list.get("repaymentSchedule") ;
periods = (ArrayList)repaymentSchedule.get("periods") ;
periods.remove(0) ; //Repayments Schedule includes disbursement also. So remove this.
assertAfterSubmit(periods, toVerifyData) ;
}
@Test
public void testAllVariationsDecliningBalancewithEqualPrincipal() {
// Request: Delete 20 December 2011 26,262.38, Modify 20 November 2011 from 26,262.38 to 30000, Add 25 December 2011 5000
// Result: 20 October 2011 - 27000.0, 20 November 2011 - 31500.0, 25 December 2011 - 6045.16, 20 January 2012 - 40670.97
VariableIntallmentsTransactionHelper transactionHelper = new VariableIntallmentsTransactionHelper(requestSpec, responseSpec) ;
final String loanProductJson = VariableInstallmentsDecliningBalanceHelper.createLoanProductWithVaribleConfigwithEqualPrincipal(false, NONE);
Integer loanProductID = this.loanTransactionHelper.getLoanProductId(loanProductJson);
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
final String json = VariableInstallmentsDecliningBalanceHelper.applyForLoanApplicationWithEqualPrincipal(clientID, loanProductID, null, null, "1,00,000.00");
final Integer loanID = this.loanTransactionHelper.getLoanId(json);
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
// Integer loanID = 109 ;
Map list = transactionHelper.retrieveSchedule(loanID) ;
Map repaymentSchedule = (Map)list.get("repaymentSchedule") ;
ArrayList periods = (ArrayList)repaymentSchedule.get("periods") ;
String addVariationsjsondata = VariableInstallmentsDecliningBalanceHelper.createAllVariationsWithEqualPrincipal() ; //0th position will have disbursement
HashMap modifiedReschdule = transactionHelper.validateVariations(addVariationsjsondata, loanID) ;
ArrayList newperiods = (ArrayList) modifiedReschdule.get("periods") ;
ArrayList toVerifyData = VariableInstallmentsDecliningBalanceHelper.constructVerifyData(new String[] {"20 October 2011", "20 November 2011", "25 December 2011", "20 January 2012"},
new String[] {"27000.0", "31500.0", "6045.16", "40670.97"}) ;
assertAfterSubmit(newperiods, toVerifyData) ;
transactionHelper.submitVariations(addVariationsjsondata, loanID) ;
list = transactionHelper.retrieveSchedule(loanID) ;
repaymentSchedule = (Map)list.get("repaymentSchedule") ;
periods = (ArrayList)repaymentSchedule.get("periods") ;
periods.remove(0) ; //Repayments Schedule includes disbursement also. So remove this.
assertAfterSubmit(periods, toVerifyData) ;
}
@Test
public void testModifyDatesWithDecliningBalanceEqualInstallments() {
//Modify 20 December 2011:25000 -> 04 January 2012:20000
//Modify 20 January 2012 -> 08 February 2012
//Result 20 October 2011 -26262.38, 20 November 2011 - 26262.38, 04 January 2012 -20000, 08 February 2012 - 33242.97
VariableIntallmentsTransactionHelper transactionHelper = new VariableIntallmentsTransactionHelper(requestSpec, responseSpec) ;
final String loanProductJson = VariableInstallmentsDecliningBalanceHelper.createLoanProductWithVaribleConfig(false, NONE);
Integer loanProductID = this.loanTransactionHelper.getLoanProductId(loanProductJson);
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
final String json = VariableInstallmentsDecliningBalanceHelper.applyForLoanApplication(clientID, loanProductID, null, null, "1,00,000.00");
final Integer loanID = this.loanTransactionHelper.getLoanId(json);
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
//Integer loanID = 57 ;
Map list = transactionHelper.retrieveSchedule(loanID) ;
Map repaymentSchedule = (Map)list.get("repaymentSchedule") ;
ArrayList periods = (ArrayList)repaymentSchedule.get("periods") ;
//
//
String addVariationsjsondata = VariableInstallmentsDecliningBalanceHelper.createModifiyDateVariations(new String[]{"20 December 2011", "20 January 2012"}, new String[]{"04 January 2012", "08 February 2012"}, new String[]{"20000"}) ; //0th position will have disbursement
HashMap modifiedReschdule = transactionHelper.validateVariations(addVariationsjsondata, loanID) ;
ArrayList newperiods = (ArrayList) modifiedReschdule.get("periods") ;
ArrayList toVerifyData = VariableInstallmentsDecliningBalanceHelper.constructVerifyData(new String[] {"20 October 2011", "20 November 2011", "04 January 2012", "08 February 2012"},
new String[] {"26262.38", "26262.38", "20000.0", "33242.97"}) ;
assertAfterSubmit(newperiods, toVerifyData) ;
transactionHelper.submitVariations(addVariationsjsondata, loanID) ;
list = transactionHelper.retrieveSchedule(loanID) ;
repaymentSchedule = (Map)list.get("repaymentSchedule") ;
periods = (ArrayList)repaymentSchedule.get("periods") ;
periods.remove(0) ; //Repayments Schedule includes disbursement also. So remove this.
assertAfterSubmit(periods, toVerifyData) ;
}
// Interest Type is FLAT
@Test
public void testDeleteInstallmentsWithInterestTypeFlat() {
VariableIntallmentsTransactionHelper transactionHelper = new VariableIntallmentsTransactionHelper(requestSpec, responseSpec) ;
final String loanProductJson = VariableInstallmentsFlatHelper.createLoanProductWithVaribleConfig(false, NONE);
Integer loanProductID = this.loanTransactionHelper.getLoanProductId(loanProductJson);
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
final String json = VariableInstallmentsFlatHelper.applyForLoanApplication(clientID, loanProductID, null, null, "1,00,000.00");
final Integer loanID = this.loanTransactionHelper.getLoanId(json);
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
Map list = transactionHelper.retrieveSchedule(loanID) ;
Map repaymentSchedule = (Map)list.get("repaymentSchedule") ;
ArrayList periods = (ArrayList)repaymentSchedule.get("periods") ;
ArrayList toDelete = new ArrayList<>() ;
toDelete.add(periods.get(1)) ;
String toDeletedata = VariableInstallmentsFlatHelper.createDeleteVariations(toDelete) ;
HashMap modifiedReschdule = transactionHelper.validateVariations(toDeletedata, loanID) ;
ArrayList newperiods = (ArrayList) modifiedReschdule.get("periods") ;
ArrayList toVerifyData = VariableInstallmentsFlatHelper.constructVerifyData(new String[] {"20 November 2011", "20 December 2011", "20 January 2012"},
new String[] {"36000.0", "36000.0", "36000.0"}) ;
assertAfterSubmit(newperiods, toVerifyData) ;
transactionHelper.submitVariations(toDeletedata, loanID) ;
list = transactionHelper.retrieveSchedule(loanID) ;
repaymentSchedule = (Map)list.get("repaymentSchedule") ;
periods = (ArrayList)repaymentSchedule.get("periods") ;
periods.remove(0) ; //Repayments Schedule includes disbursement also. So remove this.
assertAfterSubmit(periods, toVerifyData) ;
}
@Test
public void testAddInstallmentsWithInterestTypeFlat() {
//31 October 2011 - 5000
//Result: 20 October 2011 - 21600.0, 31 October 2011 - 6600.0, 20 November 2011 26600.0, 20 December 2011 26600.0, 20 January 2012 26600.0
VariableIntallmentsTransactionHelper transactionHelper = new VariableIntallmentsTransactionHelper(requestSpec, responseSpec) ;
final String loanProductJson = VariableInstallmentsFlatHelper.createLoanProductWithVaribleConfig(false, NONE);
Integer loanProductID = this.loanTransactionHelper.getLoanProductId(loanProductJson);
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
final String json = VariableInstallmentsFlatHelper.applyForLoanApplication(clientID, loanProductID, null, null, "1,00,000.00");
final Integer loanID = this.loanTransactionHelper.getLoanId(json);
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
//Integer loanID = 67 ;
Map list = transactionHelper.retrieveSchedule(loanID) ;
Map repaymentSchedule = (Map)list.get("repaymentSchedule") ;
ArrayList periods = (ArrayList)repaymentSchedule.get("periods") ;
String addVariationsjsondata = VariableInstallmentsFlatHelper.createAddVariations() ;
HashMap modifiedReschdule = transactionHelper.validateVariations(addVariationsjsondata, loanID) ;
ArrayList newperiods = (ArrayList) modifiedReschdule.get("periods") ;
ArrayList toVerifyData = VariableInstallmentsFlatHelper.constructVerifyData(new String[] {"20 October 2011", "31 October 2011", "20 November 2011", "20 December 2011", "20 January 2012"},
new String[] {"21600.0", "6600.0", "26600.0", "26600.0", "26600.0"}) ;
assertAfterSubmit(newperiods, toVerifyData) ;
transactionHelper.submitVariations(addVariationsjsondata, loanID) ;
list = transactionHelper.retrieveSchedule(loanID) ;
repaymentSchedule = (Map)list.get("repaymentSchedule") ;
periods = (ArrayList)repaymentSchedule.get("periods") ;
periods.remove(0) ; //Repayments Schedule includes disbursement also. So remove this.
assertAfterSubmit(periods, toVerifyData) ;
}
@Test
public void testModifyInstallmentsWithInterestTypeisFlat() {
//20 October 2011 - 30000 modify
//Result 20 October 2011 - 32000.0, 20 November 2011 - 25333.33, 20 December 2011 - 25333.33, 20 January 2012 - 25333.34
VariableIntallmentsTransactionHelper transactionHelper = new VariableIntallmentsTransactionHelper(requestSpec, responseSpec) ;
final String loanProductJson = VariableInstallmentsFlatHelper.createLoanProductWithVaribleConfig(false, NONE);
Integer loanProductID = this.loanTransactionHelper.getLoanProductId(loanProductJson);
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
final String json = VariableInstallmentsFlatHelper.applyForLoanApplication(clientID, loanProductID, null, null, "1,00,000.00");
final Integer loanID = this.loanTransactionHelper.getLoanId(json);
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
//Integer loanID = 67 ;
Map list = transactionHelper.retrieveSchedule(loanID) ;
Map repaymentSchedule = (Map)list.get("repaymentSchedule") ;
ArrayList periods = (ArrayList)repaymentSchedule.get("periods") ;
String addVariationsjsondata = VariableInstallmentsFlatHelper.createModifiyVariations((Map)periods.get(1)) ; //0th position will have disbursement
HashMap modifiedReschdule = transactionHelper.validateVariations(addVariationsjsondata, loanID) ;
ArrayList newperiods = (ArrayList) modifiedReschdule.get("periods") ;
ArrayList toVerifyData = VariableInstallmentsFlatHelper.constructVerifyData(new String[] {"20 October 2011", "20 November 2011", "20 December 2011", "20 January 2012"},
new String[] {"32000.0", "25333.33", "25333.33", "25333.34"}) ;
assertAfterSubmit(newperiods, toVerifyData) ;
transactionHelper.submitVariations(addVariationsjsondata, loanID) ;
list = transactionHelper.retrieveSchedule(loanID) ;
repaymentSchedule = (Map)list.get("repaymentSchedule") ;
periods = (ArrayList)repaymentSchedule.get("periods") ;
periods.remove(0) ; //Repayments Schedule includes disbursement also. So remove this.
assertAfterSubmit(periods, toVerifyData) ;
}
@Test
public void testAllVariationsWithInterestTypeFlat() {
// Request: Delete 20 December 2011 25000.0, Modify 20 November 2011 from 25,000 to 30000, Add 25 December 2011 5000
// Result: 20 October 2011 - 27000.0, 20 November 2011 - 32000.0, 25 December 2011 - 7000.0, 20 January 2012 - 42000.0
VariableIntallmentsTransactionHelper transactionHelper = new VariableIntallmentsTransactionHelper(requestSpec, responseSpec) ;
final String loanProductJson = VariableInstallmentsFlatHelper.createLoanProductWithVaribleConfig(false, NONE);
Integer loanProductID = this.loanTransactionHelper.getLoanProductId(loanProductJson);
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
final String json = VariableInstallmentsFlatHelper.applyForLoanApplication(clientID, loanProductID, null, null, "1,00,000.00");
final Integer loanID = this.loanTransactionHelper.getLoanId(json);
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
//Integer loanID = 67 ;
Map list = transactionHelper.retrieveSchedule(loanID) ;
Map repaymentSchedule = (Map)list.get("repaymentSchedule") ;
ArrayList periods = (ArrayList)repaymentSchedule.get("periods") ;
String addVariationsjsondata = VariableInstallmentsFlatHelper.createAllVariations() ; //0th position will have disbursement
HashMap modifiedReschdule = transactionHelper.validateVariations(addVariationsjsondata, loanID) ;
ArrayList newperiods = (ArrayList) modifiedReschdule.get("periods") ;
ArrayList toVerifyData = VariableInstallmentsFlatHelper.constructVerifyData(new String[] {"20 October 2011", "20 November 2011", "25 December 2011", "20 January 2012"},
new String[] {"27000.0", "32000.0", "7000.0", "42000.0"}) ;
assertAfterSubmit(newperiods, toVerifyData) ;
transactionHelper.submitVariations(addVariationsjsondata, loanID) ;
list = transactionHelper.retrieveSchedule(loanID) ;
repaymentSchedule = (Map)list.get("repaymentSchedule") ;
periods = (ArrayList)repaymentSchedule.get("periods") ;
periods.remove(0) ; //Repayments Schedule includes disbursement also. So remove this.
assertAfterSubmit(periods, toVerifyData) ;
}
@Test
public void testModifyDatesWithInterestTypeFlat() {
//Modify 20 December 2011:25000 -> 04 January 2012:20000
//Modify 20 January 2012 -> 08 February 2012
//Result 20 October 2011 -27306.45, 20 November 2011 - 27306.45, 04 January 2012 -22306.45, 08 February 2012 - 32306.46
VariableIntallmentsTransactionHelper transactionHelper = new VariableIntallmentsTransactionHelper(requestSpec, responseSpec) ;
final String loanProductJson = VariableInstallmentsFlatHelper.createLoanProductWithVaribleConfig(false, NONE);
Integer loanProductID = this.loanTransactionHelper.getLoanProductId(loanProductJson);
final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec);
ClientHelper.verifyClientCreatedOnServer(this.requestSpec, this.responseSpec, clientID);
final String json = VariableInstallmentsFlatHelper.applyForLoanApplication(clientID, loanProductID, null, null, "1,00,000.00");
final Integer loanID = this.loanTransactionHelper.getLoanId(json);
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID);
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
//Integer loanID = 67 ;
Map list = transactionHelper.retrieveSchedule(loanID) ;
Map repaymentSchedule = (Map)list.get("repaymentSchedule") ;
ArrayList periods = (ArrayList)repaymentSchedule.get("periods") ;
//
//
String addVariationsjsondata = VariableInstallmentsFlatHelper.createModifiyDateVariations(new String[]{"20 December 2011", "20 January 2012"}, new String[]{"04 January 2012", "08 February 2012"}, new String[]{"20000"}) ; //0th position will have disbursement
HashMap modifiedReschdule = transactionHelper.validateVariations(addVariationsjsondata, loanID) ;
ArrayList newperiods = (ArrayList) modifiedReschdule.get("periods") ;
ArrayList toVerifyData = VariableInstallmentsFlatHelper.constructVerifyData(new String[] {"20 October 2011", "20 November 2011", "04 January 2012", "08 February 2012"},
new String[] {"27306.45", "27306.45", "22306.45", "32306.46"}) ;
assertAfterSubmit(newperiods, toVerifyData) ;
transactionHelper.submitVariations(addVariationsjsondata, loanID) ;
list = transactionHelper.retrieveSchedule(loanID) ;
repaymentSchedule = (Map)list.get("repaymentSchedule") ;
periods = (ArrayList)repaymentSchedule.get("periods") ;
periods.remove(0) ; //Repayments Schedule includes disbursement also. So remove this.
assertAfterSubmit(periods, toVerifyData) ;
}
}
@@ -0,0 +1,46 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.integrationtests.variableinstallments;
import java.util.HashMap;
import java.util.Map;
import org.mifosplatform.integrationtests.common.Utils;
import com.jayway.restassured.specification.RequestSpecification;
import com.jayway.restassured.specification.ResponseSpecification;
@SuppressWarnings("rawtypes")
public class VariableIntallmentsTransactionHelper {
private final String URL = "https://localhost:8443/mifosng-provider/api/v1/loans/" ;
private final RequestSpecification requestSpec;
private final ResponseSpecification responseSpec;
public VariableIntallmentsTransactionHelper(final RequestSpecification requestSpec,
final ResponseSpecification responseSpec) {
this.requestSpec = requestSpec ;
this.responseSpec = responseSpec ;
}
public Map retrieveSchedule(Integer loanId) {
String url = URL+loanId+"?associations=repaymentSchedule&exclude=guarantors&"+Utils.TENANT_IDENTIFIER ;
return Utils.performServerGet(requestSpec, responseSpec, url, "");
}
public HashMap validateVariations(final String exceptions, Integer loanId) {
String url = URL+loanId+"/schedule?command=calculateLoanSchedule&"+Utils.TENANT_IDENTIFIER ;
return Utils.performServerPost(this.requestSpec, this.responseSpec, url, exceptions, "");
}
public HashMap submitVariations(final String exceptions, Integer loanId) {
String url = URL+loanId+"/schedule?command=addVariations&"+Utils.TENANT_IDENTIFIER ;
return Utils.performServerPost(this.requestSpec, this.responseSpec, url, exceptions, "");
}
}
@@ -41,7 +41,8 @@ public class CodeValue extends AbstractPersistable<Long> {
@Column(name = "is_active") @Column(name = "is_active")
private boolean isActive; private boolean isActive;
public static CodeValue createNew(final Code code, final String label, final int position, final String description, final boolean isActive) { public static CodeValue createNew(final Code code, final String label, final int position, final String description,
final boolean isActive) {
return new CodeValue(code, label, position, description, isActive); return new CodeValue(code, label, position, description, isActive);
} }
@@ -70,7 +71,11 @@ public class CodeValue extends AbstractPersistable<Long> {
final String label = command.stringValueOfParameterNamed(CODEVALUE_JSON_INPUT_PARAMS.NAME.getValue()); final String label = command.stringValueOfParameterNamed(CODEVALUE_JSON_INPUT_PARAMS.NAME.getValue());
Integer position = command.integerValueSansLocaleOfParameterNamed(CODEVALUE_JSON_INPUT_PARAMS.POSITION.getValue()); Integer position = command.integerValueSansLocaleOfParameterNamed(CODEVALUE_JSON_INPUT_PARAMS.POSITION.getValue());
String description = command.stringValueOfParameterNamed(CODEVALUE_JSON_INPUT_PARAMS.DESCRIPTION.getValue()); String description = command.stringValueOfParameterNamed(CODEVALUE_JSON_INPUT_PARAMS.DESCRIPTION.getValue());
boolean isActive = command.booleanPrimitiveValueOfParameterNamed(CODEVALUE_JSON_INPUT_PARAMS.IS_ACTIVE.getValue()); Boolean isActiveObj = command.booleanObjectValueOfParameterNamed(CODEVALUE_JSON_INPUT_PARAMS.IS_ACTIVE.getValue());
boolean isActive = true;
if (isActiveObj != null) {
isActive = isActiveObj;
}
if (position == null) { if (position == null) {
position = new Integer(0); position = new Integer(0);
} }
@@ -67,8 +67,10 @@ public final class CodeValueCommandFromApiJsonDeserializer {
this.fromApiJsonHelper.extractIntegerSansLocaleNamed(CODEVALUE_JSON_INPUT_PARAMS.POSITION.getValue(), element); this.fromApiJsonHelper.extractIntegerSansLocaleNamed(CODEVALUE_JSON_INPUT_PARAMS.POSITION.getValue(), element);
} }
final Boolean isActive = this.fromApiJsonHelper.extractBooleanNamed(CODEVALUE_JSON_INPUT_PARAMS.IS_ACTIVE.getValue(), element); if (this.fromApiJsonHelper.parameterExists(CODEVALUE_JSON_INPUT_PARAMS.IS_ACTIVE.getValue(), element)) {
baseDataValidator.reset().parameter(CODEVALUE_JSON_INPUT_PARAMS.IS_ACTIVE.getValue()).value(isActive).validateForBooleanValue(); final Boolean isActive = this.fromApiJsonHelper.extractBooleanNamed(CODEVALUE_JSON_INPUT_PARAMS.IS_ACTIVE.getValue(), element);
baseDataValidator.reset().parameter(CODEVALUE_JSON_INPUT_PARAMS.IS_ACTIVE.getValue()).value(isActive).validateForBooleanValue();
}
throwExceptionIfValidationWarningsExist(dataValidationErrors); throwExceptionIfValidationWarningsExist(dataValidationErrors);
} }
@@ -86,6 +86,7 @@ import org.mifosplatform.portfolio.loanaccount.loanschedule.service.LoanSchedule
import org.mifosplatform.portfolio.loanaccount.loanschedule.service.LoanScheduleHistoryReadPlatformService; import org.mifosplatform.portfolio.loanaccount.loanschedule.service.LoanScheduleHistoryReadPlatformService;
import org.mifosplatform.portfolio.loanaccount.service.LoanChargeReadPlatformService; import org.mifosplatform.portfolio.loanaccount.service.LoanChargeReadPlatformService;
import org.mifosplatform.portfolio.loanaccount.service.LoanReadPlatformService; import org.mifosplatform.portfolio.loanaccount.service.LoanReadPlatformService;
import org.mifosplatform.portfolio.loanproduct.LoanProductConstants;
import org.mifosplatform.portfolio.loanproduct.data.LoanProductData; import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
import org.mifosplatform.portfolio.loanproduct.data.TransactionProcessingStrategyData; import org.mifosplatform.portfolio.loanproduct.data.TransactionProcessingStrategyData;
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod; import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
@@ -109,19 +110,20 @@ import com.google.gson.JsonElement;
public class LoansApiResource { public class LoansApiResource {
private final Set<String> LOAN_DATA_PARAMETERS = new HashSet<>(Arrays.asList("id", "accountNo", "status", "externalId", "clientId", private final Set<String> LOAN_DATA_PARAMETERS = new HashSet<>(Arrays.asList("id", "accountNo", "status", "externalId", "clientId",
"group", "loanProductId", "loanProductName", "loanProductDescription", "isLoanProductLinkedToFloatingRate", "fundId", "fundName", "loanPurposeId", "group", "loanProductId", "loanProductName", "loanProductDescription", "isLoanProductLinkedToFloatingRate", "fundId",
"loanPurposeName", "loanOfficerId", "loanOfficerName", "currency", "principal", "totalOverpaid", "inArrearsTolerance", "fundName", "loanPurposeId", "loanPurposeName", "loanOfficerId", "loanOfficerName", "currency", "principal", "totalOverpaid",
"termFrequency", "termPeriodFrequencyType", "numberOfRepayments", "repaymentEvery", "interestRatePerPeriod", "inArrearsTolerance", "termFrequency", "termPeriodFrequencyType", "numberOfRepayments", "repaymentEvery",
"annualInterestRate", "repaymentFrequencyType", "transactionProcessingStrategyId", "transactionProcessingStrategyName", "interestRatePerPeriod", "annualInterestRate", "repaymentFrequencyType", "transactionProcessingStrategyId",
"interestRateFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType", "transactionProcessingStrategyName", "interestRateFrequencyType", "amortizationType", "interestType",
"expectedFirstRepaymentOnDate", "graceOnPrincipalPayment", "graceOnInterestPayment", "graceOnInterestCharged", "interestCalculationPeriodType", LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName, "expectedFirstRepaymentOnDate",
"interestChargedFromDate", "timeline", "totalFeeChargesAtDisbursement", "summary", "repaymentSchedule", "transactions", "graceOnPrincipalPayment", "graceOnInterestPayment", "graceOnInterestCharged", "interestChargedFromDate", "timeline",
"charges", "collateral", "guarantors", "meeting", "productOptions", "amortizationTypeOptions", "interestTypeOptions", "totalFeeChargesAtDisbursement", "summary", "repaymentSchedule", "transactions", "charges", "collateral", "guarantors",
"interestCalculationPeriodTypeOptions", "repaymentFrequencyTypeOptions", "repaymentFrequencyNthDayTypeOptions", "meeting", "productOptions", "amortizationTypeOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions",
"repaymentFrequencyDaysOfWeekTypeOptions", "termFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "fundOptions", "repaymentFrequencyTypeOptions", "repaymentFrequencyNthDayTypeOptions", "repaymentFrequencyDaysOfWeekTypeOptions",
"repaymentStrategyOptions", "chargeOptions", "loanOfficerOptions", "loanPurposeOptions", "loanCollateralOptions", "termFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "fundOptions", "repaymentStrategyOptions", "chargeOptions",
"chargeTemplate", "calendarOptions", "syncDisbursementWithMeeting", "loanCounter", "loanProductCounter", "notes", "loanOfficerOptions", "loanPurposeOptions", "loanCollateralOptions", "chargeTemplate", "calendarOptions",
"accountLinkingOptions", "linkedAccount", "interestRateDifferential", "isFloatingInterestRate", "interestRatesPeriods")); "syncDisbursementWithMeeting", "loanCounter", "loanProductCounter", "notes", "accountLinkingOptions", "linkedAccount",
"interestRateDifferential", "isFloatingInterestRate", "interestRatesPeriods"));
private final Set<String> LOAN_APPROVAL_DATA_PARAMETERS = new HashSet<>(Arrays.asList("approvalDate", "approvalAmount")); private final Set<String> LOAN_APPROVAL_DATA_PARAMETERS = new HashSet<>(Arrays.asList("approvalDate", "approvalAmount"));
private final String resourceNameForPermissions = "LOAN"; private final String resourceNameForPermissions = "LOAN";
@@ -494,21 +496,21 @@ public class LoansApiResource {
interestRateFrequencyTypeOptions = this.dropdownReadPlatformService.retrieveInterestRateFrequencyTypeOptions(); interestRateFrequencyTypeOptions = this.dropdownReadPlatformService.retrieveInterestRateFrequencyTypeOptions();
amortizationTypeOptions = this.dropdownReadPlatformService.retrieveLoanAmortizationTypeOptions(); amortizationTypeOptions = this.dropdownReadPlatformService.retrieveLoanAmortizationTypeOptions();
if(product.isLinkedToFloatingInterestRates()){ if (product.isLinkedToFloatingInterestRates()) {
interestTypeOptions = Arrays.asList(interestType(InterestMethod.DECLINING_BALANCE)); interestTypeOptions = Arrays.asList(interestType(InterestMethod.DECLINING_BALANCE));
}else { } else {
interestTypeOptions = this.dropdownReadPlatformService.retrieveLoanInterestTypeOptions(); interestTypeOptions = this.dropdownReadPlatformService.retrieveLoanInterestTypeOptions();
} }
interestCalculationPeriodTypeOptions = this.dropdownReadPlatformService.retrieveLoanInterestRateCalculatedInPeriodOptions(); interestCalculationPeriodTypeOptions = this.dropdownReadPlatformService.retrieveLoanInterestRateCalculatedInPeriodOptions();
fundOptions = this.fundReadPlatformService.retrieveAllFunds(); fundOptions = this.fundReadPlatformService.retrieveAllFunds();
repaymentStrategyOptions = this.dropdownReadPlatformService.retreiveTransactionProcessingStrategies(); repaymentStrategyOptions = this.dropdownReadPlatformService.retreiveTransactionProcessingStrategies();
if(product.getMultiDisburseLoan()){ if (product.getMultiDisburseLoan()) {
chargeOptions = this.chargeReadPlatformService.retrieveLoanAccountApplicableCharges(loanId, chargeOptions = this.chargeReadPlatformService.retrieveLoanAccountApplicableCharges(loanId,
new ChargeTimeType[] { ChargeTimeType.OVERDUE_INSTALLMENT }); new ChargeTimeType[] { ChargeTimeType.OVERDUE_INSTALLMENT });
}else{ } else {
chargeOptions = this.chargeReadPlatformService.retrieveLoanAccountApplicableCharges(loanId, chargeOptions = this.chargeReadPlatformService.retrieveLoanAccountApplicableCharges(loanId, new ChargeTimeType[] {
new ChargeTimeType[] { ChargeTimeType.OVERDUE_INSTALLMENT, ChargeTimeType.TRANCHE_DISBURSEMENT }); ChargeTimeType.OVERDUE_INSTALLMENT, ChargeTimeType.TRANCHE_DISBURSEMENT });
} }
chargeTemplate = this.loanChargeReadPlatformService.retrieveLoanChargeTemplate(); chargeTemplate = this.loanChargeReadPlatformService.retrieveLoanChargeTemplate();
@@ -98,6 +98,7 @@ public class LoanAccountData {
private final EnumOptionData amortizationType; private final EnumOptionData amortizationType;
private final EnumOptionData interestType; private final EnumOptionData interestType;
private final EnumOptionData interestCalculationPeriodType; private final EnumOptionData interestCalculationPeriodType;
private final Boolean allowPartialPeriodInterestCalcualtion;
private final BigDecimal inArrearsTolerance; private final BigDecimal inArrearsTolerance;
private final Long transactionProcessingStrategyId; private final Long transactionProcessingStrategyId;
private final String transactionProcessingStrategyName; private final String transactionProcessingStrategyName;
@@ -242,6 +243,7 @@ public class LoanAccountData {
final boolean isFloatingInterestRate = false; final boolean isFloatingInterestRate = false;
final BigDecimal interestRateDifferential = null; final BigDecimal interestRateDifferential = null;
final EnumOptionData interestCalculationPeriodType = null; final EnumOptionData interestCalculationPeriodType = null;
final Boolean allowPartialPeriodInterestCalcualtion = null;
final LocalDate expectedFirstRepaymentOnDate = null; final LocalDate expectedFirstRepaymentOnDate = null;
final Integer graceOnPrincipalPayment = null; final Integer graceOnPrincipalPayment = null;
final Integer graceOnInterestPayment = null; final Integer graceOnInterestPayment = null;
@@ -304,22 +306,23 @@ public class LoanAccountData {
final Integer minimumGap = null; final Integer minimumGap = null;
final Integer maximumGap = null; final Integer maximumGap = null;
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group, loanType, loanProductId, return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group,
loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, loanType, loanProductId, loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName,
currencyData, proposedPrincipal, principal, principal, totalOverpaid, inArrearsTolerance, termFrequency, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, currencyData, proposedPrincipal, principal, principal,
termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, repaymentFrequencyNthDayType, totalOverpaid, inArrearsTolerance, termFrequency, termPeriodFrequencyType, numberOfRepayments, repaymentEvery,
repaymentFrequencyDayOfWeekType, transactionProcessingStrategyId, transactionProcessingStrategyName, amortizationType, repaymentFrequencyType, repaymentFrequencyNthDayType, repaymentFrequencyDayOfWeekType, transactionProcessingStrategyId,
interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType, isFloatingInterestRate, transactionProcessingStrategyName, amortizationType, interestRatePerPeriod, interestRateFrequencyType, annualInterestRate,
interestRateDifferential, interestCalculationPeriodType, expectedFirstRepaymentOnDate, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, interestType, isFloatingInterestRate, interestRateDifferential, interestCalculationPeriodType,
interestChargedFromDate, timeline, summary, feeChargesDueAtDisbursementCharged, repaymentSchedule, transactions, charges, allowPartialPeriodInterestCalcualtion, expectedFirstRepaymentOnDate, graceOnPrincipalPayment, graceOnInterestPayment,
collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, graceOnInterestCharged, interestChargedFromDate, timeline, summary, feeChargesDueAtDisbursementCharged, repaymentSchedule,
repaymentFrequencyNthDayTypeOptions, repaymentFrequencyDayOfWeekTypeOptions, transactionProcessingStrategyOptions, transactions, charges, collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions,
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, repaymentFrequencyTypeOptions, repaymentFrequencyNthDayTypeOptions, repaymentFrequencyDayOfWeekTypeOptions,
fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions, transactionProcessingStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions,
syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, accountLinkingOptions, linkedAccount, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions,
disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount, maxOutstandingLoanBalance, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter, notes,
emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType, accountLinkingOptions, linkedAccount, disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount,
daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule, maxOutstandingLoanBalance, emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges,
isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule,
createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods, isVariableInstallmentsAllowed, minimumGap, createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods, isVariableInstallmentsAllowed, minimumGap,
maximumGap); maximumGap);
@@ -329,8 +332,8 @@ public class LoanAccountData {
* Used to produce a {@link LoanAccountData} with only client information * Used to produce a {@link LoanAccountData} with only client information
* defaulted. * defaulted.
*/ */
public static LoanAccountData clientDefaults(final Long clientId, final String clientAccountNo, final String clientName, final Long clientOfficeId, public static LoanAccountData clientDefaults(final Long clientId, final String clientAccountNo, final String clientName,
final LocalDate expectedDisbursementDate) { final Long clientOfficeId, final LocalDate expectedDisbursementDate) {
final Long id = null; final Long id = null;
final String accountNo = null; final String accountNo = null;
final LoanStatusEnumData status = null; final LoanStatusEnumData status = null;
@@ -370,6 +373,7 @@ public class LoanAccountData {
final boolean isFloatingInterestRate = false; final boolean isFloatingInterestRate = false;
final BigDecimal interestRateDifferential = null; final BigDecimal interestRateDifferential = null;
final EnumOptionData interestCalculationPeriodType = null; final EnumOptionData interestCalculationPeriodType = null;
final Boolean allowPartialPeriodInterestCalcualtion = null;
final LocalDate expectedFirstRepaymentOnDate = null; final LocalDate expectedFirstRepaymentOnDate = null;
final Integer graceOnPrincipalPayment = null; final Integer graceOnPrincipalPayment = null;
final Integer graceOnInterestPayment = null; final Integer graceOnInterestPayment = null;
@@ -434,23 +438,23 @@ public class LoanAccountData {
final Integer minimumGap = null; final Integer minimumGap = null;
final Integer maximumGap = null; final Integer maximumGap = null;
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group, loanType, loanProductId, return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group,
loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, loanType, loanProductId, loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName,
currencyData, proposedPrincipal, principal, principal, totalOverpaid, inArrearsTolerance, termFrequency, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, currencyData, proposedPrincipal, principal, principal,
termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, repaymentFrequencyNthDayType, totalOverpaid, inArrearsTolerance, termFrequency, termPeriodFrequencyType, numberOfRepayments, repaymentEvery,
repaymentFrequencyDayOfWeekType, transactionProcessingStrategyId, transactionProcessingStrategyName, amortizationType, repaymentFrequencyType, repaymentFrequencyNthDayType, repaymentFrequencyDayOfWeekType, transactionProcessingStrategyId,
interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType, transactionProcessingStrategyName, amortizationType, interestRatePerPeriod, interestRateFrequencyType, annualInterestRate,
isFloatingInterestRate, interestRateDifferential, interestCalculationPeriodType, interestType, isFloatingInterestRate, interestRateDifferential, interestCalculationPeriodType,
expectedFirstRepaymentOnDate, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, allowPartialPeriodInterestCalcualtion, expectedFirstRepaymentOnDate, graceOnPrincipalPayment, graceOnInterestPayment,
interestChargedFromDate, timeline, summary, feeChargesDueAtDisbursementCharged, repaymentSchedule, transactions, charges, graceOnInterestCharged, interestChargedFromDate, timeline, summary, feeChargesDueAtDisbursementCharged, repaymentSchedule,
collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, transactions, charges, collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions,
repaymentFrequencyNthDayTypeOptions, repaymentFrequencyDayOfWeekTypeOptions, repaymentStrategyOptions, repaymentFrequencyTypeOptions, repaymentFrequencyNthDayTypeOptions, repaymentFrequencyDayOfWeekTypeOptions,
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions,
fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions,
syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, accountLinkingOptions, linkedAccount, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter, notes,
disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount, maxOutstandingLoanBalance, accountLinkingOptions, linkedAccount, disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount,
emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType, maxOutstandingLoanBalance, emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges,
daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule, isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule,
createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods, isVariableInstallmentsAllowed, minimumGap, createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods, isVariableInstallmentsAllowed, minimumGap,
maximumGap); maximumGap);
@@ -458,19 +462,20 @@ public class LoanAccountData {
public static LoanAccountData populateClientDefaults(final LoanAccountData acc, final LoanAccountData clientAcc) { public static LoanAccountData populateClientDefaults(final LoanAccountData acc, final LoanAccountData clientAcc) {
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, clientAcc.clientId, clientAcc.clientAccountNo, clientAcc.clientName, return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, clientAcc.clientId, clientAcc.clientAccountNo,
clientAcc.clientOfficeId, acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.isLoanProductLinkedToFloatingRate, clientAcc.clientName, clientAcc.clientOfficeId, acc.group, acc.loanType, acc.loanProductId, acc.loanProductName,
acc.fundId, acc.fundName, acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.loanProductDescription, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, acc.loanPurposeId,
acc.proposedPrincipal, acc.principal, acc.approvedPrincipal, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal, acc.principal,
acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType, acc.approvedPrincipal, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency, acc.termPeriodFrequencyType,
acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType, acc.repaymentFrequencyNthDayType,
acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId, acc.transactionProcessingStrategyName,
acc.annualInterestRate, acc.interestType, acc.isFloatingInterestRate, acc.interestRateDifferential, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType, acc.annualInterestRate, acc.interestType,
acc.interestCalculationPeriodType, acc.expectedFirstRepaymentOnDate, acc.isFloatingInterestRate, acc.interestRateDifferential, acc.interestCalculationPeriodType,
acc.graceOnPrincipalPayment, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate, acc.allowPartialPeriodInterestCalcualtion, acc.expectedFirstRepaymentOnDate, acc.graceOnPrincipalPayment,
clientAcc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate, clientAcc.timeline, acc.summary,
acc.collateral, acc.guarantors, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges, acc.collateral, acc.guarantors,
acc.repaymentFrequencyTypeOptions, acc.repaymentFrequencyNthDayTypeOptions, acc.repaymentFrequencyDaysOfWeekTypeOptions, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions, acc.repaymentFrequencyTypeOptions,
acc.repaymentFrequencyNthDayTypeOptions, acc.repaymentFrequencyDaysOfWeekTypeOptions,
acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions, acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions,
acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null, acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null,
acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions, acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions,
@@ -530,6 +535,7 @@ public class LoanAccountData {
final boolean isFloatingInterestRate = false; final boolean isFloatingInterestRate = false;
final BigDecimal interestRateDifferential = null; final BigDecimal interestRateDifferential = null;
final EnumOptionData interestCalculationPeriodType = null; final EnumOptionData interestCalculationPeriodType = null;
final Boolean allowPartialPeriodInterestCalcualtion = null;
final LocalDate expectedFirstRepaymentOnDate = null; final LocalDate expectedFirstRepaymentOnDate = null;
final Integer graceOnPrincipalPayment = null; final Integer graceOnPrincipalPayment = null;
final Integer graceOnInterestPayment = null; final Integer graceOnInterestPayment = null;
@@ -594,24 +600,23 @@ public class LoanAccountData {
final Integer minimumGap = null; final Integer minimumGap = null;
final Integer maximumGap = null; final Integer maximumGap = null;
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group,
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group, loanType, loanProductId, loanType, loanProductId, loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName,
loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, currencyData, proposedPrincipal, principal, principal,
currencyData, proposedPrincipal, principal, principal, totalOverpaid, inArrearsTolerance, termFrequency, totalOverpaid, inArrearsTolerance, termFrequency, termPeriodFrequencyType, numberOfRepayments, repaymentEvery,
termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, repaymentFrequencyNthDayType, repaymentFrequencyType, repaymentFrequencyNthDayType, repaymentFrequencyDayOfWeekType, transactionProcessingStrategyId,
repaymentFrequencyDayOfWeekType, transactionProcessingStrategyId, transactionProcessingStrategyName, amortizationType, transactionProcessingStrategyName, amortizationType, interestRatePerPeriod, interestRateFrequencyType, annualInterestRate,
interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType, interestType, isFloatingInterestRate, interestRateDifferential, interestCalculationPeriodType,
isFloatingInterestRate, interestRateDifferential, interestCalculationPeriodType, allowPartialPeriodInterestCalcualtion, expectedFirstRepaymentOnDate, graceOnPrincipalPayment, graceOnInterestPayment,
expectedFirstRepaymentOnDate, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, graceOnInterestCharged, interestChargedFromDate, timeline, summary, feeChargesDueAtDisbursementCharged, repaymentSchedule,
interestChargedFromDate, timeline, summary, feeChargesDueAtDisbursementCharged, repaymentSchedule, transactions, charges, transactions, charges, collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions,
collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentFrequencyNthDayTypeOptions, repaymentFrequencyDayOfWeekTypeOptions,
repaymentFrequencyNthDayTypeOptions, repaymentFrequencyDayOfWeekTypeOptions, repaymentStrategyOptions, repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions,
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions,
fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter, notes,
syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, accountLinkingOptions, linkedAccount, accountLinkingOptions, linkedAccount, disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount,
disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount, maxOutstandingBalance, maxOutstandingBalance, emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges,
emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType, isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule,
daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule,
createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods, isVariableInstallmentsAllowed, minimumGap, createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods, isVariableInstallmentsAllowed, minimumGap,
maximumGap); maximumGap);
@@ -619,19 +624,20 @@ public class LoanAccountData {
public static LoanAccountData populateGroupDefaults(final LoanAccountData acc, final LoanAccountData groupAcc) { public static LoanAccountData populateGroupDefaults(final LoanAccountData acc, final LoanAccountData groupAcc) {
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName, acc.clientOfficeId, return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName,
groupAcc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, acc.clientOfficeId, groupAcc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription,
acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId,
acc.principal, acc.approvedPrincipal, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency, acc.loanOfficerName, acc.currency, acc.proposedPrincipal, acc.principal, acc.approvedPrincipal, acc.totalOverpaid,
acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType, acc.inArrearsTolerance, acc.termFrequency, acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery,
acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId, acc.repaymentFrequencyType, acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType,
acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType, acc.transactionProcessingStrategyId, acc.transactionProcessingStrategyName, acc.amortizationType,
acc.annualInterestRate, acc.interestType, acc.isFloatingInterestRate, acc.interestRateDifferential, acc.interestRatePerPeriod, acc.interestRateFrequencyType, acc.annualInterestRate, acc.interestType,
acc.interestCalculationPeriodType, acc.expectedFirstRepaymentOnDate, acc.isFloatingInterestRate, acc.interestRateDifferential, acc.interestCalculationPeriodType,
acc.graceOnPrincipalPayment, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate, acc.allowPartialPeriodInterestCalcualtion, acc.expectedFirstRepaymentOnDate, acc.graceOnPrincipalPayment,
groupAcc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate, groupAcc.timeline, acc.summary,
acc.collateral, acc.guarantors, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges, acc.collateral, acc.guarantors,
acc.repaymentFrequencyTypeOptions, acc.repaymentFrequencyNthDayTypeOptions, acc.repaymentFrequencyDaysOfWeekTypeOptions, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions, acc.repaymentFrequencyTypeOptions,
acc.repaymentFrequencyNthDayTypeOptions, acc.repaymentFrequencyDaysOfWeekTypeOptions,
acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions, acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions,
acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null, acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null,
acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions, acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions,
@@ -766,25 +772,26 @@ public class LoanAccountData {
final Integer minimumGap = null; final Integer minimumGap = null;
final Integer maximumGap = null; final Integer maximumGap = null;
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group, loanType, return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group,
product.getId(), product.getName(), product.getDescription(), product.isLinkedToFloatingInterestRates(), product.getFundId(), product.getFundName(), loanPurposeId, loanType, product.getId(), product.getName(), product.getDescription(), product.isLinkedToFloatingInterestRates(),
loanPurposeName, loanOfficerId, loanOfficerName, product.getCurrency(), proposedPrincipal, principal, principal, product.getFundId(), product.getFundName(), loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
totalOverpaid, product.getInArrearsTolerance(), termFrequency, termPeriodFrequencyType, numberOfRepayments, product.getCurrency(), proposedPrincipal, principal, principal, totalOverpaid, product.getInArrearsTolerance(),
product.getRepaymentEvery(), product.getRepaymentFrequencyType(), null, null, product.getTransactionProcessingStrategyId(), termFrequency, termPeriodFrequencyType, numberOfRepayments, product.getRepaymentEvery(),
product.getRepaymentFrequencyType(), null, null, product.getTransactionProcessingStrategyId(),
transactionProcessingStrategyName, product.getAmortizationType(), interestRatePerPeriod, transactionProcessingStrategyName, product.getAmortizationType(), interestRatePerPeriod,
product.getInterestRateFrequencyType(), product.getAnnualInterestRate(), product.getInterestType(), product.getInterestRateFrequencyType(), product.getAnnualInterestRate(), product.getInterestType(),
product.isFloatingInterestRateCalculationAllowed(), product.getDefaultDifferentialLendingRate(), product.isFloatingInterestRateCalculationAllowed(), product.getDefaultDifferentialLendingRate(),
product.getInterestCalculationPeriodType(), expectedFirstRepaymentOnDate, product.getGraceOnPrincipalPayment(), product.getInterestCalculationPeriodType(), product.getAllowPartialPeriodInterestCalcualtion(),
product.getGraceOnInterestPayment(), product.getGraceOnInterestCharged(), interestChargedFromDate, timeline, summary, expectedFirstRepaymentOnDate, product.getGraceOnPrincipalPayment(), product.getGraceOnInterestPayment(),
feeChargesDueAtDisbursementCharged, repaymentSchedule, transactions, charges, collateral, guarantors, calendarData, product.getGraceOnInterestCharged(), interestChargedFromDate, timeline, summary, feeChargesDueAtDisbursementCharged,
productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentFrequencyNthDayTypeOptions, repaymentSchedule, transactions, charges, collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions,
repaymentFrequencyDayOfWeekTypeOptions, repaymentStrategyOptions, interestRateFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentFrequencyNthDayTypeOptions, repaymentFrequencyDayOfWeekTypeOptions,
amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions,
chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions,
syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, accountLinkingOptions, linkedAccount, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter, notes,
disbursementData, product.getMultiDisburseLoan(), product.canDefineInstallmentAmount(), fixedEmi, accountLinkingOptions, linkedAccount, disbursementData, product.getMultiDisburseLoan(),
product.getOutstandingLoanBalance(), emiAmountVariations, memberVariations, product, inArrears, product.canDefineInstallmentAmount(), fixedEmi, product.getOutstandingLoanBalance(), emiAmountVariations, memberVariations,
product.getGraceOnArrearsAgeing(), product.overdueFeeCharges(), isNPA, product.getDaysInMonthType(), product, inArrears, product.getGraceOnArrearsAgeing(), product.overdueFeeCharges(), isNPA, product.getDaysInMonthType(),
product.getDaysInYearType(), product.isInterestRecalculationEnabled(), product.toLoanInterestRecalculationData(), product.getDaysInYearType(), product.isInterestRecalculationEnabled(), product.toLoanInterestRecalculationData(),
originalSchedule, createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods, originalSchedule, createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods,
product.isVariableInstallmentsAllowed(), product.getMinimumGapBetweenInstallments(), product.isVariableInstallmentsAllowed(), product.getMinimumGapBetweenInstallments(),
@@ -824,16 +831,17 @@ public class LoanAccountData {
charges.add(charge.toLoanChargeData()); charges.add(charge.toLoanChargeData());
} }
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName, acc.clientOfficeId, return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName,
acc.group, acc.loanType, product.getId(), product.getName(), product.getDescription(), product.isLinkedToFloatingInterestRates(), product.getFundId(), acc.clientOfficeId, acc.group, acc.loanType, product.getId(), product.getName(), product.getDescription(),
product.getFundName(), acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, product.isLinkedToFloatingInterestRates(), product.getFundId(), product.getFundName(), acc.loanPurposeId,
product.getCurrency(), product.getPrincipal(), product.getPrincipal(), product.getPrincipal(), acc.totalOverpaid, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, product.getCurrency(), product.getPrincipal(),
product.getInArrearsTolerance(), termFrequency, termPeriodFrequencyType, product.getNumberOfRepayments(), product.getPrincipal(), product.getPrincipal(), acc.totalOverpaid, product.getInArrearsTolerance(), termFrequency,
product.getRepaymentEvery(), product.getRepaymentFrequencyType(), null, null, product.getTransactionProcessingStrategyId(), termPeriodFrequencyType, product.getNumberOfRepayments(), product.getRepaymentEvery(), product.getRepaymentFrequencyType(),
product.getTransactionProcessingStrategyName(), product.getAmortizationType(), product.getInterestRatePerPeriod(), null, null, product.getTransactionProcessingStrategyId(), product.getTransactionProcessingStrategyName(),
product.getInterestRateFrequencyType(), product.getAnnualInterestRate(), product.getInterestType(), product.getAmortizationType(), product.getInterestRatePerPeriod(), product.getInterestRateFrequencyType(),
product.isFloatingInterestRateCalculationAllowed(), product.getDefaultDifferentialLendingRate(), product.getAnnualInterestRate(), product.getInterestType(), product.isFloatingInterestRateCalculationAllowed(),
product.getInterestCalculationPeriodType(), acc.expectedFirstRepaymentOnDate, product.getGraceOnPrincipalPayment(), product.getDefaultDifferentialLendingRate(), product.getInterestCalculationPeriodType(),
product.getAllowPartialPeriodInterestCalcualtion(), acc.expectedFirstRepaymentOnDate, product.getGraceOnPrincipalPayment(),
product.getGraceOnInterestPayment(), product.getGraceOnInterestCharged(), acc.interestChargedFromDate, acc.timeline, product.getGraceOnInterestPayment(), product.getGraceOnInterestCharged(), acc.interestChargedFromDate, acc.timeline,
acc.summary, acc.feeChargesAtDisbursementCharged, repaymentSchedule, transactions, charges, collateral, guarantors, acc.summary, acc.feeChargesAtDisbursementCharged, repaymentSchedule, transactions, charges, collateral, guarantors,
calendarData, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, null, null, calendarData, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, null, null,
@@ -845,8 +853,8 @@ public class LoanAccountData {
acc.memberVariations, product, acc.inArrears, product.getGraceOnArrearsAgeing(), product.overdueFeeCharges(), acc.isNPA, acc.memberVariations, product, acc.inArrears, product.getGraceOnArrearsAgeing(), product.overdueFeeCharges(), acc.isNPA,
product.getDaysInMonthType(), product.getDaysInYearType(), product.isInterestRecalculationEnabled(), product.getDaysInMonthType(), product.getDaysInYearType(), product.isInterestRecalculationEnabled(),
product.toLoanInterestRecalculationData(), acc.originalSchedule, acc.createStandingInstructionAtDisbursement, product.toLoanInterestRecalculationData(), acc.originalSchedule, acc.createStandingInstructionAtDisbursement,
paidInAdvance, acc.interestRatesPeriods, product.isVariableInstallmentsAllowed(), product.getMinimumGapBetweenInstallments(), paidInAdvance, acc.interestRatesPeriods, product.isVariableInstallmentsAllowed(),
product.getMaximumGapBetweenInstallments()); product.getMinimumGapBetweenInstallments(), product.getMaximumGapBetweenInstallments());
} }
@@ -855,25 +863,26 @@ public class LoanAccountData {
* query. * query.
*/ */
public static LoanAccountData basicLoanDetails(final Long id, final String accountNo, final LoanStatusEnumData status, public static LoanAccountData basicLoanDetails(final Long id, final String accountNo, final LoanStatusEnumData status,
final String externalId, final Long clientId, final String clientAccountNo, final String clientName, final Long clientOfficeId, final GroupGeneralData group, final String externalId, final Long clientId, final String clientAccountNo, final String clientName, final Long clientOfficeId,
final EnumOptionData loanType, final Long loanProductId, final String loanProductName, final String loanProductDescription, final GroupGeneralData group, final EnumOptionData loanType, final Long loanProductId, final String loanProductName,
final boolean isLoanProductLinkedToFloatingRate, final Long fundId, final String fundName, final Long loanPurposeId, final String loanProductDescription, final boolean isLoanProductLinkedToFloatingRate, final Long fundId, final String fundName,
final String loanPurposeName, final Long loanOfficerId, final String loanOfficerName, final CurrencyData currencyData, final Long loanPurposeId, final String loanPurposeName, final Long loanOfficerId, final String loanOfficerName,
final BigDecimal proposedPrincipal, final BigDecimal principal, final BigDecimal approvedPrincipal, final CurrencyData currencyData, final BigDecimal proposedPrincipal, final BigDecimal principal,
final BigDecimal totalOverpaid, final BigDecimal inArrearsTolerance, final Integer termFrequency, final BigDecimal approvedPrincipal, final BigDecimal totalOverpaid, final BigDecimal inArrearsTolerance,
final EnumOptionData termPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery, final Integer termFrequency, final EnumOptionData termPeriodFrequencyType, final Integer numberOfRepayments,
final EnumOptionData repaymentFrequencyType, EnumOptionData repaymentFrequencyNthDayType, final Integer repaymentEvery, final EnumOptionData repaymentFrequencyType, EnumOptionData repaymentFrequencyNthDayType,
EnumOptionData repaymentFrequencyDayOfWeekType, final Long transactionStrategyId, final String transactionStrategyName, EnumOptionData repaymentFrequencyDayOfWeekType, final Long transactionStrategyId, final String transactionStrategyName,
final EnumOptionData amortizationType, final BigDecimal interestRatePerPeriod, final EnumOptionData interestRateFrequencyType, final EnumOptionData amortizationType, final BigDecimal interestRatePerPeriod, final EnumOptionData interestRateFrequencyType,
final BigDecimal annualInterestRate, final EnumOptionData interestType, final boolean isFloatingInterestRate, final BigDecimal annualInterestRate, final EnumOptionData interestType, final boolean isFloatingInterestRate,
final BigDecimal interestRateDifferential, final EnumOptionData interestCalculationPeriodType, final BigDecimal interestRateDifferential, final EnumOptionData interestCalculationPeriodType,
final LocalDate expectedFirstRepaymentOnDate, final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment, Boolean allowPartialPeriodInterestCalcualtion, final LocalDate expectedFirstRepaymentOnDate,
final Integer graceOnInterestCharged, final LocalDate interestChargedFromDate, final LoanApplicationTimelineData timeline, final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment, final Integer graceOnInterestCharged,
final LoanSummaryData loanSummary, final BigDecimal feeChargesDueAtDisbursementCharged, final LocalDate interestChargedFromDate, final LoanApplicationTimelineData timeline, final LoanSummaryData loanSummary,
final Boolean syncDisbursementWithMeeting, final Integer loancounter, final Integer loanProductCounter, final BigDecimal feeChargesDueAtDisbursementCharged, final Boolean syncDisbursementWithMeeting, final Integer loancounter,
final Boolean multiDisburseLoan, Boolean canDefineInstallmentAmount, final BigDecimal fixedEmiAmont, final Integer loanProductCounter, final Boolean multiDisburseLoan, Boolean canDefineInstallmentAmount,
final BigDecimal outstandingLoanBalance, final Boolean inArrears, final Integer graceOnArrearsAgeing, final Boolean isNPA, final BigDecimal fixedEmiAmont, final BigDecimal outstandingLoanBalance, final Boolean inArrears,
final EnumOptionData daysInMonthType, final EnumOptionData daysInYearType, final boolean isInterestRecalculationEnabled, final Integer graceOnArrearsAgeing, final Boolean isNPA, final EnumOptionData daysInMonthType,
final EnumOptionData daysInYearType, final boolean isInterestRecalculationEnabled,
final LoanInterestRecalculationData interestRecalculationData, final Boolean createStandingInstructionAtDisbursement, final LoanInterestRecalculationData interestRecalculationData, final Boolean createStandingInstructionAtDisbursement,
final Boolean isVariableInstallmentsAllowed, Integer minimumGap, Integer maximumGap) { final Boolean isVariableInstallmentsAllowed, Integer minimumGap, Integer maximumGap) {
@@ -912,24 +921,23 @@ public class LoanAccountData {
final PaidInAdvanceData paidInAdvance = null; final PaidInAdvanceData paidInAdvance = null;
final Collection<InterestRatePeriodData> interestRatesPeriods = null; final Collection<InterestRatePeriodData> interestRatesPeriods = null;
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group,
return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group, loanType, loanProductId, loanType, loanProductId, loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName,
loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, currencyData, proposedPrincipal, principal,
currencyData, proposedPrincipal, principal, approvedPrincipal, totalOverpaid, inArrearsTolerance, termFrequency, approvedPrincipal, totalOverpaid, inArrearsTolerance, termFrequency, termPeriodFrequencyType, numberOfRepayments,
termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, repaymentFrequencyNthDayType, repaymentEvery, repaymentFrequencyType, repaymentFrequencyNthDayType, repaymentFrequencyDayOfWeekType,
repaymentFrequencyDayOfWeekType, transactionStrategyId, transactionStrategyName, amortizationType, interestRatePerPeriod, transactionStrategyId, transactionStrategyName, amortizationType, interestRatePerPeriod, interestRateFrequencyType,
interestRateFrequencyType, annualInterestRate, interestType, isFloatingInterestRate, interestRateDifferential, annualInterestRate, interestType, isFloatingInterestRate, interestRateDifferential, interestCalculationPeriodType,
interestCalculationPeriodType, expectedFirstRepaymentOnDate, allowPartialPeriodInterestCalcualtion, expectedFirstRepaymentOnDate, graceOnPrincipalPayment, graceOnInterestPayment,
graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, timeline, loanSummary, graceOnInterestCharged, interestChargedFromDate, timeline, loanSummary, feeChargesDueAtDisbursementCharged,
feeChargesDueAtDisbursementCharged, repaymentSchedule, transactions, charges, collateral, guarantors, calendarData, repaymentSchedule, transactions, charges, collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions,
productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentFrequencyNthDayTypeOptions, repaymentFrequencyTypeOptions, repaymentFrequencyNthDayTypeOptions, repaymentFrequencyDayOfWeekTypeOptions,
repaymentFrequencyDayOfWeekTypeOptions, repaymentStrategyOptions, interestRateFrequencyTypeOptions, repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions,
amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions,
chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter, notes,
syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, accountLinkingOptions, linkedAccount, accountLinkingOptions, linkedAccount, disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmont,
disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmont, outstandingLoanBalance, outstandingLoanBalance, emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges,
emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType, isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule,
daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule,
createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods, isVariableInstallmentsAllowed, minimumGap, createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods, isVariableInstallmentsAllowed, minimumGap,
maximumGap); maximumGap);
} }
@@ -960,22 +968,22 @@ public class LoanAccountData {
loanProductConfigurableAttributes = acc.product.getloanProductConfigurableAttributes(); loanProductConfigurableAttributes = acc.product.getloanProductConfigurableAttributes();
} }
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName,
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName, acc.clientOfficeId, acc.clientOfficeId, acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription,
acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId,
acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal, acc.loanOfficerName, acc.currency, acc.proposedPrincipal, acc.principal, acc.approvedPrincipal, acc.totalOverpaid,
acc.principal, acc.approvedPrincipal, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency, acc.inArrearsTolerance, acc.termFrequency, acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery,
acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType, acc.repaymentFrequencyType, acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType,
acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId, acc.transactionProcessingStrategyId, acc.transactionProcessingStrategyName, acc.amortizationType,
acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType, acc.interestRatePerPeriod, acc.interestRateFrequencyType, acc.annualInterestRate, acc.interestType,
acc.annualInterestRate, acc.interestType, acc.isFloatingInterestRate, acc.interestRateDifferential, acc.isFloatingInterestRate, acc.interestRateDifferential, acc.interestCalculationPeriodType,
acc.interestCalculationPeriodType, acc.expectedFirstRepaymentOnDate, acc.allowPartialPeriodInterestCalcualtion, acc.expectedFirstRepaymentOnDate, acc.graceOnPrincipalPayment,
acc.graceOnPrincipalPayment, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate, acc.timeline, acc.summary,
acc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, repaymentSchedule, transactions, charges, collateral, acc.feeChargesAtDisbursementCharged, repaymentSchedule, transactions, charges, collateral, guarantors, calendarData,
guarantors, calendarData, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentFrequencyNthDayTypeOptions,
repaymentFrequencyNthDayTypeOptions, repaymentFrequencyDayOfWeekTypeOptions, transactionProcessingStrategyOptions, repaymentFrequencyDayOfWeekTypeOptions, transactionProcessingStrategyOptions, interestRateFrequencyTypeOptions,
interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions,
fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions,
acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, notes, accountLinkingOptions, linkedAccount, acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, notes, accountLinkingOptions, linkedAccount,
disbursementDetails, acc.multiDisburseLoan, acc.canDefineInstallmentAmount, acc.fixedEmiAmount, disbursementDetails, acc.multiDisburseLoan, acc.canDefineInstallmentAmount, acc.fixedEmiAmount,
acc.maxOutstandingLoanBalance, emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.maxOutstandingLoanBalance, emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears,
@@ -1000,19 +1008,20 @@ public class LoanAccountData {
public static LoanAccountData associateGroup(final LoanAccountData acc, final GroupGeneralData group) { public static LoanAccountData associateGroup(final LoanAccountData acc, final GroupGeneralData group) {
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName, acc.clientOfficeId, return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName,
group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, acc.clientOfficeId, group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription,
acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId,
acc.principal, acc.approvedPrincipal, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency, acc.loanOfficerName, acc.currency, acc.proposedPrincipal, acc.principal, acc.approvedPrincipal, acc.totalOverpaid,
acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType, acc.inArrearsTolerance, acc.termFrequency, acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery,
acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId, acc.repaymentFrequencyType, acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType,
acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType, acc.transactionProcessingStrategyId, acc.transactionProcessingStrategyName, acc.amortizationType,
acc.annualInterestRate, acc.interestType, acc.isFloatingInterestRate, acc.interestRateDifferential, acc.interestRatePerPeriod, acc.interestRateFrequencyType, acc.annualInterestRate, acc.interestType,
acc.interestCalculationPeriodType, acc.expectedFirstRepaymentOnDate, acc.isFloatingInterestRate, acc.interestRateDifferential, acc.interestCalculationPeriodType,
acc.graceOnPrincipalPayment, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate, acc.allowPartialPeriodInterestCalcualtion, acc.expectedFirstRepaymentOnDate, acc.graceOnPrincipalPayment,
acc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate, acc.timeline, acc.summary,
acc.collateral, acc.guarantors, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges, acc.collateral, acc.guarantors,
acc.repaymentFrequencyTypeOptions, acc.repaymentFrequencyNthDayTypeOptions, acc.repaymentFrequencyDaysOfWeekTypeOptions, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions, acc.repaymentFrequencyTypeOptions,
acc.repaymentFrequencyNthDayTypeOptions, acc.repaymentFrequencyDaysOfWeekTypeOptions,
acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions, acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions,
acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null, acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null,
acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions, acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions,
@@ -1063,19 +1072,20 @@ public class LoanAccountData {
memberVariations.put(clientId, borrowerCycleData); memberVariations.put(clientId, borrowerCycleData);
} }
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName, acc.clientOfficeId, return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName,
acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, acc.clientOfficeId, acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription,
acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId,
acc.principal, acc.approvedPrincipal, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency, acc.loanOfficerName, acc.currency, acc.proposedPrincipal, acc.principal, acc.approvedPrincipal, acc.totalOverpaid,
acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType, acc.inArrearsTolerance, acc.termFrequency, acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery,
acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId, acc.repaymentFrequencyType, acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType,
acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType, acc.transactionProcessingStrategyId, acc.transactionProcessingStrategyName, acc.amortizationType,
acc.annualInterestRate, acc.interestType, acc.isFloatingInterestRate, acc.interestRateDifferential, acc.interestRatePerPeriod, acc.interestRateFrequencyType, acc.annualInterestRate, acc.interestType,
acc.interestCalculationPeriodType, acc.expectedFirstRepaymentOnDate, acc.isFloatingInterestRate, acc.interestRateDifferential, acc.interestCalculationPeriodType,
acc.graceOnPrincipalPayment, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate, acc.allowPartialPeriodInterestCalcualtion, acc.expectedFirstRepaymentOnDate, acc.graceOnPrincipalPayment,
acc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate, acc.timeline, acc.summary,
acc.collateral, acc.guarantors, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges, acc.collateral, acc.guarantors,
acc.repaymentFrequencyTypeOptions, acc.repaymentFrequencyNthDayTypeOptions, acc.repaymentFrequencyDaysOfWeekTypeOptions, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions, acc.repaymentFrequencyTypeOptions,
acc.repaymentFrequencyNthDayTypeOptions, acc.repaymentFrequencyDaysOfWeekTypeOptions,
acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions, acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions,
acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null, acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null,
acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions, acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions,
@@ -1095,19 +1105,20 @@ public class LoanAccountData {
final LoanInterestRecalculationData interestRecalculationData = LoanInterestRecalculationData.withCalendarData( final LoanInterestRecalculationData interestRecalculationData = LoanInterestRecalculationData.withCalendarData(
acc.interestRecalculationData, calendarData, compoundingCalendarData); acc.interestRecalculationData, calendarData, compoundingCalendarData);
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName, acc.clientOfficeId, return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName,
acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, acc.clientOfficeId, acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription,
acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId,
acc.principal, acc.approvedPrincipal, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency, acc.loanOfficerName, acc.currency, acc.proposedPrincipal, acc.principal, acc.approvedPrincipal, acc.totalOverpaid,
acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType, acc.inArrearsTolerance, acc.termFrequency, acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery,
acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId, acc.repaymentFrequencyType, acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType,
acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType, acc.transactionProcessingStrategyId, acc.transactionProcessingStrategyName, acc.amortizationType,
acc.annualInterestRate, acc.interestType, acc.isFloatingInterestRate, acc.interestRateDifferential, acc.interestRatePerPeriod, acc.interestRateFrequencyType, acc.annualInterestRate, acc.interestType,
acc.interestCalculationPeriodType, acc.expectedFirstRepaymentOnDate, acc.isFloatingInterestRate, acc.interestRateDifferential, acc.interestCalculationPeriodType,
acc.graceOnPrincipalPayment, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate, acc.allowPartialPeriodInterestCalcualtion, acc.expectedFirstRepaymentOnDate, acc.graceOnPrincipalPayment,
acc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate, acc.timeline, acc.summary,
acc.collateral, acc.guarantors, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges, acc.collateral, acc.guarantors,
acc.repaymentFrequencyTypeOptions, acc.repaymentFrequencyNthDayTypeOptions, acc.repaymentFrequencyDaysOfWeekTypeOptions, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions, acc.repaymentFrequencyTypeOptions,
acc.repaymentFrequencyNthDayTypeOptions, acc.repaymentFrequencyDaysOfWeekTypeOptions,
acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions, acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions,
acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null, acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null,
acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions, acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions,
@@ -1122,20 +1133,20 @@ public class LoanAccountData {
public static LoanAccountData withOriginalSchedule(final LoanAccountData acc, final LoanScheduleData originalSchedule) { public static LoanAccountData withOriginalSchedule(final LoanAccountData acc, final LoanScheduleData originalSchedule) {
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName,
return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName, acc.clientOfficeId, acc.clientOfficeId, acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription,
acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId,
acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal, acc.loanOfficerName, acc.currency, acc.proposedPrincipal, acc.principal, acc.approvedPrincipal, acc.totalOverpaid,
acc.principal, acc.approvedPrincipal, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency, acc.inArrearsTolerance, acc.termFrequency, acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery,
acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType, acc.repaymentFrequencyType, acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType,
acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId, acc.transactionProcessingStrategyId, acc.transactionProcessingStrategyName, acc.amortizationType,
acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType, acc.interestRatePerPeriod, acc.interestRateFrequencyType, acc.annualInterestRate, acc.interestType,
acc.annualInterestRate, acc.interestType, acc.isFloatingInterestRate, acc.interestRateDifferential, acc.isFloatingInterestRate, acc.interestRateDifferential, acc.interestCalculationPeriodType,
acc.interestCalculationPeriodType, acc.expectedFirstRepaymentOnDate, acc.allowPartialPeriodInterestCalcualtion, acc.expectedFirstRepaymentOnDate, acc.graceOnPrincipalPayment,
acc.graceOnPrincipalPayment, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate, acc.timeline, acc.summary,
acc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges, acc.collateral, acc.guarantors,
acc.collateral, acc.guarantors, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions, acc.repaymentFrequencyTypeOptions,
acc.repaymentFrequencyTypeOptions, acc.repaymentFrequencyNthDayTypeOptions, acc.repaymentFrequencyDaysOfWeekTypeOptions, acc.repaymentFrequencyNthDayTypeOptions, acc.repaymentFrequencyDaysOfWeekTypeOptions,
acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions, acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions,
acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null, acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null,
acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions, acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions,
@@ -1185,9 +1196,10 @@ public class LoanAccountData {
final EnumOptionData amortizationType, final BigDecimal interestRatePerPeriod, final EnumOptionData interestRateFrequencyType, final EnumOptionData amortizationType, final BigDecimal interestRatePerPeriod, final EnumOptionData interestRateFrequencyType,
final BigDecimal annualInterestRate, final EnumOptionData interestType, final boolean isFloatingInterestRate, final BigDecimal annualInterestRate, final EnumOptionData interestType, final boolean isFloatingInterestRate,
final BigDecimal interestRateDifferential, final EnumOptionData interestCalculationPeriodType, final BigDecimal interestRateDifferential, final EnumOptionData interestCalculationPeriodType,
final LocalDate expectedFirstRepaymentOnDate, final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment, final Boolean allowPartialPeriodInterestCalcualtion, final LocalDate expectedFirstRepaymentOnDate,
final Integer graceOnInterestCharged, final LocalDate interestChargedFromDate, final LoanApplicationTimelineData timeline, final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment, final Integer graceOnInterestCharged,
final LoanSummaryData summary, final BigDecimal feeChargesDueAtDisbursementCharged, final LoanScheduleData repaymentSchedule, final LocalDate interestChargedFromDate, final LoanApplicationTimelineData timeline, final LoanSummaryData summary,
final BigDecimal feeChargesDueAtDisbursementCharged, final LoanScheduleData repaymentSchedule,
final Collection<LoanTransactionData> transactions, final Collection<LoanChargeData> charges, final Collection<LoanTransactionData> transactions, final Collection<LoanChargeData> charges,
final Collection<CollateralData> collateral, final Collection<GuarantorData> guarantors, final CalendarData meeting, final Collection<CollateralData> collateral, final Collection<GuarantorData> guarantors, final CalendarData meeting,
final Collection<LoanProductData> productOptions, final Collection<EnumOptionData> termFrequencyTypeOptions, final Collection<LoanProductData> productOptions, final Collection<EnumOptionData> termFrequencyTypeOptions,
@@ -1256,6 +1268,7 @@ public class LoanAccountData {
this.isFloatingInterestRate = isFloatingInterestRate; this.isFloatingInterestRate = isFloatingInterestRate;
this.interestRateDifferential = interestRateDifferential; this.interestRateDifferential = interestRateDifferential;
this.interestCalculationPeriodType = interestCalculationPeriodType; this.interestCalculationPeriodType = interestCalculationPeriodType;
this.allowPartialPeriodInterestCalcualtion = allowPartialPeriodInterestCalcualtion;
this.expectedFirstRepaymentOnDate = expectedFirstRepaymentOnDate; this.expectedFirstRepaymentOnDate = expectedFirstRepaymentOnDate;
this.graceOnPrincipalPayment = graceOnPrincipalPayment; this.graceOnPrincipalPayment = graceOnPrincipalPayment;
this.graceOnInterestPayment = graceOnInterestPayment; this.graceOnInterestPayment = graceOnInterestPayment;
@@ -1445,7 +1458,8 @@ public class LoanAccountData {
} }
private static boolean isLoanCycleValuesWhenConditionEqual(Integer loanCycleNumber, LoanProductBorrowerCycleVariationData data) { private static boolean isLoanCycleValuesWhenConditionEqual(Integer loanCycleNumber, LoanProductBorrowerCycleVariationData data) {
return data.getBorrowerCycleNumber().equals(loanCycleNumber) && data.getValueConditionType().equals(LoanProductValueConditionType.EQUAL); return data.getBorrowerCycleNumber().equals(loanCycleNumber)
&& data.getValueConditionType().equals(LoanProductValueConditionType.EQUAL);
} }
public LoanProductData product() { public LoanProductData product() {
@@ -108,8 +108,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
this.paymentPeriodsInOneYearCalculator, mc); this.paymentPeriodsInOneYearCalculator, mc);
boolean isFirstRepayment = true; boolean isFirstRepayment = true;
LocalDate firstRepaymentdate = this.scheduledDateGenerator.generateNextRepaymentDate(scheduleParams.getPeriodStartDate(), LocalDate firstRepaymentdate = this.scheduledDateGenerator.generateNextRepaymentDate(
loanApplicationTerms, isFirstRepayment, holidayDetailDTO); loanApplicationTerms.getExpectedDisbursementDate(), loanApplicationTerms, isFirstRepayment, holidayDetailDTO);
final LocalDate idealDisbursementDate = this.scheduledDateGenerator.idealDisbursementDateBasedOnFirstRepaymentDate( final LocalDate idealDisbursementDate = this.scheduledDateGenerator.idealDisbursementDateBasedOnFirstRepaymentDate(
loanApplicationTerms.getLoanTermPeriodFrequencyType(), loanApplicationTerms.getRepaymentEvery(), firstRepaymentdate); loanApplicationTerms.getLoanTermPeriodFrequencyType(), loanApplicationTerms.getRepaymentEvery(), firstRepaymentdate);
@@ -1520,7 +1520,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
|| loanApplicationTerms.getInterestChargedFromLocalDate().isAfter(periodStartDate)) { || loanApplicationTerms.getInterestChargedFromLocalDate().isAfter(periodStartDate)) {
periodStartDateApplicableForInterest = loanApplicationTerms.getInterestChargedFromLocalDate(); periodStartDateApplicableForInterest = loanApplicationTerms.getInterestChargedFromLocalDate();
} }
} else { } else if(periodStartDate.isEqual(loanApplicationTerms.getExpectedDisbursementDate())){
periodStartDateApplicableForInterest = idealDisbursementDate; periodStartDateApplicableForInterest = idealDisbursementDate;
} }
} }
@@ -62,6 +62,7 @@ public final class LoanApplicationTerms {
private final PeriodFrequencyType interestRatePeriodFrequencyType; private final PeriodFrequencyType interestRatePeriodFrequencyType;
private BigDecimal annualNominalInterestRate; private BigDecimal annualNominalInterestRate;
private final InterestCalculationPeriodMethod interestCalculationPeriodMethod; private final InterestCalculationPeriodMethod interestCalculationPeriodMethod;
private final boolean allowPartialPeriodInterestCalcualtion;
private Money principal; private Money principal;
private final LocalDate expectedDisbursementDate; private final LocalDate expectedDisbursementDate;
@@ -169,8 +170,8 @@ public final class LoanApplicationTerms {
final PeriodFrequencyType repaymentPeriodFrequencyType, Integer nthDay, DayOfWeekType weekDayType, final PeriodFrequencyType repaymentPeriodFrequencyType, Integer nthDay, DayOfWeekType weekDayType,
final AmortizationMethod amortizationMethod, final InterestMethod interestMethod, final BigDecimal interestRatePerPeriod, final AmortizationMethod amortizationMethod, final InterestMethod interestMethod, final BigDecimal interestRatePerPeriod,
final PeriodFrequencyType interestRatePeriodFrequencyType, final BigDecimal annualNominalInterestRate, final PeriodFrequencyType interestRatePeriodFrequencyType, final BigDecimal annualNominalInterestRate,
final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final Money principalMoney, final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final boolean allowPartialPeriodInterestCalcualtion,
final LocalDate expectedDisbursementDate, final LocalDate repaymentsStartingFromDate, final Money principalMoney, final LocalDate expectedDisbursementDate, final LocalDate repaymentsStartingFromDate,
final LocalDate calculatedRepaymentsStartingFromDate, final Integer graceOnPrincipalPayment, final LocalDate calculatedRepaymentsStartingFromDate, final Integer graceOnPrincipalPayment,
final Integer graceOnInterestPayment, final Integer graceOnInterestCharged, final LocalDate interestChargedFromDate, final Integer graceOnInterestPayment, final Integer graceOnInterestCharged, final LocalDate interestChargedFromDate,
final Money inArrearsTolerance, final boolean multiDisburseLoan, final BigDecimal emiAmount, final Money inArrearsTolerance, final boolean multiDisburseLoan, final BigDecimal emiAmount,
@@ -186,13 +187,14 @@ public final class LoanApplicationTerms {
final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod = null; final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod = null;
return new LoanApplicationTerms(currency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments, repaymentEvery, return new LoanApplicationTerms(currency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments, repaymentEvery,
repaymentPeriodFrequencyType, nthDay, weekDayType, amortizationMethod, interestMethod, interestRatePerPeriod, repaymentPeriodFrequencyType, nthDay, weekDayType, amortizationMethod, interestMethod, interestRatePerPeriod,
interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod, principalMoney, interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod,
expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate, graceOnPrincipalPayment, allowPartialPeriodInterestCalcualtion, principalMoney, expectedDisbursementDate, repaymentsStartingFromDate,
graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsTolerance, multiDisburseLoan, emiAmount, calculatedRepaymentsStartingFromDate, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged,
disbursementDatas, maxOutstandingBalance, graceOnArrearsAgeing, daysInMonthType, daysInYearType, interestChargedFromDate, inArrearsTolerance, multiDisburseLoan, emiAmount, disbursementDatas, maxOutstandingBalance,
isInterestRecalculationEnabled, rescheduleStrategyMethod, interestRecalculationCompoundingMethod, restCalendarInstance, graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, rescheduleStrategyMethod,
recalculationFrequencyType, compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment, interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType, compoundingCalendarInstance,
installmentAmountInMultiplesOf, preClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations); compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
preClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations);
} }
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency, public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
@@ -241,6 +243,7 @@ public final class LoanApplicationTerms {
final PeriodFrequencyType interestRatePeriodFrequencyType = loanProductRelatedDetail.getInterestPeriodFrequencyType(); final PeriodFrequencyType interestRatePeriodFrequencyType = loanProductRelatedDetail.getInterestPeriodFrequencyType();
final InterestCalculationPeriodMethod interestCalculationPeriodMethod = loanProductRelatedDetail final InterestCalculationPeriodMethod interestCalculationPeriodMethod = loanProductRelatedDetail
.getInterestCalculationPeriodMethod(); .getInterestCalculationPeriodMethod();
final boolean allowPartialPeriodInterestCalcualtion = loanProductRelatedDetail.isAllowPartialPeriodInterestCalcualtion();
final Money principalMoney = loanProductRelatedDetail.getPrincipal(); final Money principalMoney = loanProductRelatedDetail.getPrincipal();
// //
@@ -255,13 +258,13 @@ public final class LoanApplicationTerms {
return new LoanApplicationTerms(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments, return new LoanApplicationTerms(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments,
repaymentEvery, repaymentPeriodFrequencyType, nthDay.getValue(), dayOfWeek, amortizationMethod, interestMethod, repaymentEvery, repaymentPeriodFrequencyType, nthDay.getValue(), dayOfWeek, amortizationMethod, interestMethod,
interestRatePerPeriod, interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod, interestRatePerPeriod, interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod,
principalMoney, expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate, allowPartialPeriodInterestCalcualtion, principalMoney, expectedDisbursementDate, repaymentsStartingFromDate,
graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsTolerance, calculatedRepaymentsStartingFromDate, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged,
multiDisburseLoan, emiAmount, disbursementDatas, maxOutstandingBalance, loanProductRelatedDetail.getGraceOnDueDate(), interestChargedFromDate, inArrearsTolerance, multiDisburseLoan, emiAmount, disbursementDatas, maxOutstandingBalance,
daysInMonthType, daysInYearType, isInterestRecalculationEnabled, rescheduleStrategyMethod, compoundingMethod, loanProductRelatedDetail.getGraceOnDueDate(), daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
restCalendarInstance, recalculationFrequencyType, compoundingCalendarInstance, compoundingFrequencyType, rescheduleStrategyMethod, compoundingMethod, restCalendarInstance, recalculationFrequencyType, compoundingCalendarInstance,
principalThresholdForLastInstalment, installmentAmountInMultiplesOf, loanPreClosureInterestCalculationStrategy, compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
loanCalendar, approvedAmount, loanTermVariations); loanPreClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations);
} }
public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency, public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency,
@@ -285,6 +288,7 @@ public final class LoanApplicationTerms {
final PeriodFrequencyType interestRatePeriodFrequencyType = loanProductRelatedDetail.getInterestPeriodFrequencyType(); final PeriodFrequencyType interestRatePeriodFrequencyType = loanProductRelatedDetail.getInterestPeriodFrequencyType();
final InterestCalculationPeriodMethod interestCalculationPeriodMethod = loanProductRelatedDetail final InterestCalculationPeriodMethod interestCalculationPeriodMethod = loanProductRelatedDetail
.getInterestCalculationPeriodMethod(); .getInterestCalculationPeriodMethod();
final boolean allowPartialPeriodInterestCalcualtion = loanProductRelatedDetail.isAllowPartialPeriodInterestCalcualtion();
final Money principalMoney = loanProductRelatedDetail.getPrincipal(); final Money principalMoney = loanProductRelatedDetail.getPrincipal();
// //
@@ -305,13 +309,14 @@ public final class LoanApplicationTerms {
final Calendar loanCalendar = null; final Calendar loanCalendar = null;
return new LoanApplicationTerms(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments, return new LoanApplicationTerms(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments,
repaymentEvery, repaymentPeriodFrequencyType, null, null, amortizationMethod, interestMethod, interestRatePerPeriod, repaymentEvery, repaymentPeriodFrequencyType, null, null, amortizationMethod, interestMethod, interestRatePerPeriod,
interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod, principalMoney, interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod,
expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate, graceOnPrincipalPayment, allowPartialPeriodInterestCalcualtion, principalMoney, expectedDisbursementDate, repaymentsStartingFromDate,
graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsTolerance, multiDisburseLoan, emiAmount, calculatedRepaymentsStartingFromDate, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged,
disbursementDatas, maxOutstandingBalance, loanProductRelatedDetail.getGraceOnDueDate(), daysInMonthType, daysInYearType, interestChargedFromDate, inArrearsTolerance, multiDisburseLoan, emiAmount, disbursementDatas, maxOutstandingBalance,
isInterestRecalculationEnabled, rescheduleStrategyMethod, interestRecalculationCompoundingMethod, restCalendarInstance, loanProductRelatedDetail.getGraceOnDueDate(), daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
recalculationFrequencyType, compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment, rescheduleStrategyMethod, interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType,
installmentAmountInMultiplesOf, loanPreClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations); compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf,
loanPreClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations);
} }
public static LoanApplicationTerms assembleFrom(final LoanApplicationTerms applicationTerms, public static LoanApplicationTerms assembleFrom(final LoanApplicationTerms applicationTerms,
@@ -321,18 +326,19 @@ public final class LoanApplicationTerms {
applicationTerms.repaymentPeriodFrequencyType, applicationTerms.nthDay, applicationTerms.weekDayType, applicationTerms.repaymentPeriodFrequencyType, applicationTerms.nthDay, applicationTerms.weekDayType,
applicationTerms.amortizationMethod, applicationTerms.interestMethod, applicationTerms.interestRatePerPeriod, applicationTerms.amortizationMethod, applicationTerms.interestMethod, applicationTerms.interestRatePerPeriod,
applicationTerms.interestRatePeriodFrequencyType, applicationTerms.annualNominalInterestRate, applicationTerms.interestRatePeriodFrequencyType, applicationTerms.annualNominalInterestRate,
applicationTerms.interestCalculationPeriodMethod, applicationTerms.principal, applicationTerms.expectedDisbursementDate, applicationTerms.interestCalculationPeriodMethod, applicationTerms.allowPartialPeriodInterestCalcualtion,
applicationTerms.repaymentsStartingFromDate, applicationTerms.calculatedRepaymentsStartingFromDate, applicationTerms.principal, applicationTerms.expectedDisbursementDate, applicationTerms.repaymentsStartingFromDate,
applicationTerms.principalGrace, applicationTerms.interestPaymentGrace, applicationTerms.interestChargingGrace, applicationTerms.calculatedRepaymentsStartingFromDate, applicationTerms.principalGrace,
applicationTerms.interestChargedFromDate, applicationTerms.inArrearsTolerance, applicationTerms.multiDisburseLoan, applicationTerms.interestPaymentGrace, applicationTerms.interestChargingGrace, applicationTerms.interestChargedFromDate,
applicationTerms.actualFixedEmiAmount, applicationTerms.disbursementDatas, applicationTerms.maxOutstandingBalance, applicationTerms.inArrearsTolerance, applicationTerms.multiDisburseLoan, applicationTerms.actualFixedEmiAmount,
applicationTerms.graceOnArrearsAgeing, applicationTerms.daysInMonthType, applicationTerms.daysInYearType, applicationTerms.disbursementDatas, applicationTerms.maxOutstandingBalance, applicationTerms.graceOnArrearsAgeing,
applicationTerms.interestRecalculationEnabled, applicationTerms.rescheduleStrategyMethod, applicationTerms.daysInMonthType, applicationTerms.daysInYearType, applicationTerms.interestRecalculationEnabled,
applicationTerms.interestRecalculationCompoundingMethod, applicationTerms.restCalendarInstance, applicationTerms.rescheduleStrategyMethod, applicationTerms.interestRecalculationCompoundingMethod,
applicationTerms.recalculationFrequencyType, applicationTerms.compoundingCalendarInstance, applicationTerms.restCalendarInstance, applicationTerms.recalculationFrequencyType,
applicationTerms.compoundingFrequencyType, applicationTerms.principalThresholdForLastInstalment, applicationTerms.compoundingCalendarInstance, applicationTerms.compoundingFrequencyType,
applicationTerms.installmentAmountInMultiplesOf, applicationTerms.preClosureInterestCalculationStrategy, applicationTerms.principalThresholdForLastInstalment, applicationTerms.installmentAmountInMultiplesOf,
applicationTerms.loanCalendar, applicationTerms.approvedPrincipal.getAmount(), loanTermVariations); applicationTerms.preClosureInterestCalculationStrategy, applicationTerms.loanCalendar,
applicationTerms.approvedPrincipal.getAmount(), loanTermVariations);
} }
private LoanApplicationTerms(final ApplicationCurrency currency, final Integer loanTermFrequency, private LoanApplicationTerms(final ApplicationCurrency currency, final Integer loanTermFrequency,
@@ -340,8 +346,8 @@ public final class LoanApplicationTerms {
final PeriodFrequencyType repaymentPeriodFrequencyType, final Integer nthDay, final DayOfWeekType weekDayType, final PeriodFrequencyType repaymentPeriodFrequencyType, final Integer nthDay, final DayOfWeekType weekDayType,
final AmortizationMethod amortizationMethod, final InterestMethod interestMethod, final BigDecimal interestRatePerPeriod, final AmortizationMethod amortizationMethod, final InterestMethod interestMethod, final BigDecimal interestRatePerPeriod,
final PeriodFrequencyType interestRatePeriodFrequencyType, final BigDecimal annualNominalInterestRate, final PeriodFrequencyType interestRatePeriodFrequencyType, final BigDecimal annualNominalInterestRate,
final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final Money principal, final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final boolean allowPartialPeriodInterestCalcualtion,
final LocalDate expectedDisbursementDate, final LocalDate repaymentsStartingFromDate, final Money principal, final LocalDate expectedDisbursementDate, final LocalDate repaymentsStartingFromDate,
final LocalDate calculatedRepaymentsStartingFromDate, final Integer principalGrace, final Integer interestPaymentGrace, final LocalDate calculatedRepaymentsStartingFromDate, final Integer principalGrace, final Integer interestPaymentGrace,
final Integer interestChargingGrace, final LocalDate interestChargedFromDate, final Money inArrearsTolerance, final Integer interestChargingGrace, final LocalDate interestChargedFromDate, final Money inArrearsTolerance,
final boolean multiDisburseLoan, final BigDecimal emiAmount, final List<DisbursementData> disbursementDatas, final boolean multiDisburseLoan, final BigDecimal emiAmount, final List<DisbursementData> disbursementDatas,
@@ -369,6 +375,7 @@ public final class LoanApplicationTerms {
this.interestRatePeriodFrequencyType = interestRatePeriodFrequencyType; this.interestRatePeriodFrequencyType = interestRatePeriodFrequencyType;
this.annualNominalInterestRate = annualNominalInterestRate; this.annualNominalInterestRate = annualNominalInterestRate;
this.interestCalculationPeriodMethod = interestCalculationPeriodMethod; this.interestCalculationPeriodMethod = interestCalculationPeriodMethod;
this.allowPartialPeriodInterestCalcualtion = allowPartialPeriodInterestCalcualtion;
this.principal = principal; this.principal = principal;
this.expectedDisbursementDate = expectedDisbursementDate; this.expectedDisbursementDate = expectedDisbursementDate;
@@ -814,7 +821,7 @@ public final class LoanApplicationTerms {
final BigDecimal loanTermPeriodsInYearBigDecimal = BigDecimal.valueOf(loanTermPeriodsInOneYear); final BigDecimal loanTermPeriodsInYearBigDecimal = BigDecimal.valueOf(loanTermPeriodsInOneYear);
BigDecimal periodicInterestRate = BigDecimal.ZERO; BigDecimal periodicInterestRate = BigDecimal.ZERO;
BigDecimal loanTermFrequencyBigDecimal = calculatePeriodsBetweenDates(periodStartDate, periodEndDate); BigDecimal loanTermFrequencyBigDecimal = calculateLoanTermFrequency(periodStartDate, periodEndDate);
switch (this.interestCalculationPeriodMethod) { switch (this.interestCalculationPeriodMethod) {
case INVALID: case INVALID:
break; break;
@@ -867,6 +874,14 @@ public final class LoanApplicationTerms {
return periodicInterestRate; return periodicInterestRate;
} }
private BigDecimal calculateLoanTermFrequency(final LocalDate periodStartDate, final LocalDate periodEndDate) {
BigDecimal loanTermFrequencyBigDecimal = BigDecimal.valueOf(this.repaymentEvery);
if (this.interestCalculationPeriodMethod.isDaily() || this.allowPartialPeriodInterestCalcualtion) {
loanTermFrequencyBigDecimal = calculatePeriodsBetweenDates(periodStartDate, periodEndDate);
}
return loanTermFrequencyBigDecimal;
}
public BigDecimal interestRateFor(final PaymentPeriodsInOneYearCalculator calculator, final MathContext mc, public BigDecimal interestRateFor(final PaymentPeriodsInOneYearCalculator calculator, final MathContext mc,
final Money outstandingBalance, final LocalDate fromDate, final LocalDate toDate) { final Money outstandingBalance, final LocalDate fromDate, final LocalDate toDate) {
@@ -1079,10 +1094,10 @@ public final class LoanApplicationTerms {
return LoanProductRelatedDetail.createFrom(currency, this.principal.getAmount(), this.interestRatePerPeriod, return LoanProductRelatedDetail.createFrom(currency, this.principal.getAmount(), this.interestRatePerPeriod,
this.interestRatePeriodFrequencyType, this.annualNominalInterestRate, this.interestMethod, this.interestRatePeriodFrequencyType, this.annualNominalInterestRate, this.interestMethod,
this.interestCalculationPeriodMethod, this.repaymentEvery, this.repaymentPeriodFrequencyType, this.numberOfRepayments, this.interestCalculationPeriodMethod, this.allowPartialPeriodInterestCalcualtion, this.repaymentEvery,
this.principalGrace, this.interestPaymentGrace, this.interestChargingGrace, this.amortizationMethod, this.repaymentPeriodFrequencyType, this.numberOfRepayments, this.principalGrace, this.interestPaymentGrace,
this.inArrearsTolerance.getAmount(), this.graceOnArrearsAgeing, this.daysInMonthType.getValue(), this.interestChargingGrace, this.amortizationMethod, this.inArrearsTolerance.getAmount(), this.graceOnArrearsAgeing,
this.daysInYearType.getValue(), this.interestRecalculationEnabled); this.daysInMonthType.getValue(), this.daysInYearType.getValue(), this.interestRecalculationEnabled);
} }
public Integer getLoanTermFrequency() { public Integer getLoanTermFrequency() {
@@ -199,6 +199,11 @@ public class LoanScheduleAssembler {
element); element);
final InterestCalculationPeriodMethod interestCalculationPeriodMethod = InterestCalculationPeriodMethod final InterestCalculationPeriodMethod interestCalculationPeriodMethod = InterestCalculationPeriodMethod
.fromInt(interestCalculationPeriodType); .fromInt(interestCalculationPeriodType);
Boolean allowPartialPeriodInterestCalcualtion = this.fromApiJsonHelper.extractBooleanNamed(
LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName, element);
if (allowPartialPeriodInterestCalcualtion == null) {
allowPartialPeriodInterestCalcualtion = loanProduct.getLoanProductRelatedDetail().isAllowPartialPeriodInterestCalcualtion();
}
final BigDecimal interestRatePerPeriod = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("interestRatePerPeriod", element); final BigDecimal interestRatePerPeriod = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("interestRatePerPeriod", element);
final PeriodFrequencyType interestRatePeriodFrequencyType = loanProduct.getInterestPeriodFrequencyType(); final PeriodFrequencyType interestRatePeriodFrequencyType = loanProduct.getInterestPeriodFrequencyType();
@@ -366,12 +371,13 @@ public class LoanScheduleAssembler {
return LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments, return LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments,
repaymentEvery, repaymentPeriodFrequencyType, nthDay, weekDayType, amortizationMethod, interestMethod, repaymentEvery, repaymentPeriodFrequencyType, nthDay, weekDayType, amortizationMethod, interestMethod,
interestRatePerPeriod, interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod, interestRatePerPeriod, interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod,
principalMoney, expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate, allowPartialPeriodInterestCalcualtion, principalMoney, expectedDisbursementDate, repaymentsStartingFromDate,
graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsToleranceMoney, calculatedRepaymentsStartingFromDate, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged,
loanProduct.isMultiDisburseLoan(), emiAmount, disbursementDatas, maxOutstandingBalance, graceOnArrearsAgeing, interestChargedFromDate, inArrearsToleranceMoney, loanProduct.isMultiDisburseLoan(), emiAmount, disbursementDatas,
daysInMonthType, daysInYearType, isInterestRecalculationEnabled, recalculationFrequencyType, restCalendarInstance, maxOutstandingBalance, graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf, recalculationFrequencyType, restCalendarInstance, compoundingCalendarInstance, compoundingFrequencyType,
loanProduct.preCloseInterestCalculationStrategy(), calendar, BigDecimal.ZERO, loanTermVariations); principalThresholdForLastInstalment, installmentAmountInMultiplesOf, loanProduct.preCloseInterestCalculationStrategy(),
calendar, BigDecimal.ZERO, loanTermVariations);
} }
private CalendarInstance createInterestRecalculationCalendarInstance(final LocalDate calendarStartDate, private CalendarInstance createInterestRecalculationCalendarInstance(final LocalDate calendarStartDate,
@@ -630,7 +636,7 @@ public class LoanScheduleAssembler {
if (termVariations.fetchTermApplicaDate().isAfter(lastDate)) { if (termVariations.fetchTermApplicaDate().isAfter(lastDate)) {
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode( baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(
"variable.schedule.insert.not.allowed.after.last.period.date", "Loan schedule insert request invalid"); "variable.schedule.insert.not.allowed.after.last.period.date", "Loan schedule insert request invalid");
} else if(termVariations.fetchTermApplicaDate().isBefore(loan.getExpectedDisbursedOnLocalDate())){ } else if (termVariations.fetchTermApplicaDate().isBefore(loan.getExpectedDisbursedOnLocalDate())) {
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode( baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(
"variable.schedule.insert.not.allowed.before.disbursement.date", "Loan schedule insert request invalid"); "variable.schedule.insert.not.allowed.before.disbursement.date", "Loan schedule insert request invalid");
} }
@@ -664,7 +670,7 @@ public class LoanScheduleAssembler {
} else { } else {
dueDates.add(termVariations.fetchDateValue()); dueDates.add(termVariations.fetchDateValue());
} }
if(termVariations.fetchDateValue().isBefore(loan.getExpectedDisbursedOnLocalDate())){ if (termVariations.fetchDateValue().isBefore(loan.getExpectedDisbursedOnLocalDate())) {
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode( baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode(
"variable.schedule.insert.not.allowed.before.disbursement.date", "Loan schedule insert request invalid"); "variable.schedule.insert.not.allowed.before.disbursement.date", "Loan schedule insert request invalid");
} }
@@ -713,8 +719,11 @@ public class LoanScheduleAssembler {
int gap = Days.daysBetween(previousDate, duedate).getDays(); int gap = Days.daysBetween(previousDate, duedate).getDays();
previousDate = duedate; previousDate = duedate;
if (gap < minGap || (maxGap != null && gap > maxGap)) { if (gap < minGap || (maxGap != null && gap > maxGap)) {
baseDataValidator.reset().value(duedate) baseDataValidator
.failWithCodeNoParameterAddedToErrorCode("variable.schedule.date.must.be.in.min.max.range", "Loan schedule date invalid"); .reset()
.value(duedate)
.failWithCodeNoParameterAddedToErrorCode("variable.schedule.date.must.be.in.min.max.range",
"Loan schedule date invalid");
} else if (loanCalendar != null && !actualDueDates.contains(duedate) && !loanCalendar.isValidRecurringDate(duedate)) { } else if (loanCalendar != null && !actualDueDates.contains(duedate) && !loanCalendar.isValidRecurringDate(duedate)) {
baseDataValidator baseDataValidator
.reset() .reset()
@@ -37,13 +37,14 @@ public final class CalculateLoanScheduleQueryFromApiJsonHelper {
"accountNo", "externalId", "fundId", "loanOfficerId", "loanPurposeId", "transactionProcessingStrategyId", "principal", "accountNo", "externalId", "fundId", "loanOfficerId", "loanPurposeId", "transactionProcessingStrategyId", "principal",
"inArrearsTolerance", "interestRatePerPeriod", "repaymentEvery", "numberOfRepayments", "loanTermFrequency", "inArrearsTolerance", "interestRatePerPeriod", "repaymentEvery", "numberOfRepayments", "loanTermFrequency",
"loanTermFrequencyType", "repaymentFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType", "loanTermFrequencyType", "repaymentFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType",
"interestRateFrequencyType", "expectedDisbursementDate", "repaymentsStartingFromDate", "graceOnPrincipalPayment", LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName, "interestRateFrequencyType", "expectedDisbursementDate",
"graceOnInterestPayment", "graceOnInterestCharged", "interestChargedFromDate", "submittedOnDate", "submittedOnNote", "locale", "repaymentsStartingFromDate", "graceOnPrincipalPayment", "graceOnInterestPayment", "graceOnInterestCharged",
"dateFormat", "charges", "collateral", "syncDisbursementWithMeeting", "linkAccountId", "interestChargedFromDate", "submittedOnDate", "submittedOnNote", "locale", "dateFormat", "charges", "collateral",
LoanApiConstants.disbursementDataParameterName, LoanApiConstants.emiAmountParameterName, "syncDisbursementWithMeeting", "linkAccountId", LoanApiConstants.disbursementDataParameterName,
LoanApiConstants.maxOutstandingBalanceParameterName, LoanProductConstants.graceOnArrearsAgeingParameterName, LoanApiConstants.emiAmountParameterName, LoanApiConstants.maxOutstandingBalanceParameterName,
LoanProductConstants.recalculationRestFrequencyDateParamName, "createStandingInstructionAtDisbursement", LoanProductConstants.graceOnArrearsAgeingParameterName, LoanProductConstants.recalculationRestFrequencyDateParamName,
LoanApiConstants.isFloatingInterestRateParameterName, LoanApiConstants.interestRateDifferentialParameterName)); "createStandingInstructionAtDisbursement", LoanApiConstants.isFloatingInterestRateParameterName,
LoanApiConstants.interestRateDifferentialParameterName));
private final FromJsonHelper fromApiJsonHelper; private final FromJsonHelper fromApiJsonHelper;
@@ -95,17 +96,9 @@ public final class CalculateLoanScheduleQueryFromApiJsonHelper {
repaymentsStartingFromDate = this.fromApiJsonHelper.extractLocalDateNamed(repaymentsStartingFromDateParameterName, element); repaymentsStartingFromDate = this.fromApiJsonHelper.extractLocalDateNamed(repaymentsStartingFromDateParameterName, element);
} }
LocalDate interestChargedFromDate = null;
final String interestChargedFromDateParameterName = "interestChargedFromDate";
if (this.fromApiJsonHelper.parameterExists(interestChargedFromDateParameterName, element)) {
interestChargedFromDate = this.fromApiJsonHelper.extractLocalDateNamed(interestChargedFromDateParameterName, element);
}
validateRepaymentsStartingFromDateIsAfterDisbursementDate(dataValidationErrors, expectedDisbursementDate, validateRepaymentsStartingFromDateIsAfterDisbursementDate(dataValidationErrors, expectedDisbursementDate,
repaymentsStartingFromDate); repaymentsStartingFromDate);
validateRepaymentsStartingFromDateAndInterestChargedFromDate(dataValidationErrors, expectedDisbursementDate,
repaymentsStartingFromDate, interestChargedFromDate);
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); } "Validation errors exist.", dataValidationErrors); }
@@ -135,27 +128,6 @@ public final class CalculateLoanScheduleQueryFromApiJsonHelper {
} }
} }
private void validateRepaymentsStartingFromDateAndInterestChargedFromDate(final List<ApiParameterError> dataValidationErrors,
final LocalDate expectedDisbursementDate, final LocalDate repaymentsStartingFromDate, final LocalDate interestChargedFromDate) {
if (repaymentsStartingFromDate != null && interestChargedFromDate == null) {
final ApiParameterError error = ApiParameterError.parameterError(
"validation.msg.loan.interestChargedFromDate.must.be.entered.when.using.repayments.startfrom.field",
"The parameter interestChargedFromDate cannot be empty when repaymentsStartingFromDate is provided.",
"interestChargedFromDate", repaymentsStartingFromDate);
dataValidationErrors.add(error);
} else if (repaymentsStartingFromDate == null && interestChargedFromDate != null) {
/* if (expectedDisbursementDate != null && expectedDisbursementDate.isAfter(interestChargedFromDate)) {
final ApiParameterError error = ApiParameterError.parameterError(
"validation.msg.loan.interestChargedFromDate.cannot.be.before.disbursement.date",
"The parameter interestChargedFromDate cannot be before the date given for expectedDisbursementDate.",
"interestChargedFromDate", interestChargedFromDate, expectedDisbursementDate);
dataValidationErrors.add(error);
}*/
}
}
private void validateRepaymentsStartingFromDateIsAfterDisbursementDate(final List<ApiParameterError> dataValidationErrors, private void validateRepaymentsStartingFromDateIsAfterDisbursementDate(final List<ApiParameterError> dataValidationErrors,
final LocalDate expectedDisbursementDate, final LocalDate repaymentsStartingFromDate) { final LocalDate expectedDisbursementDate, final LocalDate repaymentsStartingFromDate) {
if (expectedDisbursementDate != null) { if (expectedDisbursementDate != null) {
@@ -29,6 +29,7 @@ import org.mifosplatform.portfolio.loanaccount.domain.Loan;
import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge; import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge;
import org.mifosplatform.portfolio.loanaccount.domain.LoanInterestRecalculationDetails; import org.mifosplatform.portfolio.loanaccount.domain.LoanInterestRecalculationDetails;
import org.mifosplatform.portfolio.loanproduct.LoanProductConstants; import org.mifosplatform.portfolio.loanproduct.LoanProductConstants;
import org.mifosplatform.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod; import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct; import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct;
import org.mifosplatform.portfolio.savings.domain.SavingsAccount; import org.mifosplatform.portfolio.savings.domain.SavingsAccount;
@@ -49,19 +50,15 @@ public final class LoanApplicationCommandFromApiJsonHelper {
final Set<String> supportedParameters = new HashSet<>(Arrays.asList("dateFormat", "locale", "id", "clientId", "groupId", "loanType", final Set<String> supportedParameters = new HashSet<>(Arrays.asList("dateFormat", "locale", "id", "clientId", "groupId", "loanType",
"productId", "principal", "loanTermFrequency", "loanTermFrequencyType", "numberOfRepayments", "repaymentEvery", "productId", "principal", "loanTermFrequency", "loanTermFrequencyType", "numberOfRepayments", "repaymentEvery",
"repaymentFrequencyType", "repaymentFrequencyNthDayType", "repaymentFrequencyDayOfWeekType", "interestRatePerPeriod", "repaymentFrequencyType", "repaymentFrequencyNthDayType", "repaymentFrequencyDayOfWeekType", "interestRatePerPeriod",
"amortizationType", "interestType", "amortizationType", "interestType", LoanApiConstants.isFloatingInterestRate, LoanApiConstants.interestRateDifferential,
LoanApiConstants.isFloatingInterestRate, "interestCalculationPeriodType", LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName,
LoanApiConstants.interestRateDifferential, "interestRateFrequencyType", "expectedDisbursementDate", "repaymentsStartingFromDate",
"interestCalculationPeriodType",
"interestRateFrequencyType",
"expectedDisbursementDate",
"repaymentsStartingFromDate",
"graceOnPrincipalPayment", "graceOnPrincipalPayment",
"graceOnInterestPayment", "graceOnInterestPayment",
"graceOnInterestCharged", "graceOnInterestCharged",
"interestChargedFromDate", // "interestChargedFromDate",
"submittedOnDate", "submittedOnDate",
"submittedOnNote", // "submittedOnNote",
"accountNo", "accountNo",
"externalId", "externalId",
"fundId", "fundId",
@@ -451,7 +448,7 @@ public final class LoanApplicationCommandFromApiJsonHelper {
.ignoreIfNull().positiveAmount(); .ignoreIfNull().positiveAmount();
} }
validateLoanMultiDisbursementdate(element, baseDataValidator, expectedDisbursementDate, principal); validateLoanMultiDisbursementdate(element, baseDataValidator, expectedDisbursementDate, principal);
validatePartialPeriodSupport(interestCalculationPeriodType, baseDataValidator, element, loanProduct);
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
} }
@@ -670,10 +667,11 @@ public final class LoanApplicationCommandFromApiJsonHelper {
} }
Integer interestCalculationPeriodType = loanProduct.getLoanProductRelatedDetail().getInterestCalculationPeriodMethod().getValue();
final String interestCalculationPeriodTypeParameterName = "interestCalculationPeriodType"; final String interestCalculationPeriodTypeParameterName = "interestCalculationPeriodType";
if (this.fromApiJsonHelper.parameterExists(interestCalculationPeriodTypeParameterName, element)) { if (this.fromApiJsonHelper.parameterExists(interestCalculationPeriodTypeParameterName, element)) {
atLeastOneParameterPassedForUpdate = true; atLeastOneParameterPassedForUpdate = true;
final Integer interestCalculationPeriodType = this.fromApiJsonHelper.extractIntegerWithLocaleNamed( interestCalculationPeriodType = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(
interestCalculationPeriodTypeParameterName, element); interestCalculationPeriodTypeParameterName, element);
baseDataValidator.reset().parameter(interestCalculationPeriodTypeParameterName).value(interestCalculationPeriodType).notNull() baseDataValidator.reset().parameter(interestCalculationPeriodTypeParameterName).value(interestCalculationPeriodType).notNull()
.inMinMaxRange(0, 1); .inMinMaxRange(0, 1);
@@ -877,6 +875,7 @@ public final class LoanApplicationCommandFromApiJsonHelper {
.ignoreIfNull().positiveAmount(); .ignoreIfNull().positiveAmount();
} }
validateLoanMultiDisbursementdate(element, baseDataValidator, expectedDisbursementDate, principal); validateLoanMultiDisbursementdate(element, baseDataValidator, expectedDisbursementDate, principal);
validatePartialPeriodSupport(interestCalculationPeriodType, baseDataValidator, element, loanProduct);
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); } "Validation errors exist.", dataValidationErrors); }
@@ -1152,4 +1151,52 @@ public final class LoanApplicationCommandFromApiJsonHelper {
.validateDateForEqual(expectedDisbursementDate); .validateDateForEqual(expectedDisbursementDate);
} }
private void validatePartialPeriodSupport(final Integer interestCalculationPeriodType, final DataValidatorBuilder baseDataValidator,
final JsonElement element, final LoanProduct loanProduct) {
if (interestCalculationPeriodType != null) {
final InterestCalculationPeriodMethod interestCalculationPeriodMethod = InterestCalculationPeriodMethod
.fromInt(interestCalculationPeriodType);
boolean considerPartialPeriodUpdates = interestCalculationPeriodMethod.isDaily() ? interestCalculationPeriodMethod.isDaily()
: loanProduct.getLoanProductRelatedDetail().isAllowPartialPeriodInterestCalcualtion();
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName, element)) {
final Boolean considerPartialInterestEnabled = this.fromApiJsonHelper.extractBooleanNamed(
LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName, element);
baseDataValidator.reset().parameter(LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName)
.value(considerPartialInterestEnabled).notNull().isOneOfTheseValues(true, false);
boolean considerPartialPeriods = considerPartialInterestEnabled == null ? false : considerPartialInterestEnabled;
if (interestCalculationPeriodMethod.isDaily()) {
if (considerPartialPeriods) {
baseDataValidator.reset().parameter(LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName)
.failWithCode("not.supported.for.daily.calcualtions");
}
} else {
considerPartialPeriodUpdates = considerPartialPeriods;
}
}
if (!considerPartialPeriodUpdates) {
if (loanProduct.isInterestRecalculationEnabled()) {
baseDataValidator.reset().parameter(LoanProductConstants.isInterestRecalculationEnabledParameterName)
.failWithCode("not.supported.for.selected.interest.calcualtion.type");
}
if (loanProduct.isMultiDisburseLoan()) {
baseDataValidator.reset().parameter(LoanProductConstants.multiDisburseLoanParameterName)
.failWithCode("not.supported.for.selected.interest.calcualtion.type");
}
if (loanProduct.allowVariabeInstallments()) {
baseDataValidator.reset().parameter(LoanProductConstants.allowVariableInstallmentsParamName)
.failWithCode("not.supported.for.selected.interest.calcualtion.type");
}
if (loanProduct.isLinkedToFloatingInterestRate()) {
baseDataValidator.reset().parameter("isLinkedToFloatingInterestRates")
.failWithCode("not.supported.for.selected.interest.calcualtion.type");
}
}
}
}
} }
@@ -328,8 +328,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final ClientData clientAccount = this.clientReadPlatformService.retrieveOne(clientId); final ClientData clientAccount = this.clientReadPlatformService.retrieveOne(clientId);
final LocalDate expectedDisbursementDate = DateUtils.getLocalDateOfTenant(); final LocalDate expectedDisbursementDate = DateUtils.getLocalDateOfTenant();
LoanAccountData loanTemplateDetails = LoanAccountData.clientDefaults(clientAccount.id(), clientAccount.accountNo(), clientAccount.displayName(), LoanAccountData loanTemplateDetails = LoanAccountData.clientDefaults(clientAccount.id(), clientAccount.accountNo(),
clientAccount.officeId(), expectedDisbursementDate); clientAccount.displayName(), clientAccount.officeId(), expectedDisbursementDate);
if (productId != null) { if (productId != null) {
final LoanProductData selectedProduct = this.loanProductReadPlatformService.retrieveLoanProduct(productId); final LoanProductData selectedProduct = this.loanProductReadPlatformService.retrieveLoanProduct(productId);
@@ -577,6 +577,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
+ " l.repayment_period_frequency_enum as repaymentFrequencyType, l.repayment_frequency_nth_day_enum as repaymentFrequencyNthDayType, l.repayment_frequency_day_of_week_enum as repaymentFrequencyDayOfWeekType, l.interest_period_frequency_enum as interestRateFrequencyType, " + " l.repayment_period_frequency_enum as repaymentFrequencyType, l.repayment_frequency_nth_day_enum as repaymentFrequencyNthDayType, l.repayment_frequency_day_of_week_enum as repaymentFrequencyDayOfWeekType, l.interest_period_frequency_enum as interestRateFrequencyType, "
+ " l.term_frequency as termFrequency, l.term_period_frequency_enum as termPeriodFrequencyType, " + " l.term_frequency as termFrequency, l.term_period_frequency_enum as termPeriodFrequencyType, "
+ " l.amortization_method_enum as amortizationType, l.interest_method_enum as interestType, l.interest_calculated_in_period_enum as interestCalculationPeriodType," + " l.amortization_method_enum as amortizationType, l.interest_method_enum as interestType, l.interest_calculated_in_period_enum as interestCalculationPeriodType,"
+ " l.allow_partial_period_interest_calcualtion as allowPartialPeriodInterestCalcualtion,"
+ " l.loan_status_id as lifeCycleStatusId, l.loan_transaction_strategy_id as transactionStrategyId, " + " l.loan_status_id as lifeCycleStatusId, l.loan_transaction_strategy_id as transactionStrategyId, "
+ " lps.name as transactionStrategyName, " + " lps.name as transactionStrategyName, "
+ " l.currency_code as currencyCode, l.currency_digits as currencyDigits, l.currency_multiplesof as inMultiplesOf, rc.`name` as currencyName, rc.display_symbol as currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode, " + " l.currency_code as currencyCode, l.currency_digits as currencyDigits, l.currency_multiplesof as inMultiplesOf, rc.`name` as currencyName, rc.display_symbol as currencyDisplaySymbol, rc.internationalized_name_code as currencyNameCode, "
@@ -796,6 +797,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final EnumOptionData interestType = LoanEnumerations.interestType(interestTypeInt); final EnumOptionData interestType = LoanEnumerations.interestType(interestTypeInt);
final EnumOptionData interestCalculationPeriodType = LoanEnumerations final EnumOptionData interestCalculationPeriodType = LoanEnumerations
.interestCalculationPeriodType(interestCalculationPeriodTypeInt); .interestCalculationPeriodType(interestCalculationPeriodTypeInt);
final Boolean allowPartialPeriodInterestCalcualtion = rs.getBoolean("allowPartialPeriodInterestCalcualtion");
final Integer lifeCycleStatusId = JdbcSupport.getInteger(rs, "lifeCycleStatusId"); final Integer lifeCycleStatusId = JdbcSupport.getInteger(rs, "lifeCycleStatusId");
final LoanStatusEnumData status = LoanEnumerations.status(lifeCycleStatusId); final LoanStatusEnumData status = LoanEnumerations.status(lifeCycleStatusId);
@@ -913,18 +915,20 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
compoundingCalendarData, compoundingFrequencyType, compoundingInterval, compoundingFrequencyDate); compoundingCalendarData, compoundingFrequencyType, compoundingInterval, compoundingFrequencyDate);
} }
return LoanAccountData.basicLoanDetails(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, groupData, return LoanAccountData.basicLoanDetails(id, accountNo, status, externalId, clientId, clientAccountNo, clientName,
loanType, loanProductId, loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName, loanPurposeId, loanPurposeName, clientOfficeId, groupData, loanType, loanProductId, loanProductName, loanProductDescription,
loanOfficerId, loanOfficerName, currencyData, proposedPrincipal, principal, approvedPrincipal, totalOverpaid, isLoanProductLinkedToFloatingRate, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName,
inArrearsTolerance, termFrequency, termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, currencyData, proposedPrincipal, principal, approvedPrincipal, totalOverpaid, inArrearsTolerance, termFrequency,
repaymentFrequencyNthDayType, repaymentFrequencyDayOfWeekType, transactionStrategyId, transactionStrategyName, termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, repaymentFrequencyNthDayType,
amortizationType, interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType, repaymentFrequencyDayOfWeekType, transactionStrategyId, transactionStrategyName, amortizationType,
isFloatingInterestRate, interestRateDifferential, interestCalculationPeriodType, expectedFirstRepaymentOnDate, interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType, isFloatingInterestRate,
graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, timeline, interestRateDifferential, interestCalculationPeriodType, allowPartialPeriodInterestCalcualtion,
loanSummary, feeChargesDueAtDisbursementCharged, syncDisbursementWithMeeting, loanCounter, loanProductCounter, expectedFirstRepaymentOnDate, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged,
multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount, outstandingLoanBalance, inArrears, graceOnArrearsAgeing, interestChargedFromDate, timeline, loanSummary, feeChargesDueAtDisbursementCharged, syncDisbursementWithMeeting,
isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, loanCounter, loanProductCounter, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount, outstandingLoanBalance,
createStandingInstructionAtDisbursement, isvariableInstallmentsAllowed, minimumGap, maximumGap); inArrears, graceOnArrearsAgeing, isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
interestRecalculationData, createStandingInstructionAtDisbursement, isvariableInstallmentsAllowed, minimumGap,
maximumGap);
} }
} }
@@ -1411,8 +1415,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
final ClientData clientAccount = this.clientReadPlatformService.retrieveOne(clientId); final ClientData clientAccount = this.clientReadPlatformService.retrieveOne(clientId);
final LocalDate expectedDisbursementDate = DateUtils.getLocalDateOfTenant(); final LocalDate expectedDisbursementDate = DateUtils.getLocalDateOfTenant();
return LoanAccountData.clientDefaults(clientAccount.id(), clientAccount.accountNo(), clientAccount.displayName(), clientAccount.officeId(), return LoanAccountData.clientDefaults(clientAccount.id(), clientAccount.accountNo(), clientAccount.displayName(),
expectedDisbursementDate); clientAccount.officeId(), expectedDisbursementDate);
} }
@Override @Override
@@ -109,5 +109,7 @@ public interface LoanProductConstants {
public static final String maximumGapBetweenInstallments = "maximumGap" ; public static final String maximumGapBetweenInstallments = "maximumGap" ;
public static final String allowPartialPeriodInterestCalcualtionParamName = "allowPartialPeriodInterestCalcualtion";
} }
@@ -48,6 +48,7 @@ import org.mifosplatform.portfolio.floatingrates.data.FloatingRateData;
import org.mifosplatform.portfolio.floatingrates.service.FloatingRatesReadPlatformService; import org.mifosplatform.portfolio.floatingrates.service.FloatingRatesReadPlatformService;
import org.mifosplatform.portfolio.fund.data.FundData; import org.mifosplatform.portfolio.fund.data.FundData;
import org.mifosplatform.portfolio.fund.service.FundReadPlatformService; import org.mifosplatform.portfolio.fund.service.FundReadPlatformService;
import org.mifosplatform.portfolio.loanproduct.LoanProductConstants;
import org.mifosplatform.portfolio.loanproduct.data.LoanProductData; import org.mifosplatform.portfolio.loanproduct.data.LoanProductData;
import org.mifosplatform.portfolio.loanproduct.data.TransactionProcessingStrategyData; import org.mifosplatform.portfolio.loanproduct.data.TransactionProcessingStrategyData;
import org.mifosplatform.portfolio.loanproduct.productmix.data.ProductMixData; import org.mifosplatform.portfolio.loanproduct.productmix.data.ProductMixData;
@@ -70,14 +71,14 @@ public class LoanProductsApiResource {
"minNumberOfRepayments", "maxNumberOfRepayments", "repaymentEvery", "repaymentFrequencyType", "graceOnPrincipalPayment", "minNumberOfRepayments", "maxNumberOfRepayments", "repaymentEvery", "repaymentFrequencyType", "graceOnPrincipalPayment",
"graceOnInterestPayment", "graceOnInterestCharged", "interestRatePerPeriod", "minInterestRatePerPeriod", "graceOnInterestPayment", "graceOnInterestCharged", "interestRatePerPeriod", "minInterestRatePerPeriod",
"maxInterestRatePerPeriod", "interestRateFrequencyType", "annualInterestRate", "amortizationType", "interestType", "maxInterestRatePerPeriod", "interestRateFrequencyType", "annualInterestRate", "amortizationType", "interestType",
"interestCalculationPeriodType", "inArrearsTolerance", "transactionProcessingStrategyId", "transactionProcessingStrategyName", "interestCalculationPeriodType", LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName, "inArrearsTolerance",
"charges", "accountingRule", "externalId", "accountingMappings", "paymentChannelToFundSourceMappings", "fundOptions", "transactionProcessingStrategyId", "transactionProcessingStrategyName", "charges", "accountingRule", "externalId",
"paymentTypeOptions", "currencyOptions", "repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "accountingMappings", "paymentChannelToFundSourceMappings", "fundOptions", "paymentTypeOptions", "currencyOptions",
"amortizationTypeOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions", "repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "amortizationTypeOptions", "interestTypeOptions",
"transactionProcessingStrategyOptions", "chargeOptions", "accountingOptions", "accountingRuleOptions", "interestCalculationPeriodTypeOptions", "transactionProcessingStrategyOptions", "chargeOptions", "accountingOptions",
"accountingMappingOptions", "floatingRateOptions", "isLinkedToFloatingInterestRates", "floatingRatesId", "interestRateDifferential", "accountingRuleOptions", "accountingMappingOptions", "floatingRateOptions", "isLinkedToFloatingInterestRates",
"minDifferentialLendingRate", "defaultDifferentialLendingRate", "maxDifferentialLendingRate", "floatingRatesId", "interestRateDifferential", "minDifferentialLendingRate", "defaultDifferentialLendingRate",
"isFloatingInterestRateCalculationAllowed")); "maxDifferentialLendingRate", "isFloatingInterestRateCalculationAllowed"));
private final Set<String> PRODUCT_MIX_DATA_PARAMETERS = new HashSet<>(Arrays.asList("productId", "productName", "restrictedProducts", private final Set<String> PRODUCT_MIX_DATA_PARAMETERS = new HashSet<>(Arrays.asList("productId", "productName", "restrictedProducts",
"allowedProducts", "productOptions")); "allowedProducts", "productOptions"));
@@ -87,6 +87,7 @@ public class LoanProductData {
private final EnumOptionData amortizationType; private final EnumOptionData amortizationType;
private final EnumOptionData interestType; private final EnumOptionData interestType;
private final EnumOptionData interestCalculationPeriodType; private final EnumOptionData interestCalculationPeriodType;
private final Boolean allowPartialPeriodInterestCalcualtion;
private final BigDecimal inArrearsTolerance; private final BigDecimal inArrearsTolerance;
private final Long transactionProcessingStrategyId; private final Long transactionProcessingStrategyId;
private final String transactionProcessingStrategyName; private final String transactionProcessingStrategyName;
@@ -198,6 +199,7 @@ public class LoanProductData {
final EnumOptionData amortizationType = null; final EnumOptionData amortizationType = null;
final EnumOptionData interestType = null; final EnumOptionData interestType = null;
final EnumOptionData interestCalculationPeriodType = null; final EnumOptionData interestCalculationPeriodType = null;
final Boolean allowPartialPeriodInterestCalcualtion = null;
final Long fundId = null; final Long fundId = null;
final String fundName = null; final String fundName = null;
final Long transactionProcessingStrategyId = null; final Long transactionProcessingStrategyId = null;
@@ -238,16 +240,17 @@ public class LoanProductData {
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance, return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType,
amortizationType, interestType, interestCalculationPeriodType, fundId, fundName, transactionProcessingStrategyId, amortizationType, interestType, interestCalculationPeriodType, allowPartialPeriodInterestCalcualtion, fundId, fundName,
transactionProcessingStrategyName, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, charges, transactionProcessingStrategyId, transactionProcessingStrategyName, graceOnPrincipalPayment, graceOnInterestPayment,
accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, externalId, principalVariations, graceOnInterestCharged, charges, accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status,
interestRateVariations, numberOfRepaymentVariations, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance, externalId, principalVariations, interestRateVariations, numberOfRepaymentVariations, multiDisburseLoan, maxTrancheCount,
graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, outstandingLoanBalance, graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType,
interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, productGuaranteeData, isInterestRecalculationEnabled, interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment,
principalThresholdForLastInstallment, accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount, holdGuaranteeFunds, productGuaranteeData, principalThresholdForLastInstallment,
installmentAmountInMultiplesOf, loanProductConfigurableAttributes, isLinkedToFloatingInterestRates, floatingRateId, accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount, installmentAmountInMultiplesOf,
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate, loanProductConfigurableAttributes, isLinkedToFloatingInterestRates, floatingRateId, floatingRateName,
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap); interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate, maxDifferentialLendingRate,
isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap);
} }
@@ -282,6 +285,7 @@ public class LoanProductData {
final EnumOptionData amortizationType = null; final EnumOptionData amortizationType = null;
final EnumOptionData interestType = null; final EnumOptionData interestType = null;
final EnumOptionData interestCalculationPeriodType = null; final EnumOptionData interestCalculationPeriodType = null;
final Boolean allowPartialPeriodInterestCalcualtion = null;
final Long fundId = null; final Long fundId = null;
final String fundName = null; final String fundName = null;
final Long transactionProcessingStrategyId = null; final Long transactionProcessingStrategyId = null;
@@ -324,16 +328,17 @@ public class LoanProductData {
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance, return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType,
amortizationType, interestType, interestCalculationPeriodType, fundId, fundName, transactionProcessingStrategyId, amortizationType, interestType, interestCalculationPeriodType, allowPartialPeriodInterestCalcualtion, fundId, fundName,
transactionProcessingStrategyName, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, charges, transactionProcessingStrategyId, transactionProcessingStrategyName, graceOnPrincipalPayment, graceOnInterestPayment,
accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, externalId, principalVariations, graceOnInterestCharged, charges, accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status,
interestRateVariations, numberOfRepaymentVariations, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance, externalId, principalVariations, interestRateVariations, numberOfRepaymentVariations, multiDisburseLoan, maxTrancheCount,
graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, outstandingLoanBalance, graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType,
interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, productGuaranteeData, isInterestRecalculationEnabled, interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment,
principalThresholdForLastInstallment, accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount, holdGuaranteeFunds, productGuaranteeData, principalThresholdForLastInstallment,
installmentAmountInMultiplesOf, loanProductConfigurableAttributes, isLinkedToFloatingInterestRates, floatingRateId, accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount, installmentAmountInMultiplesOf,
floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate, loanProductConfigurableAttributes, isLinkedToFloatingInterestRates, floatingRateId, floatingRateName,
maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap); interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate, maxDifferentialLendingRate,
isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap);
} }
@@ -373,6 +378,7 @@ public class LoanProductData {
final EnumOptionData interestType = LoanEnumerations.interestType(InterestMethod.DECLINING_BALANCE); final EnumOptionData interestType = LoanEnumerations.interestType(InterestMethod.DECLINING_BALANCE);
final EnumOptionData interestCalculationPeriodType = LoanEnumerations final EnumOptionData interestCalculationPeriodType = LoanEnumerations
.interestCalculationPeriodType(InterestCalculationPeriodMethod.SAME_AS_REPAYMENT_PERIOD); .interestCalculationPeriodType(InterestCalculationPeriodMethod.SAME_AS_REPAYMENT_PERIOD);
final Boolean allowPartialPeriodInterestCalcualtion = null;
final Long fundId = null; final Long fundId = null;
final String fundName = null; final String fundName = null;
final Long transactionProcessingStrategyId = null; final Long transactionProcessingStrategyId = null;
@@ -417,17 +423,17 @@ public class LoanProductData {
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance, return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType,
amortizationType, interestType, interestCalculationPeriodType, fundId, fundName, transactionProcessingStrategyId, amortizationType, interestType, interestCalculationPeriodType, allowPartialPeriodInterestCalcualtion, fundId, fundName,
transactionProcessingStrategyName, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, charges, transactionProcessingStrategyId, transactionProcessingStrategyName, graceOnPrincipalPayment, graceOnInterestPayment,
accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, externalId, graceOnInterestCharged, charges, accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status,
principalVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle, numberOfRepaymentVariationsForBorrowerCycle, externalId, principalVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle,
multiDisburseLoan, maxTrancheCount, outstandingLoanBalance, graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, numberOfRepaymentVariationsForBorrowerCycle, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance,
daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
holdGuaranteeFunds, productGuaranteeData, principalThresholdForLastInstallment, interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, productGuaranteeData,
accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount, installmentAmountInMultiplesOf, principalThresholdForLastInstallment, accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount,
loanProductConfigurableAttributes, isLinkedToFloatingInterestRates, floatingRateId, floatingRateName, installmentAmountInMultiplesOf, loanProductConfigurableAttributes, isLinkedToFloatingInterestRates, floatingRateId,
interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate, maxDifferentialLendingRate, floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate,
isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap); maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap);
} }
@@ -448,8 +454,8 @@ public class LoanProductData {
final Integer repaymentEvery, final BigDecimal interestRatePerPeriod, final BigDecimal minInterestRatePerPeriod, final Integer repaymentEvery, final BigDecimal interestRatePerPeriod, final BigDecimal minInterestRatePerPeriod,
final BigDecimal maxInterestRatePerPeriod, final BigDecimal annualInterestRate, final EnumOptionData repaymentFrequencyType, final BigDecimal maxInterestRatePerPeriod, final BigDecimal annualInterestRate, final EnumOptionData repaymentFrequencyType,
final EnumOptionData interestRateFrequencyType, final EnumOptionData amortizationType, final EnumOptionData interestType, final EnumOptionData interestRateFrequencyType, final EnumOptionData amortizationType, final EnumOptionData interestType,
final EnumOptionData interestCalculationPeriodType, final Long fundId, final String fundName, final EnumOptionData interestCalculationPeriodType, final Boolean allowPartialPeriodInterestCalcualtion, final Long fundId,
final Long transactionProcessingStrategyId, final String transactionProcessingStrategyName, final String fundName, final Long transactionProcessingStrategyId, final String transactionProcessingStrategyName,
final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment, final Integer graceOnInterestCharged, final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment, final Integer graceOnInterestCharged,
final Collection<ChargeData> charges, final EnumOptionData accountingType, final boolean includeInBorrowerCycle, final Collection<ChargeData> charges, final EnumOptionData accountingType, final boolean includeInBorrowerCycle,
boolean useBorrowerCycle, final LocalDate startDate, final LocalDate closeDate, final String status, final String externalId, boolean useBorrowerCycle, final LocalDate startDate, final LocalDate closeDate, final String status, final String externalId,
@@ -503,6 +509,7 @@ public class LoanProductData {
this.amortizationType = amortizationType; this.amortizationType = amortizationType;
this.interestType = interestType; this.interestType = interestType;
this.interestCalculationPeriodType = interestCalculationPeriodType; this.interestCalculationPeriodType = interestCalculationPeriodType;
this.allowPartialPeriodInterestCalcualtion = allowPartialPeriodInterestCalcualtion;
this.fundId = fundId; this.fundId = fundId;
this.fundName = fundName; this.fundName = fundName;
this.transactionProcessingStrategyId = transactionProcessingStrategyId; this.transactionProcessingStrategyId = transactionProcessingStrategyId;
@@ -613,6 +620,7 @@ public class LoanProductData {
this.amortizationType = productData.amortizationType; this.amortizationType = productData.amortizationType;
this.interestType = productData.interestType; this.interestType = productData.interestType;
this.interestCalculationPeriodType = productData.interestCalculationPeriodType; this.interestCalculationPeriodType = productData.interestCalculationPeriodType;
this.allowPartialPeriodInterestCalcualtion = productData.allowPartialPeriodInterestCalcualtion;
this.startDate = productData.startDate; this.startDate = productData.startDate;
this.closeDate = productData.closeDate; this.closeDate = productData.closeDate;
this.status = productData.status; this.status = productData.status;
@@ -1002,4 +1010,9 @@ public class LoanProductData {
public Integer getMaximumGapBetweenInstallments() { public Integer getMaximumGapBetweenInstallments() {
return this.maximumGap; return this.maximumGap;
} }
public Boolean getAllowPartialPeriodInterestCalcualtion() {
return this.allowPartialPeriodInterestCalcualtion;
}
} }
@@ -188,6 +188,8 @@ public class LoanProduct extends AbstractPersistable<Long> {
final InterestMethod interestMethod = InterestMethod.fromInt(command.integerValueOfParameterNamed("interestType")); final InterestMethod interestMethod = InterestMethod.fromInt(command.integerValueOfParameterNamed("interestType"));
final InterestCalculationPeriodMethod interestCalculationPeriodMethod = InterestCalculationPeriodMethod.fromInt(command final InterestCalculationPeriodMethod interestCalculationPeriodMethod = InterestCalculationPeriodMethod.fromInt(command
.integerValueOfParameterNamed("interestCalculationPeriodType")); .integerValueOfParameterNamed("interestCalculationPeriodType"));
final boolean allowPartialPeriodInterestCalcualtion = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName);
final AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(command.integerValueOfParameterNamed("amortizationType")); final AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(command.integerValueOfParameterNamed("amortizationType"));
final PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType.fromInt(command final PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType.fromInt(command
.integerValueOfParameterNamed("repaymentFrequencyType")); .integerValueOfParameterNamed("repaymentFrequencyType"));
@@ -311,16 +313,16 @@ public class LoanProduct extends AbstractPersistable<Long> {
return new LoanProduct(fund, loanTransactionProcessingStrategy, name, shortName, description, currency, principal, minPrincipal, return new LoanProduct(fund, loanTransactionProcessingStrategy, name, shortName, description, currency, principal, minPrincipal,
maxPrincipal, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, interestFrequencyType, maxPrincipal, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, interestFrequencyType,
annualInterestRate, interestMethod, interestCalculationPeriodMethod, repaymentEvery, repaymentFrequencyType, annualInterestRate, interestMethod, interestCalculationPeriodMethod, allowPartialPeriodInterestCalcualtion, repaymentEvery,
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, graceOnPrincipalPayment, graceOnInterestPayment, repaymentFrequencyType, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, graceOnPrincipalPayment,
graceOnInterestCharged, amortizationMethod, inArrearsTolerance, productCharges, accountingRuleType, includeInBorrowerCycle, graceOnInterestPayment, graceOnInterestCharged, amortizationMethod, inArrearsTolerance, productCharges, accountingRuleType,
startDate, closeDate, externalId, useBorrowerCycle, loanProductBorrowerCycleVariations, multiDisburseLoan, maxTrancheCount, includeInBorrowerCycle, startDate, closeDate, externalId, useBorrowerCycle, loanProductBorrowerCycleVariations,
outstandingLoanBalance, graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance, graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType,
isInterestRecalculationEnabled, interestRecalculationSettings, minimumDaysBetweenDisbursalAndFirstRepayment, daysInYearType, isInterestRecalculationEnabled, interestRecalculationSettings,
holdGuarantorFunds, loanProductGuaranteeDetails, principalThresholdForLastInstallment, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuarantorFunds, loanProductGuaranteeDetails,
accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineEmiAmount, installmentAmountInMultiplesOf, principalThresholdForLastInstallment, accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineEmiAmount,
loanConfigurableAttributes, isLinkedToFloatingInterestRates, floatingRate, interestRateDifferential, installmentAmountInMultiplesOf, loanConfigurableAttributes, isLinkedToFloatingInterestRates, floatingRate,
minDifferentialLendingRate, maxDifferentialLendingRate, defaultDifferentialLendingRate, interestRateDifferential, minDifferentialLendingRate, maxDifferentialLendingRate, defaultDifferentialLendingRate,
isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGapBetweenInstallments, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGapBetweenInstallments,
maximumGapBetweenInstallments); maximumGapBetweenInstallments);
@@ -534,8 +536,8 @@ public class LoanProduct extends AbstractPersistable<Long> {
final BigDecimal defaultNominalInterestRatePerPeriod, final BigDecimal defaultMinNominalInterestRatePerPeriod, final BigDecimal defaultNominalInterestRatePerPeriod, final BigDecimal defaultMinNominalInterestRatePerPeriod,
final BigDecimal defaultMaxNominalInterestRatePerPeriod, final PeriodFrequencyType interestPeriodFrequencyType, final BigDecimal defaultMaxNominalInterestRatePerPeriod, final PeriodFrequencyType interestPeriodFrequencyType,
final BigDecimal defaultAnnualNominalInterestRate, final InterestMethod interestMethod, final BigDecimal defaultAnnualNominalInterestRate, final InterestMethod interestMethod,
final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final Integer repayEvery, final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final boolean considerPartialPeriodInterest,
final PeriodFrequencyType repaymentFrequencyType, final Integer defaultNumberOfInstallments, final Integer repayEvery, final PeriodFrequencyType repaymentFrequencyType, final Integer defaultNumberOfInstallments,
final Integer defaultMinNumberOfInstallments, final Integer defaultMaxNumberOfInstallments, final Integer defaultMinNumberOfInstallments, final Integer defaultMaxNumberOfInstallments,
final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment, final Integer graceOnInterestCharged, final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment, final Integer graceOnInterestCharged,
final AmortizationMethod amortizationMethod, final BigDecimal inArrearsTolerance, final List<Charge> charges, final AmortizationMethod amortizationMethod, final BigDecimal inArrearsTolerance, final List<Charge> charges,
@@ -582,10 +584,10 @@ public class LoanProduct extends AbstractPersistable<Long> {
} }
this.loanProductRelatedDetail = new LoanProductRelatedDetail(currency, defaultPrincipal, defaultNominalInterestRatePerPeriod, this.loanProductRelatedDetail = new LoanProductRelatedDetail(currency, defaultPrincipal, defaultNominalInterestRatePerPeriod,
interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery, interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod,
repaymentFrequencyType, defaultNumberOfInstallments, graceOnPrincipalPayment, graceOnInterestPayment, considerPartialPeriodInterest, repayEvery, repaymentFrequencyType, defaultNumberOfInstallments, graceOnPrincipalPayment,
graceOnInterestCharged, amortizationMethod, inArrearsTolerance, graceOnArrearsAgeing, daysInMonthType.getValue(), graceOnInterestPayment, graceOnInterestCharged, amortizationMethod, inArrearsTolerance, graceOnArrearsAgeing,
daysInYearType.getValue(), isInterestRecalculationEnabled); daysInMonthType.getValue(), daysInYearType.getValue(), isInterestRecalculationEnabled);
this.loanProductRelatedDetail.validateRepaymentPeriodWithGraceSettings(); this.loanProductRelatedDetail.validateRepaymentPeriodWithGraceSettings();
@@ -67,6 +67,9 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
@Column(name = "interest_calculated_in_period_enum", nullable = false) @Column(name = "interest_calculated_in_period_enum", nullable = false)
private InterestCalculationPeriodMethod interestCalculationPeriodMethod; private InterestCalculationPeriodMethod interestCalculationPeriodMethod;
@Column(name = "allow_partial_period_interest_calcualtion", nullable = false)
private boolean allowPartialPeriodInterestCalcualtion;
@Column(name = "repay_every", nullable = false) @Column(name = "repay_every", nullable = false)
private Integer repayEvery; private Integer repayEvery;
@@ -112,16 +115,17 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
public static LoanProductRelatedDetail createFrom(final MonetaryCurrency currency, final BigDecimal principal, public static LoanProductRelatedDetail createFrom(final MonetaryCurrency currency, final BigDecimal principal,
final BigDecimal nominalInterestRatePerPeriod, final PeriodFrequencyType interestRatePeriodFrequencyType, final BigDecimal nominalInterestRatePerPeriod, final PeriodFrequencyType interestRatePeriodFrequencyType,
final BigDecimal nominalAnnualInterestRate, final InterestMethod interestMethod, final BigDecimal nominalAnnualInterestRate, final InterestMethod interestMethod,
final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final Integer repaymentEvery, final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final boolean allowPartialPeriodInterestCalcualtion,
final PeriodFrequencyType repaymentPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery, final PeriodFrequencyType repaymentPeriodFrequencyType, final Integer numberOfRepayments,
final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment, final Integer graceOnInterestCharged, final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment, final Integer graceOnInterestCharged,
final AmortizationMethod amortizationMethod, final BigDecimal inArrearsTolerance, final Integer graceOnArrearsAgeing, final AmortizationMethod amortizationMethod, final BigDecimal inArrearsTolerance, final Integer graceOnArrearsAgeing,
final Integer daysInMonthType, final Integer daysInYearType, final boolean isInterestRecalculationEnabled) { final Integer daysInMonthType, final Integer daysInYearType, final boolean isInterestRecalculationEnabled) {
return new LoanProductRelatedDetail(currency, principal, nominalInterestRatePerPeriod, interestRatePeriodFrequencyType, return new LoanProductRelatedDetail(currency, principal, nominalInterestRatePerPeriod, interestRatePeriodFrequencyType,
nominalAnnualInterestRate, interestMethod, interestCalculationPeriodMethod, repaymentEvery, repaymentPeriodFrequencyType, nominalAnnualInterestRate, interestMethod, interestCalculationPeriodMethod, allowPartialPeriodInterestCalcualtion,
numberOfRepayments, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, amortizationMethod, repaymentEvery, repaymentPeriodFrequencyType, numberOfRepayments, graceOnPrincipalPayment, graceOnInterestPayment,
inArrearsTolerance, graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled); graceOnInterestCharged, amortizationMethod, inArrearsTolerance, graceOnArrearsAgeing, daysInMonthType, daysInYearType,
isInterestRecalculationEnabled);
} }
protected LoanProductRelatedDetail() { protected LoanProductRelatedDetail() {
@@ -131,8 +135,8 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
public LoanProductRelatedDetail(final MonetaryCurrency currency, final BigDecimal defaultPrincipal, public LoanProductRelatedDetail(final MonetaryCurrency currency, final BigDecimal defaultPrincipal,
final BigDecimal defaultNominalInterestRatePerPeriod, final PeriodFrequencyType interestPeriodFrequencyType, final BigDecimal defaultNominalInterestRatePerPeriod, final PeriodFrequencyType interestPeriodFrequencyType,
final BigDecimal defaultAnnualNominalInterestRate, final InterestMethod interestMethod, final BigDecimal defaultAnnualNominalInterestRate, final InterestMethod interestMethod,
final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final Integer repayEvery, final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final boolean allowPartialPeriodInterestCalcualtion,
final PeriodFrequencyType repaymentFrequencyType, final Integer defaultNumberOfRepayments, final Integer repayEvery, final PeriodFrequencyType repaymentFrequencyType, final Integer defaultNumberOfRepayments,
final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment, final Integer graceOnInterestCharged, final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment, final Integer graceOnInterestCharged,
final AmortizationMethod amortizationMethod, final BigDecimal inArrearsTolerance, final Integer graceOnArrearsAgeing, final AmortizationMethod amortizationMethod, final BigDecimal inArrearsTolerance, final Integer graceOnArrearsAgeing,
final Integer daysInMonthType, final Integer daysInYearType, final boolean isInterestRecalculationEnabled) { final Integer daysInMonthType, final Integer daysInYearType, final boolean isInterestRecalculationEnabled) {
@@ -143,6 +147,7 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
this.annualNominalInterestRate = defaultAnnualNominalInterestRate; this.annualNominalInterestRate = defaultAnnualNominalInterestRate;
this.interestMethod = interestMethod; this.interestMethod = interestMethod;
this.interestCalculationPeriodMethod = interestCalculationPeriodMethod; this.interestCalculationPeriodMethod = interestCalculationPeriodMethod;
this.allowPartialPeriodInterestCalcualtion = allowPartialPeriodInterestCalcualtion;
this.repayEvery = repayEvery; this.repayEvery = repayEvery;
this.repaymentPeriodFrequencyType = repaymentFrequencyType; this.repaymentPeriodFrequencyType = repaymentFrequencyType;
this.numberOfRepayments = defaultNumberOfRepayments; this.numberOfRepayments = defaultNumberOfRepayments;
@@ -205,20 +210,19 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
@Override @Override
public BigDecimal getNominalInterestRatePerPeriod() { public BigDecimal getNominalInterestRatePerPeriod() {
return this.nominalInterestRatePerPeriod == null? null return this.nominalInterestRatePerPeriod == null ? null : BigDecimal.valueOf(Double.valueOf(this.nominalInterestRatePerPeriod
: BigDecimal.valueOf(Double.valueOf(this.nominalInterestRatePerPeriod.stripTrailingZeros().toString())); .stripTrailingZeros().toString()));
} }
@Override @Override
public PeriodFrequencyType getInterestPeriodFrequencyType() { public PeriodFrequencyType getInterestPeriodFrequencyType() {
return this.interestPeriodFrequencyType == null? PeriodFrequencyType.INVALID return this.interestPeriodFrequencyType == null ? PeriodFrequencyType.INVALID : this.interestPeriodFrequencyType;
: this.interestPeriodFrequencyType;
} }
@Override @Override
public BigDecimal getAnnualNominalInterestRate() { public BigDecimal getAnnualNominalInterestRate() {
return this.annualNominalInterestRate == null? null return this.annualNominalInterestRate == null ? null : BigDecimal.valueOf(Double.valueOf(this.annualNominalInterestRate
:BigDecimal.valueOf(Double.valueOf(this.annualNominalInterestRate.stripTrailingZeros().toString())); .stripTrailingZeros().toString()));
} }
@Override @Override
@@ -368,8 +372,8 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
} }
final String interestRateFrequencyTypeParamName = "interestRateFrequencyType"; final String interestRateFrequencyTypeParamName = "interestRateFrequencyType";
final int interestPeriodFrequencyType = this.interestPeriodFrequencyType == null? final int interestPeriodFrequencyType = this.interestPeriodFrequencyType == null ? PeriodFrequencyType.INVALID.getValue()
PeriodFrequencyType.INVALID.getValue() : this.interestPeriodFrequencyType.getValue(); : this.interestPeriodFrequencyType.getValue();
if (command.isChangeInIntegerParameterNamed(interestRateFrequencyTypeParamName, interestPeriodFrequencyType)) { if (command.isChangeInIntegerParameterNamed(interestRateFrequencyTypeParamName, interestPeriodFrequencyType)) {
final Integer newValue = command.integerValueOfParameterNamed(interestRateFrequencyTypeParamName); final Integer newValue = command.integerValueOfParameterNamed(interestRateFrequencyTypeParamName);
actualChanges.put(interestRateFrequencyTypeParamName, newValue); actualChanges.put(interestRateFrequencyTypeParamName, newValue);
@@ -395,6 +399,18 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
this.interestCalculationPeriodMethod = InterestCalculationPeriodMethod.fromInt(newValue); this.interestCalculationPeriodMethod = InterestCalculationPeriodMethod.fromInt(newValue);
} }
if (command.isChangeInBooleanParameterNamed(LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName,
this.allowPartialPeriodInterestCalcualtion)) {
final boolean newValue = command
.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName);
actualChanges.put(LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName, newValue);
this.allowPartialPeriodInterestCalcualtion = newValue;
}
if (this.interestCalculationPeriodMethod.isDaily()) {
this.allowPartialPeriodInterestCalcualtion = false;
}
final String graceOnPrincipalPaymentParamName = "graceOnPrincipalPayment"; final String graceOnPrincipalPaymentParamName = "graceOnPrincipalPayment";
if (command.isChangeInIntegerParameterNamed(graceOnPrincipalPaymentParamName, this.graceOnPrincipalPayment)) { if (command.isChangeInIntegerParameterNamed(graceOnPrincipalPaymentParamName, this.graceOnPrincipalPayment)) {
final Integer newValue = command.integerValueOfParameterNamed(graceOnPrincipalPaymentParamName); final Integer newValue = command.integerValueOfParameterNamed(graceOnPrincipalPaymentParamName);
@@ -572,10 +588,14 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche
return this.inArrearsTolerance; return this.inArrearsTolerance;
} }
public void updateForFloatingInterestRates() { public void updateForFloatingInterestRates() {
this.nominalInterestRatePerPeriod = null; this.nominalInterestRatePerPeriod = null;
this.interestPeriodFrequencyType = PeriodFrequencyType.INVALID; this.interestPeriodFrequencyType = PeriodFrequencyType.INVALID;
this.annualNominalInterestRate = null; this.annualNominalInterestRate = null;
} }
public boolean isAllowPartialPeriodInterestCalcualtion() {
return this.allowPartialPeriodInterestCalcualtion;
}
} }
@@ -27,6 +27,7 @@ import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidation
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType; import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType;
import org.mifosplatform.portfolio.loanproduct.LoanProductConstants; import org.mifosplatform.portfolio.loanproduct.LoanProductConstants;
import org.mifosplatform.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod; import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod;
import org.mifosplatform.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod; import org.mifosplatform.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod;
import org.mifosplatform.portfolio.loanproduct.domain.LoanPreClosureInterestCalculationStrategy; import org.mifosplatform.portfolio.loanproduct.domain.LoanPreClosureInterestCalculationStrategy;
@@ -52,16 +53,17 @@ public final class LoanProductDataValidator {
"currencyCode", "digitsAfterDecimal", "inMultiplesOf", "principal", "minPrincipal", "maxPrincipal", "repaymentEvery", "currencyCode", "digitsAfterDecimal", "inMultiplesOf", "principal", "minPrincipal", "maxPrincipal", "repaymentEvery",
"numberOfRepayments", "minNumberOfRepayments", "maxNumberOfRepayments", "repaymentFrequencyType", "interestRatePerPeriod", "numberOfRepayments", "minNumberOfRepayments", "maxNumberOfRepayments", "repaymentFrequencyType", "interestRatePerPeriod",
"minInterestRatePerPeriod", "maxInterestRatePerPeriod", "interestRateFrequencyType", "amortizationType", "interestType", "minInterestRatePerPeriod", "maxInterestRatePerPeriod", "interestRateFrequencyType", "amortizationType", "interestType",
"interestCalculationPeriodType", "inArrearsTolerance", "transactionProcessingStrategyId", "graceOnPrincipalPayment", "interestCalculationPeriodType", LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName, "inArrearsTolerance",
"graceOnInterestPayment", "graceOnInterestCharged", "charges", "accountingRule", "includeInBorrowerCycle", "startDate", "transactionProcessingStrategyId", "graceOnPrincipalPayment", "graceOnInterestPayment", "graceOnInterestCharged", "charges",
"closeDate", "externalId", "isLinkedToFloatingInterestRates", "floatingRatesId", "interestRateDifferential", "accountingRule", "includeInBorrowerCycle", "startDate", "closeDate", "externalId", "isLinkedToFloatingInterestRates",
"minDifferentialLendingRate", "defaultDifferentialLendingRate", "maxDifferentialLendingRate", "floatingRatesId", "interestRateDifferential", "minDifferentialLendingRate", "defaultDifferentialLendingRate",
"isFloatingInterestRateCalculationAllowed", LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), "maxDifferentialLendingRate", "isFloatingInterestRateCalculationAllowed",
LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(),
LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(),
LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(),
LOAN_PRODUCT_ACCOUNTING_PARAMS.OVERPAYMENT.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.OVERPAYMENT.getValue(),
LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(),
LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(),
LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(),
LOAN_PRODUCT_ACCOUNTING_PARAMS.FEE_INCOME_ACCOUNT_MAPPING.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.FEE_INCOME_ACCOUNT_MAPPING.getValue(),
LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_RECOVERY.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_RECOVERY.getValue(),
@@ -601,6 +603,8 @@ public final class LoanProductDataValidator {
validateVariableInstallmentSettings(baseDataValidator, element); validateVariableInstallmentSettings(baseDataValidator, element);
validatePartialPeriodSupport(interestCalculationPeriodType, baseDataValidator, element, null);
throwExceptionIfValidationWarningsExist(dataValidationErrors); throwExceptionIfValidationWarningsExist(dataValidationErrors);
} }
@@ -1024,10 +1028,10 @@ public final class LoanProductDataValidator {
final Integer interestType = this.fromApiJsonHelper.extractIntegerNamed("interestType", element, Locale.getDefault()); final Integer interestType = this.fromApiJsonHelper.extractIntegerNamed("interestType", element, Locale.getDefault());
baseDataValidator.reset().parameter("interestType").value(interestType).notNull().inMinMaxRange(0, 1); baseDataValidator.reset().parameter("interestType").value(interestType).notNull().inMinMaxRange(0, 1);
} }
Integer interestCalculationPeriodType = loanProduct.getLoanProductRelatedDetail().getInterestCalculationPeriodMethod().getValue();
if (this.fromApiJsonHelper.parameterExists("interestCalculationPeriodType", element)) { if (this.fromApiJsonHelper.parameterExists("interestCalculationPeriodType", element)) {
final Integer interestCalculationPeriodType = this.fromApiJsonHelper.extractIntegerNamed("interestCalculationPeriodType", interestCalculationPeriodType = this.fromApiJsonHelper.extractIntegerNamed("interestCalculationPeriodType", element,
element, Locale.getDefault()); Locale.getDefault());
baseDataValidator.reset().parameter("interestCalculationPeriodType").value(interestCalculationPeriodType).notNull() baseDataValidator.reset().parameter("interestCalculationPeriodType").value(interestCalculationPeriodType).notNull()
.inMinMaxRange(0, 1); .inMinMaxRange(0, 1);
} }
@@ -1395,6 +1399,9 @@ public final class LoanProductDataValidator {
// validateLoanConfigurableAttributes(baseDataValidator,element); // validateLoanConfigurableAttributes(baseDataValidator,element);
validateVariableInstallmentSettings(baseDataValidator, element); validateVariableInstallmentSettings(baseDataValidator, element);
validatePartialPeriodSupport(interestCalculationPeriodType, baseDataValidator, element, loanProduct);
throwExceptionIfValidationWarningsExist(dataValidationErrors); throwExceptionIfValidationWarningsExist(dataValidationErrors);
} }
@@ -1925,4 +1932,78 @@ public final class LoanProductDataValidator {
} }
private void validatePartialPeriodSupport(final Integer interestCalculationPeriodType, final DataValidatorBuilder baseDataValidator,
final JsonElement element, final LoanProduct loanProduct) {
if (interestCalculationPeriodType != null) {
final InterestCalculationPeriodMethod interestCalculationPeriodMethod = InterestCalculationPeriodMethod
.fromInt(interestCalculationPeriodType);
boolean considerPartialPeriodUpdates = interestCalculationPeriodMethod.isDaily();
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName, element)) {
final Boolean considerPartialInterestEnabled = this.fromApiJsonHelper.extractBooleanNamed(
LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName, element);
baseDataValidator.reset().parameter(LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName)
.value(considerPartialInterestEnabled).notNull().isOneOfTheseValues(true, false);
final boolean considerPartialPeriods = considerPartialInterestEnabled == null ? false : considerPartialInterestEnabled;
if (interestCalculationPeriodMethod.isDaily()) {
if (considerPartialPeriods) {
baseDataValidator.reset().parameter(LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName)
.failWithCode("not.supported.for.daily.calcualtions");
}
} else {
considerPartialPeriodUpdates = considerPartialPeriods;
}
}
if (!considerPartialPeriodUpdates) {
Boolean isInterestRecalculationEnabled = null;
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.isInterestRecalculationEnabledParameterName, element)) {
isInterestRecalculationEnabled = this.fromApiJsonHelper.extractBooleanNamed(
LoanProductConstants.isInterestRecalculationEnabledParameterName, element);
} else if (loanProduct != null) {
isInterestRecalculationEnabled = loanProduct.isInterestRecalculationEnabled();
}
if (isInterestRecalculationEnabled != null && isInterestRecalculationEnabled) {
baseDataValidator.reset().parameter(LoanProductConstants.isInterestRecalculationEnabledParameterName)
.failWithCode("not.supported.for.selected.interest.calcualtion.type");
}
Boolean multiDisburseLoan = null;
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.multiDisburseLoanParameterName, element)) {
multiDisburseLoan = this.fromApiJsonHelper.extractBooleanNamed(LoanProductConstants.multiDisburseLoanParameterName,
element);
} else if (loanProduct != null) {
isInterestRecalculationEnabled = loanProduct.isMultiDisburseLoan();
}
if (multiDisburseLoan != null && multiDisburseLoan) {
baseDataValidator.reset().parameter(LoanProductConstants.multiDisburseLoanParameterName)
.failWithCode("not.supported.for.selected.interest.calcualtion.type");
}
Boolean variableInstallments = null;
if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.allowVariableInstallmentsParamName, element)) {
variableInstallments = this.fromApiJsonHelper.extractBooleanNamed(
LoanProductConstants.allowVariableInstallmentsParamName, element);
} else if (loanProduct != null) {
isInterestRecalculationEnabled = loanProduct.allowVariabeInstallments();
}
if (variableInstallments != null && variableInstallments) {
baseDataValidator.reset().parameter(LoanProductConstants.allowVariableInstallmentsParamName)
.failWithCode("not.supported.for.selected.interest.calcualtion.type");
}
Boolean floatingInterestRates = null;
if (this.fromApiJsonHelper.parameterExists("isLinkedToFloatingInterestRates", element)) {
floatingInterestRates = this.fromApiJsonHelper.extractBooleanNamed("isLinkedToFloatingInterestRates", element);
} else if (loanProduct != null) {
isInterestRecalculationEnabled = loanProduct.isLinkedToFloatingInterestRate();
}
if (floatingInterestRates != null && floatingInterestRates) {
baseDataValidator.reset().parameter("isLinkedToFloatingInterestRates")
.failWithCode("not.supported.for.selected.interest.calcualtion.type");
}
}
}
}
} }
@@ -169,7 +169,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
+ "lp.name as name, lp.short_name as shortName, lp.description as description, " + "lp.name as name, lp.short_name as shortName, lp.description as description, "
+ "lp.principal_amount as principal, lp.min_principal_amount as minPrincipal, lp.max_principal_amount as maxPrincipal, lp.currency_code as currencyCode, lp.currency_digits as currencyDigits, lp.currency_multiplesof as inMultiplesOf, " + "lp.principal_amount as principal, lp.min_principal_amount as minPrincipal, lp.max_principal_amount as maxPrincipal, lp.currency_code as currencyCode, lp.currency_digits as currencyDigits, lp.currency_multiplesof as inMultiplesOf, "
+ "lp.nominal_interest_rate_per_period as interestRatePerPeriod, lp.min_nominal_interest_rate_per_period as minInterestRatePerPeriod, lp.max_nominal_interest_rate_per_period as maxInterestRatePerPeriod, lp.interest_period_frequency_enum as interestRatePerPeriodFreq, " + "lp.nominal_interest_rate_per_period as interestRatePerPeriod, lp.min_nominal_interest_rate_per_period as minInterestRatePerPeriod, lp.max_nominal_interest_rate_per_period as maxInterestRatePerPeriod, lp.interest_period_frequency_enum as interestRatePerPeriodFreq, "
+ "lp.annual_nominal_interest_rate as annualInterestRate, lp.interest_method_enum as interestMethod, lp.interest_calculated_in_period_enum as interestCalculationInPeriodMethod," + "lp.annual_nominal_interest_rate as annualInterestRate, lp.interest_method_enum as interestMethod, lp.interest_calculated_in_period_enum as interestCalculationInPeriodMethod,lp.allow_partial_period_interest_calcualtion as allowPartialPeriodInterestCalcualtion, "
+ "lp.repay_every as repaidEvery, lp.repayment_period_frequency_enum as repaymentPeriodFrequency, lp.number_of_repayments as numberOfRepayments, lp.min_number_of_repayments as minNumberOfRepayments, lp.max_number_of_repayments as maxNumberOfRepayments, " + "lp.repay_every as repaidEvery, lp.repayment_period_frequency_enum as repaymentPeriodFrequency, lp.number_of_repayments as numberOfRepayments, lp.min_number_of_repayments as minNumberOfRepayments, lp.max_number_of_repayments as maxNumberOfRepayments, "
+ "lp.grace_on_principal_periods as graceOnPrincipalPayment, lp.grace_on_interest_periods as graceOnInterestPayment, lp.grace_interest_free_periods as graceOnInterestCharged,lp.grace_on_arrears_ageing as graceOnArrearsAgeing,lp.overdue_days_for_npa as overdueDaysForNPA, " + "lp.grace_on_principal_periods as graceOnPrincipalPayment, lp.grace_on_interest_periods as graceOnInterestPayment, lp.grace_interest_free_periods as graceOnInterestCharged,lp.grace_on_arrears_ageing as graceOnArrearsAgeing,lp.overdue_days_for_npa as overdueDaysForNPA, "
+ "lp.min_days_between_disbursal_and_first_repayment As minimumDaysBetweenDisbursalAndFirstRepayment, " + "lp.min_days_between_disbursal_and_first_repayment As minimumDaysBetweenDisbursalAndFirstRepayment, "
@@ -291,6 +291,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
final EnumOptionData interestType = LoanEnumerations.interestType(interestTypeId); final EnumOptionData interestType = LoanEnumerations.interestType(interestTypeId);
final int interestCalculationPeriodTypeId = JdbcSupport.getInteger(rs, "interestCalculationInPeriodMethod"); final int interestCalculationPeriodTypeId = JdbcSupport.getInteger(rs, "interestCalculationInPeriodMethod");
final Boolean allowPartialPeriodInterestCalcualtion = rs.getBoolean("allowPartialPeriodInterestCalcualtion");
final EnumOptionData interestCalculationPeriodType = LoanEnumerations final EnumOptionData interestCalculationPeriodType = LoanEnumerations
.interestCalculationPeriodType(interestCalculationPeriodTypeId); .interestCalculationPeriodType(interestCalculationPeriodTypeId);
@@ -396,10 +397,11 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo
return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance, return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance,
numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod,
minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType,
interestRateFrequencyType, amortizationType, interestType, interestCalculationPeriodType, fundId, fundName, interestRateFrequencyType, amortizationType, interestType, interestCalculationPeriodType,
transactionStrategyId, transactionStrategyName, graceOnPrincipalPayment, graceOnInterestPayment, allowPartialPeriodInterestCalcualtion, fundId, fundName, transactionStrategyId, transactionStrategyName,
graceOnInterestCharged, this.charges, accountingRuleType, includeInBorrowerCycle, useBorrowerCycle, startDate, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, this.charges, accountingRuleType,
closeDate, status, externalId, principalVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, externalId,
principalVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle,
numberOfRepaymentVariationsForBorrowerCycle, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance, numberOfRepaymentVariationsForBorrowerCycle, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance,
graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled,
interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, loanProductGuaranteeData, interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, loanProductGuaranteeData,
@@ -0,0 +1,10 @@
ALTER TABLE `m_product_loan`
ADD COLUMN `allow_partial_period_interest_calcualtion` TINYINT(1) NOT NULL DEFAULT '0' AFTER `interest_calculated_in_period_enum`;
ALTER TABLE `m_loan`
ADD COLUMN `allow_partial_period_interest_calcualtion` TINYINT(1) NOT NULL DEFAULT '0' AFTER `interest_calculated_in_period_enum`;
UPDATE m_product_loan mpl inner join (select mp.id as productId from m_product_loan mp where mp.interest_calculated_in_period_enum = 1 and (mp.interest_recalculation_enabled = 1 or mp.allow_multiple_disbursals = 1 or mp.is_linked_to_floating_interest_rates =1 or mp.allow_variabe_installments =1)) x on x.productId = mpl.id SET mpl.allow_partial_period_interest_calcualtion = 1;
UPDATE m_loan ml inner join (select loan.id as loanId from m_product_loan mp inner join m_loan loan on loan.product_id = mp.id where mp.allow_partial_period_interest_calcualtion = 1) x on x.loanId = ml.id SET ml.allow_partial_period_interest_calcualtion=1;
@@ -138,10 +138,11 @@ public class LoanProductRelatedDetailTestHelper {
final Integer daysInMonthType = DaysInMonthType.ACTUAL.getValue(); final Integer daysInMonthType = DaysInMonthType.ACTUAL.getValue();
final Integer daysInYearType = DaysInYearType.ACTUAL.getValue(); final Integer daysInYearType = DaysInYearType.ACTUAL.getValue();
final boolean isInterestRecalculationEnabled = false; final boolean isInterestRecalculationEnabled = false;
final boolean considerPartialPeriodInterest = false;
return new LoanProductRelatedDetail(currency, defaultPrincipal, defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType, return new LoanProductRelatedDetail(currency, defaultPrincipal, defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType,
defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery, repaymentFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, considerPartialPeriodInterest, repayEvery,
defaultNumberOfRepayments, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, amortizationMethod, repaymentFrequencyType, defaultNumberOfRepayments, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged,
inArrearsTolerance, graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled); amortizationMethod, inArrearsTolerance, graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled);
} }
} }