Repository: incubator-fineract Updated Branches: refs/heads/develop 8dfcd1364 -> 56da30c3f
validating disbursement date against expected disbursement date Project: http://git-wip-us.apache.org/repos/asf/incubator-fineract/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-fineract/commit/68f013ab Tree: http://git-wip-us.apache.org/repos/asf/incubator-fineract/tree/68f013ab Diff: http://git-wip-us.apache.org/repos/asf/incubator-fineract/diff/68f013ab Branch: refs/heads/develop Commit: 68f013abc221686e74e933b7d9c5811843edaefe Parents: 8dfcd13 Author: jinjurajan <[email protected]> Authored: Thu Jun 9 18:47:55 2016 +0530 Committer: Nazeer Hussain Shaik <[email protected]> Committed: Tue Aug 2 11:53:22 2016 +0530 ---------------------------------------------------------------------- .../LoanDisbursalDateValidationTest.java | 117 +++++++++++++++++++ .../common/loans/LoanProductTestBuilder.java | 9 ++ .../common/loans/LoanTransactionHelper.java | 10 ++ .../exception/DateMismatchException.java | 39 +++++++ ...anWritePlatformServiceJpaRepositoryImpl.java | 29 ++++- .../loanproduct/data/LoanProductData.java | 24 +++- .../loanproduct/domain/LoanProduct.java | 29 ++++- .../serialization/LoanProductDataValidator.java | 2 +- .../LoanProductReadPlatformServiceImpl.java | 6 +- ...with_disbursement_date_in_m_product_loan.sql | 1 + 10 files changed, 253 insertions(+), 13 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/68f013ab/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/LoanDisbursalDateValidationTest.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/LoanDisbursalDateValidationTest.java b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/LoanDisbursalDateValidationTest.java new file mode 100644 index 0000000..c7235da --- /dev/null +++ b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/LoanDisbursalDateValidationTest.java @@ -0,0 +1,117 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.integrationtests; + +import java.util.HashMap; +import java.util.List; + +import org.apache.fineract.integrationtests.common.ClientHelper; +import org.apache.fineract.integrationtests.common.CommonConstants; +import org.apache.fineract.integrationtests.common.Utils; +import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; +import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder; +import org.apache.fineract.integrationtests.common.loans.LoanStatusChecker; +import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import com.jayway.restassured.builder.RequestSpecBuilder; +import com.jayway.restassured.builder.ResponseSpecBuilder; +import com.jayway.restassured.http.ContentType; +import com.jayway.restassured.specification.RequestSpecification; +import com.jayway.restassured.specification.ResponseSpecification; + +@SuppressWarnings("rawtypes") +public class LoanDisbursalDateValidationTest { + + private ResponseSpecification responseSpec; + private RequestSpecification requestSpec; + private LoanTransactionHelper loanTransactionHelper; + private ResponseSpecification responseForbiddenError; + + @Before + public void setup() { + Utils.initializeRESTAssured(); + this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); + this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); + this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); + this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec); + this.responseForbiddenError = new ResponseSpecBuilder().expectStatusCode(403).build(); + } + + @Test + public void LoanApplicationValidateDisbursalDate() { + + final String proposedAmount = "5000"; + final String approveDate = "1 March 2014"; + final String disbursalDate = "02 March 2014"; + + // CREATE CLIENT + final Integer clientID = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 January 2014"); + System.out.println("---------------------------------CLIENT CREATED WITH ID---------------------------------------------------" + + clientID); + + // CREATE LOAN PRODUCT + final Integer loanProductID = this.loanTransactionHelper.getLoanProductId(new LoanProductTestBuilder() + .withSyncExpectedWithDisbursementDate(true).build(null)); + System.out.println("----------------------------------LOAN PRODUCT CREATED WITH ID-------------------------------------------" + + loanProductID); + + // APPLY FOR LOAN + final Integer loanID = applyForLoanApplication(clientID, loanProductID, proposedAmount); + 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.approveLoan(approveDate, loanID); + + // VALIDATE THE LOAN IS APPROVED + LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap); + LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap); + + // DISBURSE A LOAN + @SuppressWarnings("unchecked") + List<HashMap> disbursalError = (List<HashMap>) this.loanTransactionHelper.disburseLoan(disbursalDate, loanID, this.responseForbiddenError); + + Assert.assertEquals("error.msg.actual.disbursement.date.does.not.match.with.expected.disbursal.date", + disbursalError.get(0).get(CommonConstants.RESPONSE_ERROR_MESSAGE_CODE)); + + } + + private Integer applyForLoanApplication(final Integer clientID, final Integer loanProductID, final String proposedAmount) { + final String loanApplication = new LoanApplicationTestBuilder() + .withPrincipal(proposedAmount).withLoanTermFrequency("5") + .withLoanTermFrequencyAsMonths().withNumberOfRepayments("5") + .withRepaymentEveryAfter("1") + .withRepaymentFrequencyTypeAsMonths() + .withInterestRatePerPeriod("2") + .withExpectedDisbursementDate("1 March 2014") + .withSubmittedOnDate("26 February 2014"). + build(clientID.toString(), loanProductID.toString(), null); + return this.loanTransactionHelper.getLoanId(loanApplication); + } + + + +} http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/68f013ab/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java index 5f90468..45dae9f 100644 --- a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java +++ b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java @@ -124,6 +124,7 @@ public class LoanProductTestBuilder { private Integer recalculationRestFrequencyOnDayType = null; private Integer recalculationCompoundingFrequencyDayOfWeekType = null; private Integer recalculationRestFrequencyDayOfWeekType = null; + private boolean syncExpectedWithDisbursementDate = false; public String build(final String chargeId) { final HashMap<String, Object> map = new HashMap<>(); @@ -211,6 +212,8 @@ public class LoanProductTestBuilder { map.put("minimumGap", minimumGap) ; map.put("maximumGap", maximumGap) ; } + map.put("syncExpectedWithDisbursementDate", + this.syncExpectedWithDisbursementDate); return new Gson().toJson(map); } @@ -498,4 +501,10 @@ public class LoanProductTestBuilder { this.maximumGap = maximumGap; return this ; } + + public LoanProductTestBuilder withSyncExpectedWithDisbursementDate(Boolean syncExpectedWithDisbursementDate) { + this.syncExpectedWithDisbursementDate = + syncExpectedWithDisbursementDate ; + return this ; + } } http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/68f013ab/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java index 4f2c8cb..65cf2b6 100755 --- a/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java +++ b/fineract-provider/src/integrationTest/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java @@ -25,6 +25,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import org.apache.fineract.integrationtests.common.CommonConstants; import org.apache.fineract.integrationtests.common.Utils; import org.joda.time.LocalDate; @@ -176,6 +177,10 @@ public class LoanTransactionHelper { return performLoanTransaction(createLoanOperationURL(DISBURSE_LOAN_COMMAND, loanID), getDisburseLoanAsJSON(date, disburseAmt)); } + public Object disburseLoan(final String date, final Integer loanID, ResponseSpecification responseValidationError) { + return performLoanTransaction(createLoanOperationURL(DISBURSE_LOAN_COMMAND, loanID), getDisburseLoanAsJSON(date, null), responseValidationError); + } + public HashMap disburseLoanToSavings(final String date, final Integer loanID) { return performLoanTransaction(createLoanOperationURL(DISBURSE_LOAN_TO_SAVINGS_COMMAND, loanID), getDisburseLoanAsJSON(date, null)); } @@ -492,6 +497,11 @@ public class LoanTransactionHelper { private Object performLoanTransaction(final String postURLForLoanTransaction, final String jsonToBeSent, final String responseAttribute) { return Utils.performServerPost(this.requestSpec, this.responseSpec, postURLForLoanTransaction, jsonToBeSent, responseAttribute); } + + private Object performLoanTransaction(final String postURLForLoanTransaction, final String jsonToBeSent, ResponseSpecification responseValidationError) { + + return Utils.performServerPost(this.requestSpec, responseValidationError, postURLForLoanTransaction, jsonToBeSent, CommonConstants.RESPONSE_ERROR); + } public Object adjustLoanTransaction(final Integer loanId, final Integer transactionId, final String date, final String transactionAmount, final String responseAttribute) { http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/68f013ab/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/exception/DateMismatchException.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/exception/DateMismatchException.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/exception/DateMismatchException.java new file mode 100644 index 0000000..b0e09c4 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/exception/DateMismatchException.java @@ -0,0 +1,39 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.portfolio.loanaccount.exception; + +import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException; +import org.joda.time.LocalDate; + +/** + * {@link AbstractPlatformDomainRuleException} thrown when + * actual disbursement date does not match with + * expected disbursement date + * + */ +public class DateMismatchException extends AbstractPlatformDomainRuleException { + + public DateMismatchException(final LocalDate actualDisbursementDate, + final LocalDate expectedDisbursedOnLocalDate) { + super("error.msg.actual.disbursement.date.does.not.match.with.expected.disbursal.date", + "Actual disbursement date (" + actualDisbursementDate + ") " + + "should be equal to Expected disbursal date (" + expectedDisbursedOnLocalDate+ ")", actualDisbursementDate, + expectedDisbursedOnLocalDate, null); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/68f013ab/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java index ad04d15..e3f6ccb 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java @@ -142,6 +142,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanTrancheDisbursementC import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository; import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType; +import org.apache.fineract.portfolio.loanaccount.exception.DateMismatchException; import org.apache.fineract.portfolio.loanaccount.exception.ExceedingTrancheCountException; import org.apache.fineract.portfolio.loanaccount.exception.InvalidPaidInAdvanceAmountException; import org.apache.fineract.portfolio.loanaccount.exception.LoanDisbursalException; @@ -164,6 +165,7 @@ import org.apache.fineract.portfolio.loanaccount.serialization.LoanEventApiJsonV import org.apache.fineract.portfolio.loanaccount.serialization.LoanUpdateCommandFromApiJsonDeserializer; import org.apache.fineract.portfolio.loanproduct.data.LoanOverdueDTO; import org.apache.fineract.portfolio.loanproduct.data.LoanProductData; +import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct; import org.apache.fineract.portfolio.loanproduct.exception.InvalidCurrencyException; import org.apache.fineract.portfolio.loanproduct.exception.LinkedAccountRequiredException; import org.apache.fineract.portfolio.loanproduct.service.LoanProductReadPlatformService; @@ -312,6 +314,14 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf this.loanEventApiJsonValidator.validateDisbursement(command.json(), isAccountTransfer); final Loan loan = this.loanAssembler.assembleFrom(loanId); + + final LocalDate actualDisbursementDate = command.localDateValueOfParameterNamed("actualDisbursementDate"); + + // validate ActualDisbursement Date Against Expected Disbursement Date + LoanProduct loanProduct = loan.loanProduct(); + if(loanProduct.syncExpectedWithDisbursementDate()){ + syncExpectedDateWithActualDisbursementDate(loan, actualDisbursementDate); + } checkClientOrGroupActive(loan); final LocalDate nextPossibleRepaymentDate = loan.getNextPossibleRepaymentDateForRescheduling(); @@ -321,14 +331,12 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf checkForProductMixRestrictions(loan); LocalDate recalculateFrom = null; - final LocalDate actualDisbursementDate = command.localDateValueOfParameterNamed("actualDisbursementDate"); ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom); // validate actual disbursement date against meeting date final CalendarInstance calendarInstance = this.calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(), CalendarEntityType.LOANS.getValue()); if (loan.isSyncDisbursementWithMeeting()) { - this.loanEventApiJsonValidator.validateDisbursementDateWithMeetingDate(actualDisbursementDate, calendarInstance, scheduleGeneratorDTO.isSkipRepaymentOnFirstDayofMonth(), scheduleGeneratorDTO.getNumberOfdays()); } @@ -346,6 +354,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf final Boolean isPaymnetypeApplicableforDisbursementCharge = configurationDomainService .isPaymnetypeApplicableforDisbursementCharge(); + // Recalculate first repayment date based in actual disbursement date. updateLoanCounters(loan, actualDisbursementDate); Money amountBeforeAdjust = loan.getPrincpal(); loan.validateAccountStatus(LoanEvent.LOAN_DISBURSED); @@ -571,6 +580,13 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf final SingleDisbursalCommand singleLoanDisbursalCommand = disbursalCommand[i]; final Loan loan = this.loanAssembler.assembleFrom(singleLoanDisbursalCommand.getLoanId()); + final LocalDate actualDisbursementDate = command.localDateValueOfParameterNamed("actualDisbursementDate"); + + // validate ActualDisbursement Date Against Expected Disbursement Date + LoanProduct loanProduct = loan.loanProduct(); + if(loanProduct.syncExpectedWithDisbursementDate()){ + syncExpectedDateWithActualDisbursementDate(loan, actualDisbursementDate); + } checkClientOrGroupActive(loan); this.businessEventNotifierService.notifyBusinessEventToBeExecuted(BUSINESS_EVENTS.LOAN_DISBURSAL, constructEntityMap(BUSINESS_ENTITY.LOAN, loan)); @@ -586,7 +602,6 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf // disbursement date and next available meeting dates // assuming repayment schedule won't regenerate because expected // disbursement and actual disbursement happens on same date - final LocalDate actualDisbursementDate = command.localDateValueOfParameterNamed("actualDisbursementDate"); loan.validateAccountStatus(LoanEvent.LOAN_DISBURSED); updateLoanCounters(loan, actualDisbursementDate); boolean canDisburse = loan.canDisburse(actualDisbursementDate); @@ -2949,4 +2964,12 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf } } + + private void syncExpectedDateWithActualDisbursementDate(final Loan loan, LocalDate actualDisbursementDate){ + if(!loan.getExpectedDisbursedOnLocalDate().equals(actualDisbursementDate)){ + throw new DateMismatchException(actualDisbursementDate, + loan.getExpectedDisbursedOnLocalDate()); + } + + } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/68f013ab/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java index 2418945..68d1724 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java @@ -181,6 +181,7 @@ public class LoanProductData { private final LoanProductGuaranteeData productGuaranteeData; private final Boolean accountMovesOutOfNPAOnlyOnArrearsCompletion; private LoanProductConfigurableAttributes allowAttributeOverrides; + private final boolean syncExpectedWithDisbursementDate; /** * Used when returning lookup information about loan product for dropdowns. @@ -255,6 +256,7 @@ public class LoanProductData { final boolean canDefineInstallmentAmount = false; final Integer installmentAmountInMultiplesOf = null; final LoanProductConfigurableAttributes loanProductConfigurableAttributes = null; + final boolean syncExpectedWithDisbursementDate = false; return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, @@ -269,7 +271,8 @@ public class LoanProductData { accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount, installmentAmountInMultiplesOf, loanProductConfigurableAttributes, isLinkedToFloatingInterestRates, floatingRateId, floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate, maxDifferentialLendingRate, - isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap); + isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap, + syncExpectedWithDisbursementDate); } @@ -344,6 +347,7 @@ public class LoanProductData { final boolean canDefineInstallmentAmount = false; final Integer installmentAmountInMultiplesOf = null; final LoanProductConfigurableAttributes loanProductConfigurableAttributes = null; + final boolean syncExpectedWithDisbursementDate = false; return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, @@ -358,7 +362,8 @@ public class LoanProductData { accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount, installmentAmountInMultiplesOf, loanProductConfigurableAttributes, isLinkedToFloatingInterestRates, floatingRateId, floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate, maxDifferentialLendingRate, - isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap); + isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap, + syncExpectedWithDisbursementDate); } @@ -440,6 +445,7 @@ public class LoanProductData { final boolean canDefineInstallmentAmount = false; final Integer installmentAmountInMultiplesOf = null; final LoanProductConfigurableAttributes loanProductConfigurableAttributes = null; + final boolean syncExpectedWithDisbursementDate = false; return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, @@ -454,8 +460,10 @@ public class LoanProductData { principalThresholdForLastInstallment, accountMovesOutOfNPAOnlyOnArrearsCompletion, canDefineInstallmentAmount, installmentAmountInMultiplesOf, loanProductConfigurableAttributes, isLinkedToFloatingInterestRates, floatingRateId, floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate, - maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap); + maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGap, maximumGap, + syncExpectedWithDisbursementDate); + } public static LoanProductData withAccountingDetails(final LoanProductData productData, final Map<String, Object> accountingMappings, @@ -493,7 +501,8 @@ public class LoanProductData { boolean isLinkedToFloatingInterestRates, Integer floatingRateId, String floatingRateName, BigDecimal interestRateDifferential, BigDecimal minDifferentialLendingRate, BigDecimal defaultDifferentialLendingRate, BigDecimal maxDifferentialLendingRate, boolean isFloatingInterestRateCalculationAllowed, final boolean isVariableInstallmentsAllowed, - final Integer minimumGapBetweenInstallments, final Integer maximumGapBetweenInstallments) { + final Integer minimumGapBetweenInstallments, final Integer maximumGapBetweenInstallments, + final boolean syncExpectedWithDisbursementDate) { this.id = id; this.name = name; this.shortName = shortName; @@ -595,6 +604,7 @@ public class LoanProductData { this.canDefineInstallmentAmount = canDefineInstallmentAmount; this.installmentAmountInMultiplesOf = installmentAmountInMultiplesOf; this.preClosureInterestCalculationStrategyOptions = null; + this.syncExpectedWithDisbursementDate = syncExpectedWithDisbursementDate; } @@ -729,6 +739,7 @@ public class LoanProductData { this.canDefineInstallmentAmount = productData.canDefineInstallmentAmount; this.installmentAmountInMultiplesOf = productData.installmentAmountInMultiplesOf; this.preClosureInterestCalculationStrategyOptions = preCloseInterestCalculationStrategyOptions; + this.syncExpectedWithDisbursementDate = productData.syncExpectedWithDisbursementDate; } private Collection<ChargeData> nullIfEmpty(final Collection<ChargeData> charges) { @@ -1077,4 +1088,9 @@ public class LoanProductData { public Boolean getAllowPartialPeriodInterestCalcualtion() { return this.allowPartialPeriodInterestCalcualtion; } + + public boolean syncExpectedWithDisbursementDate() { + return syncExpectedWithDisbursementDate; + } + } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/68f013ab/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java index c66e70b..2cdb0d1 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/domain/LoanProduct.java @@ -175,6 +175,9 @@ public class LoanProduct extends AbstractPersistable<Long> { @OneToOne(cascade = CascadeType.ALL, mappedBy = "loanProduct", optional = true, orphanRemoval = true, fetch=FetchType.EAGER) private LoanProductVariableInstallmentConfig variableInstallmentConfig; + + @Column(name = "sync_expected_with_disbursement_date") + private boolean syncExpectedWithDisbursementDate; public static LoanProduct assembleFromJson(final Fund fund, final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy, final List<Charge> productCharges, final JsonCommand command, final AprCalculator aprCalculator, FloatingRate floatingRate) { @@ -318,6 +321,8 @@ public class LoanProduct extends AbstractPersistable<Long> { final Integer installmentAmountInMultiplesOf = command .integerValueOfParameterNamed(LoanProductConstants.installmentAmountInMultiplesOfParamName); + final boolean syncExpectedWithDisbursementDate = command.booleanPrimitiveValueOfParameterNamed("syncExpectedWithDisbursementDate"); + return new LoanProduct(fund, loanTransactionProcessingStrategy, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, interestFrequencyType, annualInterestRate, interestMethod, interestCalculationPeriodMethod, allowPartialPeriodInterestCalcualtion, repaymentEvery, @@ -331,7 +336,7 @@ public class LoanProduct extends AbstractPersistable<Long> { installmentAmountInMultiplesOf, loanConfigurableAttributes, isLinkedToFloatingInterestRates, floatingRate, interestRateDifferential, minDifferentialLendingRate, maxDifferentialLendingRate, defaultDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableInstallmentsAllowed, minimumGapBetweenInstallments, - maximumGapBetweenInstallments); + maximumGapBetweenInstallments, syncExpectedWithDisbursementDate); } @@ -562,7 +567,8 @@ public class LoanProduct extends AbstractPersistable<Long> { Boolean isLinkedToFloatingInterestRates, FloatingRate floatingRate, BigDecimal interestRateDifferential, BigDecimal minDifferentialLendingRate, BigDecimal maxDifferentialLendingRate, BigDecimal defaultDifferentialLendingRate, Boolean isFloatingInterestRateCalculationAllowed, final Boolean isVariableInstallmentsAllowed, - final Integer minimumGapBetweenInstallments, final Integer maximumGapBetweenInstallments) { + final Integer minimumGapBetweenInstallments, final Integer maximumGapBetweenInstallments, + final boolean syncExpectedWithDisbursementDate) { this.fund = fund; this.transactionProcessingStrategy = transactionProcessingStrategy; this.name = name.trim(); @@ -636,6 +642,8 @@ public class LoanProduct extends AbstractPersistable<Long> { this.accountMovesOutOfNPAOnlyOnArrearsCompletion = accountMovesOutOfNPAOnlyOnArrearsCompletion; this.canDefineInstallmentAmount = canDefineEmiAmount; this.installmentAmountInMultiplesOf = installmentAmountInMultiplesOf; + this.syncExpectedWithDisbursementDate = + syncExpectedWithDisbursementDate; } public MonetaryCurrency getCurrency() { @@ -858,6 +866,13 @@ public class LoanProduct extends AbstractPersistable<Long> { actualChanges.put("locale", localeAsInput); this.minimumDaysBetweenDisbursalAndFirstRepayment = newValue; } + + if(command.isChangeInBooleanParameterNamed("syncExpectedWithDisbursementDate" + , this.syncExpectedWithDisbursementDate)){ + final boolean newValue = command.booleanPrimitiveValueOfParameterNamed("syncExpectedWithDisbursementDate"); + actualChanges.put("syncExpectedWithDisbursementDate", newValue); + this.syncExpectedWithDisbursementDate = newValue; + } /** * Update interest recalculation settings @@ -1154,8 +1169,16 @@ public class LoanProduct extends AbstractPersistable<Long> { } return borrowerCycleVariation; } + + public boolean syncExpectedWithDisbursementDate() { + return syncExpectedWithDisbursementDate; + } + + public void setSyncExpectedWithDisbursementDate(boolean syncExpectedWithDisbursementDate) { + this.syncExpectedWithDisbursementDate = syncExpectedWithDisbursementDate; + } - public Map<String, BigDecimal> fetchBorrowerCycleVariationsForCycleNumber(final Integer cycleNumber) { + public Map<String, BigDecimal> fetchBorrowerCycleVariationsForCycleNumber(final Integer cycleNumber) { Map<String, BigDecimal> borrowerCycleVariations = new HashMap<>(); borrowerCycleVariations.put(LoanProductConstants.principal, this.loanProductRelatedDetail.getPrincipal().getAmount()); borrowerCycleVariations.put(LoanProductConstants.interestRatePerPeriod, http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/68f013ab/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java index d8cb55d..f9c673b 100755 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/serialization/LoanProductDataValidator.java @@ -70,7 +70,7 @@ public final class LoanProductDataValidator { "transactionProcessingStrategyId", "graceOnPrincipalPayment", "recurringMoratoriumOnPrincipalPeriods", "graceOnInterestPayment", "graceOnInterestCharged", "charges", "accountingRule", "includeInBorrowerCycle", "startDate", "closeDate", "externalId", "isLinkedToFloatingInterestRates", "floatingRatesId", "interestRateDifferential", "minDifferentialLendingRate", "defaultDifferentialLendingRate", - "maxDifferentialLendingRate", "isFloatingInterestRateCalculationAllowed","recurringMoratoriumOnPrincipalPeriods", + "maxDifferentialLendingRate", "isFloatingInterestRateCalculationAllowed", "syncExpectedWithDisbursementDate", 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(), http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/68f013ab/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java index 31c7903..e3a511d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/service/LoanProductReadPlatformServiceImpl.java @@ -206,6 +206,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo + "lpr.allow_compounding_on_eod as allowCompoundingOnEod, " + "lp.hold_guarantee_funds as holdGuaranteeFunds, " + "lp.principal_threshold_for_last_installment as principalThresholdForLastInstallment, " + + "lp.sync_expected_with_disbursement_date as syncExpectedWithDisbursementDate, " + "lpg.id as lpgId, lpg.mandatory_guarantee as mandatoryGuarantee, " + "lpg.minimum_guarantee_from_own_funds as minimumGuaranteeFromOwnFunds, lpg.minimum_guarantee_from_guarantor_funds as minimumGuaranteeFromGuarantor, " + "lp.account_moves_out_of_npa_only_on_arrears_completion as accountMovesOutOfNPAOnlyOnArrearsCompletion, " @@ -441,7 +442,8 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo final BigDecimal principalThresholdForLastInstallment = rs.getBigDecimal("principalThresholdForLastInstallment"); final boolean accountMovesOutOfNPAOnlyOnArrearsCompletion = rs.getBoolean("accountMovesOutOfNPAOnlyOnArrearsCompletion"); - + final boolean syncExpectedWithDisbursementDate = rs.getBoolean("syncExpectedWithDisbursementDate"); + return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, annualInterestRate, repaymentFrequencyType, @@ -457,7 +459,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo installmentAmountInMultiplesOf, allowAttributeOverrides, isLinkedToFloatingInterestRates, floatingRateId, floatingRateName, interestRateDifferential, minDifferentialLendingRate, defaultDifferentialLendingRate, maxDifferentialLendingRate, isFloatingInterestRateCalculationAllowed, isVariableIntallmentsAllowed, minimumGap, - maximumGap); + maximumGap, syncExpectedWithDisbursementDate); } } http://git-wip-us.apache.org/repos/asf/incubator-fineract/blob/68f013ab/fineract-provider/src/main/resources/sql/migrations/core_db/V310__add_sync_expected_with_disbursement_date_in_m_product_loan.sql ---------------------------------------------------------------------- diff --git a/fineract-provider/src/main/resources/sql/migrations/core_db/V310__add_sync_expected_with_disbursement_date_in_m_product_loan.sql b/fineract-provider/src/main/resources/sql/migrations/core_db/V310__add_sync_expected_with_disbursement_date_in_m_product_loan.sql new file mode 100644 index 0000000..980d6d3 --- /dev/null +++ b/fineract-provider/src/main/resources/sql/migrations/core_db/V310__add_sync_expected_with_disbursement_date_in_m_product_loan.sql @@ -0,0 +1 @@ +ALTER TABLE `m_product_loan`ADD COLUMN `sync_expected_with_disbursement_date` TINYINT NULL DEFAULT '0' AFTER `instalment_amount_in_multiples_of`; \ No newline at end of file
