From 96ea36b1017b5a3e5b916d688ed42825d0ca17d4 Mon Sep 17 00:00:00 2001 From: pramod Date: Mon, 11 Jan 2016 14:40:43 +0530 Subject: [PATCH] MIFOSX-2419 : added flag to consider partial periods while interest calculation --- api-docs/apiLive.htm | 20 +- .../ClientLoanIntegrationTest.java | 12 +- .../ConcurrencyIntegrationTest.java | 9 +- .../LoanApplicationApprovalTest.java | 3 +- .../LoanApplicationUndoLastTrancheTest.java | 51 +- ...oanDisbursementDetailsIntegrationTest.java | 47 +- .../common/ProvisioningIntegrationTest.java | 9 +- .../common/loans/LoanProductTestBuilder.java | 7 +- .../codes/domain/CodeValue.java | 15 +- ...deValueCommandFromApiJsonDeserializer.java | 10 +- .../loanaccount/api/LoansApiResource.java | 46 +- .../loanaccount/data/LoanAccountData.java | 442 +++++++++--------- .../domain/AbstractLoanScheduleGenerator.java | 6 +- .../domain/LoanApplicationTerms.java | 99 ++-- .../service/LoanScheduleAssembler.java | 29 +- ...ateLoanScheduleQueryFromApiJsonHelper.java | 44 +- ...anApplicationCommandFromApiJsonHelper.java | 69 ++- .../service/LoanReadPlatformServiceImpl.java | 36 +- .../loanproduct/LoanProductConstants.java | 2 + .../api/LoanProductsApiResource.java | 17 +- .../loanproduct/data/LoanProductData.java | 79 ++-- .../loanproduct/domain/LoanProduct.java | 34 +- .../domain/LoanProductRelatedDetail.java | 60 ++- .../LoanProductDataValidator.java | 107 ++++- .../LoanProductReadPlatformServiceImpl.java | 12 +- ...6__partial_period_interest_calcualtion.sql | 10 + .../LoanProductRelatedDetailTestHelper.java | 7 +- 27 files changed, 759 insertions(+), 523 deletions(-) create mode 100644 mifosng-provider/src/main/resources/sql/migrations/core_db/V286__partial_period_interest_calcualtion.sql diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm index 720597eed..2f6b08b4f 100644 --- a/api-docs/apiLive.htm +++ b/api-docs/apiLive.htm @@ -8003,6 +8003,14 @@ GET https://DomainName/mifosng-provider/api/v1/groups?paged=true Example Values: 0=Daily, 1=Same as repayment period + + allowPartialPeriodInterestCalcualtion + + + This value will be supported along with interestCalculationPeriodType as Same as repayment period to calculate interest for partial periods. + Example: 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) + + inArrearsTolerance @@ -9219,7 +9227,7 @@ Request Body:
Optional Fields
- graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, linkAccountId, + graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, linkAccountId, allowPartialPeriodInterestCalcualtion, fixedEmiAmount, maxOutstandingLoanBalance, disbursementData, graceOnArrearsAgeing, createStandingInstructionAtDisbursement (requires linkedAccountId if set to true) @@ -12759,6 +12767,14 @@ Request Body: Example Values: 0=Daily, 1=Same as repayment period + + allowPartialPeriodInterestCalcualtion + + + This value will be supported along with interestCalculationPeriodType as Same as repayment period to calculate interest for partial periods. + Example: 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) + + inArrearsTolerance @@ -14236,7 +14252,7 @@ GET https://DomainName/api/v1/loanproducts/{productId} numberOfRepaymentVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle, multiDisburseLoan,maxTrancheCount, - outstandingLoanBalance,overdueDaysForNPA,holdGuaranteeFunds, principalThresholdForLastInstalment, accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount, installmentAmountInMultiplesOf, allowAttributeOverrides + outstandingLoanBalance,overdueDaysForNPA,holdGuaranteeFunds, principalThresholdForLastInstalment, accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount, installmentAmountInMultiplesOf, allowAttributeOverrides, allowPartialPeriodInterestCalcualtion diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ClientLoanIntegrationTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ClientLoanIntegrationTest.java index a5b8a7c56..ed7499dff 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ClientLoanIntegrationTest.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ClientLoanIntegrationTest.java @@ -868,7 +868,7 @@ public class ClientLoanIntegrationTest { private Integer createLoanProduct(final boolean multiDisburseLoan, final String accountingRule, final Account... accounts) { System.out.println("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------"); - final String loanProductJSON = new LoanProductTestBuilder() // + LoanProductTestBuilder builder = new LoanProductTestBuilder() // .withPrincipal("12,000.00") // .withNumberOfRepayments("4") // .withRepaymentAfterEvery("1") // @@ -878,7 +878,11 @@ public class ClientLoanIntegrationTest { .withAmortizationTypeAsEqualInstallments() // .withInterestTypeAsDecliningBalance() // .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); } @@ -4166,14 +4170,13 @@ public class ClientLoanIntegrationTest { testLoanScheduleWithInterestRecalculation_FOR_PRE_CLOSE_WITH_MORATORIUM( LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_ON_PRE_CLOSE_DATE, "10006.59"); } - + @Test public void testLoanScheduleWithInterestRecalculation_FOR_PRE_CLOSE_WITH_MORATORIUM_INTEREST_APPLICABLE_STRATEGY_REST_DATE() { testLoanScheduleWithInterestRecalculation_FOR_PRE_CLOSE_WITH_MORATORIUM( LoanProductTestBuilder.INTEREST_APPLICABLE_STRATEGY_REST_DATE, "10046.15"); } - private void testLoanScheduleWithInterestRecalculation_FOR_PRE_CLOSE_WITH_MORATORIUM(final String preCloseStrategy, final String preCloseAmount) { this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec); @@ -4307,6 +4310,7 @@ public class ClientLoanIntegrationTest { .withInterestRateFrequencyTypeAsMonths() .withRepaymentStrategy(repaymentStrategy) .withAmortizationTypeAsEqualPrincipalPayment() + .withInterestCalculationPeriodTypeAsRepaymentPeriod(true) .withInterestTypeAsDecliningBalance() .withInterestRecalculationDetails(interestRecalculationCompoundingMethod, rescheduleStrategyMethod, preCloseInterestCalculationStrategy) diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ConcurrencyIntegrationTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ConcurrencyIntegrationTest.java index 32cec67b7..ae70e93ad 100755 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ConcurrencyIntegrationTest.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ConcurrencyIntegrationTest.java @@ -80,7 +80,7 @@ public class ConcurrencyIntegrationTest { private Integer createLoanProduct(final boolean multiDisburseLoan, final String accountingRule, final Account... accounts) { System.out.println("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------"); - final String loanProductJSON = new LoanProductTestBuilder() // + LoanProductTestBuilder builder = new LoanProductTestBuilder() // .withPrincipal("12,000.00") // .withNumberOfRepayments("4") // .withRepaymentAfterEvery("1") // @@ -90,7 +90,12 @@ public class ConcurrencyIntegrationTest { .withAmortizationTypeAsEqualInstallments() // .withInterestTypeAsDecliningBalance() // .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); } diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/LoanApplicationApprovalTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/LoanApplicationApprovalTest.java index 214e3abb9..5b015d58f 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/LoanApplicationApprovalTest.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/LoanApplicationApprovalTest.java @@ -121,7 +121,8 @@ public class LoanApplicationApprovalTest { + clientID); 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-------------------------------------------" + loanProductID); diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/LoanApplicationUndoLastTrancheTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/LoanApplicationUndoLastTrancheTest.java index d3eb5d27a..36bd91c35 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/LoanApplicationUndoLastTrancheTest.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/LoanApplicationUndoLastTrancheTest.java @@ -11,7 +11,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; - import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -31,12 +30,12 @@ import org.mifosplatform.integrationtests.LoanApplicationApprovalTest; @SuppressWarnings("rawtypes") public class LoanApplicationUndoLastTrancheTest { - - private ResponseSpecification responseSpec; + + private ResponseSpecification responseSpec; private RequestSpecification requestSpec; private LoanTransactionHelper loanTransactionHelper; private LoanApplicationApprovalTest loanApplicationApprovalTest; - + @Before public void setup() { Utils.initializeRESTAssured(); @@ -46,32 +45,33 @@ public class LoanApplicationUndoLastTrancheTest { this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec); this.loanApplicationApprovalTest = new LoanApplicationApprovalTest(); } - + @Test - public void LoanApplicationUndoLastTranche(){ - - final String proposedAmount = "5000"; + public void LoanApplicationUndoLastTranche() { + + final String proposedAmount = "5000"; final String approvalAmount = "2000"; final String approveDate = "1 March 2014"; final String expectedDisbursementDate = "1 March 2014"; final String disbursalDate = "1 March 2014"; - + // 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---------------------------------------------------" + clientID); // CREATE LOAN MULTIDISBURSAL PRODUCT 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-------------------------------------------" + loanProductID); - + // CREATE TRANCHES List createTranches = new ArrayList<>(); createTranches.add(this.loanApplicationApprovalTest.createTrancheDetail("1 March 2014", "1000")); createTranches.add(this.loanApplicationApprovalTest.createTrancheDetail("23 June 2014", "4000")); - + // APPROVE TRANCHES List approveTranches = new ArrayList<>(); approveTranches.add(this.loanApplicationApprovalTest.createTrancheDetail("1 March 2014", "1000")); @@ -82,25 +82,25 @@ public class LoanApplicationUndoLastTrancheTest { System.out.println("-----------------------------------LOAN CREATED WITH LOANID-------------------------------------------------" + loanID); HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID); - + // VALIDATE THE LOAN STATUS LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap); System.out.println("-----------------------------------APPROVE LOAN-----------------------------------------------------------"); loanStatusHashMap = this.loanTransactionHelper.approveLoanWithApproveAmount(approveDate, expectedDisbursementDate, approvalAmount, loanID, approveTranches); - + // VALIDATE THE LOAN IS APPROVED LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap); LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap); - + // DISBURSE A LOAN this.loanTransactionHelper.disburseLoan(disbursalDate, loanID); loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID); - + // VALIDATE THE LOAN IS ACTIVE STATUS LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap); - + System.out.println("-------------Make repayment 1-----------"); this.loanTransactionHelper.makeRepayment("01 April 2014", Float.valueOf("420"), loanID); System.out.println("-------------Make repayment 2-----------"); @@ -111,15 +111,15 @@ public class LoanApplicationUndoLastTrancheTest { this.loanTransactionHelper.disburseLoan("23 June 2014", loanID); // UNDO LAST TRANCHE Float disbursedAmount = this.loanTransactionHelper.undoLastDisbursal(loanID); - validateDisbursedAmount(disbursedAmount); + validateDisbursedAmount(disbursedAmount); } - - private void validateDisbursedAmount(Float disbursedAmount) { - Assert.assertEquals(Float.valueOf("1000.0"), disbursedAmount); - - } - public Integer applyForLoanApplicationWithTranches(final Integer clientID, final Integer loanProductID, String principal, + private void validateDisbursedAmount(Float disbursedAmount) { + Assert.assertEquals(Float.valueOf("1000.0"), disbursedAmount); + + } + + public Integer applyForLoanApplicationWithTranches(final Integer clientID, final Integer loanProductID, String principal, List tranches) { System.out.println("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------"); final String loanApplicationJSON = new LoanApplicationTestBuilder() @@ -140,6 +140,5 @@ public class LoanApplicationUndoLastTrancheTest { return this.loanTransactionHelper.getLoanId(loanApplicationJSON); } - } diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/LoanDisbursementDetailsIntegrationTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/LoanDisbursementDetailsIntegrationTest.java index 32198f677..a0257903a 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/LoanDisbursementDetailsIntegrationTest.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/LoanDisbursementDetailsIntegrationTest.java @@ -64,12 +64,12 @@ public class LoanDisbursementDetailsIntegrationTest { createTranches.add(this.loanTransactionHelper.createTrancheDetail(id, "01 Sep 2015", "5000")); final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2014"); - System.out.println( - "---------------------------------CLIENT CREATED WITH ID---------------------------------------------------" + clientID); + System.out.println("---------------------------------CLIENT CREATED WITH ID---------------------------------------------------" + + clientID); - final Integer loanProductID = this.loanTransactionHelper - .getLoanProductId(new LoanProductTestBuilder().withInterestTypeAsDecliningBalance().withMoratorium("", "") - .withAmortizationTypeAsEqualInstallments().withTranches(true).build(null)); + final Integer loanProductID = this.loanTransactionHelper.getLoanProductId(new LoanProductTestBuilder() + .withInterestTypeAsDecliningBalance().withMoratorium("", "").withAmortizationTypeAsEqualInstallments().withTranches(true) + .withInterestCalculationPeriodTypeAsRepaymentPeriod(true).build(null)); System.out.println("----------------------------------LOAN PRODUCT CREATED WITH ID-------------------------------------------" + loanProductID); @@ -96,8 +96,8 @@ public class LoanDisbursementDetailsIntegrationTest { createTranches); LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap); LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap); - System.out.println( - "-----------------------------------MULTI DISBURSAL LOAN WITH EMI APPROVED SUCCESSFULLY---------------------------------------"); + System.out + .println("-----------------------------------MULTI DISBURSAL LOAN WITH EMI APPROVED SUCCESSFULLY---------------------------------------"); final Integer loanIDWithoutEmi = applyForLoanApplicationWithEmiAmount(clientID, loanProductID, proposedAmount, createTranches, withoutInstallmentAmount); @@ -108,8 +108,8 @@ public class LoanDisbursementDetailsIntegrationTest { ArrayList periods1 = (ArrayList) repaymentScheduleWithEmi.get("periods"); assertEquals(periods1.size(), 15); - System.out.println( - "-----------------------------------LOAN CREATED WITHOUT EMI LOANID-------------------------------------------------" + System.out + .println("-----------------------------------LOAN CREATED WITHOUT EMI LOANID-------------------------------------------------" + loanIDWithoutEmi); /* To be uncommented once issue MIFOSX-2006 is closed. */ @@ -123,8 +123,8 @@ public class LoanDisbursementDetailsIntegrationTest { loanIDWithoutEmi, createTranches); LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap); LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap); - System.out.println( - "-----------------------------------MULTI DISBURSAL LOAN WITHOUT EMI APPROVED SUCCESSFULLY---------------------------------------"); + System.out + .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("principalLoanBalanceOutstanding"), expectedRepaymentSchedule.getPrincipalLoanBalanceOutstanding()); System.out.println(period.get("totalOriginalDueForPeriod").toString()); - assertEquals(new Float(period.get("totalOriginalDueForPeriod").toString()), - expectedRepaymentSchedule.getTotalOriginalDueForPeriod().floatValue(), 0.0f); + assertEquals(new Float(period.get("totalOriginalDueForPeriod").toString()), expectedRepaymentSchedule + .getTotalOriginalDueForPeriod().floatValue(), 0.0f); assertEquals(new Float(period.get("totalOutstandingForPeriod").toString()).floatValue(), expectedRepaymentSchedule.getTotalOutstandingForPeriod(), 0.0f); @@ -335,7 +335,7 @@ public class LoanDisbursementDetailsIntegrationTest { System.out.println("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------"); final String loanApplicationJSON = new LoanApplicationTestBuilder() - // + // .withPrincipal(proposedAmount) // .withLoanTermFrequency("12") @@ -364,17 +364,18 @@ public class LoanDisbursementDetailsIntegrationTest { createTranches.add(this.loanTransactionHelper.createTrancheDetail(id, "01 March 2014", "1000")); final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2014"); - System.out.println( - "---------------------------------CLIENT CREATED WITH ID---------------------------------------------------" + clientID); + System.out.println("---------------------------------CLIENT CREATED WITH ID---------------------------------------------------" + + clientID); - final Integer loanProductID = this.loanTransactionHelper - .getLoanProductId(new LoanProductTestBuilder().withInterestTypeAsDecliningBalance().withTranches(true).build(null)); + final Integer loanProductID = this.loanTransactionHelper.getLoanProductId(new LoanProductTestBuilder() + .withInterestTypeAsDecliningBalance().withTranches(true).withInterestCalculationPeriodTypeAsRepaymentPeriod(true) + .build(null)); System.out.println("----------------------------------LOAN PRODUCT CREATED WITH ID-------------------------------------------" + loanProductID); this.loanID = applyForLoanApplicationWithTranches(clientID, loanProductID, proposedAmount, createTranches); - System.out.println( - "-----------------------------------LOAN CREATED WITH LOANID-------------------------------------------------" + loanID); + System.out.println("-----------------------------------LOAN CREATED WITH LOANID-------------------------------------------------" + + loanID); HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(this.requestSpec, this.responseSpec, loanID); LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap); @@ -384,8 +385,8 @@ public class LoanDisbursementDetailsIntegrationTest { loanID, createTranches); LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap); LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap); - System.out.println( - "-----------------------------------MULTI DISBURSAL LOAN APPROVED SUCCESSFULLY---------------------------------------"); + System.out + .println("-----------------------------------MULTI DISBURSAL LOAN APPROVED SUCCESSFULLY---------------------------------------"); ArrayList disbursementDetails = (ArrayList) this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, this.loanID, "disbursementDetails"); this.disbursementId = (Integer) disbursementDetails.get(0).get("id"); @@ -466,7 +467,7 @@ public class LoanDisbursementDetailsIntegrationTest { List tranches) { System.out.println("--------------------------------APPLYING FOR LOAN APPLICATION--------------------------------"); final String loanApplicationJSON = new LoanApplicationTestBuilder() - // + // .withPrincipal(principal) // .withLoanTermFrequency("5") diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/ProvisioningIntegrationTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/ProvisioningIntegrationTest.java index 5d8193b55..c79232195 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/ProvisioningIntegrationTest.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/ProvisioningIntegrationTest.java @@ -161,7 +161,7 @@ public class ProvisioningIntegrationTest { private Integer createLoanProduct(final boolean multiDisburseLoan, final String accountingRule, final Account... accounts) { System.out.println("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------"); - final String loanProductJSON = new LoanProductTestBuilder() // + LoanProductTestBuilder builder = new LoanProductTestBuilder() // .withPrincipal("1,00,000.00") // .withNumberOfRepayments("4") // .withRepaymentAfterEvery("1") // @@ -171,7 +171,12 @@ public class ProvisioningIntegrationTest { .withAmortizationTypeAsEqualInstallments() // .withInterestTypeAsDecliningBalance() // .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); } diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanProductTestBuilder.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanProductTestBuilder.java index 455e58bd4..cf5063221 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanProductTestBuilder.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanProductTestBuilder.java @@ -104,6 +104,7 @@ public class LoanProductTestBuilder { private String graceOnPrincipalPayment = "1"; private String graceOnInterestPayment = "1"; private JsonObject allowAttributeOverrides = null; + private Boolean allowPartialPeriodInterestCalcualtion = false; public String build(final String chargeId) { final HashMap map = new HashMap<>(); @@ -183,6 +184,7 @@ public class LoanProductTestBuilder { if (allowAttributeOverrides != null) { map.put("allowAttributeOverrides", this.allowAttributeOverrides); } + map.put("allowPartialPeriodInterestCalcualtion", this.allowPartialPeriodInterestCalcualtion); return new Gson().toJson(map); } @@ -276,8 +278,9 @@ public class LoanProductTestBuilder { return this; } - public LoanProductTestBuilder withInterestCalculationPeriodTypeAsRepaymentPeriod() { + public LoanProductTestBuilder withInterestCalculationPeriodTypeAsRepaymentPeriod(final Boolean allowPartialPeriodInterestCalcualtion) { this.interestCalculationPeriodType = CALCULATION_PERIOD_SAME_AS_REPAYMENT_PERIOD; + this.allowPartialPeriodInterestCalcualtion = allowPartialPeriodInterestCalcualtion; return this; } @@ -419,7 +422,7 @@ public class LoanProductTestBuilder { this.recalculationRestFrequencyDate = recalculationRestFrequencyDate; return this; } - + public LoanProductTestBuilder withInterestRecalculationCompoundingFrequencyDetails(final String recalculationCompoundingFrequencyType, final String recalculationCompoundingFrequencyInterval, final String recalculationCompoundingFrequencyDate) { this.isInterestRecalculationEnabled = true; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/domain/CodeValue.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/domain/CodeValue.java index ec2cb3fec..0795549c3 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/domain/CodeValue.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/domain/CodeValue.java @@ -40,8 +40,9 @@ public class CodeValue extends AbstractPersistable { @Column(name = "is_active") 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); } @@ -70,7 +71,11 @@ public class CodeValue extends AbstractPersistable { final String label = command.stringValueOfParameterNamed(CODEVALUE_JSON_INPUT_PARAMS.NAME.getValue()); Integer position = command.integerValueSansLocaleOfParameterNamed(CODEVALUE_JSON_INPUT_PARAMS.POSITION.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) { position = new Integer(0); } @@ -87,7 +92,7 @@ public class CodeValue extends AbstractPersistable { actualChanges.put(labelParamName, newValue); this.label = StringUtils.defaultIfEmpty(newValue, null); } - + final String decriptionParamName = CODEVALUE_JSON_INPUT_PARAMS.DESCRIPTION.getValue(); if (command.isChangeInStringParameterNamed(decriptionParamName, this.description)) { final String newValue = command.stringValueOfParameterNamed(decriptionParamName); @@ -101,7 +106,7 @@ public class CodeValue extends AbstractPersistable { actualChanges.put(positionParamName, newValue); this.position = newValue.intValue(); } - + final String isActiveParamName = CODEVALUE_JSON_INPUT_PARAMS.IS_ACTIVE.getValue(); if (command.isChangeInBooleanParameterNamed(isActiveParamName, this.isActive)) { final Boolean newValue = command.booleanPrimitiveValueOfParameterNamed(isActiveParamName); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/serialization/CodeValueCommandFromApiJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/serialization/CodeValueCommandFromApiJsonDeserializer.java index bf65e38cc..01d283d55 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/serialization/CodeValueCommandFromApiJsonDeserializer.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/codes/serialization/CodeValueCommandFromApiJsonDeserializer.java @@ -66,9 +66,11 @@ public final class CodeValueCommandFromApiJsonDeserializer { // Validate input value is a valid Integer this.fromApiJsonHelper.extractIntegerSansLocaleNamed(CODEVALUE_JSON_INPUT_PARAMS.POSITION.getValue(), element); } - - 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(); + + if (this.fromApiJsonHelper.parameterExists(CODEVALUE_JSON_INPUT_PARAMS.IS_ACTIVE.getValue(), element)) { + 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); } @@ -100,7 +102,7 @@ public final class CodeValueCommandFromApiJsonDeserializer { // Validate input value is a valid Integer this.fromApiJsonHelper.extractIntegerSansLocaleNamed(CODEVALUE_JSON_INPUT_PARAMS.POSITION.getValue(), element); } - + if (this.fromApiJsonHelper.parameterExists(CODEVALUE_JSON_INPUT_PARAMS.IS_ACTIVE.getValue(), element)) { 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(); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoansApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoansApiResource.java index cfc89540f..f37b0d273 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoansApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/api/LoansApiResource.java @@ -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.service.LoanChargeReadPlatformService; 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.TransactionProcessingStrategyData; import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod; @@ -109,19 +110,20 @@ import com.google.gson.JsonElement; public class LoansApiResource { private final Set LOAN_DATA_PARAMETERS = new HashSet<>(Arrays.asList("id", "accountNo", "status", "externalId", "clientId", - "group", "loanProductId", "loanProductName", "loanProductDescription", "isLoanProductLinkedToFloatingRate", "fundId", "fundName", "loanPurposeId", - "loanPurposeName", "loanOfficerId", "loanOfficerName", "currency", "principal", "totalOverpaid", "inArrearsTolerance", - "termFrequency", "termPeriodFrequencyType", "numberOfRepayments", "repaymentEvery", "interestRatePerPeriod", - "annualInterestRate", "repaymentFrequencyType", "transactionProcessingStrategyId", "transactionProcessingStrategyName", - "interestRateFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType", - "expectedFirstRepaymentOnDate", "graceOnPrincipalPayment", "graceOnInterestPayment", "graceOnInterestCharged", - "interestChargedFromDate", "timeline", "totalFeeChargesAtDisbursement", "summary", "repaymentSchedule", "transactions", - "charges", "collateral", "guarantors", "meeting", "productOptions", "amortizationTypeOptions", "interestTypeOptions", - "interestCalculationPeriodTypeOptions", "repaymentFrequencyTypeOptions", "repaymentFrequencyNthDayTypeOptions", - "repaymentFrequencyDaysOfWeekTypeOptions", "termFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "fundOptions", - "repaymentStrategyOptions", "chargeOptions", "loanOfficerOptions", "loanPurposeOptions", "loanCollateralOptions", - "chargeTemplate", "calendarOptions", "syncDisbursementWithMeeting", "loanCounter", "loanProductCounter", "notes", - "accountLinkingOptions", "linkedAccount", "interestRateDifferential", "isFloatingInterestRate", "interestRatesPeriods")); + "group", "loanProductId", "loanProductName", "loanProductDescription", "isLoanProductLinkedToFloatingRate", "fundId", + "fundName", "loanPurposeId", "loanPurposeName", "loanOfficerId", "loanOfficerName", "currency", "principal", "totalOverpaid", + "inArrearsTolerance", "termFrequency", "termPeriodFrequencyType", "numberOfRepayments", "repaymentEvery", + "interestRatePerPeriod", "annualInterestRate", "repaymentFrequencyType", "transactionProcessingStrategyId", + "transactionProcessingStrategyName", "interestRateFrequencyType", "amortizationType", "interestType", + "interestCalculationPeriodType", LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName, "expectedFirstRepaymentOnDate", + "graceOnPrincipalPayment", "graceOnInterestPayment", "graceOnInterestCharged", "interestChargedFromDate", "timeline", + "totalFeeChargesAtDisbursement", "summary", "repaymentSchedule", "transactions", "charges", "collateral", "guarantors", + "meeting", "productOptions", "amortizationTypeOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions", + "repaymentFrequencyTypeOptions", "repaymentFrequencyNthDayTypeOptions", "repaymentFrequencyDaysOfWeekTypeOptions", + "termFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "fundOptions", "repaymentStrategyOptions", "chargeOptions", + "loanOfficerOptions", "loanPurposeOptions", "loanCollateralOptions", "chargeTemplate", "calendarOptions", + "syncDisbursementWithMeeting", "loanCounter", "loanProductCounter", "notes", "accountLinkingOptions", "linkedAccount", + "interestRateDifferential", "isFloatingInterestRate", "interestRatesPeriods")); private final Set LOAN_APPROVAL_DATA_PARAMETERS = new HashSet<>(Arrays.asList("approvalDate", "approvalAmount")); private final String resourceNameForPermissions = "LOAN"; @@ -359,7 +361,7 @@ public class LoansApiResource { } Collection interestRatesPeriods = this.loanReadPlatformService.retrieveLoanInterestRatePeriodData(loanId); - + Collection loanRepayments = null; LoanScheduleData repaymentSchedule = null; Collection charges = null; @@ -494,21 +496,21 @@ public class LoansApiResource { interestRateFrequencyTypeOptions = this.dropdownReadPlatformService.retrieveInterestRateFrequencyTypeOptions(); amortizationTypeOptions = this.dropdownReadPlatformService.retrieveLoanAmortizationTypeOptions(); - if(product.isLinkedToFloatingInterestRates()){ - interestTypeOptions = Arrays.asList(interestType(InterestMethod.DECLINING_BALANCE)); - }else { + if (product.isLinkedToFloatingInterestRates()) { + interestTypeOptions = Arrays.asList(interestType(InterestMethod.DECLINING_BALANCE)); + } else { interestTypeOptions = this.dropdownReadPlatformService.retrieveLoanInterestTypeOptions(); } interestCalculationPeriodTypeOptions = this.dropdownReadPlatformService.retrieveLoanInterestRateCalculatedInPeriodOptions(); fundOptions = this.fundReadPlatformService.retrieveAllFunds(); repaymentStrategyOptions = this.dropdownReadPlatformService.retreiveTransactionProcessingStrategies(); - if(product.getMultiDisburseLoan()){ - chargeOptions = this.chargeReadPlatformService.retrieveLoanAccountApplicableCharges(loanId, + if (product.getMultiDisburseLoan()) { + chargeOptions = this.chargeReadPlatformService.retrieveLoanAccountApplicableCharges(loanId, new ChargeTimeType[] { ChargeTimeType.OVERDUE_INSTALLMENT }); - }else{ - chargeOptions = this.chargeReadPlatformService.retrieveLoanAccountApplicableCharges(loanId, - new ChargeTimeType[] { ChargeTimeType.OVERDUE_INSTALLMENT, ChargeTimeType.TRANCHE_DISBURSEMENT }); + } else { + chargeOptions = this.chargeReadPlatformService.retrieveLoanAccountApplicableCharges(loanId, new ChargeTimeType[] { + ChargeTimeType.OVERDUE_INSTALLMENT, ChargeTimeType.TRANCHE_DISBURSEMENT }); } chargeTemplate = this.loanChargeReadPlatformService.retrieveLoanChargeTemplate(); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanAccountData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanAccountData.java index b55a4de41..b1765f6f8 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanAccountData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/data/LoanAccountData.java @@ -98,6 +98,7 @@ public class LoanAccountData { private final EnumOptionData amortizationType; private final EnumOptionData interestType; private final EnumOptionData interestCalculationPeriodType; + private final Boolean allowPartialPeriodInterestCalcualtion; private final BigDecimal inArrearsTolerance; private final Long transactionProcessingStrategyId; private final String transactionProcessingStrategyName; @@ -242,6 +243,7 @@ public class LoanAccountData { final boolean isFloatingInterestRate = false; final BigDecimal interestRateDifferential = null; final EnumOptionData interestCalculationPeriodType = null; + final Boolean allowPartialPeriodInterestCalcualtion = null; final LocalDate expectedFirstRepaymentOnDate = null; final Integer graceOnPrincipalPayment = null; final Integer graceOnInterestPayment = null; @@ -304,22 +306,23 @@ public class LoanAccountData { final Integer minimumGap = null; final Integer maximumGap = null; - return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group, loanType, loanProductId, - loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, - currencyData, proposedPrincipal, principal, principal, totalOverpaid, inArrearsTolerance, termFrequency, - termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, repaymentFrequencyNthDayType, - repaymentFrequencyDayOfWeekType, transactionProcessingStrategyId, transactionProcessingStrategyName, amortizationType, - interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType, isFloatingInterestRate, - interestRateDifferential, interestCalculationPeriodType, expectedFirstRepaymentOnDate, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, - interestChargedFromDate, timeline, summary, feeChargesDueAtDisbursementCharged, repaymentSchedule, transactions, charges, - collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, - repaymentFrequencyNthDayTypeOptions, repaymentFrequencyDayOfWeekTypeOptions, transactionProcessingStrategyOptions, - interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, - fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions, - syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, accountLinkingOptions, linkedAccount, - disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount, maxOutstandingLoanBalance, - emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType, - daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule, + return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group, + loanType, loanProductId, loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName, + loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, currencyData, proposedPrincipal, principal, principal, + totalOverpaid, inArrearsTolerance, termFrequency, termPeriodFrequencyType, numberOfRepayments, repaymentEvery, + repaymentFrequencyType, repaymentFrequencyNthDayType, repaymentFrequencyDayOfWeekType, transactionProcessingStrategyId, + transactionProcessingStrategyName, amortizationType, interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, + interestType, isFloatingInterestRate, interestRateDifferential, interestCalculationPeriodType, + allowPartialPeriodInterestCalcualtion, expectedFirstRepaymentOnDate, graceOnPrincipalPayment, graceOnInterestPayment, + graceOnInterestCharged, interestChargedFromDate, timeline, summary, feeChargesDueAtDisbursementCharged, repaymentSchedule, + transactions, charges, collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions, + repaymentFrequencyTypeOptions, repaymentFrequencyNthDayTypeOptions, repaymentFrequencyDayOfWeekTypeOptions, + transactionProcessingStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, + interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, + loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, + accountLinkingOptions, linkedAccount, disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount, + maxOutstandingLoanBalance, emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, + isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule, createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods, isVariableInstallmentsAllowed, minimumGap, maximumGap); @@ -329,8 +332,8 @@ public class LoanAccountData { * Used to produce a {@link LoanAccountData} with only client information * defaulted. */ - public static LoanAccountData clientDefaults(final Long clientId, final String clientAccountNo, final String clientName, final Long clientOfficeId, - final LocalDate expectedDisbursementDate) { + public static LoanAccountData clientDefaults(final Long clientId, final String clientAccountNo, final String clientName, + final Long clientOfficeId, final LocalDate expectedDisbursementDate) { final Long id = null; final String accountNo = null; final LoanStatusEnumData status = null; @@ -370,6 +373,7 @@ public class LoanAccountData { final boolean isFloatingInterestRate = false; final BigDecimal interestRateDifferential = null; final EnumOptionData interestCalculationPeriodType = null; + final Boolean allowPartialPeriodInterestCalcualtion = null; final LocalDate expectedFirstRepaymentOnDate = null; final Integer graceOnPrincipalPayment = null; final Integer graceOnInterestPayment = null; @@ -434,23 +438,23 @@ public class LoanAccountData { final Integer minimumGap = null; final Integer maximumGap = null; - return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group, loanType, loanProductId, - loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, - currencyData, proposedPrincipal, principal, principal, totalOverpaid, inArrearsTolerance, termFrequency, - termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, repaymentFrequencyNthDayType, - repaymentFrequencyDayOfWeekType, transactionProcessingStrategyId, transactionProcessingStrategyName, amortizationType, - interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType, - isFloatingInterestRate, interestRateDifferential, interestCalculationPeriodType, - expectedFirstRepaymentOnDate, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, - interestChargedFromDate, timeline, summary, feeChargesDueAtDisbursementCharged, repaymentSchedule, transactions, charges, - collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, - repaymentFrequencyNthDayTypeOptions, repaymentFrequencyDayOfWeekTypeOptions, repaymentStrategyOptions, - interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, - fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions, - syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, accountLinkingOptions, linkedAccount, - disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount, maxOutstandingLoanBalance, - emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType, - daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule, + return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group, + loanType, loanProductId, loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName, + loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, currencyData, proposedPrincipal, principal, principal, + totalOverpaid, inArrearsTolerance, termFrequency, termPeriodFrequencyType, numberOfRepayments, repaymentEvery, + repaymentFrequencyType, repaymentFrequencyNthDayType, repaymentFrequencyDayOfWeekType, transactionProcessingStrategyId, + transactionProcessingStrategyName, amortizationType, interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, + interestType, isFloatingInterestRate, interestRateDifferential, interestCalculationPeriodType, + allowPartialPeriodInterestCalcualtion, expectedFirstRepaymentOnDate, graceOnPrincipalPayment, graceOnInterestPayment, + graceOnInterestCharged, interestChargedFromDate, timeline, summary, feeChargesDueAtDisbursementCharged, repaymentSchedule, + transactions, charges, collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions, + repaymentFrequencyTypeOptions, repaymentFrequencyNthDayTypeOptions, repaymentFrequencyDayOfWeekTypeOptions, + repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, + interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, + loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, + accountLinkingOptions, linkedAccount, disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount, + maxOutstandingLoanBalance, emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, + isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule, createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods, isVariableInstallmentsAllowed, minimumGap, maximumGap); @@ -458,19 +462,20 @@ public class LoanAccountData { 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, - clientAcc.clientOfficeId, acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.isLoanProductLinkedToFloatingRate, - acc.fundId, acc.fundName, acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, - acc.proposedPrincipal, acc.principal, acc.approvedPrincipal, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency, - acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType, - acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId, - acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType, - acc.annualInterestRate, acc.interestType, acc.isFloatingInterestRate, acc.interestRateDifferential, - acc.interestCalculationPeriodType, acc.expectedFirstRepaymentOnDate, - acc.graceOnPrincipalPayment, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate, - clientAcc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges, - acc.collateral, acc.guarantors, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions, - acc.repaymentFrequencyTypeOptions, acc.repaymentFrequencyNthDayTypeOptions, acc.repaymentFrequencyDaysOfWeekTypeOptions, + return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, clientAcc.clientId, clientAcc.clientAccountNo, + clientAcc.clientName, clientAcc.clientOfficeId, acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, + acc.loanProductDescription, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, acc.loanPurposeId, + acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal, acc.principal, + acc.approvedPrincipal, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency, acc.termPeriodFrequencyType, + acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType, acc.repaymentFrequencyNthDayType, + acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId, acc.transactionProcessingStrategyName, + acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType, acc.annualInterestRate, acc.interestType, + acc.isFloatingInterestRate, acc.interestRateDifferential, acc.interestCalculationPeriodType, + acc.allowPartialPeriodInterestCalcualtion, acc.expectedFirstRepaymentOnDate, acc.graceOnPrincipalPayment, + acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate, clientAcc.timeline, acc.summary, + acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges, acc.collateral, acc.guarantors, + acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions, acc.repaymentFrequencyTypeOptions, + acc.repaymentFrequencyNthDayTypeOptions, acc.repaymentFrequencyDaysOfWeekTypeOptions, acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions, acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null, acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions, @@ -530,6 +535,7 @@ public class LoanAccountData { final boolean isFloatingInterestRate = false; final BigDecimal interestRateDifferential = null; final EnumOptionData interestCalculationPeriodType = null; + final Boolean allowPartialPeriodInterestCalcualtion = null; final LocalDate expectedFirstRepaymentOnDate = null; final Integer graceOnPrincipalPayment = null; final Integer graceOnInterestPayment = null; @@ -594,24 +600,23 @@ public class LoanAccountData { final Integer minimumGap = null; final Integer maximumGap = null; - - return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group, loanType, loanProductId, - loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, - currencyData, proposedPrincipal, principal, principal, totalOverpaid, inArrearsTolerance, termFrequency, - termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, repaymentFrequencyNthDayType, - repaymentFrequencyDayOfWeekType, transactionProcessingStrategyId, transactionProcessingStrategyName, amortizationType, - interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType, - isFloatingInterestRate, interestRateDifferential, interestCalculationPeriodType, - expectedFirstRepaymentOnDate, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, - interestChargedFromDate, timeline, summary, feeChargesDueAtDisbursementCharged, repaymentSchedule, transactions, charges, - collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, - repaymentFrequencyNthDayTypeOptions, repaymentFrequencyDayOfWeekTypeOptions, repaymentStrategyOptions, - interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, - fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions, - syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, accountLinkingOptions, linkedAccount, - disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount, maxOutstandingBalance, - emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType, - daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule, + return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group, + loanType, loanProductId, loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName, + loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, currencyData, proposedPrincipal, principal, principal, + totalOverpaid, inArrearsTolerance, termFrequency, termPeriodFrequencyType, numberOfRepayments, repaymentEvery, + repaymentFrequencyType, repaymentFrequencyNthDayType, repaymentFrequencyDayOfWeekType, transactionProcessingStrategyId, + transactionProcessingStrategyName, amortizationType, interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, + interestType, isFloatingInterestRate, interestRateDifferential, interestCalculationPeriodType, + allowPartialPeriodInterestCalcualtion, expectedFirstRepaymentOnDate, graceOnPrincipalPayment, graceOnInterestPayment, + graceOnInterestCharged, interestChargedFromDate, timeline, summary, feeChargesDueAtDisbursementCharged, repaymentSchedule, + transactions, charges, collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions, + repaymentFrequencyTypeOptions, repaymentFrequencyNthDayTypeOptions, repaymentFrequencyDayOfWeekTypeOptions, + repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, + interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, + loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, + accountLinkingOptions, linkedAccount, disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount, + maxOutstandingBalance, emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, + isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule, createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods, isVariableInstallmentsAllowed, minimumGap, maximumGap); @@ -619,19 +624,20 @@ public class LoanAccountData { 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, - groupAcc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, - acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal, - acc.principal, acc.approvedPrincipal, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency, - acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType, - acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId, - acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType, - acc.annualInterestRate, acc.interestType, acc.isFloatingInterestRate, acc.interestRateDifferential, - acc.interestCalculationPeriodType, acc.expectedFirstRepaymentOnDate, - acc.graceOnPrincipalPayment, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate, - groupAcc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges, - acc.collateral, acc.guarantors, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions, - acc.repaymentFrequencyTypeOptions, acc.repaymentFrequencyNthDayTypeOptions, acc.repaymentFrequencyDaysOfWeekTypeOptions, + return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName, + acc.clientOfficeId, groupAcc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, + acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, + acc.loanOfficerName, acc.currency, acc.proposedPrincipal, acc.principal, acc.approvedPrincipal, acc.totalOverpaid, + acc.inArrearsTolerance, acc.termFrequency, acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, + acc.repaymentFrequencyType, acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, + acc.transactionProcessingStrategyId, acc.transactionProcessingStrategyName, acc.amortizationType, + acc.interestRatePerPeriod, acc.interestRateFrequencyType, acc.annualInterestRate, acc.interestType, + acc.isFloatingInterestRate, acc.interestRateDifferential, acc.interestCalculationPeriodType, + acc.allowPartialPeriodInterestCalcualtion, acc.expectedFirstRepaymentOnDate, acc.graceOnPrincipalPayment, + acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate, groupAcc.timeline, acc.summary, + acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges, acc.collateral, acc.guarantors, + acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions, acc.repaymentFrequencyTypeOptions, + acc.repaymentFrequencyNthDayTypeOptions, acc.repaymentFrequencyDaysOfWeekTypeOptions, acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions, acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null, acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions, @@ -766,25 +772,26 @@ public class LoanAccountData { final Integer minimumGap = null; final Integer maximumGap = null; - return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group, loanType, - product.getId(), product.getName(), product.getDescription(), product.isLinkedToFloatingInterestRates(), product.getFundId(), product.getFundName(), loanPurposeId, - loanPurposeName, loanOfficerId, loanOfficerName, product.getCurrency(), proposedPrincipal, principal, principal, - totalOverpaid, product.getInArrearsTolerance(), termFrequency, termPeriodFrequencyType, numberOfRepayments, - product.getRepaymentEvery(), product.getRepaymentFrequencyType(), null, null, product.getTransactionProcessingStrategyId(), + return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group, + loanType, product.getId(), product.getName(), product.getDescription(), product.isLinkedToFloatingInterestRates(), + product.getFundId(), product.getFundName(), loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, + product.getCurrency(), proposedPrincipal, principal, principal, totalOverpaid, product.getInArrearsTolerance(), + termFrequency, termPeriodFrequencyType, numberOfRepayments, product.getRepaymentEvery(), + product.getRepaymentFrequencyType(), null, null, product.getTransactionProcessingStrategyId(), transactionProcessingStrategyName, product.getAmortizationType(), interestRatePerPeriod, product.getInterestRateFrequencyType(), product.getAnnualInterestRate(), product.getInterestType(), product.isFloatingInterestRateCalculationAllowed(), product.getDefaultDifferentialLendingRate(), - product.getInterestCalculationPeriodType(), expectedFirstRepaymentOnDate, product.getGraceOnPrincipalPayment(), - product.getGraceOnInterestPayment(), product.getGraceOnInterestCharged(), interestChargedFromDate, timeline, summary, - feeChargesDueAtDisbursementCharged, repaymentSchedule, transactions, charges, collateral, guarantors, calendarData, - productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentFrequencyNthDayTypeOptions, - repaymentFrequencyDayOfWeekTypeOptions, repaymentStrategyOptions, interestRateFrequencyTypeOptions, - amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, - chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions, - syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, accountLinkingOptions, linkedAccount, - disbursementData, product.getMultiDisburseLoan(), product.canDefineInstallmentAmount(), fixedEmi, - product.getOutstandingLoanBalance(), emiAmountVariations, memberVariations, product, inArrears, - product.getGraceOnArrearsAgeing(), product.overdueFeeCharges(), isNPA, product.getDaysInMonthType(), + product.getInterestCalculationPeriodType(), product.getAllowPartialPeriodInterestCalcualtion(), + expectedFirstRepaymentOnDate, product.getGraceOnPrincipalPayment(), product.getGraceOnInterestPayment(), + product.getGraceOnInterestCharged(), interestChargedFromDate, timeline, summary, feeChargesDueAtDisbursementCharged, + repaymentSchedule, transactions, charges, collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions, + repaymentFrequencyTypeOptions, repaymentFrequencyNthDayTypeOptions, repaymentFrequencyDayOfWeekTypeOptions, + repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, + interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, + loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, + accountLinkingOptions, linkedAccount, disbursementData, product.getMultiDisburseLoan(), + product.canDefineInstallmentAmount(), fixedEmi, product.getOutstandingLoanBalance(), emiAmountVariations, memberVariations, + product, inArrears, product.getGraceOnArrearsAgeing(), product.overdueFeeCharges(), isNPA, product.getDaysInMonthType(), product.getDaysInYearType(), product.isInterestRecalculationEnabled(), product.toLoanInterestRecalculationData(), originalSchedule, createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods, product.isVariableInstallmentsAllowed(), product.getMinimumGapBetweenInstallments(), @@ -824,16 +831,17 @@ public class LoanAccountData { charges.add(charge.toLoanChargeData()); } - return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName, acc.clientOfficeId, - acc.group, acc.loanType, product.getId(), product.getName(), product.getDescription(), product.isLinkedToFloatingInterestRates(), product.getFundId(), - product.getFundName(), acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, - product.getCurrency(), product.getPrincipal(), product.getPrincipal(), product.getPrincipal(), acc.totalOverpaid, - product.getInArrearsTolerance(), termFrequency, termPeriodFrequencyType, product.getNumberOfRepayments(), - product.getRepaymentEvery(), product.getRepaymentFrequencyType(), null, null, product.getTransactionProcessingStrategyId(), - product.getTransactionProcessingStrategyName(), product.getAmortizationType(), product.getInterestRatePerPeriod(), - product.getInterestRateFrequencyType(), product.getAnnualInterestRate(), product.getInterestType(), - product.isFloatingInterestRateCalculationAllowed(), product.getDefaultDifferentialLendingRate(), - product.getInterestCalculationPeriodType(), acc.expectedFirstRepaymentOnDate, product.getGraceOnPrincipalPayment(), + return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName, + acc.clientOfficeId, acc.group, acc.loanType, product.getId(), product.getName(), product.getDescription(), + product.isLinkedToFloatingInterestRates(), product.getFundId(), product.getFundName(), acc.loanPurposeId, + acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, product.getCurrency(), product.getPrincipal(), + product.getPrincipal(), product.getPrincipal(), acc.totalOverpaid, product.getInArrearsTolerance(), termFrequency, + termPeriodFrequencyType, product.getNumberOfRepayments(), product.getRepaymentEvery(), product.getRepaymentFrequencyType(), + null, null, product.getTransactionProcessingStrategyId(), product.getTransactionProcessingStrategyName(), + product.getAmortizationType(), product.getInterestRatePerPeriod(), product.getInterestRateFrequencyType(), + product.getAnnualInterestRate(), product.getInterestType(), product.isFloatingInterestRateCalculationAllowed(), + product.getDefaultDifferentialLendingRate(), product.getInterestCalculationPeriodType(), + product.getAllowPartialPeriodInterestCalcualtion(), acc.expectedFirstRepaymentOnDate, product.getGraceOnPrincipalPayment(), product.getGraceOnInterestPayment(), product.getGraceOnInterestCharged(), acc.interestChargedFromDate, acc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, repaymentSchedule, transactions, charges, collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, null, null, @@ -844,9 +852,9 @@ public class LoanAccountData { product.canDefineInstallmentAmount(), acc.fixedEmiAmount, product.getOutstandingLoanBalance(), acc.emiAmountVariations, acc.memberVariations, product, acc.inArrears, product.getGraceOnArrearsAgeing(), product.overdueFeeCharges(), acc.isNPA, product.getDaysInMonthType(), product.getDaysInYearType(), product.isInterestRecalculationEnabled(), - product.toLoanInterestRecalculationData(), acc.originalSchedule, acc.createStandingInstructionAtDisbursement, - paidInAdvance, acc.interestRatesPeriods, product.isVariableInstallmentsAllowed(), product.getMinimumGapBetweenInstallments(), - product.getMaximumGapBetweenInstallments()); + product.toLoanInterestRecalculationData(), acc.originalSchedule, acc.createStandingInstructionAtDisbursement, + paidInAdvance, acc.interestRatesPeriods, product.isVariableInstallmentsAllowed(), + product.getMinimumGapBetweenInstallments(), product.getMaximumGapBetweenInstallments()); } @@ -855,25 +863,26 @@ public class LoanAccountData { * query. */ 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 EnumOptionData loanType, final Long loanProductId, final String loanProductName, final String loanProductDescription, - final boolean isLoanProductLinkedToFloatingRate, final Long fundId, final String fundName, final Long loanPurposeId, - final String loanPurposeName, final Long loanOfficerId, final String loanOfficerName, final CurrencyData currencyData, - final BigDecimal proposedPrincipal, final BigDecimal principal, final BigDecimal approvedPrincipal, - final BigDecimal totalOverpaid, final BigDecimal inArrearsTolerance, final Integer termFrequency, - final EnumOptionData termPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery, - final EnumOptionData repaymentFrequencyType, EnumOptionData repaymentFrequencyNthDayType, + final String externalId, final Long clientId, final String clientAccountNo, final String clientName, final Long clientOfficeId, + final GroupGeneralData group, final EnumOptionData loanType, final Long loanProductId, final String loanProductName, + final String loanProductDescription, final boolean isLoanProductLinkedToFloatingRate, final Long fundId, final String fundName, + final Long loanPurposeId, final String loanPurposeName, final Long loanOfficerId, final String loanOfficerName, + final CurrencyData currencyData, final BigDecimal proposedPrincipal, final BigDecimal principal, + final BigDecimal approvedPrincipal, final BigDecimal totalOverpaid, final BigDecimal inArrearsTolerance, + final Integer termFrequency, final EnumOptionData termPeriodFrequencyType, final Integer numberOfRepayments, + final Integer repaymentEvery, final EnumOptionData repaymentFrequencyType, EnumOptionData repaymentFrequencyNthDayType, EnumOptionData repaymentFrequencyDayOfWeekType, final Long transactionStrategyId, final String transactionStrategyName, final EnumOptionData amortizationType, final BigDecimal interestRatePerPeriod, final EnumOptionData interestRateFrequencyType, final BigDecimal annualInterestRate, final EnumOptionData interestType, final boolean isFloatingInterestRate, final BigDecimal interestRateDifferential, final EnumOptionData interestCalculationPeriodType, - final LocalDate expectedFirstRepaymentOnDate, final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment, - final Integer graceOnInterestCharged, final LocalDate interestChargedFromDate, final LoanApplicationTimelineData timeline, - final LoanSummaryData loanSummary, final BigDecimal feeChargesDueAtDisbursementCharged, - final Boolean syncDisbursementWithMeeting, final Integer loancounter, final Integer loanProductCounter, - final Boolean multiDisburseLoan, Boolean canDefineInstallmentAmount, final BigDecimal fixedEmiAmont, - final BigDecimal outstandingLoanBalance, final Boolean inArrears, final Integer graceOnArrearsAgeing, final Boolean isNPA, - final EnumOptionData daysInMonthType, final EnumOptionData daysInYearType, final boolean isInterestRecalculationEnabled, + Boolean allowPartialPeriodInterestCalcualtion, final LocalDate expectedFirstRepaymentOnDate, + final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment, final Integer graceOnInterestCharged, + final LocalDate interestChargedFromDate, final LoanApplicationTimelineData timeline, final LoanSummaryData loanSummary, + final BigDecimal feeChargesDueAtDisbursementCharged, final Boolean syncDisbursementWithMeeting, final Integer loancounter, + final Integer loanProductCounter, final Boolean multiDisburseLoan, Boolean canDefineInstallmentAmount, + final BigDecimal fixedEmiAmont, final BigDecimal outstandingLoanBalance, final Boolean inArrears, + final Integer graceOnArrearsAgeing, final Boolean isNPA, final EnumOptionData daysInMonthType, + final EnumOptionData daysInYearType, final boolean isInterestRecalculationEnabled, final LoanInterestRecalculationData interestRecalculationData, final Boolean createStandingInstructionAtDisbursement, final Boolean isVariableInstallmentsAllowed, Integer minimumGap, Integer maximumGap) { @@ -912,24 +921,23 @@ public class LoanAccountData { final PaidInAdvanceData paidInAdvance = null; final Collection interestRatesPeriods = null; - - return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group, loanType, loanProductId, - loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, - currencyData, proposedPrincipal, principal, approvedPrincipal, totalOverpaid, inArrearsTolerance, termFrequency, - termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, repaymentFrequencyNthDayType, - repaymentFrequencyDayOfWeekType, transactionStrategyId, transactionStrategyName, amortizationType, interestRatePerPeriod, - interestRateFrequencyType, annualInterestRate, interestType, isFloatingInterestRate, interestRateDifferential, - interestCalculationPeriodType, expectedFirstRepaymentOnDate, - graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, timeline, loanSummary, - feeChargesDueAtDisbursementCharged, repaymentSchedule, transactions, charges, collateral, guarantors, calendarData, - productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentFrequencyNthDayTypeOptions, - repaymentFrequencyDayOfWeekTypeOptions, repaymentStrategyOptions, interestRateFrequencyTypeOptions, - amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, - chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions, - syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, accountLinkingOptions, linkedAccount, - disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmont, outstandingLoanBalance, - emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType, - daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule, + return new LoanAccountData(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, group, + loanType, loanProductId, loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName, + loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, currencyData, proposedPrincipal, principal, + approvedPrincipal, totalOverpaid, inArrearsTolerance, termFrequency, termPeriodFrequencyType, numberOfRepayments, + repaymentEvery, repaymentFrequencyType, repaymentFrequencyNthDayType, repaymentFrequencyDayOfWeekType, + transactionStrategyId, transactionStrategyName, amortizationType, interestRatePerPeriod, interestRateFrequencyType, + annualInterestRate, interestType, isFloatingInterestRate, interestRateDifferential, interestCalculationPeriodType, + allowPartialPeriodInterestCalcualtion, expectedFirstRepaymentOnDate, graceOnPrincipalPayment, graceOnInterestPayment, + graceOnInterestCharged, interestChargedFromDate, timeline, loanSummary, feeChargesDueAtDisbursementCharged, + repaymentSchedule, transactions, charges, collateral, guarantors, calendarData, productOptions, termFrequencyTypeOptions, + repaymentFrequencyTypeOptions, repaymentFrequencyNthDayTypeOptions, repaymentFrequencyDayOfWeekTypeOptions, + repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, + interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, + loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, + accountLinkingOptions, linkedAccount, disbursementData, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmont, + outstandingLoanBalance, emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, + isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule, createStandingInstructionAtDisbursement, paidInAdvance, interestRatesPeriods, isVariableInstallmentsAllowed, minimumGap, maximumGap); } @@ -960,22 +968,22 @@ public class LoanAccountData { loanProductConfigurableAttributes = acc.product.getloanProductConfigurableAttributes(); } - - return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName, acc.clientOfficeId, - acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, - acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal, - acc.principal, acc.approvedPrincipal, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency, - acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType, - acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId, - acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType, - acc.annualInterestRate, acc.interestType, acc.isFloatingInterestRate, acc.interestRateDifferential, - acc.interestCalculationPeriodType, acc.expectedFirstRepaymentOnDate, - acc.graceOnPrincipalPayment, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate, - acc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, repaymentSchedule, transactions, charges, collateral, - guarantors, calendarData, productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, - repaymentFrequencyNthDayTypeOptions, repaymentFrequencyDayOfWeekTypeOptions, transactionProcessingStrategyOptions, - interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, - fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions, + return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName, + acc.clientOfficeId, acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, + acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, + acc.loanOfficerName, acc.currency, acc.proposedPrincipal, acc.principal, acc.approvedPrincipal, acc.totalOverpaid, + acc.inArrearsTolerance, acc.termFrequency, acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, + acc.repaymentFrequencyType, acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, + acc.transactionProcessingStrategyId, acc.transactionProcessingStrategyName, acc.amortizationType, + acc.interestRatePerPeriod, acc.interestRateFrequencyType, acc.annualInterestRate, acc.interestType, + acc.isFloatingInterestRate, acc.interestRateDifferential, acc.interestCalculationPeriodType, + acc.allowPartialPeriodInterestCalcualtion, acc.expectedFirstRepaymentOnDate, acc.graceOnPrincipalPayment, + acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate, acc.timeline, acc.summary, + acc.feeChargesAtDisbursementCharged, repaymentSchedule, transactions, charges, collateral, guarantors, calendarData, + productOptions, termFrequencyTypeOptions, repaymentFrequencyTypeOptions, repaymentFrequencyNthDayTypeOptions, + repaymentFrequencyDayOfWeekTypeOptions, transactionProcessingStrategyOptions, interestRateFrequencyTypeOptions, + amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, + chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions, acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, notes, accountLinkingOptions, linkedAccount, disbursementDetails, acc.multiDisburseLoan, acc.canDefineInstallmentAmount, acc.fixedEmiAmount, 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) { - return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName, acc.clientOfficeId, - group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, - acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal, - acc.principal, acc.approvedPrincipal, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency, - acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType, - acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId, - acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType, - acc.annualInterestRate, acc.interestType, acc.isFloatingInterestRate, acc.interestRateDifferential, - acc.interestCalculationPeriodType, acc.expectedFirstRepaymentOnDate, - acc.graceOnPrincipalPayment, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate, - acc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges, - acc.collateral, acc.guarantors, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions, - acc.repaymentFrequencyTypeOptions, acc.repaymentFrequencyNthDayTypeOptions, acc.repaymentFrequencyDaysOfWeekTypeOptions, + return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName, + acc.clientOfficeId, group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, + acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, + acc.loanOfficerName, acc.currency, acc.proposedPrincipal, acc.principal, acc.approvedPrincipal, acc.totalOverpaid, + acc.inArrearsTolerance, acc.termFrequency, acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, + acc.repaymentFrequencyType, acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, + acc.transactionProcessingStrategyId, acc.transactionProcessingStrategyName, acc.amortizationType, + acc.interestRatePerPeriod, acc.interestRateFrequencyType, acc.annualInterestRate, acc.interestType, + acc.isFloatingInterestRate, acc.interestRateDifferential, acc.interestCalculationPeriodType, + acc.allowPartialPeriodInterestCalcualtion, acc.expectedFirstRepaymentOnDate, acc.graceOnPrincipalPayment, + acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate, acc.timeline, acc.summary, + acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges, acc.collateral, acc.guarantors, + acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions, acc.repaymentFrequencyTypeOptions, + acc.repaymentFrequencyNthDayTypeOptions, acc.repaymentFrequencyDaysOfWeekTypeOptions, acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions, acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null, acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions, @@ -1063,19 +1072,20 @@ public class LoanAccountData { memberVariations.put(clientId, borrowerCycleData); } - return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName, acc.clientOfficeId, - acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, - acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal, - acc.principal, acc.approvedPrincipal, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency, - acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType, - acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId, - acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType, - acc.annualInterestRate, acc.interestType, acc.isFloatingInterestRate, acc.interestRateDifferential, - acc.interestCalculationPeriodType, acc.expectedFirstRepaymentOnDate, - acc.graceOnPrincipalPayment, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate, - acc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges, - acc.collateral, acc.guarantors, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions, - acc.repaymentFrequencyTypeOptions, acc.repaymentFrequencyNthDayTypeOptions, acc.repaymentFrequencyDaysOfWeekTypeOptions, + return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName, + acc.clientOfficeId, acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, + acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, + acc.loanOfficerName, acc.currency, acc.proposedPrincipal, acc.principal, acc.approvedPrincipal, acc.totalOverpaid, + acc.inArrearsTolerance, acc.termFrequency, acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, + acc.repaymentFrequencyType, acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, + acc.transactionProcessingStrategyId, acc.transactionProcessingStrategyName, acc.amortizationType, + acc.interestRatePerPeriod, acc.interestRateFrequencyType, acc.annualInterestRate, acc.interestType, + acc.isFloatingInterestRate, acc.interestRateDifferential, acc.interestCalculationPeriodType, + acc.allowPartialPeriodInterestCalcualtion, acc.expectedFirstRepaymentOnDate, acc.graceOnPrincipalPayment, + acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate, acc.timeline, acc.summary, + acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges, acc.collateral, acc.guarantors, + acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions, acc.repaymentFrequencyTypeOptions, + acc.repaymentFrequencyNthDayTypeOptions, acc.repaymentFrequencyDaysOfWeekTypeOptions, acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions, acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null, acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions, @@ -1095,19 +1105,20 @@ public class LoanAccountData { final LoanInterestRecalculationData interestRecalculationData = LoanInterestRecalculationData.withCalendarData( acc.interestRecalculationData, calendarData, compoundingCalendarData); - return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName, acc.clientOfficeId, - acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, - acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal, - acc.principal, acc.approvedPrincipal, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency, - acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType, - acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId, - acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType, - acc.annualInterestRate, acc.interestType, acc.isFloatingInterestRate, acc.interestRateDifferential, - acc.interestCalculationPeriodType, acc.expectedFirstRepaymentOnDate, - acc.graceOnPrincipalPayment, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate, - acc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges, - acc.collateral, acc.guarantors, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions, - acc.repaymentFrequencyTypeOptions, acc.repaymentFrequencyNthDayTypeOptions, acc.repaymentFrequencyDaysOfWeekTypeOptions, + return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName, + acc.clientOfficeId, acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, + acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, + acc.loanOfficerName, acc.currency, acc.proposedPrincipal, acc.principal, acc.approvedPrincipal, acc.totalOverpaid, + acc.inArrearsTolerance, acc.termFrequency, acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, + acc.repaymentFrequencyType, acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, + acc.transactionProcessingStrategyId, acc.transactionProcessingStrategyName, acc.amortizationType, + acc.interestRatePerPeriod, acc.interestRateFrequencyType, acc.annualInterestRate, acc.interestType, + acc.isFloatingInterestRate, acc.interestRateDifferential, acc.interestCalculationPeriodType, + acc.allowPartialPeriodInterestCalcualtion, acc.expectedFirstRepaymentOnDate, acc.graceOnPrincipalPayment, + acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate, acc.timeline, acc.summary, + acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges, acc.collateral, acc.guarantors, + acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions, acc.repaymentFrequencyTypeOptions, + acc.repaymentFrequencyNthDayTypeOptions, acc.repaymentFrequencyDaysOfWeekTypeOptions, acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions, acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null, 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) { - - return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName, acc.clientOfficeId, - acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, - acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, acc.loanOfficerName, acc.currency, acc.proposedPrincipal, - acc.principal, acc.approvedPrincipal, acc.totalOverpaid, acc.inArrearsTolerance, acc.termFrequency, - acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, acc.repaymentFrequencyType, - acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, acc.transactionProcessingStrategyId, - acc.transactionProcessingStrategyName, acc.amortizationType, acc.interestRatePerPeriod, acc.interestRateFrequencyType, - acc.annualInterestRate, acc.interestType, acc.isFloatingInterestRate, acc.interestRateDifferential, - acc.interestCalculationPeriodType, acc.expectedFirstRepaymentOnDate, - acc.graceOnPrincipalPayment, acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate, - acc.timeline, acc.summary, acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges, - acc.collateral, acc.guarantors, acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions, - acc.repaymentFrequencyTypeOptions, acc.repaymentFrequencyNthDayTypeOptions, acc.repaymentFrequencyDaysOfWeekTypeOptions, + return new LoanAccountData(acc.id, acc.accountNo, acc.status, acc.externalId, acc.clientId, acc.clientAccountNo, acc.clientName, + acc.clientOfficeId, acc.group, acc.loanType, acc.loanProductId, acc.loanProductName, acc.loanProductDescription, + acc.isLoanProductLinkedToFloatingRate, acc.fundId, acc.fundName, acc.loanPurposeId, acc.loanPurposeName, acc.loanOfficerId, + acc.loanOfficerName, acc.currency, acc.proposedPrincipal, acc.principal, acc.approvedPrincipal, acc.totalOverpaid, + acc.inArrearsTolerance, acc.termFrequency, acc.termPeriodFrequencyType, acc.numberOfRepayments, acc.repaymentEvery, + acc.repaymentFrequencyType, acc.repaymentFrequencyNthDayType, acc.repaymentFrequencyDayOfWeekType, + acc.transactionProcessingStrategyId, acc.transactionProcessingStrategyName, acc.amortizationType, + acc.interestRatePerPeriod, acc.interestRateFrequencyType, acc.annualInterestRate, acc.interestType, + acc.isFloatingInterestRate, acc.interestRateDifferential, acc.interestCalculationPeriodType, + acc.allowPartialPeriodInterestCalcualtion, acc.expectedFirstRepaymentOnDate, acc.graceOnPrincipalPayment, + acc.graceOnInterestPayment, acc.graceOnInterestCharged, acc.interestChargedFromDate, acc.timeline, acc.summary, + acc.feeChargesAtDisbursementCharged, acc.repaymentSchedule, acc.transactions, acc.charges, acc.collateral, acc.guarantors, + acc.meeting, acc.productOptions, acc.termFrequencyTypeOptions, acc.repaymentFrequencyTypeOptions, + acc.repaymentFrequencyNthDayTypeOptions, acc.repaymentFrequencyDaysOfWeekTypeOptions, acc.transactionProcessingStrategyOptions, acc.interestRateFrequencyTypeOptions, acc.amortizationTypeOptions, acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null, 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 BigDecimal annualInterestRate, final EnumOptionData interestType, final boolean isFloatingInterestRate, final BigDecimal interestRateDifferential, final EnumOptionData interestCalculationPeriodType, - final LocalDate expectedFirstRepaymentOnDate, final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment, - final Integer graceOnInterestCharged, final LocalDate interestChargedFromDate, final LoanApplicationTimelineData timeline, - final LoanSummaryData summary, final BigDecimal feeChargesDueAtDisbursementCharged, final LoanScheduleData repaymentSchedule, + final Boolean allowPartialPeriodInterestCalcualtion, final LocalDate expectedFirstRepaymentOnDate, + final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment, final Integer graceOnInterestCharged, + final LocalDate interestChargedFromDate, final LoanApplicationTimelineData timeline, final LoanSummaryData summary, + final BigDecimal feeChargesDueAtDisbursementCharged, final LoanScheduleData repaymentSchedule, final Collection transactions, final Collection charges, final Collection collateral, final Collection guarantors, final CalendarData meeting, final Collection productOptions, final Collection termFrequencyTypeOptions, @@ -1256,6 +1268,7 @@ public class LoanAccountData { this.isFloatingInterestRate = isFloatingInterestRate; this.interestRateDifferential = interestRateDifferential; this.interestCalculationPeriodType = interestCalculationPeriodType; + this.allowPartialPeriodInterestCalcualtion = allowPartialPeriodInterestCalcualtion; this.expectedFirstRepaymentOnDate = expectedFirstRepaymentOnDate; this.graceOnPrincipalPayment = graceOnPrincipalPayment; this.graceOnInterestPayment = graceOnInterestPayment; @@ -1445,7 +1458,8 @@ public class LoanAccountData { } 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() { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java index 93c259f98..a8b905a36 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/AbstractLoanScheduleGenerator.java @@ -108,8 +108,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener this.paymentPeriodsInOneYearCalculator, mc); boolean isFirstRepayment = true; - LocalDate firstRepaymentdate = this.scheduledDateGenerator.generateNextRepaymentDate(scheduleParams.getPeriodStartDate(), - loanApplicationTerms, isFirstRepayment, holidayDetailDTO); + LocalDate firstRepaymentdate = this.scheduledDateGenerator.generateNextRepaymentDate( + loanApplicationTerms.getExpectedDisbursementDate(), loanApplicationTerms, isFirstRepayment, holidayDetailDTO); final LocalDate idealDisbursementDate = this.scheduledDateGenerator.idealDisbursementDateBasedOnFirstRepaymentDate( loanApplicationTerms.getLoanTermPeriodFrequencyType(), loanApplicationTerms.getRepaymentEvery(), firstRepaymentdate); @@ -1520,7 +1520,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener || loanApplicationTerms.getInterestChargedFromLocalDate().isAfter(periodStartDate)) { periodStartDateApplicableForInterest = loanApplicationTerms.getInterestChargedFromLocalDate(); } - } else { + } else if(periodStartDate.isEqual(loanApplicationTerms.getExpectedDisbursementDate())){ periodStartDateApplicableForInterest = idealDisbursementDate; } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java index 4c43e3981..e7038888d 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/domain/LoanApplicationTerms.java @@ -62,6 +62,7 @@ public final class LoanApplicationTerms { private final PeriodFrequencyType interestRatePeriodFrequencyType; private BigDecimal annualNominalInterestRate; private final InterestCalculationPeriodMethod interestCalculationPeriodMethod; + private final boolean allowPartialPeriodInterestCalcualtion; private Money principal; private final LocalDate expectedDisbursementDate; @@ -169,8 +170,8 @@ public final class LoanApplicationTerms { final PeriodFrequencyType repaymentPeriodFrequencyType, Integer nthDay, DayOfWeekType weekDayType, final AmortizationMethod amortizationMethod, final InterestMethod interestMethod, final BigDecimal interestRatePerPeriod, final PeriodFrequencyType interestRatePeriodFrequencyType, final BigDecimal annualNominalInterestRate, - final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final Money principalMoney, - final LocalDate expectedDisbursementDate, final LocalDate repaymentsStartingFromDate, + final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final boolean allowPartialPeriodInterestCalcualtion, + final Money principalMoney, final LocalDate expectedDisbursementDate, final LocalDate repaymentsStartingFromDate, final LocalDate calculatedRepaymentsStartingFromDate, final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment, final Integer graceOnInterestCharged, final LocalDate interestChargedFromDate, final Money inArrearsTolerance, final boolean multiDisburseLoan, final BigDecimal emiAmount, @@ -186,13 +187,14 @@ public final class LoanApplicationTerms { final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod = null; return new LoanApplicationTerms(currency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentPeriodFrequencyType, nthDay, weekDayType, amortizationMethod, interestMethod, interestRatePerPeriod, - interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod, principalMoney, - expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate, graceOnPrincipalPayment, - graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsTolerance, multiDisburseLoan, emiAmount, - disbursementDatas, maxOutstandingBalance, graceOnArrearsAgeing, daysInMonthType, daysInYearType, - isInterestRecalculationEnabled, rescheduleStrategyMethod, interestRecalculationCompoundingMethod, restCalendarInstance, - recalculationFrequencyType, compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment, - installmentAmountInMultiplesOf, preClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations); + interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod, + allowPartialPeriodInterestCalcualtion, principalMoney, expectedDisbursementDate, repaymentsStartingFromDate, + calculatedRepaymentsStartingFromDate, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, + interestChargedFromDate, inArrearsTolerance, multiDisburseLoan, emiAmount, disbursementDatas, maxOutstandingBalance, + graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, rescheduleStrategyMethod, + interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType, compoundingCalendarInstance, + compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf, + preClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations); } public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency, @@ -241,6 +243,7 @@ public final class LoanApplicationTerms { final PeriodFrequencyType interestRatePeriodFrequencyType = loanProductRelatedDetail.getInterestPeriodFrequencyType(); final InterestCalculationPeriodMethod interestCalculationPeriodMethod = loanProductRelatedDetail .getInterestCalculationPeriodMethod(); + final boolean allowPartialPeriodInterestCalcualtion = loanProductRelatedDetail.isAllowPartialPeriodInterestCalcualtion(); final Money principalMoney = loanProductRelatedDetail.getPrincipal(); // @@ -255,13 +258,13 @@ public final class LoanApplicationTerms { return new LoanApplicationTerms(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentPeriodFrequencyType, nthDay.getValue(), dayOfWeek, amortizationMethod, interestMethod, interestRatePerPeriod, interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod, - principalMoney, expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate, - graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsTolerance, - multiDisburseLoan, emiAmount, disbursementDatas, maxOutstandingBalance, loanProductRelatedDetail.getGraceOnDueDate(), - daysInMonthType, daysInYearType, isInterestRecalculationEnabled, rescheduleStrategyMethod, compoundingMethod, - restCalendarInstance, recalculationFrequencyType, compoundingCalendarInstance, compoundingFrequencyType, - principalThresholdForLastInstalment, installmentAmountInMultiplesOf, loanPreClosureInterestCalculationStrategy, - loanCalendar, approvedAmount, loanTermVariations); + allowPartialPeriodInterestCalcualtion, principalMoney, expectedDisbursementDate, repaymentsStartingFromDate, + calculatedRepaymentsStartingFromDate, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, + interestChargedFromDate, inArrearsTolerance, multiDisburseLoan, emiAmount, disbursementDatas, maxOutstandingBalance, + loanProductRelatedDetail.getGraceOnDueDate(), daysInMonthType, daysInYearType, isInterestRecalculationEnabled, + rescheduleStrategyMethod, compoundingMethod, restCalendarInstance, recalculationFrequencyType, compoundingCalendarInstance, + compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf, + loanPreClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations); } public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency, @@ -285,6 +288,7 @@ public final class LoanApplicationTerms { final PeriodFrequencyType interestRatePeriodFrequencyType = loanProductRelatedDetail.getInterestPeriodFrequencyType(); final InterestCalculationPeriodMethod interestCalculationPeriodMethod = loanProductRelatedDetail .getInterestCalculationPeriodMethod(); + final boolean allowPartialPeriodInterestCalcualtion = loanProductRelatedDetail.isAllowPartialPeriodInterestCalcualtion(); final Money principalMoney = loanProductRelatedDetail.getPrincipal(); // @@ -305,13 +309,14 @@ public final class LoanApplicationTerms { final Calendar loanCalendar = null; return new LoanApplicationTerms(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentPeriodFrequencyType, null, null, amortizationMethod, interestMethod, interestRatePerPeriod, - interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod, principalMoney, - expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate, graceOnPrincipalPayment, - graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsTolerance, multiDisburseLoan, emiAmount, - disbursementDatas, maxOutstandingBalance, loanProductRelatedDetail.getGraceOnDueDate(), daysInMonthType, daysInYearType, - isInterestRecalculationEnabled, rescheduleStrategyMethod, interestRecalculationCompoundingMethod, restCalendarInstance, - recalculationFrequencyType, compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment, - installmentAmountInMultiplesOf, loanPreClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations); + interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod, + allowPartialPeriodInterestCalcualtion, principalMoney, expectedDisbursementDate, repaymentsStartingFromDate, + calculatedRepaymentsStartingFromDate, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, + interestChargedFromDate, inArrearsTolerance, multiDisburseLoan, emiAmount, disbursementDatas, maxOutstandingBalance, + loanProductRelatedDetail.getGraceOnDueDate(), daysInMonthType, daysInYearType, isInterestRecalculationEnabled, + rescheduleStrategyMethod, interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType, + compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf, + loanPreClosureInterestCalculationStrategy, loanCalendar, approvedAmount, loanTermVariations); } public static LoanApplicationTerms assembleFrom(final LoanApplicationTerms applicationTerms, @@ -321,18 +326,19 @@ public final class LoanApplicationTerms { applicationTerms.repaymentPeriodFrequencyType, applicationTerms.nthDay, applicationTerms.weekDayType, applicationTerms.amortizationMethod, applicationTerms.interestMethod, applicationTerms.interestRatePerPeriod, applicationTerms.interestRatePeriodFrequencyType, applicationTerms.annualNominalInterestRate, - applicationTerms.interestCalculationPeriodMethod, applicationTerms.principal, applicationTerms.expectedDisbursementDate, - applicationTerms.repaymentsStartingFromDate, applicationTerms.calculatedRepaymentsStartingFromDate, - applicationTerms.principalGrace, applicationTerms.interestPaymentGrace, applicationTerms.interestChargingGrace, - applicationTerms.interestChargedFromDate, applicationTerms.inArrearsTolerance, applicationTerms.multiDisburseLoan, - applicationTerms.actualFixedEmiAmount, applicationTerms.disbursementDatas, applicationTerms.maxOutstandingBalance, - applicationTerms.graceOnArrearsAgeing, applicationTerms.daysInMonthType, applicationTerms.daysInYearType, - applicationTerms.interestRecalculationEnabled, applicationTerms.rescheduleStrategyMethod, - applicationTerms.interestRecalculationCompoundingMethod, applicationTerms.restCalendarInstance, - applicationTerms.recalculationFrequencyType, applicationTerms.compoundingCalendarInstance, - applicationTerms.compoundingFrequencyType, applicationTerms.principalThresholdForLastInstalment, - applicationTerms.installmentAmountInMultiplesOf, applicationTerms.preClosureInterestCalculationStrategy, - applicationTerms.loanCalendar, applicationTerms.approvedPrincipal.getAmount(), loanTermVariations); + applicationTerms.interestCalculationPeriodMethod, applicationTerms.allowPartialPeriodInterestCalcualtion, + applicationTerms.principal, applicationTerms.expectedDisbursementDate, applicationTerms.repaymentsStartingFromDate, + applicationTerms.calculatedRepaymentsStartingFromDate, applicationTerms.principalGrace, + applicationTerms.interestPaymentGrace, applicationTerms.interestChargingGrace, applicationTerms.interestChargedFromDate, + applicationTerms.inArrearsTolerance, applicationTerms.multiDisburseLoan, applicationTerms.actualFixedEmiAmount, + applicationTerms.disbursementDatas, applicationTerms.maxOutstandingBalance, applicationTerms.graceOnArrearsAgeing, + applicationTerms.daysInMonthType, applicationTerms.daysInYearType, applicationTerms.interestRecalculationEnabled, + applicationTerms.rescheduleStrategyMethod, applicationTerms.interestRecalculationCompoundingMethod, + applicationTerms.restCalendarInstance, applicationTerms.recalculationFrequencyType, + applicationTerms.compoundingCalendarInstance, applicationTerms.compoundingFrequencyType, + applicationTerms.principalThresholdForLastInstalment, applicationTerms.installmentAmountInMultiplesOf, + applicationTerms.preClosureInterestCalculationStrategy, applicationTerms.loanCalendar, + applicationTerms.approvedPrincipal.getAmount(), loanTermVariations); } 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 AmortizationMethod amortizationMethod, final InterestMethod interestMethod, final BigDecimal interestRatePerPeriod, final PeriodFrequencyType interestRatePeriodFrequencyType, final BigDecimal annualNominalInterestRate, - final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final Money principal, - final LocalDate expectedDisbursementDate, final LocalDate repaymentsStartingFromDate, + final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final boolean allowPartialPeriodInterestCalcualtion, + final Money principal, final LocalDate expectedDisbursementDate, final LocalDate repaymentsStartingFromDate, final LocalDate calculatedRepaymentsStartingFromDate, final Integer principalGrace, final Integer interestPaymentGrace, final Integer interestChargingGrace, final LocalDate interestChargedFromDate, final Money inArrearsTolerance, final boolean multiDisburseLoan, final BigDecimal emiAmount, final List disbursementDatas, @@ -369,6 +375,7 @@ public final class LoanApplicationTerms { this.interestRatePeriodFrequencyType = interestRatePeriodFrequencyType; this.annualNominalInterestRate = annualNominalInterestRate; this.interestCalculationPeriodMethod = interestCalculationPeriodMethod; + this.allowPartialPeriodInterestCalcualtion = allowPartialPeriodInterestCalcualtion; this.principal = principal; this.expectedDisbursementDate = expectedDisbursementDate; @@ -814,7 +821,7 @@ public final class LoanApplicationTerms { final BigDecimal loanTermPeriodsInYearBigDecimal = BigDecimal.valueOf(loanTermPeriodsInOneYear); BigDecimal periodicInterestRate = BigDecimal.ZERO; - BigDecimal loanTermFrequencyBigDecimal = calculatePeriodsBetweenDates(periodStartDate, periodEndDate); + BigDecimal loanTermFrequencyBigDecimal = calculateLoanTermFrequency(periodStartDate, periodEndDate); switch (this.interestCalculationPeriodMethod) { case INVALID: break; @@ -867,6 +874,14 @@ public final class LoanApplicationTerms { 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, 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, this.interestRatePeriodFrequencyType, this.annualNominalInterestRate, this.interestMethod, - this.interestCalculationPeriodMethod, this.repaymentEvery, this.repaymentPeriodFrequencyType, this.numberOfRepayments, - this.principalGrace, this.interestPaymentGrace, this.interestChargingGrace, this.amortizationMethod, - this.inArrearsTolerance.getAmount(), this.graceOnArrearsAgeing, this.daysInMonthType.getValue(), - this.daysInYearType.getValue(), this.interestRecalculationEnabled); + this.interestCalculationPeriodMethod, this.allowPartialPeriodInterestCalcualtion, this.repaymentEvery, + this.repaymentPeriodFrequencyType, this.numberOfRepayments, this.principalGrace, this.interestPaymentGrace, + this.interestChargingGrace, this.amortizationMethod, this.inArrearsTolerance.getAmount(), this.graceOnArrearsAgeing, + this.daysInMonthType.getValue(), this.daysInYearType.getValue(), this.interestRecalculationEnabled); } public Integer getLoanTermFrequency() { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java index adf569835..abf0183fa 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/service/LoanScheduleAssembler.java @@ -199,6 +199,11 @@ public class LoanScheduleAssembler { element); final InterestCalculationPeriodMethod interestCalculationPeriodMethod = InterestCalculationPeriodMethod .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 PeriodFrequencyType interestRatePeriodFrequencyType = loanProduct.getInterestPeriodFrequencyType(); @@ -366,12 +371,13 @@ public class LoanScheduleAssembler { return LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentPeriodFrequencyType, nthDay, weekDayType, amortizationMethod, interestMethod, interestRatePerPeriod, interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod, - principalMoney, expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate, - graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsToleranceMoney, - loanProduct.isMultiDisburseLoan(), emiAmount, disbursementDatas, maxOutstandingBalance, graceOnArrearsAgeing, - daysInMonthType, daysInYearType, isInterestRecalculationEnabled, recalculationFrequencyType, restCalendarInstance, - compoundingCalendarInstance, compoundingFrequencyType, principalThresholdForLastInstalment, installmentAmountInMultiplesOf, - loanProduct.preCloseInterestCalculationStrategy(), calendar, BigDecimal.ZERO, loanTermVariations); + allowPartialPeriodInterestCalcualtion, principalMoney, expectedDisbursementDate, repaymentsStartingFromDate, + calculatedRepaymentsStartingFromDate, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, + interestChargedFromDate, inArrearsToleranceMoney, loanProduct.isMultiDisburseLoan(), emiAmount, disbursementDatas, + maxOutstandingBalance, graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, + recalculationFrequencyType, restCalendarInstance, compoundingCalendarInstance, compoundingFrequencyType, + principalThresholdForLastInstalment, installmentAmountInMultiplesOf, loanProduct.preCloseInterestCalculationStrategy(), + calendar, BigDecimal.ZERO, loanTermVariations); } private CalendarInstance createInterestRecalculationCalendarInstance(final LocalDate calendarStartDate, @@ -630,7 +636,7 @@ public class LoanScheduleAssembler { if (termVariations.fetchTermApplicaDate().isAfter(lastDate)) { baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode( "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( "variable.schedule.insert.not.allowed.before.disbursement.date", "Loan schedule insert request invalid"); } @@ -664,7 +670,7 @@ public class LoanScheduleAssembler { } else { dueDates.add(termVariations.fetchDateValue()); } - if(termVariations.fetchDateValue().isBefore(loan.getExpectedDisbursedOnLocalDate())){ + if (termVariations.fetchDateValue().isBefore(loan.getExpectedDisbursedOnLocalDate())) { baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode( "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(); previousDate = duedate; if (gap < minGap || (maxGap != null && gap > maxGap)) { - baseDataValidator.reset().value(duedate) - .failWithCodeNoParameterAddedToErrorCode("variable.schedule.date.must.be.in.min.max.range", "Loan schedule date invalid"); + baseDataValidator + .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)) { baseDataValidator .reset() diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/serialization/CalculateLoanScheduleQueryFromApiJsonHelper.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/serialization/CalculateLoanScheduleQueryFromApiJsonHelper.java index 657c7de7c..88b7ce306 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/serialization/CalculateLoanScheduleQueryFromApiJsonHelper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/serialization/CalculateLoanScheduleQueryFromApiJsonHelper.java @@ -37,13 +37,14 @@ public final class CalculateLoanScheduleQueryFromApiJsonHelper { "accountNo", "externalId", "fundId", "loanOfficerId", "loanPurposeId", "transactionProcessingStrategyId", "principal", "inArrearsTolerance", "interestRatePerPeriod", "repaymentEvery", "numberOfRepayments", "loanTermFrequency", "loanTermFrequencyType", "repaymentFrequencyType", "amortizationType", "interestType", "interestCalculationPeriodType", - "interestRateFrequencyType", "expectedDisbursementDate", "repaymentsStartingFromDate", "graceOnPrincipalPayment", - "graceOnInterestPayment", "graceOnInterestCharged", "interestChargedFromDate", "submittedOnDate", "submittedOnNote", "locale", - "dateFormat", "charges", "collateral", "syncDisbursementWithMeeting", "linkAccountId", - LoanApiConstants.disbursementDataParameterName, LoanApiConstants.emiAmountParameterName, - LoanApiConstants.maxOutstandingBalanceParameterName, LoanProductConstants.graceOnArrearsAgeingParameterName, - LoanProductConstants.recalculationRestFrequencyDateParamName, "createStandingInstructionAtDisbursement", - LoanApiConstants.isFloatingInterestRateParameterName, LoanApiConstants.interestRateDifferentialParameterName)); + LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName, "interestRateFrequencyType", "expectedDisbursementDate", + "repaymentsStartingFromDate", "graceOnPrincipalPayment", "graceOnInterestPayment", "graceOnInterestCharged", + "interestChargedFromDate", "submittedOnDate", "submittedOnNote", "locale", "dateFormat", "charges", "collateral", + "syncDisbursementWithMeeting", "linkAccountId", LoanApiConstants.disbursementDataParameterName, + LoanApiConstants.emiAmountParameterName, LoanApiConstants.maxOutstandingBalanceParameterName, + LoanProductConstants.graceOnArrearsAgeingParameterName, LoanProductConstants.recalculationRestFrequencyDateParamName, + "createStandingInstructionAtDisbursement", LoanApiConstants.isFloatingInterestRateParameterName, + LoanApiConstants.interestRateDifferentialParameterName)); private final FromJsonHelper fromApiJsonHelper; @@ -95,17 +96,9 @@ public final class CalculateLoanScheduleQueryFromApiJsonHelper { 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, repaymentsStartingFromDate); - validateRepaymentsStartingFromDateAndInterestChargedFromDate(dataValidationErrors, expectedDisbursementDate, - repaymentsStartingFromDate, interestChargedFromDate); if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors); } @@ -135,27 +128,6 @@ public final class CalculateLoanScheduleQueryFromApiJsonHelper { } } - private void validateRepaymentsStartingFromDateAndInterestChargedFromDate(final List 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 dataValidationErrors, final LocalDate expectedDisbursementDate, final LocalDate repaymentsStartingFromDate) { if (expectedDisbursementDate != null) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java index 96b9f7b49..4cd698001 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/serialization/LoanApplicationCommandFromApiJsonHelper.java @@ -29,6 +29,7 @@ import org.mifosplatform.portfolio.loanaccount.domain.Loan; import org.mifosplatform.portfolio.loanaccount.domain.LoanCharge; import org.mifosplatform.portfolio.loanaccount.domain.LoanInterestRecalculationDetails; import org.mifosplatform.portfolio.loanproduct.LoanProductConstants; +import org.mifosplatform.portfolio.loanproduct.domain.InterestCalculationPeriodMethod; import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod; import org.mifosplatform.portfolio.loanproduct.domain.LoanProduct; import org.mifosplatform.portfolio.savings.domain.SavingsAccount; @@ -49,19 +50,15 @@ public final class LoanApplicationCommandFromApiJsonHelper { final Set supportedParameters = new HashSet<>(Arrays.asList("dateFormat", "locale", "id", "clientId", "groupId", "loanType", "productId", "principal", "loanTermFrequency", "loanTermFrequencyType", "numberOfRepayments", "repaymentEvery", "repaymentFrequencyType", "repaymentFrequencyNthDayType", "repaymentFrequencyDayOfWeekType", "interestRatePerPeriod", - "amortizationType", "interestType", - LoanApiConstants.isFloatingInterestRate, - LoanApiConstants.interestRateDifferential, - "interestCalculationPeriodType", - "interestRateFrequencyType", - "expectedDisbursementDate", - "repaymentsStartingFromDate", + "amortizationType", "interestType", LoanApiConstants.isFloatingInterestRate, LoanApiConstants.interestRateDifferential, + "interestCalculationPeriodType", LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName, + "interestRateFrequencyType", "expectedDisbursementDate", "repaymentsStartingFromDate", "graceOnPrincipalPayment", "graceOnInterestPayment", "graceOnInterestCharged", - "interestChargedFromDate", // + "interestChargedFromDate", "submittedOnDate", - "submittedOnNote", // + "submittedOnNote", "accountNo", "externalId", "fundId", @@ -451,7 +448,7 @@ public final class LoanApplicationCommandFromApiJsonHelper { .ignoreIfNull().positiveAmount(); } validateLoanMultiDisbursementdate(element, baseDataValidator, expectedDisbursementDate, principal); - + validatePartialPeriodSupport(interestCalculationPeriodType, baseDataValidator, element, loanProduct); 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"; if (this.fromApiJsonHelper.parameterExists(interestCalculationPeriodTypeParameterName, element)) { atLeastOneParameterPassedForUpdate = true; - final Integer interestCalculationPeriodType = this.fromApiJsonHelper.extractIntegerWithLocaleNamed( + interestCalculationPeriodType = this.fromApiJsonHelper.extractIntegerWithLocaleNamed( interestCalculationPeriodTypeParameterName, element); baseDataValidator.reset().parameter(interestCalculationPeriodTypeParameterName).value(interestCalculationPeriodType).notNull() .inMinMaxRange(0, 1); @@ -877,6 +875,7 @@ public final class LoanApplicationCommandFromApiJsonHelper { .ignoreIfNull().positiveAmount(); } validateLoanMultiDisbursementdate(element, baseDataValidator, expectedDisbursementDate, principal); + validatePartialPeriodSupport(interestCalculationPeriodType, baseDataValidator, element, loanProduct); if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", dataValidationErrors); } @@ -1152,4 +1151,52 @@ public final class LoanApplicationCommandFromApiJsonHelper { .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"); + } + } + + } + } + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java index 02f8df98e..5b9673278 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java @@ -328,8 +328,8 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { final ClientData clientAccount = this.clientReadPlatformService.retrieveOne(clientId); final LocalDate expectedDisbursementDate = DateUtils.getLocalDateOfTenant(); - LoanAccountData loanTemplateDetails = LoanAccountData.clientDefaults(clientAccount.id(), clientAccount.accountNo(), clientAccount.displayName(), - clientAccount.officeId(), expectedDisbursementDate); + LoanAccountData loanTemplateDetails = LoanAccountData.clientDefaults(clientAccount.id(), clientAccount.accountNo(), + clientAccount.displayName(), clientAccount.officeId(), expectedDisbursementDate); if (productId != null) { 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.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.allow_partial_period_interest_calcualtion as allowPartialPeriodInterestCalcualtion," + " l.loan_status_id as lifeCycleStatusId, l.loan_transaction_strategy_id as transactionStrategyId, " + " 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, " @@ -796,6 +797,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { final EnumOptionData interestType = LoanEnumerations.interestType(interestTypeInt); final EnumOptionData interestCalculationPeriodType = LoanEnumerations .interestCalculationPeriodType(interestCalculationPeriodTypeInt); + final Boolean allowPartialPeriodInterestCalcualtion = rs.getBoolean("allowPartialPeriodInterestCalcualtion"); final Integer lifeCycleStatusId = JdbcSupport.getInteger(rs, "lifeCycleStatusId"); final LoanStatusEnumData status = LoanEnumerations.status(lifeCycleStatusId); @@ -913,18 +915,20 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { compoundingCalendarData, compoundingFrequencyType, compoundingInterval, compoundingFrequencyDate); } - return LoanAccountData.basicLoanDetails(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, groupData, - loanType, loanProductId, loanProductName, loanProductDescription, isLoanProductLinkedToFloatingRate, fundId, fundName, loanPurposeId, loanPurposeName, - loanOfficerId, loanOfficerName, currencyData, proposedPrincipal, principal, approvedPrincipal, totalOverpaid, - inArrearsTolerance, termFrequency, termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, - repaymentFrequencyNthDayType, repaymentFrequencyDayOfWeekType, transactionStrategyId, transactionStrategyName, - amortizationType, interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType, - isFloatingInterestRate, interestRateDifferential, interestCalculationPeriodType, expectedFirstRepaymentOnDate, - graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, timeline, - loanSummary, feeChargesDueAtDisbursementCharged, syncDisbursementWithMeeting, loanCounter, loanProductCounter, - multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount, outstandingLoanBalance, inArrears, graceOnArrearsAgeing, - isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, - createStandingInstructionAtDisbursement, isvariableInstallmentsAllowed, minimumGap, maximumGap); + return LoanAccountData.basicLoanDetails(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, + clientOfficeId, groupData, loanType, loanProductId, loanProductName, loanProductDescription, + isLoanProductLinkedToFloatingRate, fundId, fundName, loanPurposeId, loanPurposeName, loanOfficerId, loanOfficerName, + currencyData, proposedPrincipal, principal, approvedPrincipal, totalOverpaid, inArrearsTolerance, termFrequency, + termPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentFrequencyType, repaymentFrequencyNthDayType, + repaymentFrequencyDayOfWeekType, transactionStrategyId, transactionStrategyName, amortizationType, + interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType, isFloatingInterestRate, + interestRateDifferential, interestCalculationPeriodType, allowPartialPeriodInterestCalcualtion, + expectedFirstRepaymentOnDate, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, + interestChargedFromDate, timeline, loanSummary, feeChargesDueAtDisbursementCharged, syncDisbursementWithMeeting, + loanCounter, loanProductCounter, multiDisburseLoan, canDefineInstallmentAmount, fixedEmiAmount, outstandingLoanBalance, + 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 LocalDate expectedDisbursementDate = DateUtils.getLocalDateOfTenant(); - return LoanAccountData.clientDefaults(clientAccount.id(), clientAccount.accountNo(), clientAccount.displayName(), clientAccount.officeId(), - expectedDisbursementDate); + return LoanAccountData.clientDefaults(clientAccount.id(), clientAccount.accountNo(), clientAccount.displayName(), + clientAccount.officeId(), expectedDisbursementDate); } @Override diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/LoanProductConstants.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/LoanProductConstants.java index 0835bc738..15488ce37 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/LoanProductConstants.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/LoanProductConstants.java @@ -109,5 +109,7 @@ public interface LoanProductConstants { public static final String maximumGapBetweenInstallments = "maximumGap" ; + public static final String allowPartialPeriodInterestCalcualtionParamName = "allowPartialPeriodInterestCalcualtion"; + } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/api/LoanProductsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/api/LoanProductsApiResource.java index 73c8e8007..9ba7bf293 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/api/LoanProductsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/api/LoanProductsApiResource.java @@ -48,6 +48,7 @@ import org.mifosplatform.portfolio.floatingrates.data.FloatingRateData; import org.mifosplatform.portfolio.floatingrates.service.FloatingRatesReadPlatformService; import org.mifosplatform.portfolio.fund.data.FundData; 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.TransactionProcessingStrategyData; import org.mifosplatform.portfolio.loanproduct.productmix.data.ProductMixData; @@ -70,14 +71,14 @@ public class LoanProductsApiResource { "minNumberOfRepayments", "maxNumberOfRepayments", "repaymentEvery", "repaymentFrequencyType", "graceOnPrincipalPayment", "graceOnInterestPayment", "graceOnInterestCharged", "interestRatePerPeriod", "minInterestRatePerPeriod", "maxInterestRatePerPeriod", "interestRateFrequencyType", "annualInterestRate", "amortizationType", "interestType", - "interestCalculationPeriodType", "inArrearsTolerance", "transactionProcessingStrategyId", "transactionProcessingStrategyName", - "charges", "accountingRule", "externalId", "accountingMappings", "paymentChannelToFundSourceMappings", "fundOptions", - "paymentTypeOptions", "currencyOptions", "repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions", - "amortizationTypeOptions", "interestTypeOptions", "interestCalculationPeriodTypeOptions", - "transactionProcessingStrategyOptions", "chargeOptions", "accountingOptions", "accountingRuleOptions", - "accountingMappingOptions", "floatingRateOptions", "isLinkedToFloatingInterestRates", "floatingRatesId", "interestRateDifferential", - "minDifferentialLendingRate", "defaultDifferentialLendingRate", "maxDifferentialLendingRate", - "isFloatingInterestRateCalculationAllowed")); + "interestCalculationPeriodType", LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName, "inArrearsTolerance", + "transactionProcessingStrategyId", "transactionProcessingStrategyName", "charges", "accountingRule", "externalId", + "accountingMappings", "paymentChannelToFundSourceMappings", "fundOptions", "paymentTypeOptions", "currencyOptions", + "repaymentFrequencyTypeOptions", "interestRateFrequencyTypeOptions", "amortizationTypeOptions", "interestTypeOptions", + "interestCalculationPeriodTypeOptions", "transactionProcessingStrategyOptions", "chargeOptions", "accountingOptions", + "accountingRuleOptions", "accountingMappingOptions", "floatingRateOptions", "isLinkedToFloatingInterestRates", + "floatingRatesId", "interestRateDifferential", "minDifferentialLendingRate", "defaultDifferentialLendingRate", + "maxDifferentialLendingRate", "isFloatingInterestRateCalculationAllowed")); private final Set PRODUCT_MIX_DATA_PARAMETERS = new HashSet<>(Arrays.asList("productId", "productName", "restrictedProducts", "allowedProducts", "productOptions")); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/data/LoanProductData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/data/LoanProductData.java index d19103dec..049d2fb94 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/data/LoanProductData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/data/LoanProductData.java @@ -87,6 +87,7 @@ public class LoanProductData { private final EnumOptionData amortizationType; private final EnumOptionData interestType; private final EnumOptionData interestCalculationPeriodType; + private final Boolean allowPartialPeriodInterestCalcualtion; private final BigDecimal inArrearsTolerance; private final Long transactionProcessingStrategyId; private final String transactionProcessingStrategyName; @@ -198,6 +199,7 @@ public class LoanProductData { final EnumOptionData amortizationType = null; final EnumOptionData interestType = null; final EnumOptionData interestCalculationPeriodType = null; + final Boolean allowPartialPeriodInterestCalcualtion = null; final Long fundId = null; final String fundName = null; final Long transactionProcessingStrategyId = null; @@ -238,16 +240,17 @@ public class LoanProductData { return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, - amortizationType, interestType, interestCalculationPeriodType, fundId, fundName, transactionProcessingStrategyId, - transactionProcessingStrategyName, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, charges, - accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, externalId, principalVariations, - interestRateVariations, numberOfRepaymentVariations, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance, - graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, - interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, productGuaranteeData, - principalThresholdForLastInstallment, accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount, - installmentAmountInMultiplesOf, loanProductConfigurableAttributes, isLinkedToFloatingInterestRates, floatingRateId, - floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate, - maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap); + amortizationType, interestType, interestCalculationPeriodType, allowPartialPeriodInterestCalcualtion, fundId, fundName, + transactionProcessingStrategyId, transactionProcessingStrategyName, graceOnPrincipalPayment, graceOnInterestPayment, + graceOnInterestCharged, charges, accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, + externalId, principalVariations, interestRateVariations, numberOfRepaymentVariations, multiDisburseLoan, maxTrancheCount, + outstandingLoanBalance, graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, + isInterestRecalculationEnabled, interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, + holdGuaranteeFunds, productGuaranteeData, principalThresholdForLastInstallment, + accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount, installmentAmountInMultiplesOf, + loanProductConfigurableAttributes, isLinkedToFloatingInterestRates, floatingRateId, floatingRateName, + interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate, maxDifferentialLendingRate, + isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap); } @@ -282,6 +285,7 @@ public class LoanProductData { final EnumOptionData amortizationType = null; final EnumOptionData interestType = null; final EnumOptionData interestCalculationPeriodType = null; + final Boolean allowPartialPeriodInterestCalcualtion = null; final Long fundId = null; final String fundName = null; final Long transactionProcessingStrategyId = null; @@ -324,16 +328,17 @@ public class LoanProductData { return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, - amortizationType, interestType, interestCalculationPeriodType, fundId, fundName, transactionProcessingStrategyId, - transactionProcessingStrategyName, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, charges, - accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, externalId, principalVariations, - interestRateVariations, numberOfRepaymentVariations, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance, - graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, - interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, productGuaranteeData, - principalThresholdForLastInstallment, accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount, - installmentAmountInMultiplesOf, loanProductConfigurableAttributes, isLinkedToFloatingInterestRates, floatingRateId, - floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate, - maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap); + amortizationType, interestType, interestCalculationPeriodType, allowPartialPeriodInterestCalcualtion, fundId, fundName, + transactionProcessingStrategyId, transactionProcessingStrategyName, graceOnPrincipalPayment, graceOnInterestPayment, + graceOnInterestCharged, charges, accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, + externalId, principalVariations, interestRateVariations, numberOfRepaymentVariations, multiDisburseLoan, maxTrancheCount, + outstandingLoanBalance, graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, + isInterestRecalculationEnabled, interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, + holdGuaranteeFunds, productGuaranteeData, principalThresholdForLastInstallment, + accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount, installmentAmountInMultiplesOf, + loanProductConfigurableAttributes, isLinkedToFloatingInterestRates, floatingRateId, floatingRateName, + 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 interestCalculationPeriodType = LoanEnumerations .interestCalculationPeriodType(InterestCalculationPeriodMethod.SAME_AS_REPAYMENT_PERIOD); + final Boolean allowPartialPeriodInterestCalcualtion = null; final Long fundId = null; final String fundName = null; final Long transactionProcessingStrategyId = null; @@ -417,17 +423,17 @@ public class LoanProductData { return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, interestRateFrequencyType, - amortizationType, interestType, interestCalculationPeriodType, fundId, fundName, transactionProcessingStrategyId, - transactionProcessingStrategyName, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, charges, - accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, externalId, - principalVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle, numberOfRepaymentVariationsForBorrowerCycle, - multiDisburseLoan, maxTrancheCount, outstandingLoanBalance, graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, - daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, - holdGuaranteeFunds, productGuaranteeData, principalThresholdForLastInstallment, - accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount, installmentAmountInMultiplesOf, - loanProductConfigurableAttributes, isLinkedToFloatingInterestRates, floatingRateId, floatingRateName, - interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate, maxDifferentialLendingRate, - isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap); + amortizationType, interestType, interestCalculationPeriodType, allowPartialPeriodInterestCalcualtion, fundId, fundName, + transactionProcessingStrategyId, transactionProcessingStrategyName, graceOnPrincipalPayment, graceOnInterestPayment, + graceOnInterestCharged, charges, accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, + externalId, principalVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle, + numberOfRepaymentVariationsForBorrowerCycle, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance, + graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, + interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, productGuaranteeData, + principalThresholdForLastInstallment, accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount, + installmentAmountInMultiplesOf, loanProductConfigurableAttributes, isLinkedToFloatingInterestRates, floatingRateId, + floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate, + maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap); } @@ -448,8 +454,8 @@ public class LoanProductData { final Integer repaymentEvery, final BigDecimal interestRatePerPeriod, final BigDecimal minInterestRatePerPeriod, final BigDecimal maxInterestRatePerPeriod, final BigDecimal annualInterestRate, final EnumOptionData repaymentFrequencyType, final EnumOptionData interestRateFrequencyType, final EnumOptionData amortizationType, final EnumOptionData interestType, - final EnumOptionData interestCalculationPeriodType, final Long fundId, final String fundName, - final Long transactionProcessingStrategyId, final String transactionProcessingStrategyName, + final EnumOptionData interestCalculationPeriodType, final Boolean allowPartialPeriodInterestCalcualtion, final Long fundId, + final String fundName, final Long transactionProcessingStrategyId, final String transactionProcessingStrategyName, final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment, final Integer graceOnInterestCharged, final Collection charges, final EnumOptionData accountingType, final boolean includeInBorrowerCycle, 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.interestType = interestType; this.interestCalculationPeriodType = interestCalculationPeriodType; + this.allowPartialPeriodInterestCalcualtion = allowPartialPeriodInterestCalcualtion; this.fundId = fundId; this.fundName = fundName; this.transactionProcessingStrategyId = transactionProcessingStrategyId; @@ -613,6 +620,7 @@ public class LoanProductData { this.amortizationType = productData.amortizationType; this.interestType = productData.interestType; this.interestCalculationPeriodType = productData.interestCalculationPeriodType; + this.allowPartialPeriodInterestCalcualtion = productData.allowPartialPeriodInterestCalcualtion; this.startDate = productData.startDate; this.closeDate = productData.closeDate; this.status = productData.status; @@ -1002,4 +1010,9 @@ public class LoanProductData { public Integer getMaximumGapBetweenInstallments() { return this.maximumGap; } + + + public Boolean getAllowPartialPeriodInterestCalcualtion() { + return this.allowPartialPeriodInterestCalcualtion; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProduct.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProduct.java index 18c4a1611..539958ce5 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProduct.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProduct.java @@ -188,6 +188,8 @@ public class LoanProduct extends AbstractPersistable { final InterestMethod interestMethod = InterestMethod.fromInt(command.integerValueOfParameterNamed("interestType")); final InterestCalculationPeriodMethod interestCalculationPeriodMethod = InterestCalculationPeriodMethod.fromInt(command .integerValueOfParameterNamed("interestCalculationPeriodType")); + final boolean allowPartialPeriodInterestCalcualtion = command + .booleanPrimitiveValueOfParameterNamed(LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName); final AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(command.integerValueOfParameterNamed("amortizationType")); final PeriodFrequencyType repaymentFrequencyType = PeriodFrequencyType.fromInt(command .integerValueOfParameterNamed("repaymentFrequencyType")); @@ -311,16 +313,16 @@ public class LoanProduct extends AbstractPersistable { return new LoanProduct(fund, loanTransactionProcessingStrategy, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, interestFrequencyType, - annualInterestRate, interestMethod, interestCalculationPeriodMethod, repaymentEvery, repaymentFrequencyType, - numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, graceOnPrincipalPayment, graceOnInterestPayment, - graceOnInterestCharged, amortizationMethod, inArrearsTolerance, productCharges, accountingRuleType, includeInBorrowerCycle, - startDate, closeDate, externalId, useBorrowerCycle, loanProductBorrowerCycleVariations, multiDisburseLoan, maxTrancheCount, - outstandingLoanBalance, graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, - isInterestRecalculationEnabled, interestRecalculationSettings, minimumDaysBetweenDisbursalAndFirstRepayment, - holdGuarantorFunds, loanProductGuaranteeDetails, principalThresholdForLastInstallment, - accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineEmiAmount, installmentAmountInMultiplesOf, - loanConfigurableAttributes, isLinkedToFloatingInterestRates, floatingRate, interestRateDifferential, - minDifferentialLendingRate, maxDifferentialLendingRate, defaultDifferentialLendingRate, + annualInterestRate, interestMethod, interestCalculationPeriodMethod, allowPartialPeriodInterestCalcualtion, repaymentEvery, + repaymentFrequencyType, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, graceOnPrincipalPayment, + graceOnInterestPayment, graceOnInterestCharged, amortizationMethod, inArrearsTolerance, productCharges, accountingRuleType, + includeInBorrowerCycle, startDate, closeDate, externalId, useBorrowerCycle, loanProductBorrowerCycleVariations, + multiDisburseLoan, maxTrancheCount, outstandingLoanBalance, graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, + daysInYearType, isInterestRecalculationEnabled, interestRecalculationSettings, + minimumDaysBetweenDisbursalAndFirstRepayment, holdGuarantorFunds, loanProductGuaranteeDetails, + principalThresholdForLastInstallment, accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineEmiAmount, + installmentAmountInMultiplesOf, loanConfigurableAttributes, isLinkedToFloatingInterestRates, floatingRate, + interestRateDifferential, minDifferentialLendingRate, maxDifferentialLendingRate, defaultDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGapBetweenInstallments, maximumGapBetweenInstallments); @@ -534,8 +536,8 @@ public class LoanProduct extends AbstractPersistable { final BigDecimal defaultNominalInterestRatePerPeriod, final BigDecimal defaultMinNominalInterestRatePerPeriod, final BigDecimal defaultMaxNominalInterestRatePerPeriod, final PeriodFrequencyType interestPeriodFrequencyType, final BigDecimal defaultAnnualNominalInterestRate, final InterestMethod interestMethod, - final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final Integer repayEvery, - final PeriodFrequencyType repaymentFrequencyType, final Integer defaultNumberOfInstallments, + final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final boolean considerPartialPeriodInterest, + final Integer repayEvery, final PeriodFrequencyType repaymentFrequencyType, final Integer defaultNumberOfInstallments, final Integer defaultMinNumberOfInstallments, final Integer defaultMaxNumberOfInstallments, final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment, final Integer graceOnInterestCharged, final AmortizationMethod amortizationMethod, final BigDecimal inArrearsTolerance, final List charges, @@ -582,10 +584,10 @@ public class LoanProduct extends AbstractPersistable { } this.loanProductRelatedDetail = new LoanProductRelatedDetail(currency, defaultPrincipal, defaultNominalInterestRatePerPeriod, - interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery, - repaymentFrequencyType, defaultNumberOfInstallments, graceOnPrincipalPayment, graceOnInterestPayment, - graceOnInterestCharged, amortizationMethod, inArrearsTolerance, graceOnArrearsAgeing, daysInMonthType.getValue(), - daysInYearType.getValue(), isInterestRecalculationEnabled); + interestPeriodFrequencyType, defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, + considerPartialPeriodInterest, repayEvery, repaymentFrequencyType, defaultNumberOfInstallments, graceOnPrincipalPayment, + graceOnInterestPayment, graceOnInterestCharged, amortizationMethod, inArrearsTolerance, graceOnArrearsAgeing, + daysInMonthType.getValue(), daysInYearType.getValue(), isInterestRecalculationEnabled); this.loanProductRelatedDetail.validateRepaymentPeriodWithGraceSettings(); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProductRelatedDetail.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProductRelatedDetail.java index ee3914f81..7ec156e2d 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProductRelatedDetail.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProductRelatedDetail.java @@ -67,6 +67,9 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche @Column(name = "interest_calculated_in_period_enum", nullable = false) private InterestCalculationPeriodMethod interestCalculationPeriodMethod; + @Column(name = "allow_partial_period_interest_calcualtion", nullable = false) + private boolean allowPartialPeriodInterestCalcualtion; + @Column(name = "repay_every", nullable = false) private Integer repayEvery; @@ -112,16 +115,17 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche public static LoanProductRelatedDetail createFrom(final MonetaryCurrency currency, final BigDecimal principal, final BigDecimal nominalInterestRatePerPeriod, final PeriodFrequencyType interestRatePeriodFrequencyType, final BigDecimal nominalAnnualInterestRate, final InterestMethod interestMethod, - final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final Integer repaymentEvery, - final PeriodFrequencyType repaymentPeriodFrequencyType, final Integer numberOfRepayments, + final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final boolean allowPartialPeriodInterestCalcualtion, + final Integer repaymentEvery, final PeriodFrequencyType repaymentPeriodFrequencyType, final Integer numberOfRepayments, final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment, final Integer graceOnInterestCharged, final AmortizationMethod amortizationMethod, final BigDecimal inArrearsTolerance, final Integer graceOnArrearsAgeing, final Integer daysInMonthType, final Integer daysInYearType, final boolean isInterestRecalculationEnabled) { return new LoanProductRelatedDetail(currency, principal, nominalInterestRatePerPeriod, interestRatePeriodFrequencyType, - nominalAnnualInterestRate, interestMethod, interestCalculationPeriodMethod, repaymentEvery, repaymentPeriodFrequencyType, - numberOfRepayments, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, amortizationMethod, - inArrearsTolerance, graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled); + nominalAnnualInterestRate, interestMethod, interestCalculationPeriodMethod, allowPartialPeriodInterestCalcualtion, + repaymentEvery, repaymentPeriodFrequencyType, numberOfRepayments, graceOnPrincipalPayment, graceOnInterestPayment, + graceOnInterestCharged, amortizationMethod, inArrearsTolerance, graceOnArrearsAgeing, daysInMonthType, daysInYearType, + isInterestRecalculationEnabled); } protected LoanProductRelatedDetail() { @@ -131,8 +135,8 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche public LoanProductRelatedDetail(final MonetaryCurrency currency, final BigDecimal defaultPrincipal, final BigDecimal defaultNominalInterestRatePerPeriod, final PeriodFrequencyType interestPeriodFrequencyType, final BigDecimal defaultAnnualNominalInterestRate, final InterestMethod interestMethod, - final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final Integer repayEvery, - final PeriodFrequencyType repaymentFrequencyType, final Integer defaultNumberOfRepayments, + final InterestCalculationPeriodMethod interestCalculationPeriodMethod, final boolean allowPartialPeriodInterestCalcualtion, + final Integer repayEvery, final PeriodFrequencyType repaymentFrequencyType, final Integer defaultNumberOfRepayments, final Integer graceOnPrincipalPayment, final Integer graceOnInterestPayment, final Integer graceOnInterestCharged, final AmortizationMethod amortizationMethod, final BigDecimal inArrearsTolerance, final Integer graceOnArrearsAgeing, final Integer daysInMonthType, final Integer daysInYearType, final boolean isInterestRecalculationEnabled) { @@ -143,6 +147,7 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche this.annualNominalInterestRate = defaultAnnualNominalInterestRate; this.interestMethod = interestMethod; this.interestCalculationPeriodMethod = interestCalculationPeriodMethod; + this.allowPartialPeriodInterestCalcualtion = allowPartialPeriodInterestCalcualtion; this.repayEvery = repayEvery; this.repaymentPeriodFrequencyType = repaymentFrequencyType; this.numberOfRepayments = defaultNumberOfRepayments; @@ -205,20 +210,19 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche @Override public BigDecimal getNominalInterestRatePerPeriod() { - return this.nominalInterestRatePerPeriod == null? null - : BigDecimal.valueOf(Double.valueOf(this.nominalInterestRatePerPeriod.stripTrailingZeros().toString())); + return this.nominalInterestRatePerPeriod == null ? null : BigDecimal.valueOf(Double.valueOf(this.nominalInterestRatePerPeriod + .stripTrailingZeros().toString())); } @Override public PeriodFrequencyType getInterestPeriodFrequencyType() { - return this.interestPeriodFrequencyType == null? PeriodFrequencyType.INVALID - : this.interestPeriodFrequencyType; + return this.interestPeriodFrequencyType == null ? PeriodFrequencyType.INVALID : this.interestPeriodFrequencyType; } @Override public BigDecimal getAnnualNominalInterestRate() { - return this.annualNominalInterestRate == null? null - :BigDecimal.valueOf(Double.valueOf(this.annualNominalInterestRate.stripTrailingZeros().toString())); + return this.annualNominalInterestRate == null ? null : BigDecimal.valueOf(Double.valueOf(this.annualNominalInterestRate + .stripTrailingZeros().toString())); } @Override @@ -368,8 +372,8 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche } final String interestRateFrequencyTypeParamName = "interestRateFrequencyType"; - final int interestPeriodFrequencyType = this.interestPeriodFrequencyType == null? - PeriodFrequencyType.INVALID.getValue() : this.interestPeriodFrequencyType.getValue(); + final int interestPeriodFrequencyType = this.interestPeriodFrequencyType == null ? PeriodFrequencyType.INVALID.getValue() + : this.interestPeriodFrequencyType.getValue(); if (command.isChangeInIntegerParameterNamed(interestRateFrequencyTypeParamName, interestPeriodFrequencyType)) { final Integer newValue = command.integerValueOfParameterNamed(interestRateFrequencyTypeParamName); actualChanges.put(interestRateFrequencyTypeParamName, newValue); @@ -395,6 +399,18 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche 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"; if (command.isChangeInIntegerParameterNamed(graceOnPrincipalPaymentParamName, this.graceOnPrincipalPayment)) { final Integer newValue = command.integerValueOfParameterNamed(graceOnPrincipalPaymentParamName); @@ -572,10 +588,14 @@ public class LoanProductRelatedDetail implements LoanProductMinimumRepaymentSche return this.inArrearsTolerance; } - public void updateForFloatingInterestRates() { - this.nominalInterestRatePerPeriod = null; - this.interestPeriodFrequencyType = PeriodFrequencyType.INVALID; - this.annualNominalInterestRate = null; - } + public void updateForFloatingInterestRates() { + this.nominalInterestRatePerPeriod = null; + this.interestPeriodFrequencyType = PeriodFrequencyType.INVALID; + this.annualNominalInterestRate = null; + } + + public boolean isAllowPartialPeriodInterestCalcualtion() { + return this.allowPartialPeriodInterestCalcualtion; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/serialization/LoanProductDataValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/serialization/LoanProductDataValidator.java index 1f45e22ba..1c00c40ae 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/serialization/LoanProductDataValidator.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/serialization/LoanProductDataValidator.java @@ -27,6 +27,7 @@ import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidation import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.portfolio.common.domain.PeriodFrequencyType; import org.mifosplatform.portfolio.loanproduct.LoanProductConstants; +import org.mifosplatform.portfolio.loanproduct.domain.InterestCalculationPeriodMethod; import org.mifosplatform.portfolio.loanproduct.domain.InterestMethod; import org.mifosplatform.portfolio.loanproduct.domain.InterestRecalculationCompoundingMethod; import org.mifosplatform.portfolio.loanproduct.domain.LoanPreClosureInterestCalculationStrategy; @@ -52,16 +53,17 @@ public final class LoanProductDataValidator { "currencyCode", "digitsAfterDecimal", "inMultiplesOf", "principal", "minPrincipal", "maxPrincipal", "repaymentEvery", "numberOfRepayments", "minNumberOfRepayments", "maxNumberOfRepayments", "repaymentFrequencyType", "interestRatePerPeriod", "minInterestRatePerPeriod", "maxInterestRatePerPeriod", "interestRateFrequencyType", "amortizationType", "interestType", - "interestCalculationPeriodType", "inArrearsTolerance", "transactionProcessingStrategyId", "graceOnPrincipalPayment", - "graceOnInterestPayment", "graceOnInterestCharged", "charges", "accountingRule", "includeInBorrowerCycle", "startDate", - "closeDate", "externalId", "isLinkedToFloatingInterestRates", "floatingRatesId", "interestRateDifferential", - "minDifferentialLendingRate", "defaultDifferentialLendingRate", "maxDifferentialLendingRate", - "isFloatingInterestRateCalculationAllowed", LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), - LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), - LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), - LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), - LOAN_PRODUCT_ACCOUNTING_PARAMS.OVERPAYMENT.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue(), - LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(), + "interestCalculationPeriodType", LoanProductConstants.allowPartialPeriodInterestCalcualtionParamName, "inArrearsTolerance", + "transactionProcessingStrategyId", "graceOnPrincipalPayment", "graceOnInterestPayment", "graceOnInterestCharged", "charges", + "accountingRule", "includeInBorrowerCycle", "startDate", "closeDate", "externalId", "isLinkedToFloatingInterestRates", + "floatingRatesId", "interestRateDifferential", "minDifferentialLendingRate", "defaultDifferentialLendingRate", + "maxDifferentialLendingRate", "isFloatingInterestRateCalculationAllowed", + LOAN_PRODUCT_ACCOUNTING_PARAMS.FEES_RECEIVABLE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.FUND_SOURCE.getValue(), + LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_FEES.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_PENALTIES.getValue(), + LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_ON_LOANS.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INTEREST_RECEIVABLE.getValue(), + LOAN_PRODUCT_ACCOUNTING_PARAMS.LOAN_PORTFOLIO.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.OVERPAYMENT.getValue(), + LOAN_PRODUCT_ACCOUNTING_PARAMS.TRANSFERS_SUSPENSE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(), + LOAN_PRODUCT_ACCOUNTING_PARAMS.PENALTIES_RECEIVABLE.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.PAYMENT_CHANNEL_FUND_SOURCE_MAPPING.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.FEE_INCOME_ACCOUNT_MAPPING.getValue(), LOAN_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_RECOVERY.getValue(), @@ -601,6 +603,8 @@ public final class LoanProductDataValidator { validateVariableInstallmentSettings(baseDataValidator, element); + validatePartialPeriodSupport(interestCalculationPeriodType, baseDataValidator, element, null); + throwExceptionIfValidationWarningsExist(dataValidationErrors); } @@ -1024,10 +1028,10 @@ public final class LoanProductDataValidator { final Integer interestType = this.fromApiJsonHelper.extractIntegerNamed("interestType", element, Locale.getDefault()); baseDataValidator.reset().parameter("interestType").value(interestType).notNull().inMinMaxRange(0, 1); } - + Integer interestCalculationPeriodType = loanProduct.getLoanProductRelatedDetail().getInterestCalculationPeriodMethod().getValue(); if (this.fromApiJsonHelper.parameterExists("interestCalculationPeriodType", element)) { - final Integer interestCalculationPeriodType = this.fromApiJsonHelper.extractIntegerNamed("interestCalculationPeriodType", - element, Locale.getDefault()); + interestCalculationPeriodType = this.fromApiJsonHelper.extractIntegerNamed("interestCalculationPeriodType", element, + Locale.getDefault()); baseDataValidator.reset().parameter("interestCalculationPeriodType").value(interestCalculationPeriodType).notNull() .inMinMaxRange(0, 1); } @@ -1395,6 +1399,9 @@ public final class LoanProductDataValidator { // validateLoanConfigurableAttributes(baseDataValidator,element); validateVariableInstallmentSettings(baseDataValidator, element); + + validatePartialPeriodSupport(interestCalculationPeriodType, baseDataValidator, element, loanProduct); + 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"); + } + } + + } + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java index f4372dc9a..f82ebd655 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java @@ -169,7 +169,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo + "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.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.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, " @@ -291,6 +291,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo final EnumOptionData interestType = LoanEnumerations.interestType(interestTypeId); final int interestCalculationPeriodTypeId = JdbcSupport.getInteger(rs, "interestCalculationInPeriodMethod"); + final Boolean allowPartialPeriodInterestCalcualtion = rs.getBoolean("allowPartialPeriodInterestCalcualtion"); final EnumOptionData interestCalculationPeriodType = LoanEnumerations .interestCalculationPeriodType(interestCalculationPeriodTypeId); @@ -396,10 +397,11 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, - interestRateFrequencyType, amortizationType, interestType, interestCalculationPeriodType, fundId, fundName, - transactionStrategyId, transactionStrategyName, graceOnPrincipalPayment, graceOnInterestPayment, - graceOnInterestCharged, this.charges, accountingRuleType, includeInBorrowerCycle, useBorrowerCycle, startDate, - closeDate, status, externalId, principalVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle, + interestRateFrequencyType, amortizationType, interestType, interestCalculationPeriodType, + allowPartialPeriodInterestCalcualtion, fundId, fundName, transactionStrategyId, transactionStrategyName, + graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, this.charges, accountingRuleType, + includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, externalId, + principalVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle, numberOfRepaymentVariationsForBorrowerCycle, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance, graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, loanProductGuaranteeData, diff --git a/mifosng-provider/src/main/resources/sql/migrations/core_db/V286__partial_period_interest_calcualtion.sql b/mifosng-provider/src/main/resources/sql/migrations/core_db/V286__partial_period_interest_calcualtion.sql new file mode 100644 index 000000000..d107b7606 --- /dev/null +++ b/mifosng-provider/src/main/resources/sql/migrations/core_db/V286__partial_period_interest_calcualtion.sql @@ -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; + diff --git a/mifosng-provider/src/test/java/org/mifosplatform/portfolio/loanaccount/LoanProductRelatedDetailTestHelper.java b/mifosng-provider/src/test/java/org/mifosplatform/portfolio/loanaccount/LoanProductRelatedDetailTestHelper.java index 8a3db100e..3e620a4d8 100644 --- a/mifosng-provider/src/test/java/org/mifosplatform/portfolio/loanaccount/LoanProductRelatedDetailTestHelper.java +++ b/mifosng-provider/src/test/java/org/mifosplatform/portfolio/loanaccount/LoanProductRelatedDetailTestHelper.java @@ -138,10 +138,11 @@ public class LoanProductRelatedDetailTestHelper { final Integer daysInMonthType = DaysInMonthType.ACTUAL.getValue(); final Integer daysInYearType = DaysInYearType.ACTUAL.getValue(); final boolean isInterestRecalculationEnabled = false; + final boolean considerPartialPeriodInterest = false; return new LoanProductRelatedDetail(currency, defaultPrincipal, defaultNominalInterestRatePerPeriod, interestPeriodFrequencyType, - defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, repayEvery, repaymentFrequencyType, - defaultNumberOfRepayments, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, amortizationMethod, - inArrearsTolerance, graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled); + defaultAnnualNominalInterestRate, interestMethod, interestCalculationPeriodMethod, considerPartialPeriodInterest, repayEvery, + repaymentFrequencyType, defaultNumberOfRepayments, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, + amortizationMethod, inArrearsTolerance, graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled); } } \ No newline at end of file