From 00d00551ad72f518447a4e4e020f657d5f4f136d Mon Sep 17 00:00:00 2001 From: Pramod Nuthakki Date: Tue, 16 Dec 2014 15:17:42 +0530 Subject: [PATCH 1/2] MIFOSX-1464 : added loan installment round-off --- api-docs/apiLive.htm | 15 +- .../AccountNumberPreferencesTest.java | 5 + .../AccountNumberPreferencesHelper.java | 5 + .../AccountNumberPreferencesTestBuilder.java | 5 + .../organisation/monetary/domain/Money.java | 28 ++-- .../loanaccount/data/LoanAccountData.java | 135 ++++++++++-------- .../portfolio/loanaccount/domain/Loan.java | 47 +++--- .../domain/AbstractLoanScheduleGenerator.java | 29 ++-- .../domain/LoanApplicationTerms.java | 58 +++++--- .../service/LoanScheduleAssembler.java | 4 +- ...cheduleCalculationPlatformServiceImpl.java | 10 +- ...anApplicationCommandFromApiJsonHelper.java | 15 +- ...WritePlatformServiceJpaRepositoryImpl.java | 13 +- .../loanaccount/service/LoanAssembler.java | 18 ++- .../service/LoanReadPlatformServiceImpl.java | 8 +- .../loanproduct/LoanProductConstants.java | 4 + .../loanproduct/data/LoanProductData.java | 27 +++- .../loanproduct/domain/LoanProduct.java | 39 ++++- .../LoanProductDataValidator.java | 31 +++- .../LoanProductReadPlatformServiceImpl.java | 6 +- .../core_db/V227__fixed_emi_changes.sql | 3 + 21 files changed, 345 insertions(+), 160 deletions(-) create mode 100755 mifosng-provider/src/main/resources/sql/migrations/core_db/V227__fixed_emi_changes.sql diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm index a0dd71e7a..3df620a16 100644 --- a/api-docs/apiLive.htm +++ b/api-docs/apiLive.htm @@ -11032,6 +11032,12 @@ Request Body: Override the default value for rounding currency to multiples of value provided. + + instalmentAmountInMultiplesOf + + + Override the default value for rounding instalment amount to multiples of value provided. + principal @@ -11133,6 +11139,13 @@ Request Body: The minimum number of days allowed between a Loan disbursal and its first repayment. + + canDefineInstalmentAmount + + + if provided as true, then fixed instalment amount can be provided from loan account. + + @@ -12499,7 +12512,7 @@ GET https://DomainName/api/v1/loanproducts/{productId} numberOfRepaymentVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle, multiDisburseLoan,maxTrancheCount, - outstandingLoanBalance,overdueDaysForNPA,holdGuaranteeFunds + outstandingLoanBalance,overdueDaysForNPA, holdGuaranteeFunds, canDefineInstalmentAmount, instalmentAmountInMultiplesOf diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/AccountNumberPreferencesTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/AccountNumberPreferencesTest.java index 62eb3d050..3b0c245bd 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/AccountNumberPreferencesTest.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/AccountNumberPreferencesTest.java @@ -1,3 +1,8 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ package org.mifosplatform.integrationtests; import com.jayway.restassured.builder.RequestSpecBuilder; diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/system/AccountNumberPreferencesHelper.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/system/AccountNumberPreferencesHelper.java index 9745f7219..02f0ec059 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/system/AccountNumberPreferencesHelper.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/system/AccountNumberPreferencesHelper.java @@ -1,3 +1,8 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ package org.mifosplatform.integrationtests.common.system; import java.util.ArrayList; diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/system/AccountNumberPreferencesTestBuilder.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/system/AccountNumberPreferencesTestBuilder.java index 6488c36c0..7a6b088e1 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/system/AccountNumberPreferencesTestBuilder.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/system/AccountNumberPreferencesTestBuilder.java @@ -1,3 +1,8 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ package org.mifosplatform.integrationtests.common.system; import java.util.HashMap; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/domain/Money.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/domain/Money.java index e9e300185..076201f05 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/domain/Money.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/monetary/domain/Money.java @@ -74,21 +74,27 @@ public class Money implements Comparable { // round monetary amounts into multiplesof say 20/50. if (inMultiplesOf != null && this.currencyDigitsAfterDecimal == 0 && inMultiplesOf > 0 && amountScaled.doubleValue() > 0) { final double existingVal = amountScaled.doubleValue(); - final double ceilingOfValue = ceiling(existingVal, inMultiplesOf); - final double floorOfValue = floor(existingVal, inMultiplesOf); - - final double floorDiff = existingVal - floorOfValue; - final double ceilDiff = ceilingOfValue - existingVal; - - if (ceilDiff > floorDiff) { - amountScaled = BigDecimal.valueOf(floorOfValue); - } else { - amountScaled = BigDecimal.valueOf(ceilingOfValue); - } + amountScaled = BigDecimal.valueOf(roundToMultiplesOf(existingVal, inMultiplesOf)); } this.amount = amountScaled.setScale(this.currencyDigitsAfterDecimal, RoundingMode.HALF_EVEN); } + public static double roundToMultiplesOf(final double existingVal, final Integer inMultiplesOf) { + double amountScaled = existingVal; + final double ceilingOfValue = ceiling(existingVal, inMultiplesOf); + final double floorOfValue = floor(existingVal, inMultiplesOf); + + final double floorDiff = existingVal - floorOfValue; + final double ceilDiff = ceilingOfValue - existingVal; + + if (ceilDiff > floorDiff) { + amountScaled = floorOfValue; + } else { + amountScaled = ceilingOfValue; + } + return amountScaled; + } + public static double ceiling(final double n, final double s) { double c; 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 34fa39785..e9cda5bf1 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 @@ -152,6 +152,8 @@ public class LoanAccountData { private final Boolean multiDisburseLoan; + private final Boolean canDefineInstalmentAmount; + private final BigDecimal fixedEmiAmount; private final BigDecimal maxOutstandingLoanBalance; @@ -260,6 +262,7 @@ public class LoanAccountData { final PortfolioAccountData linkedAccount = null; final Collection disbursementData = null; final Boolean multiDisburseLoan = null; + final Boolean canDefineInstalmentAmount = null; final BigDecimal fixedEmiAmount = null; final BigDecimal maxOutstandingLoanBalance = null; final Collection emiAmountVariations = null; @@ -289,9 +292,10 @@ public class LoanAccountData { interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, accountLinkingOptions, linkedAccount, - disbursementData, multiDisburseLoan, fixedEmiAmount, maxOutstandingLoanBalance, emiAmountVariations, memberVariations, - product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType, daysInYearType, - isInterestRecalculationEnabled, interestRecalculationData, originalSchedule, createStandingInstructionAtDisbursement); + disbursementData, multiDisburseLoan, canDefineInstalmentAmount, fixedEmiAmount, maxOutstandingLoanBalance, + emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType, + daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule, + createStandingInstructionAtDisbursement); } /** @@ -377,6 +381,7 @@ public class LoanAccountData { final PortfolioAccountData linkedAccount = null; final Collection disbursementData = null; final Boolean multiDisburseLoan = null; + final Boolean canDefineInstalmentAmount = null; final BigDecimal fixedEmiAmount = null; final BigDecimal maxOutstandingLoanBalance = null; final Collection emiAmountVariations = null; @@ -406,9 +411,10 @@ public class LoanAccountData { interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, accountLinkingOptions, linkedAccount, - disbursementData, multiDisburseLoan, fixedEmiAmount, maxOutstandingLoanBalance, emiAmountVariations, memberVariations, - product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType, daysInYearType, - isInterestRecalculationEnabled, interestRecalculationData, originalSchedule, createStandingInstructionAtDisbursement); + disbursementData, multiDisburseLoan, canDefineInstalmentAmount, fixedEmiAmount, maxOutstandingLoanBalance, + emiAmountVariations, memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType, + daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, originalSchedule, + createStandingInstructionAtDisbursement); } @@ -430,10 +436,11 @@ public class LoanAccountData { acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null, acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions, acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions, - acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance, - acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges, - acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, acc.interestRecalculationData, - acc.originalSchedule, acc.createStandingInstructionAtDisbursement); + acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.canDefineInstalmentAmount, acc.fixedEmiAmount, + acc.maxOutstandingLoanBalance, acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, + acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType, + acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule, + acc.createStandingInstructionAtDisbursement); } /** @@ -520,6 +527,7 @@ public class LoanAccountData { final PortfolioAccountData linkedAccount = null; final Collection disbursementData = null; final Boolean multiDisburseLoan = null; + final Boolean canDefineInstalmentAmount = null; final BigDecimal fixedEmiAmount = null; final BigDecimal maxOutstandingBalance = null; final Collection emiAmountVariations = null; @@ -549,9 +557,9 @@ public class LoanAccountData { interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, accountLinkingOptions, linkedAccount, - disbursementData, multiDisburseLoan, fixedEmiAmount, maxOutstandingBalance, emiAmountVariations, memberVariations, product, - inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, - interestRecalculationData, originalSchedule, createStandingInstructionAtDisbursement); + disbursementData, multiDisburseLoan, canDefineInstalmentAmount, fixedEmiAmount, maxOutstandingBalance, emiAmountVariations, + memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType, daysInYearType, + isInterestRecalculationEnabled, interestRecalculationData, originalSchedule, createStandingInstructionAtDisbursement); } public static LoanAccountData populateGroupDefaults(final LoanAccountData acc, final LoanAccountData groupAcc) { @@ -572,10 +580,11 @@ public class LoanAccountData { acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null, acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions, acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions, - acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance, - acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges, - acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, acc.interestRecalculationData, - acc.originalSchedule, acc.createStandingInstructionAtDisbursement); + acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.canDefineInstalmentAmount, acc.fixedEmiAmount, + acc.maxOutstandingLoanBalance, acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, + acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType, + acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule, + acc.createStandingInstructionAtDisbursement); } public static LoanAccountData loanProductWithTemplateDefaults(final LoanProductData product, @@ -707,10 +716,11 @@ public class LoanAccountData { amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, accountLinkingOptions, linkedAccount, - disbursementData, product.getMultiDisburseLoan(), fixedEmi, product.getOutstandingLoanBalance(), emiAmountVariations, - memberVariations, product, inArrears, product.getGraceOnArrearsAgeing(), product.overdueFeeCharges(), isNPA, - product.getDaysInMonthType(), product.getDaysInYearType(), product.isInterestRecalculationEnabled(), - product.toLoanInterestRecalculationData(), originalSchedule, createStandingInstructionAtDisbursement); + disbursementData, product.getMultiDisburseLoan(), product.canDefineInstalmentAmount(), fixedEmi, + product.getOutstandingLoanBalance(), emiAmountVariations, memberVariations, product, inArrears, + product.getGraceOnArrearsAgeing(), product.overdueFeeCharges(), isNPA, product.getDaysInMonthType(), + product.getDaysInYearType(), product.isInterestRecalculationEnabled(), product.toLoanInterestRecalculationData(), + originalSchedule, createStandingInstructionAtDisbursement); } public static LoanAccountData populateLoanProductDefaults(final LoanAccountData acc, final LoanProductData product) { @@ -760,11 +770,11 @@ public class LoanAccountData { repaymentStrategyOptions, interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions, acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, notes, - acc.accountLinkingOptions, acc.linkedAccount, acc.disbursementDetails, product.getMultiDisburseLoan(), 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); + acc.accountLinkingOptions, acc.linkedAccount, acc.disbursementDetails, product.getMultiDisburseLoan(), + product.canDefineInstalmentAmount(), 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); } /* @@ -786,9 +796,9 @@ public class LoanAccountData { 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, 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 Boolean multiDisburseLoan, Boolean canDefineInstalmentAmount, 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 LoanScheduleData repaymentSchedule = null; @@ -837,9 +847,9 @@ public class LoanAccountData { amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions, syncDisbursementWithMeeting, loancounter, loanProductCounter, notes, accountLinkingOptions, linkedAccount, - disbursementData, multiDisburseLoan, fixedEmiAmont, outstandingLoanBalance, emiAmountVariations, memberVariations, product, - inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, - interestRecalculationData, originalSchedule, createStandingInstructionAtDisbursement); + disbursementData, multiDisburseLoan, canDefineInstalmentAmount, fixedEmiAmont, outstandingLoanBalance, emiAmountVariations, + memberVariations, product, inArrears, graceOnArrearsAgeing, overdueCharges, isNPA, daysInMonthType, daysInYearType, + isInterestRecalculationEnabled, interestRecalculationData, originalSchedule, createStandingInstructionAtDisbursement); } /* @@ -878,9 +888,10 @@ public class LoanAccountData { interestRateFrequencyTypeOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, fundOptions, chargeOptions, chargeTemplate, loanOfficerOptions, loanPurposeOptions, loanCollateralOptions, calendarOptions, acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, notes, accountLinkingOptions, linkedAccount, - disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance, emiAmountVariations, - acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, overdueCharges, acc.isNPA, acc.daysInMonthType, - acc.daysInYearType, acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule, + disbursementDetails, acc.multiDisburseLoan, acc.canDefineInstalmentAmount, acc.fixedEmiAmount, + acc.maxOutstandingLoanBalance, emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, + acc.graceOnArrearsAgeing, overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType, + acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule, acc.createStandingInstructionAtDisbursement); } @@ -913,10 +924,11 @@ public class LoanAccountData { acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null, acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions, acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions, - acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance, - acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges, - acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, acc.interestRecalculationData, - acc.originalSchedule, acc.createStandingInstructionAtDisbursement); + acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.canDefineInstalmentAmount, acc.fixedEmiAmount, + acc.maxOutstandingLoanBalance, acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, + acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType, + acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule, + acc.createStandingInstructionAtDisbursement); } public static LoanAccountData associateMemberVariations(final LoanAccountData acc, final Map memberLoanCycle) { @@ -973,10 +985,11 @@ public class LoanAccountData { acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null, acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions, acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions, - acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance, - acc.emiAmountVariations, memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges, - acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, acc.interestRecalculationData, - acc.originalSchedule, acc.createStandingInstructionAtDisbursement); + acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.canDefineInstalmentAmount, acc.fixedEmiAmount, + acc.maxOutstandingLoanBalance, acc.emiAmountVariations, memberVariations, acc.product, acc.inArrears, + acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType, + acc.isInterestRecalculationEnabled, acc.interestRecalculationData, acc.originalSchedule, + acc.createStandingInstructionAtDisbursement); } public static LoanAccountData withInterestRecalculationCalendarData(final LoanAccountData acc, final CalendarData calendarData) { @@ -999,10 +1012,11 @@ public class LoanAccountData { acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null, acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions, acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions, - acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance, - acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges, - acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, interestRecalculationData, - acc.originalSchedule, acc.createStandingInstructionAtDisbursement); + acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.canDefineInstalmentAmount, acc.fixedEmiAmount, + acc.maxOutstandingLoanBalance, acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, + acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType, + acc.isInterestRecalculationEnabled, interestRecalculationData, acc.originalSchedule, + acc.createStandingInstructionAtDisbursement); } public static LoanAccountData withOriginalSchedule(final LoanAccountData acc, final LoanScheduleData originalSchedule) { @@ -1023,10 +1037,11 @@ public class LoanAccountData { acc.interestTypeOptions, acc.interestCalculationPeriodTypeOptions, acc.fundOptions, acc.chargeOptions, null, acc.loanOfficerOptions, acc.loanPurposeOptions, acc.loanCollateralOptions, acc.calendarOptions, acc.syncDisbursementWithMeeting, acc.loanCounter, acc.loanProductCounter, acc.notes, acc.accountLinkingOptions, - acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.fixedEmiAmount, acc.maxOutstandingLoanBalance, - acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, acc.graceOnArrearsAgeing, acc.overdueCharges, - acc.isNPA, acc.daysInMonthType, acc.daysInYearType, acc.isInterestRecalculationEnabled, acc.interestRecalculationData, - originalSchedule, acc.createStandingInstructionAtDisbursement); + acc.linkedAccount, acc.disbursementDetails, acc.multiDisburseLoan, acc.canDefineInstalmentAmount, acc.fixedEmiAmount, + acc.maxOutstandingLoanBalance, acc.emiAmountVariations, acc.memberVariations, acc.product, acc.inArrears, + acc.graceOnArrearsAgeing, acc.overdueCharges, acc.isNPA, acc.daysInMonthType, acc.daysInYearType, + acc.isInterestRecalculationEnabled, acc.interestRecalculationData, originalSchedule, + acc.createStandingInstructionAtDisbursement); } private LoanAccountData( @@ -1081,11 +1096,11 @@ public class LoanAccountData { final Boolean syncDisbursementWithMeeting, final Integer loanCounter, final Integer loanProductCounter, final Collection notes, final Collection accountLinkingOptions, final PortfolioAccountData linkedAccount, final Collection disbursementDetails, - final Boolean multiDisburseLoan, BigDecimal fixedEmiAmount, final BigDecimal maxOutstandingLoanBalance, - final Collection emiAmountVariations, final Map memberVariations, - final LoanProductData product, final Boolean inArrears, final Integer graceOnArrearsAgeing, - final Collection overdueCharges, final Boolean isNPA, final EnumOptionData daysInMonthType, - final EnumOptionData daysInYearType, final boolean isInterestRecalculationEnabled, + final Boolean multiDisburseLoan, final Boolean canDefineInstalmentAmount, BigDecimal fixedEmiAmount, + final BigDecimal maxOutstandingLoanBalance, final Collection emiAmountVariations, + final Map memberVariations, final LoanProductData product, final Boolean inArrears, + final Integer graceOnArrearsAgeing, final Collection overdueCharges, final Boolean isNPA, + final EnumOptionData daysInMonthType, final EnumOptionData daysInYearType, final boolean isInterestRecalculationEnabled, final LoanInterestRecalculationData interestRecalculationData, final LoanScheduleData originalSchedule, final Boolean createStandingInstructionAtDisbursement) { @@ -1209,6 +1224,14 @@ public class LoanAccountData { this.accountLinkingOptions = accountLinkingOptions; this.disbursementDetails = disbursementDetails; this.multiDisburseLoan = multiDisburseLoan; + + Boolean canDefineEMIAmount = canDefineInstalmentAmount; + if (canDefineInstalmentAmount == null) { + canDefineEMIAmount = multiDisburseLoan; + } else if (multiDisburseLoan != null) { + canDefineEMIAmount = canDefineInstalmentAmount || multiDisburseLoan; + } + this.canDefineInstalmentAmount = canDefineEMIAmount; this.fixedEmiAmount = fixedEmiAmount; this.maxOutstandingLoanBalance = maxOutstandingLoanBalance; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java index e79e54826..d2e64a6d5 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/domain/Loan.java @@ -1195,9 +1195,9 @@ public class Loan extends AbstractPersistable { if (command.isChangeInBooleanParameterNamed(createSiAtDisbursementParameterName, shouldCreateStandingInstructionAtDisbursement())) { final Boolean valueAsInput = command.booleanObjectValueOfParameterNamed(createSiAtDisbursementParameterName); actualChanges.put(createSiAtDisbursementParameterName, valueAsInput); - this.createStandingInstructionAtDisbursement = valueAsInput; + this.createStandingInstructionAtDisbursement = valueAsInput; } - + final String externalIdParamName = "externalId"; if (command.isChangeInStringParameterNamed(externalIdParamName, this.externalId)) { final String newValue = command.stringValueOfParameterNamed(externalIdParamName); @@ -1398,9 +1398,6 @@ public class Loan extends AbstractPersistable { if (loanProduct.isMultiDisburseLoan()) { updateDisbursementDetails(command, actualChanges); - if (command.isChangeInBigDecimalParameterNamed(LoanApiConstants.emiAmountParameterName, this.fixedEmiAmount)) { - this.fixedEmiAmount = command.bigDecimalValueOfParameterNamed(LoanApiConstants.emiAmountParameterName); - } if (command.isChangeInBigDecimalParameterNamed(LoanApiConstants.maxOutstandingBalanceParameterName, this.maxOutstandingLoanBalance)) { this.maxOutstandingLoanBalance = command @@ -1417,6 +1414,15 @@ public class Loan extends AbstractPersistable { } } else { this.disbursementDetails.clear(); + } + + if (loanProduct.isMultiDisburseLoan() || loanProduct.canDefineInstalmentAmount()) { + if (command.isChangeInBigDecimalParameterNamed(LoanApiConstants.emiAmountParameterName, this.fixedEmiAmount)) { + this.fixedEmiAmount = command.bigDecimalValueOfParameterNamed(LoanApiConstants.emiAmountParameterName); + actualChanges.put(LoanApiConstants.emiAmountParameterName, this.fixedEmiAmount); + actualChanges.put("recalculateLoanSchedule", true); + } + } else { this.fixedEmiAmount = null; } @@ -2076,10 +2082,15 @@ public class Loan extends AbstractPersistable { public void regenerateScheduleOnDisbursement(final ScheduleGeneratorDTO scheduleGeneratorDTO, final boolean recalculateSchedule, final LocalDate actualDisbursementDate, BigDecimal emiAmount, final AppUser currentUser) { boolean isEmiAmountChanged = false; - if (this.loanProduct.isMultiDisburseLoan() && emiAmount != null && emiAmount.compareTo(retriveLastEmiAmount()) != 0) { - LoanTermVariations loanVariationTerms = new LoanTermVariations(LoanTermVariationType.EMI_AMOUNT.getValue(), - actualDisbursementDate.toDate(), emiAmount, this); - this.loanTermVariations.add(loanVariationTerms); + if ((this.loanProduct.isMultiDisburseLoan() || this.loanProduct.canDefineInstalmentAmount()) && emiAmount != null + && emiAmount.compareTo(retriveLastEmiAmount()) != 0) { + if (this.loanProduct.isMultiDisburseLoan()) { + LoanTermVariations loanVariationTerms = new LoanTermVariations(LoanTermVariationType.EMI_AMOUNT.getValue(), + actualDisbursementDate.toDate(), emiAmount, this); + this.loanTermVariations.add(loanVariationTerms); + } else { + this.fixedEmiAmount = emiAmount; + } isEmiAmountChanged = true; } @@ -2315,7 +2326,8 @@ public class Loan extends AbstractPersistable { loanTermFrequency, loanTermPeriodFrequencyType, nthDayType, dayOfWeekType, getDisbursementDate(), getExpectedFirstRepaymentOnDate(), scheduleGeneratorDTO.getCalculatedRepaymentsStartingFromDate(), getInArrearsTolerance(), this.loanRepaymentScheduleDetail, this.loanProduct.isMultiDisburseLoan(), this.fixedEmiAmount, disbursementData, - this.maxOutstandingLoanBalance, loanVariationTermsData, getInterestChargedFromDate()); + this.maxOutstandingLoanBalance, loanVariationTermsData, getInterestChargedFromDate(), + this.loanProduct.getInstalmentAmountInMultiplesOf()); final LoanScheduleModel loanSchedule = loanScheduleGenerator.generate(mc, loanApplicationTerms, charges(), scheduleGeneratorDTO.getHolidayDetailDTO()); @@ -4639,7 +4651,7 @@ public class Loan extends AbstractPersistable { calculatedRepaymentsStartingFromDate, getInArrearsTolerance(), this.loanRepaymentScheduleDetail, this.loanProduct.isMultiDisburseLoan(), this.fixedEmiAmount, disbursementData, this.maxOutstandingLoanBalance, loanVariationTermsData, getInterestChargedFromDate(), this.loanInterestRecalculationDetails, - calendarInstanceForInterestRecalculation, recalculationFrequencyType); + calendarInstanceForInterestRecalculation, recalculationFrequencyType, this.loanProduct.getInstalmentAmountInMultiplesOf()); return loanApplicationTerms; } @@ -4682,7 +4694,8 @@ public class Loan extends AbstractPersistable { final LoanApplicationTerms loanApplicationTerms = LoanApplicationTerms.assembleFrom(null, loanTermFrequency, loanTermPeriodFrequencyType, nthDayType, dayOfWeekType, getDisbursementDate(), getExpectedFirstRepaymentOnDate(), null, getInArrearsTolerance(), this.loanRepaymentScheduleDetail, this.loanProduct.isMultiDisburseLoan(), this.fixedEmiAmount, - disbursementData, this.maxOutstandingLoanBalance, loanVariationTermsData, getInterestChargedFromDate()); + disbursementData, this.maxOutstandingLoanBalance, loanVariationTermsData, getInterestChargedFromDate(), + this.loanProduct.getInstalmentAmountInMultiplesOf()); installment = loanScheduleGenerator.calculatePrepaymentAmount(this.repaymentScheduleInstallments, getCurrency(), LocalDate.now(), getInterestChargedFromDate(), loanApplicationTerms, mc, charges()); @@ -4880,10 +4893,12 @@ public class Loan extends AbstractPersistable { LoanEnumerations.loanvariationType(LoanTermVariationType.EMI_AMOUNT), expectedDisbursementDate, emiAmount); loanVariationTermsData.add(data); - return LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, nthDayType, - dayOfWeekType, expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate, - inArrearsToleranceMoney, this.loanRepaymentScheduleDetail, loanProduct.isMultiDisburseLoan(), emiAmount, disbursementData, - maxOutstandingBalance, loanVariationTermsData, interestChargedFromDate); + return LoanApplicationTerms + .assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, nthDayType, dayOfWeekType, + expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate, + inArrearsToleranceMoney, this.loanRepaymentScheduleDetail, loanProduct.isMultiDisburseLoan(), emiAmount, + disbursementData, maxOutstandingBalance, loanVariationTermsData, interestChargedFromDate, + this.loanProduct.getInstalmentAmountInMultiplesOf()); } /** 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 8b0a7b649..02673ec6b 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 @@ -117,7 +117,6 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener outstandingBalance = outstandingBalance.zero().plus(disburseAmt); } Money reducePrincipal = totalCumulativePrincipal.zero(); - Money fixedEmiAmount = totalCumulativePrincipal.zero(); int daysCalcForInstallmentNumber = 0; LocalDate scheduleStartDateAsPerFrequency = periodStartDate; while (!outstandingBalance.isZero()) { @@ -191,7 +190,6 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener BigDecimal disburseAmt = BigDecimal.ZERO; if (loanApplicationTerms.isMultiDisburseLoan()) { loanApplicationTerms.setFixedEmiAmountForPeriod(scheduledDueDate); - fixedEmiAmount = fixedEmiAmount.zero().plus(loanApplicationTerms.getFixedEmiAmount()); final Collection disbursementDatas = new ArrayList<>(); LocalDate tillDate = scheduledDueDate; if (prepayDate != null && prepayDate.isBefore(tillDate)) { @@ -233,16 +231,12 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener if (!loanApplicationTerms.isMultiDisburseLoan()) { loanApplicationTerms.setFixedEmiAmount(null); } - fixedEmiAmount = fixedEmiAmount.zero(); outstandingBalance = outstandingBalance.minus(reducePrincipal); balanceForcalculation = balanceForcalculation.minus(reducePrincipal); totalCumulativePrincipal = totalCumulativePrincipal.plus(reducePrincipal); reducePrincipal = reducePrincipal.zero(); break; case REDUCE_NUMBER_OF_INSTALLMENTS: - if (fixedEmiAmount.isGreaterThanZero()) { - loanApplicationTerms.setFixedEmiAmount(fixedEmiAmount.getAmount()); - } outstandingBalance = outstandingBalance.minus(reducePrincipal); balanceForcalculation = balanceForcalculation.minus(reducePrincipal); totalCumulativePrincipal = totalCumulativePrincipal.plus(reducePrincipal); @@ -385,14 +379,10 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener // Exclude principal portion for interest only installments if (!recalculatedInterestComponent) { principalForThisPeriod = principalInterestForThisPeriod.principal(); - if (diffAmt != null && !diffAmt.isEmpty() && loanApplicationTerms.getAmortizationMethod().isEqualInstallment()) { - Money principalToBeAdjust = principalForThisPeriod.zero(); - if (fixedEmiAmount.isZero()) { - principalToBeAdjust = principalInterestForThisPeriod.interest().minus(interestForThisinstallment); - - } else { - principalToBeAdjust = fixedEmiAmount.minus(principalForThisPeriod).minus(interestForThisinstallment); - } + if (((diffAmt != null && !diffAmt.isEmpty()) || interestToBeAdded.compareTo(BigDecimal.ZERO) == 1) + && loanApplicationTerms.getAmortizationMethod().isEqualInstallment()) { + Money principalToBeAdjust = Money.of(currency, loanApplicationTerms.getFixedEmiAmount()).minus(principalForThisPeriod) + .minus(interestForThisinstallment); principalForThisPeriod = principalForThisPeriod.plus(principalToBeAdjust); principalForThisPeriod = loanApplicationTerms.adjustPrincipalIfLastRepaymentPeriod(principalForThisPeriod, totalCumulativePrincipal.plus(principalForThisPeriod), periodNumber); @@ -407,9 +397,6 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener } } - if (fixedEmiAmount.isZero() && !recalculatedInterestComponent) { - fixedEmiAmount = principalForThisPeriod.plus(interestForThisinstallment); - } reducePrincipal = reducePrincipal.minus(reducePrincipalForCurrentInstallment); if (principalForThisPeriod.isGreaterThan(reducePrincipalForCurrentInstallment)) { @@ -543,6 +530,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener } } + loanApplicationTerms.resetFixedEmiAmount(); + return LoanScheduleModel.from(periods, applicationCurrency, loanTermInDays, principalDisbursed, totalPrincipalExpected, totalPrincipalPaid, totalInterestCharged, totalFeeChargesCharged, totalPenaltyChargesCharged, totalRepaymentExpected, totalOutstanding); @@ -794,12 +783,12 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener Money principalDue = Money.of(currency, period.principalDue()); Money interestDue = Money.of(currency, period.interestDue()); - - if(principalDue.isZero() && interestDue.isZero()) { + + if (principalDue.isZero() && interestDue.isZero()) { period.updateFeeChargesDue(Money.zero(currency)); period.updatePenaltyChargesDue(Money.zero(currency)); } - + Money feeChargesDue = Money.of(currency, period.feeChargesDue()); Money penaltyChargesDue = Money.of(currency, period.penaltyChargesDue()); 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 4aefa7775..f64378b7c 100644 --- 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 @@ -112,6 +112,8 @@ public final class LoanApplicationTerms { private BigDecimal fixedEmiAmount; + private BigDecimal actualFixedEmiAmount; + private final BigDecimal maxOutstandingBalance; private final List emiAmountVariations; @@ -132,6 +134,8 @@ public final class LoanApplicationTerms { private final RecalculationFrequencyType recalculationFrequencyType; + private final Integer instalmentAmountInMultiplesOf; + public static LoanApplicationTerms assembleFrom(final ApplicationCurrency currency, final Integer loanTermFrequency, final PeriodFrequencyType loanTermPeriodFrequencyType, final Integer numberOfRepayments, final Integer repaymentEvery, final PeriodFrequencyType repaymentPeriodFrequencyType, Integer nthDay, DayOfWeekType weekDayType, @@ -144,7 +148,8 @@ public final class LoanApplicationTerms { final Money inArrearsTolerance, final boolean multiDisburseLoan, final BigDecimal emiAmount, final List disbursementDatas, final BigDecimal maxOutstandingBalance, final List emiAmountVariations, final Integer graceOnArrearsAgeing, - final DaysInMonthType daysInMonthType, final DaysInYearType daysInYearType, final boolean isInterestRecalculationEnabled) { + final DaysInMonthType daysInMonthType, final DaysInYearType daysInYearType, final boolean isInterestRecalculationEnabled, + Integer instalmentAmountInMultiplesOf) { final LoanRescheduleStrategyMethod rescheduleStrategyMethod = null; final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod = null; @@ -157,7 +162,7 @@ public final class LoanApplicationTerms { graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsTolerance, multiDisburseLoan, emiAmount, disbursementDatas, maxOutstandingBalance, emiAmountVariations, graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, rescheduleStrategyMethod, interestRecalculationCompoundingMethod, restCalendarInstance, - recalculationFrequencyType); + recalculationFrequencyType, instalmentAmountInMultiplesOf); } public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency, @@ -166,7 +171,8 @@ public final class LoanApplicationTerms { final LocalDate calculatedRepaymentsStartingFromDate, final Money inArrearsTolerance, final LoanProductRelatedDetail loanProductRelatedDetail, final boolean multiDisburseLoan, final BigDecimal emiAmount, final List disbursementDatas, final BigDecimal maxOutstandingBalance, - final List emiAmountVariations, final LocalDate interestChargedFromDate) { + final List emiAmountVariations, final LocalDate interestChargedFromDate, + Integer instalmentAmountInMultiplesOf) { final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments(); final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery(); @@ -201,7 +207,8 @@ public final class LoanApplicationTerms { graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsTolerance, multiDisburseLoan, emiAmount, disbursementDatas, maxOutstandingBalance, emiAmountVariations, loanProductRelatedDetail.getGraceOnDueDate(), daysInMonthType, daysInYearType, isInterestRecalculationEnabled, - rescheduleStrategyMethod, interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType); + rescheduleStrategyMethod, interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType, + instalmentAmountInMultiplesOf); } public static LoanApplicationTerms assembleFrom(final ApplicationCurrency applicationCurrency, final Integer loanTermFrequency, @@ -211,7 +218,7 @@ public final class LoanApplicationTerms { final BigDecimal emiAmount, final List disbursementDatas, final BigDecimal maxOutstandingBalance, final List emiAmountVariations, final LocalDate interestChargedFromDate, final LoanInterestRecalculationDetails interestRecalculationDetails, final CalendarInstance restCalendarInstance, - final RecalculationFrequencyType recalculationFrequencyType) { + final RecalculationFrequencyType recalculationFrequencyType, Integer instalmentAmountInMultiplesOf) { final Integer numberOfRepayments = loanProductRelatedDetail.getNumberOfRepayments(); final Integer repaymentEvery = loanProductRelatedDetail.getRepayEvery(); @@ -248,7 +255,7 @@ public final class LoanApplicationTerms { graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsTolerance, multiDisburseLoan, emiAmount, disbursementDatas, maxOutstandingBalance, emiAmountVariations, loanProductRelatedDetail.getGraceOnDueDate(), daysInMonthType, daysInYearType, isInterestRecalculationEnabled, rescheduleStrategyMethod, - interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType); + interestRecalculationCompoundingMethod, restCalendarInstance, recalculationFrequencyType, instalmentAmountInMultiplesOf); } public static LoanApplicationTerms assembleFrom(final Integer repaymentEvery, final PeriodFrequencyType repaymentPeriodFrequencyType, @@ -266,7 +273,7 @@ public final class LoanApplicationTerms { applicationTerms.graceOnArrearsAgeing, applicationTerms.daysInMonthType, applicationTerms.daysInYearType, applicationTerms.interestRecalculationEnabled, applicationTerms.rescheduleStrategyMethod, applicationTerms.interestRecalculationCompoundingMethod, applicationTerms.restCalendarInstance, - applicationTerms.recalculationFrequencyType); + applicationTerms.recalculationFrequencyType, applicationTerms.instalmentAmountInMultiplesOf); } private LoanApplicationTerms(final ApplicationCurrency currency, final Integer loanTermFrequency, @@ -283,7 +290,8 @@ public final class LoanApplicationTerms { final Integer graceOnArrearsAgeing, final DaysInMonthType daysInMonthType, final DaysInYearType daysInYearType, final boolean isInterestRecalculationEnabled, final LoanRescheduleStrategyMethod rescheduleStrategyMethod, final InterestRecalculationCompoundingMethod interestRecalculationCompoundingMethod, - final CalendarInstance restCalendarInstance, final RecalculationFrequencyType recalculationFrequencyType) { + final CalendarInstance restCalendarInstance, final RecalculationFrequencyType recalculationFrequencyType, + final Integer instalmentAmountInMultiplesOf) { this.currency = currency; this.loanTermFrequency = loanTermFrequency; this.loanTermPeriodFrequencyType = loanTermPeriodFrequencyType; @@ -313,6 +321,7 @@ public final class LoanApplicationTerms { this.inArrearsTolerance = inArrearsTolerance; this.multiDisburseLoan = multiDisburseLoan; this.fixedEmiAmount = emiAmount; + this.actualFixedEmiAmount = emiAmount; this.disbursementDatas = disbursementDatas; this.maxOutstandingBalance = maxOutstandingBalance; this.emiAmountVariations = emiAmountVariations; @@ -324,6 +333,7 @@ public final class LoanApplicationTerms { this.interestRecalculationCompoundingMethod = interestRecalculationCompoundingMethod; this.restCalendarInstance = restCalendarInstance; this.recalculationFrequencyType = recalculationFrequencyType; + this.instalmentAmountInMultiplesOf = instalmentAmountInMultiplesOf; } public Money adjustPrincipalIfLastRepaymentPeriod(final Money principalForPeriod, final Money totalCumulativePrincipalToDate, @@ -508,15 +518,6 @@ public final class LoanApplicationTerms { return periodNumber == numberOfRepayments; } - private Money calculateTotalDueForEqualInstallmentLoan(final BigDecimal periodicInterestRate) { - - final int periodsElapsed = 0; - final double paymentPerRepaymentPeriod = paymentPerPeriod(periodicInterestRate, this.principal, periodsElapsed); - double totalRepayment = paymentPerRepaymentPeriod * this.numberOfRepayments; - - return Money.of(this.principal.getCurrency(), BigDecimal.valueOf(totalRepayment)); - } - /** * general method to calculate totalInterestDue discounting any grace * settings @@ -801,14 +802,21 @@ public final class LoanApplicationTerms { private double paymentPerPeriod(final BigDecimal periodicInterestRate, final Money balance, final int periodsElapsed) { - if (fixedEmiAmount != null) { return fixedEmiAmount.doubleValue(); } - final double futureValue = 0; - final double principalDouble = balance.getAmount().multiply(BigDecimal.valueOf(-1)).doubleValue(); + if (this.fixedEmiAmount == null) { + final double futureValue = 0; + final double principalDouble = balance.getAmount().multiply(BigDecimal.valueOf(-1)).doubleValue(); - final Integer periodsRemaining = this.numberOfRepayments - periodsElapsed; + final Integer periodsRemaining = this.numberOfRepayments - periodsElapsed; - return FinanicalFunctions.pmt(periodicInterestRate.doubleValue(), periodsRemaining.doubleValue(), principalDouble, futureValue, - false); + double installmentAmount = FinanicalFunctions.pmt(periodicInterestRate.doubleValue(), periodsRemaining.doubleValue(), + principalDouble, futureValue, false); + + if (this.instalmentAmountInMultiplesOf != null) { + installmentAmount = Money.roundToMultiplesOf(installmentAmount, this.instalmentAmountInMultiplesOf); + } + setFixedEmiAmount(BigDecimal.valueOf(installmentAmount)); + } + return this.fixedEmiAmount.doubleValue(); } private Money calculateDecliningInterestDueForInstallmentBeforeApplyingGrace(final PaymentPeriodsInOneYearCalculator calculator, @@ -1014,6 +1022,10 @@ public final class LoanApplicationTerms { this.fixedEmiAmount = fixedEmiAmount; } + public void resetFixedEmiAmount() { + this.fixedEmiAmount = this.actualFixedEmiAmount; + } + public LoanRescheduleStrategyMethod getLoanRescheduleStrategyMethod() { return LoanRescheduleStrategyMethod.REDUCE_EMI_AMOUNT; } 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 d877706dc..d96d7a853 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 @@ -249,6 +249,8 @@ public class LoanScheduleAssembler { final DaysInYearType daysInYearType = loanProduct.fetchDaysInYearType(); final boolean isInterestRecalculationEnabled = loanProduct.isInterestRecalculationEnabled(); + + final Integer instalmentAmountInMultiplesOf = loanProduct.getInstalmentAmountInMultiplesOf(); return LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentPeriodFrequencyType, nthDay, weekDayType, amortizationMethod, interestMethod, @@ -256,7 +258,7 @@ public class LoanScheduleAssembler { principalMoney, expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsToleranceMoney, loanProduct.isMultiDisburseLoan(), emiAmount, disbursementDatas, maxOutstandingBalance, loanVariationTermsData, - graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled); + graceOnArrearsAgeing, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, instalmentAmountInMultiplesOf); } private List fetchDisbursementData(final JsonObject command) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/service/LoanScheduleCalculationPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/service/LoanScheduleCalculationPlatformServiceImpl.java index f8942ddc1..dcda24532 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/service/LoanScheduleCalculationPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/loanschedule/service/LoanScheduleCalculationPlatformServiceImpl.java @@ -95,19 +95,19 @@ public class LoanScheduleCalculationPlatformServiceImpl implements LoanScheduleC * TODO: Vishwas, this is probably not required, test and remove the * same **/ + final Long productId = this.fromJsonHelper.extractLongNamed("productId", query.parsedJson()); + final LoanProduct loanProduct = this.loanProductRepository.findOne(productId); + if (loanProduct == null) { throw new LoanProductNotFoundException(productId); } + if (validateParams) { boolean isMeetingMandatoryForJLGLoans = configurationDomainService.isMeetingMandatoryForJLGLoans(); - this.loanApiJsonDeserializer.validateForCreate(query.json(), isMeetingMandatoryForJLGLoans); + this.loanApiJsonDeserializer.validateForCreate(query.json(), isMeetingMandatoryForJLGLoans, loanProduct); } this.fromApiJsonDeserializer.validate(query.json()); final List dataValidationErrors = new ArrayList<>(); final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan"); - final Long productId = this.fromJsonHelper.extractLongNamed("productId", query.parsedJson()); - final LoanProduct loanProduct = this.loanProductRepository.findOne(productId); - if (loanProduct == null) { throw new LoanProductNotFoundException(productId); } - if (loanProduct.useBorrowerCycle()) { final Long clientId = this.fromJsonHelper.extractLongNamed("clientId", query.parsedJson()); final Long groupId = this.fromJsonHelper.extractLongNamed("groupId", query.parsedJson()); 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 9cf83f342..9093805a6 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 @@ -21,6 +21,7 @@ import org.mifosplatform.infrastructure.core.data.ApiParameterError; import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; +import org.mifosplatform.infrastructure.core.exception.UnsupportedParameterException; import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; import org.mifosplatform.portfolio.accountdetails.domain.AccountType; import org.mifosplatform.portfolio.loanaccount.api.LoanApiConstants; @@ -78,7 +79,7 @@ public final class LoanApplicationCommandFromApiJsonHelper { this.apiJsonHelper = apiJsonHelper; } - public void validateForCreate(final String json, final boolean isMeetingMandatoryForJLGLoans) { + public void validateForCreate(final String json, final boolean isMeetingMandatoryForJLGLoans, final LoanProduct loanProduct) { if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } final Type typeOfMap = new TypeToken>() {}.getType(); @@ -362,6 +363,11 @@ public final class LoanApplicationCommandFromApiJsonHelper { } if (this.fromApiJsonHelper.parameterExists(LoanApiConstants.emiAmountParameterName, element)) { + if (!(loanProduct.canDefineInstalmentAmount() || loanProduct.isMultiDisburseLoan())) { + List unsupportedParameterList = new ArrayList<>(); + unsupportedParameterList.add(LoanApiConstants.emiAmountParameterName); + throw new UnsupportedParameterException(unsupportedParameterList); + } final BigDecimal emiAnount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(LoanApiConstants.emiAmountParameterName, element); baseDataValidator.reset().parameter(LoanApiConstants.emiAmountParameterName).value(emiAnount).ignoreIfNull().positiveAmount(); @@ -377,7 +383,7 @@ public final class LoanApplicationCommandFromApiJsonHelper { if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); } } - public void validateForModify(final String json) { + public void validateForModify(final String json, final LoanProduct loanProduct) { if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } final Type typeOfMap = new TypeToken>() {}.getType(); @@ -705,6 +711,11 @@ public final class LoanApplicationCommandFromApiJsonHelper { } if (this.fromApiJsonHelper.parameterExists(LoanApiConstants.emiAmountParameterName, element)) { + if (!(loanProduct.canDefineInstalmentAmount() || loanProduct.isMultiDisburseLoan())) { + List unsupportedParameterList = new ArrayList<>(); + unsupportedParameterList.add(LoanApiConstants.emiAmountParameterName); + throw new UnsupportedParameterException(unsupportedParameterList); + } final BigDecimal emiAnount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(LoanApiConstants.emiAmountParameterName, element); baseDataValidator.reset().parameter(LoanApiConstants.emiAmountParameterName).value(emiAnount).ignoreIfNull().positiveAmount(); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java index e754aedf7..90851f33a 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java @@ -193,15 +193,15 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa try { final AppUser currentUser = getAppUserIfPresent(); boolean isMeetingMandatoryForJLGLoans = configurationDomainService.isMeetingMandatoryForJLGLoans(); + final Long productId = this.fromJsonHelper.extractLongNamed("productId", command.parsedJson()); + final LoanProduct loanProduct = this.loanProductRepository.findOne(productId); + if (loanProduct == null) { throw new LoanProductNotFoundException(productId); } - this.fromApiJsonDeserializer.validateForCreate(command.json(), isMeetingMandatoryForJLGLoans); + this.fromApiJsonDeserializer.validateForCreate(command.json(), isMeetingMandatoryForJLGLoans, loanProduct); final List dataValidationErrors = new ArrayList<>(); final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan"); - final Long productId = this.fromJsonHelper.extractLongNamed("productId", command.parsedJson()); - final LoanProduct loanProduct = this.loanProductRepository.findOne(productId); - if (loanProduct == null) { throw new LoanProductNotFoundException(productId); } if (loanProduct.useBorrowerCycle()) { final Long clientId = this.fromJsonHelper.extractLongNamed("clientId", command.parsedJson()); final Long groupId = this.fromJsonHelper.extractLongNamed("groupId", command.parsedJson()); @@ -376,10 +376,9 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa try { AppUser currentUser = getAppUserIfPresent(); - - this.fromApiJsonDeserializer.validateForModify(command.json()); - final Loan existingLoanApplication = retrieveLoanBy(loanId); + this.fromApiJsonDeserializer.validateForModify(command.json(), existingLoanApplication.loanProduct()); + checkClientOrGroupActive(existingLoanApplication); if (!existingLoanApplication.isSubmittedAndPendingApproval()) { throw new LoanApplicationNotInSubmittedAndPendingApprovalStateCannotBeModified( diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanAssembler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanAssembler.java index 05b1b3652..59e2c512c 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanAssembler.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanAssembler.java @@ -159,8 +159,9 @@ public class LoanAssembler { final Long transactionProcessingStrategyId = this.fromApiJsonHelper.extractLongNamed("transactionProcessingStrategyId", element); final Long loanPurposeId = this.fromApiJsonHelper.extractLongNamed("loanPurposeId", element); final Boolean syncDisbursementWithMeeting = this.fromApiJsonHelper.extractBooleanNamed("syncDisbursementWithMeeting", element); - final Boolean createStandingInstructionAtDisbursement = this.fromApiJsonHelper.extractBooleanNamed("createStandingInstructionAtDisbursement", element); - + final Boolean createStandingInstructionAtDisbursement = this.fromApiJsonHelper.extractBooleanNamed( + "createStandingInstructionAtDisbursement", element); + final LoanProduct loanProduct = this.loanProductRepository.findOne(productId); if (loanProduct == null) { throw new LoanProductNotFoundException(productId); } @@ -198,11 +199,13 @@ public class LoanAssembler { final EnumOptionData loanType = AccountEnumerations.loanType(loanTypeStr); Set disbursementDetails = null; BigDecimal fixedEmiAmount = null; + if (loanProduct.isMultiDisburseLoan() || loanProduct.canDefineInstalmentAmount()) { + fixedEmiAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(LoanApiConstants.emiAmountParameterName, element); + } BigDecimal maxOutstandingLoanBalance = null; if (loanProduct.isMultiDisburseLoan()) { disbursementDetails = fetchDisbursementData(element.getAsJsonObject()); final Locale locale = this.fromApiJsonHelper.extractLocaleParameter(element.getAsJsonObject()); - fixedEmiAmount = this.fromApiJsonHelper.extractBigDecimalNamed(LoanApiConstants.emiAmountParameterName, element, locale); maxOutstandingLoanBalance = this.fromApiJsonHelper.extractBigDecimalNamed(LoanApiConstants.maxOutstandingBalanceParameterName, element, locale); if (disbursementDetails.isEmpty()) { @@ -234,14 +237,14 @@ public class LoanAssembler { loanApplication = Loan.newIndividualLoanApplicationFromGroup(accountNo, client, group, loanType.getId().intValue(), loanProduct, fund, loanOfficer, loanPurpose, loanTransactionProcessingStrategy, loanProductRelatedDetail, loanCharges, - collateral, syncDisbursementWithMeeting, fixedEmiAmount, disbursementDetails, maxOutstandingLoanBalance, + collateral, syncDisbursementWithMeeting, fixedEmiAmount, disbursementDetails, maxOutstandingLoanBalance, createStandingInstructionAtDisbursement); } else if (group != null) { loanApplication = Loan.newGroupLoanApplication(accountNo, group, loanType.getId().intValue(), loanProduct, fund, loanOfficer, loanPurpose, loanTransactionProcessingStrategy, loanProductRelatedDetail, loanCharges, collateral, - syncDisbursementWithMeeting, fixedEmiAmount, disbursementDetails, maxOutstandingLoanBalance, + syncDisbursementWithMeeting, fixedEmiAmount, disbursementDetails, maxOutstandingLoanBalance, createStandingInstructionAtDisbursement); } else if (client != null) { @@ -264,8 +267,9 @@ public class LoanAssembler { loanDisbursementDetails.updateLoan(loanApplication); } } - - final LocalDate recalculationRestFrequencyDate = this.fromApiJsonHelper.extractLocalDateNamed(LoanProductConstants.recalculationRestFrequencyDateParamName, element); + + final LocalDate recalculationRestFrequencyDate = this.fromApiJsonHelper.extractLocalDateNamed( + LoanProductConstants.recalculationRestFrequencyDateParamName, element); final LoanApplicationTerms loanApplicationTerms = this.loanScheduleAssembler.assembleLoanTerms(element); final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled(); 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 5c5f2f5f3..157ff6cf7 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 @@ -498,6 +498,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { + " l.loan_type_enum as loanType, l.loanpurpose_cv_id as loanPurposeId, cv.code_value as loanPurposeName," + " lp.id as loanProductId, lp.name as loanProductName, lp.description as loanProductDescription," + " lp.allow_multiple_disbursals as multiDisburseLoan," + + " lp.can_define_fixed_emi_amount as canDefineInstalmentAmount," + " c.id as clientId, c.display_name as clientName, c.office_id as clientOfficeId," + " g.id as groupId, g.display_name as groupName," + " g.office_id as groupOfficeId, g.staff_id As groupStaffId , g.parent_id as groupParentId, " @@ -627,6 +628,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { final String loanProductName = rs.getString("loanProductName"); final String loanProductDescription = rs.getString("loanProductDescription"); final Boolean multiDisburseLoan = rs.getBoolean("multiDisburseLoan"); + final Boolean canDefineInstalmentAmount = rs.getBoolean("canDefineInstalmentAmount"); final BigDecimal outstandingLoanBalance = rs.getBigDecimal("outstandingLoanBalance"); final LocalDate submittedOnDate = JdbcSupport.getLocalDate(rs, "submittedOnDate"); @@ -832,9 +834,9 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { amortizationType, interestRatePerPeriod, interestRateFrequencyType, annualInterestRate, interestType, interestCalculationPeriodType, expectedFirstRepaymentOnDate, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, timeline, loanSummary, feeChargesDueAtDisbursementCharged, - syncDisbursementWithMeeting, loanCounter, loanProductCounter, multiDisburseLoan, fixedEmiAmount, - outstandingLoanBalance, inArrears, graceOnArrearsAgeing, isNPA, daysInMonthType, daysInYearType, - isInterestRecalculationEnabled, interestRecalculationData, createStandingInstructionAtDisbursement); + syncDisbursementWithMeeting, loanCounter, loanProductCounter, multiDisburseLoan, canDefineInstalmentAmount, + fixedEmiAmount, outstandingLoanBalance, inArrears, graceOnArrearsAgeing, isNPA, daysInMonthType, + daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, createStandingInstructionAtDisbursement); } } 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 59a85aa99..70185ceb7 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 @@ -78,4 +78,8 @@ public interface LoanProductConstants { public static final String minimumGuaranteeFromOwnFundsParamName = "minimumGuaranteeFromOwnFunds"; public static final String minimumGuaranteeFromGuarantorParamName = "minimumGuaranteeFromGuarantor"; + // Fixed installment configuration related + public static final String canDefineEmiAmountParamName = "canDefineInstalmentAmount"; + public static final String instalmentAmountInMultiplesOfParamName = "instalmentAmountInMultiplesOf"; + } 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 8d2d27f1c..0d2f05809 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 @@ -84,6 +84,8 @@ public class LoanProductData { private final boolean isInterestRecalculationEnabled; private final LoanProductInterestRecalculationData interestRecalculationData; private final Integer minimumDaysBetweenDisbursalAndFirstRepayment; + private final boolean canDefineInstalmentAmount; + private final Integer instalmentAmountInMultiplesOf; // charges private final Collection charges; @@ -193,6 +195,8 @@ public class LoanProductData { final boolean isInterestRecalculationEnabled = false; final LoanProductInterestRecalculationData interestRecalculationData = null; final Integer minimumDaysBetweenDisbursalAndFirstRepayment = null; + final boolean canDefineInstalmentAmount = false; + final Integer instalmentAmountInMultiplesOf = null; return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, @@ -202,7 +206,8 @@ public class LoanProductData { accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, externalId, principalVariations, interestRateVariations, numberOfRepaymentVariations, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance, graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, - interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, productGuaranteeData); + interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, productGuaranteeData, + canDefineInstalmentAmount, instalmentAmountInMultiplesOf); } public static LoanProductData lookupWithCurrency(final Long id, final String name, final CurrencyData currency) { @@ -258,6 +263,8 @@ public class LoanProductData { final Integer minimumDaysBetweenDisbursalAndFirstRepayment = null; final Boolean holdGuaranteeFunds = false; final LoanProductGuaranteeData productGuaranteeData = null; + final boolean canDefineInstalmentAmount = false; + final Integer instalmentAmountInMultiplesOf = null; return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, @@ -267,7 +274,8 @@ public class LoanProductData { accountingType, includeInBorrowerCycle, useBorrowerCycle, startDate, closeDate, status, externalId, principalVariations, interestRateVariations, numberOfRepaymentVariations, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance, graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, - interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, productGuaranteeData); + interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, productGuaranteeData, + canDefineInstalmentAmount, instalmentAmountInMultiplesOf); } public static LoanProductData sensibleDefaultsForNewLoanProductCreation() { @@ -330,6 +338,8 @@ public class LoanProductData { final Integer minimumDaysBetweenDisbursalAndFirstRepayment = null; final Boolean holdGuaranteeFunds = false; final LoanProductGuaranteeData productGuaranteeData = null; + final boolean canDefineInstalmentAmount = false; + final Integer instalmentAmountInMultiplesOf = null; return new LoanProductData(id, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, tolerance, numberOfRepayments, minNumberOfRepayments, maxNumberOfRepayments, repaymentEvery, interestRatePerPeriod, @@ -340,7 +350,7 @@ public class LoanProductData { principalVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle, numberOfRepaymentVariationsForBorrowerCycle, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance, graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, - holdGuaranteeFunds, productGuaranteeData); + holdGuaranteeFunds, productGuaranteeData, canDefineInstalmentAmount, instalmentAmountInMultiplesOf); } public static LoanProductData withAccountingDetails(final LoanProductData productData, final Map accountingMappings, @@ -372,7 +382,7 @@ public class LoanProductData { final Integer overdueDaysForNPA, final EnumOptionData daysInMonthType, final EnumOptionData daysInYearType, final boolean isInterestRecalculationEnabled, final LoanProductInterestRecalculationData interestRecalculationData, final Integer minimumDaysBetweenDisbursalAndFirstRepayment, boolean holdGuaranteeFunds, - LoanProductGuaranteeData loanProductGuaranteeData) { + LoanProductGuaranteeData loanProductGuaranteeData, boolean canDefineInstalmentAmount, Integer instalmentAmountInMultiplesOf) { this.id = id; this.name = name; this.shortName = shortName; @@ -452,6 +462,9 @@ public class LoanProductData { this.rescheduleStrategyTypeOptions = null; this.interestRecalculationFrequencyTypeOptions = null; + this.canDefineInstalmentAmount = canDefineInstalmentAmount; + this.instalmentAmountInMultiplesOf = instalmentAmountInMultiplesOf; + } public LoanProductData(final LoanProductData productData, final Collection chargeOptions, @@ -560,6 +573,8 @@ public class LoanProductData { this.interestRecalculationFrequencyTypeOptions = interestRecalculationFrequencyTypeOptions; } + this.canDefineInstalmentAmount = productData.canDefineInstalmentAmount; + this.instalmentAmountInMultiplesOf = productData.instalmentAmountInMultiplesOf; } private Collection nullIfEmpty(final Collection charges) { @@ -809,4 +824,8 @@ public class LoanProductData { if (isInterestRecalculationEnabled()) { return this.interestRecalculationData.getRecalculationRestFrequencyInterval(); } return null; } + + public boolean canDefineInstalmentAmount() { + return this.canDefineInstalmentAmount; + } } \ 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 2e49759cc..d0a862906 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 @@ -136,6 +136,12 @@ public class LoanProduct extends AbstractPersistable { @OneToOne(cascade = CascadeType.ALL, mappedBy = "loanProduct", optional = true, orphanRemoval = true) private LoanProductGuaranteeDetails loanProductGuaranteeDetails; + @Column(name = "can_define_fixed_emi_amount") + private boolean canDefineInstalmentAmount; + + @Column(name = "instalment_amount_in_multiples_of", nullable = true) + private Integer instalmentAmountInMultiplesOf; + public static LoanProduct assembleFromJson(final Fund fund, final LoanTransactionProcessingStrategy loanTransactionProcessingStrategy, final List productCharges, final JsonCommand command, final AprCalculator aprCalculator) { @@ -225,6 +231,10 @@ public class LoanProduct extends AbstractPersistable { loanProductGuaranteeDetails = LoanProductGuaranteeDetails.createFrom(command); } + final boolean canDefineEmiAmount = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.canDefineEmiAmountParamName); + final Integer instalmentAmountInMultiplesOf = command + .integerValueOfParameterNamed(LoanProductConstants.instalmentAmountInMultiplesOfParamName); + return new LoanProduct(fund, loanTransactionProcessingStrategy, name, shortName, description, currency, principal, minPrincipal, maxPrincipal, interestRatePerPeriod, minInterestRatePerPeriod, maxInterestRatePerPeriod, interestFrequencyType, annualInterestRate, interestMethod, interestCalculationPeriodMethod, repaymentEvery, repaymentFrequencyType, @@ -233,7 +243,7 @@ public class LoanProduct extends AbstractPersistable { startDate, closeDate, externalId, useBorrowerCycle, loanProductBorrowerCycleVariations, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance, graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, interestRecalculationSettings, minimumDaysBetweenDisbursalAndFirstRepayment, - holdGuarantorFunds, loanProductGuaranteeDetails); + holdGuarantorFunds, loanProductGuaranteeDetails, canDefineEmiAmount, instalmentAmountInMultiplesOf); } @@ -458,7 +468,8 @@ public class LoanProduct extends AbstractPersistable { final boolean isInterestRecalculationEnabled, final LoanProductInterestRecalculationDetails productInterestRecalculationDetails, final Integer minimumDaysBetweenDisbursalAndFirstRepayment, final boolean holdGuarantorFunds, - final LoanProductGuaranteeDetails loanProductGuaranteeDetails) { + final LoanProductGuaranteeDetails loanProductGuaranteeDetails, final boolean canDefineEmiAmount, + final Integer instalmentAmountInMultiplesOf) { this.fund = fund; this.transactionProcessingStrategy = transactionProcessingStrategy; this.name = name.trim(); @@ -510,6 +521,8 @@ public class LoanProduct extends AbstractPersistable { this.minimumDaysBetweenDisbursalAndFirstRepayment = minimumDaysBetweenDisbursalAndFirstRepayment; this.holdGuaranteeFunds = holdGuarantorFunds; this.loanProductGuaranteeDetails = loanProductGuaranteeDetails; + this.canDefineInstalmentAmount = canDefineEmiAmount; + this.instalmentAmountInMultiplesOf = instalmentAmountInMultiplesOf; } public MonetaryCurrency getCurrency() { @@ -737,6 +750,20 @@ public class LoanProduct extends AbstractPersistable { this.loanProductGuaranteeDetails.update(command, actualChanges); } + if (command.isChangeInBooleanParameterNamed(LoanProductConstants.canDefineEmiAmountParamName, this.canDefineInstalmentAmount)) { + final boolean newValue = command.booleanPrimitiveValueOfParameterNamed(LoanProductConstants.canDefineEmiAmountParamName); + actualChanges.put(LoanProductConstants.canDefineEmiAmountParamName, newValue); + this.canDefineInstalmentAmount = newValue; + } + + if (command.isChangeInIntegerParameterNamedWithNullCheck(LoanProductConstants.instalmentAmountInMultiplesOfParamName, + this.instalmentAmountInMultiplesOf)) { + final Integer newValue = command.integerValueOfParameterNamed(LoanProductConstants.instalmentAmountInMultiplesOfParamName); + actualChanges.put(LoanProductConstants.instalmentAmountInMultiplesOfParamName, newValue); + actualChanges.put("locale", localeAsInput); + this.instalmentAmountInMultiplesOf = newValue; + } + return actualChanges; } @@ -989,4 +1016,12 @@ public class LoanProduct extends AbstractPersistable { return this.shortName; } + public boolean canDefineInstalmentAmount() { + return this.canDefineInstalmentAmount; + } + + public Integer getInstalmentAmountInMultiplesOf() { + return this.instalmentAmountInMultiplesOf; + } + } \ 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 a4815145d..55b198e0b 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 @@ -73,7 +73,8 @@ public final class LoanProductDataValidator { LoanProductConstants.recalculationRestFrequencyTypeParameterName, LoanProductConstants.minimumDaysBetweenDisbursalAndFirstRepayment, LoanProductConstants.mandatoryGuaranteeParamName, LoanProductConstants.holdGuaranteeFundsParamName, LoanProductConstants.minimumGuaranteeFromGuarantorParamName, - LoanProductConstants.minimumGuaranteeFromOwnFundsParamName)); + LoanProductConstants.minimumGuaranteeFromOwnFundsParamName, LoanProductConstants.canDefineEmiAmountParamName, + LoanProductConstants.instalmentAmountInMultiplesOfParamName)); private final FromJsonHelper fromApiJsonHelper; @@ -325,6 +326,20 @@ public final class LoanProductDataValidator { } } + if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.canDefineEmiAmountParamName, element)) { + final Boolean canDefineInstalmentAmount = this.fromApiJsonHelper.extractBooleanNamed( + LoanProductConstants.canDefineEmiAmountParamName, element); + baseDataValidator.reset().parameter(LoanProductConstants.canDefineEmiAmountParamName).value(canDefineInstalmentAmount) + .isOneOfTheseValues(true, false); + } + + if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.instalmentAmountInMultiplesOfParamName, element)) { + final Integer instalmentAmountInMultiplesOf = this.fromApiJsonHelper.extractIntegerWithLocaleNamed( + LoanProductConstants.instalmentAmountInMultiplesOfParamName, element); + baseDataValidator.reset().parameter(LoanProductConstants.instalmentAmountInMultiplesOfParamName) + .value(instalmentAmountInMultiplesOf).ignoreIfNull().integerGreaterThanZero(); + } + // accounting related data validation final Integer accountingRuleType = this.fromApiJsonHelper.extractIntegerNamed("accountingRule", element, Locale.getDefault()); baseDataValidator.reset().parameter("accountingRule").value(accountingRuleType).notNull().inMinMaxRange(1, 4); @@ -748,6 +763,20 @@ public final class LoanProductDataValidator { } } + if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.canDefineEmiAmountParamName, element)) { + final Boolean canDefineInstalmentAmount = this.fromApiJsonHelper.extractBooleanNamed( + LoanProductConstants.canDefineEmiAmountParamName, element); + baseDataValidator.reset().parameter(LoanProductConstants.canDefineEmiAmountParamName).value(canDefineInstalmentAmount) + .isOneOfTheseValues(true, false); + } + + if (this.fromApiJsonHelper.parameterExists(LoanProductConstants.instalmentAmountInMultiplesOfParamName, element)) { + final Integer instalmentAmountInMultiplesOf = this.fromApiJsonHelper.extractIntegerWithLocaleNamed( + LoanProductConstants.instalmentAmountInMultiplesOfParamName, element); + baseDataValidator.reset().parameter(LoanProductConstants.instalmentAmountInMultiplesOfParamName) + .value(instalmentAmountInMultiplesOf).ignoreIfNull().integerGreaterThanZero(); + } + final Integer accountingRuleType = this.fromApiJsonHelper.extractIntegerNamed("accountingRule", element, Locale.getDefault()); baseDataValidator.reset().parameter("accountingRule").value(accountingRuleType).ignoreIfNull().inMinMaxRange(1, 4); 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 f6d36339c..a6d76daea 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 @@ -126,6 +126,7 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo + "lp.accounting_type as accountingType, lp.include_in_borrower_cycle as includeInBorrowerCycle,lp.use_borrower_cycle as useBorrowerCycle, lp.start_date as startDate, lp.close_date as closeDate, " + "lp.allow_multiple_disbursals as multiDisburseLoan, lp.max_disbursals as maxTrancheCount, lp.max_outstanding_loan_balance as outstandingLoanBalance, " + "lp.days_in_month_enum as daysInMonth, lp.days_in_year_enum as daysInYear, lp.interest_recalculation_enabled as isInterestRecalculationEnabled, " + + "lp.can_define_fixed_emi_amount as canDefineInstalmentAmount, lp.instalment_amount_in_multiples_of as instalmentAmountInMultiplesOf, " + "lpr.id as lprId, lpr.product_id as productId, lpr.compound_type_enum as compoundType, lpr.reschedule_strategy_enum as rescheduleStrategy, " + "lpr.rest_frequency_type_enum as restFrequencyEnum, lpr.rest_frequency_interval as restFrequencyInterval, " + "lpr.rest_freqency_date as restFrequencyDate, " @@ -240,6 +241,8 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo final EnumOptionData daysInMonthType = CommonEnumerations.daysInMonthType(daysInMonth); final int daysInYear = JdbcSupport.getInteger(rs, "daysInYear"); final EnumOptionData daysInYearType = CommonEnumerations.daysInYearType(daysInYear); + final Integer instalmentAmountInMultiplesOf = JdbcSupport.getInteger(rs, "instalmentAmountInMultiplesOf"); + final boolean canDefineInstalmentAmount = rs.getBoolean("canDefineInstalmentAmount"); final boolean isInterestRecalculationEnabled = rs.getBoolean("isInterestRecalculationEnabled"); LoanProductInterestRecalculationData interestRecalculationData = null; @@ -282,7 +285,8 @@ public class LoanProductReadPlatformServiceImpl implements LoanProductReadPlatfo closeDate, status, externalId, principalVariationsForBorrowerCycle, interestRateVariationsForBorrowerCycle, numberOfRepaymentVariationsForBorrowerCycle, multiDisburseLoan, maxTrancheCount, outstandingLoanBalance, graceOnArrearsAgeing, overdueDaysForNPA, daysInMonthType, daysInYearType, isInterestRecalculationEnabled, - interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, loanProductGuaranteeData); + interestRecalculationData, minimumDaysBetweenDisbursalAndFirstRepayment, holdGuaranteeFunds, loanProductGuaranteeData, + canDefineInstalmentAmount, instalmentAmountInMultiplesOf); } } diff --git a/mifosng-provider/src/main/resources/sql/migrations/core_db/V227__fixed_emi_changes.sql b/mifosng-provider/src/main/resources/sql/migrations/core_db/V227__fixed_emi_changes.sql new file mode 100755 index 000000000..b36a04f7c --- /dev/null +++ b/mifosng-provider/src/main/resources/sql/migrations/core_db/V227__fixed_emi_changes.sql @@ -0,0 +1,3 @@ +ALTER TABLE `m_product_loan` + ADD COLUMN `can_define_fixed_emi_amount` TINYINT(1) NOT NULL DEFAULT '0', + ADD COLUMN `instalment_amount_in_multiples_of` DECIMAL(19,6) NULL DEFAULT NULL; \ No newline at end of file From 0182be4cf92e282b90dac054ff8bcfeccee64f08 Mon Sep 17 00:00:00 2001 From: bharathc27 Date: Fri, 30 Jan 2015 11:11:37 +0530 Subject: [PATCH 2/2] MIFOSX: client/group loan testcases fixed --- .../ClientLoanIntegrationTest.java | 208 +++++++++--------- .../GroupLoanIntegrationTest.java | 6 +- ...hanges.sql => V250__fixed_emi_changes.sql} | 0 3 files changed, 107 insertions(+), 107 deletions(-) rename mifosng-provider/src/main/resources/sql/migrations/core_db/{V227__fixed_emi_changes.sql => V250__fixed_emi_changes.sql} (100%) mode change 100755 => 100644 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 98126146c..88cf53041 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ClientLoanIntegrationTest.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ClientLoanIntegrationTest.java @@ -1002,16 +1002,16 @@ public class ClientLoanIntegrationTest { assertEquals("Checking for Due Date for 2nd Month", new ArrayList<>(Arrays.asList(2011, 11, 20)), loanSchedule.get(2) .get("dueDate")); - assertEquals("Checking for Principal Due for 2nd Month", new Float("2969.71"), loanSchedule.get(2).get("principalDue")); + assertEquals("Checking for Principal Due for 2nd Month", new Float("2969.72"), loanSchedule.get(2).get("principalDue")); assertEquals("Checking for Interest Due for 2nd Month", new Float("181.77"), loanSchedule.get(2).get("interestOriginalDue")); assertEquals("Checking for Due Date for 3rd Month", new ArrayList<>(Arrays.asList(2011, 12, 20)), loanSchedule.get(3) .get("dueDate")); - assertEquals("Checking for Principal Due for 3rd Month", new Float("3029.1"), loanSchedule.get(3).get("principalDue")); + assertEquals("Checking for Principal Due for 3rd Month", new Float("3029.11"), loanSchedule.get(3).get("principalDue")); assertEquals("Checking for Interest Due for 3rd Month", new Float("122.38"), loanSchedule.get(3).get("interestOriginalDue")); assertEquals("Checking for Due Date for 4th Month", new ArrayList<>(Arrays.asList(2012, 1, 20)), loanSchedule.get(4).get("dueDate")); - assertEquals("Checking for Principal Due for 4th Month", new Float("3089.7"), loanSchedule.get(4).get("principalDue")); + assertEquals("Checking for Principal Due for 4th Month", new Float("3089.68"), loanSchedule.get(4).get("principalDue")); assertEquals("Checking for Interest Due for 4th Month", new Float("61.79"), loanSchedule.get(4).get("interestOriginalDue")); } @@ -1269,9 +1269,9 @@ public class ClientLoanIntegrationTest { validateCharge(flatInstallmentFee, loanCharges, "50", "100.00", "50.0", "50.0"); System.out.println("----------Make repayment 2------------"); - this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3251.48"), loanID); + this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3251.49"), loanID); this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011", - new JournalEntry(Float.valueOf("3251.48"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("2969.71"), + new JournalEntry(Float.valueOf("3251.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("2969.72"), JournalEntry.TransactionType.CREDIT)); this.journalEntryHelper.checkJournalEntryForIncomeAccount(incomeAccount, "20 November 2011", new JournalEntry(Float.valueOf("100.00"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("181.77"), @@ -1309,9 +1309,9 @@ public class ClientLoanIntegrationTest { JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("240"), JournalEntry.TransactionType.CREDIT)); System.out.println("----------Make repayment 3 advance------------"); - this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3301.48"), loanID); + this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3301.49"), loanID); this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011", - new JournalEntry(Float.valueOf("3301.48"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3129.1"), + new JournalEntry(Float.valueOf("3301.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3129.11"), JournalEntry.TransactionType.CREDIT)); this.journalEntryHelper.checkJournalEntryForIncomeAccount(incomeAccount, "20 November 2011", new JournalEntry(Float.valueOf("50.00"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("122.38"), @@ -1322,7 +1322,7 @@ public class ClientLoanIntegrationTest { loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID); HashMap fourthInstallment = loanSchedule.get(4); validateNumberForEqual("100", String.valueOf(fourthInstallment.get("penaltyChargesOutstanding"))); - validateNumberForEqual("3239.70", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); + validateNumberForEqual("3239.68", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); System.out.println("----------Pay applied penalty ------------"); this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("100"), loanID); @@ -1334,12 +1334,12 @@ public class ClientLoanIntegrationTest { loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID); fourthInstallment = loanSchedule.get(4); validateNumberForEqual("0", String.valueOf(fourthInstallment.get("penaltyChargesOutstanding"))); - validateNumberForEqual("3139.70", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); + validateNumberForEqual("3139.68", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); System.out.println("----------Make repayment 4 ------------"); - this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("3139.70"), loanID); + this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("3139.68"), loanID); this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 January 2012", new JournalEntry( - Float.valueOf("3139.70"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3089.70"), + Float.valueOf("3139.68"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3089.68"), JournalEntry.TransactionType.CREDIT)); this.journalEntryHelper.checkJournalEntryForIncomeAccount(incomeAccount, "20 January 2012", new JournalEntry( Float.valueOf("50.00"), JournalEntry.TransactionType.CREDIT)); @@ -1448,9 +1448,9 @@ public class ClientLoanIntegrationTest { validateCharge(percentageInstallmentFee, loanCharges, "1", "61.19", "29.11", "29.70"); System.out.println("----------Make repayment 2------------"); - this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3271.48"), loanID); + this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3271.49"), loanID); this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011", - new JournalEntry(Float.valueOf("3271.48"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("2969.71"), + new JournalEntry(Float.valueOf("3271.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("2969.72"), JournalEntry.TransactionType.CREDIT)); this.journalEntryHelper.checkJournalEntryForIncomeAccount(incomeAccount, "20 November 2011", new JournalEntry(Float.valueOf("120.00"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("181.77"), @@ -1488,9 +1488,9 @@ public class ClientLoanIntegrationTest { JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("240"), JournalEntry.TransactionType.CREDIT)); System.out.println("----------Make repayment 3 advance------------"); - this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3301.77"), loanID); + this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3301.78"), loanID); this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011", - new JournalEntry(Float.valueOf("3301.77"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3149.10"), + new JournalEntry(Float.valueOf("3301.78"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3149.11"), JournalEntry.TransactionType.CREDIT)); this.journalEntryHelper.checkJournalEntryForIncomeAccount(incomeAccount, "20 November 2011", new JournalEntry(Float.valueOf("30.29"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("122.38"), @@ -1501,7 +1501,7 @@ public class ClientLoanIntegrationTest { loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID); HashMap fourthInstallment = loanSchedule.get(4); validateNumberForEqual("120", String.valueOf(fourthInstallment.get("penaltyChargesOutstanding"))); - validateNumberForEqual("3240.60", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); + validateNumberForEqual("3240.58", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); System.out.println("----------Pay applied penalty ------------"); this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("120"), loanID); @@ -1513,12 +1513,12 @@ public class ClientLoanIntegrationTest { loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID); fourthInstallment = loanSchedule.get(4); validateNumberForEqual("0", String.valueOf(fourthInstallment.get("penaltyChargesOutstanding"))); - validateNumberForEqual("3120.60", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); + validateNumberForEqual("3120.58", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); System.out.println("----------Make repayment 4 ------------"); - this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("3120.60"), loanID); + this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("3120.58"), loanID); this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 January 2012", new JournalEntry( - Float.valueOf("3120.60"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3089.70"), + Float.valueOf("3120.58"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3089.68"), JournalEntry.TransactionType.CREDIT)); this.journalEntryHelper.checkJournalEntryForIncomeAccount(incomeAccount, "20 January 2012", new JournalEntry( Float.valueOf("30.90"), JournalEntry.TransactionType.CREDIT)); @@ -1631,9 +1631,9 @@ public class ClientLoanIntegrationTest { validateCharge(amountPlusInterestPercentageInstallmentFee, loanCharges, "1", "63.02", "31.51", "31.51"); System.out.println("----------Make repayment 2------------"); - this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3277.54"), loanID); + this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3277.55"), loanID); this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011", - new JournalEntry(Float.valueOf("3277.54"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("2969.71"), + new JournalEntry(Float.valueOf("3277.55"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("2969.72"), JournalEntry.TransactionType.CREDIT)); this.journalEntryHelper.checkJournalEntryForIncomeAccount(incomeAccount, "20 November 2011", new JournalEntry(Float.valueOf("126.06"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("181.77"), @@ -1673,9 +1673,9 @@ public class ClientLoanIntegrationTest { JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("240"), JournalEntry.TransactionType.CREDIT)); System.out.println("----------Make repayment 3 advance------------"); - this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3302.99"), loanID); + this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3303"), loanID); this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011", - new JournalEntry(Float.valueOf("3302.99"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3149.10"), + new JournalEntry(Float.valueOf("3303"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3149.11"), JournalEntry.TransactionType.CREDIT)); this.journalEntryHelper.checkJournalEntryForIncomeAccount(incomeAccount, "20 November 2011", new JournalEntry(Float.valueOf("31.51"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("122.38"), @@ -1688,7 +1688,7 @@ public class ClientLoanIntegrationTest { loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID); HashMap fourthInstallment = loanSchedule.get(4); validateNumberForEqual("120", String.valueOf(fourthInstallment.get("penaltyChargesOutstanding"))); - validateNumberForEqual("3241.21", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); + validateNumberForEqual("3241.19", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); System.out.println("----------Pay applied penalty ------------"); this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("120"), loanID); @@ -1700,12 +1700,12 @@ public class ClientLoanIntegrationTest { loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID); fourthInstallment = loanSchedule.get(4); validateNumberForEqual("0", String.valueOf(fourthInstallment.get("penaltyChargesOutstanding"))); - validateNumberForEqual("3121.21", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); + validateNumberForEqual("3121.19", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); System.out.println("----------Make repayment 4 ------------"); - this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("3121.21"), loanID); + this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("3121.19"), loanID); this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 January 2012", new JournalEntry( - Float.valueOf("3121.21"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3089.70"), + Float.valueOf("3121.19"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("3089.68"), JournalEntry.TransactionType.CREDIT)); this.journalEntryHelper.checkJournalEntryForIncomeAccount(incomeAccount, "20 January 2012", new JournalEntry( Float.valueOf("31.51"), JournalEntry.TransactionType.CREDIT)); @@ -1830,11 +1830,11 @@ public class ClientLoanIntegrationTest { new JournalEntry(Float.valueOf("50.0"), JournalEntry.TransactionType.DEBIT)); System.out.println("----------Make repayment 2------------"); - this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3251.48"), loanID); + this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3251.49"), loanID); this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011", - new JournalEntry(Float.valueOf("3251.48"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("100"), + new JournalEntry(Float.valueOf("3251.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("100"), JournalEntry.TransactionType.CREDIT), - new JournalEntry(Float.valueOf("181.77"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2969.71"), + new JournalEntry(Float.valueOf("181.77"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2969.72"), JournalEntry.TransactionType.CREDIT)); loanSchedule.clear(); @@ -1876,11 +1876,11 @@ public class ClientLoanIntegrationTest { JournalEntry.TransactionType.CREDIT)); System.out.println("----------Make repayment 3 advance------------"); - this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3301.48"), loanID); + this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3301.49"), loanID); this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011", - new JournalEntry(Float.valueOf("3301.48"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("50.00"), + new JournalEntry(Float.valueOf("3301.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("50.00"), JournalEntry.TransactionType.CREDIT), - new JournalEntry(Float.valueOf("122.38"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3129.10"), + new JournalEntry(Float.valueOf("122.38"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3129.11"), JournalEntry.TransactionType.CREDIT)); this.loanTransactionHelper.addChargesForLoan(loanID, LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON( String.valueOf(flatPenaltySpecifiedDueDate), "10 January 2012", "100")); @@ -1888,7 +1888,7 @@ public class ClientLoanIntegrationTest { loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID); HashMap fourthInstallment = loanSchedule.get(4); validateNumberForEqual("100", String.valueOf(fourthInstallment.get("penaltyChargesOutstanding"))); - validateNumberForEqual("3239.70", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); + validateNumberForEqual("3239.68", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); System.out.println("----------Pay applied penalty ------------"); this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("100"), loanID); @@ -1898,13 +1898,13 @@ public class ClientLoanIntegrationTest { loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID); fourthInstallment = loanSchedule.get(4); validateNumberForEqual("0", String.valueOf(fourthInstallment.get("penaltyChargesOutstanding"))); - validateNumberForEqual("3139.70", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); + validateNumberForEqual("3139.68", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); System.out.println("----------Make over payment for repayment 4 ------------"); this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("3220.60"), loanID); this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 January 2012", new JournalEntry( - Float.valueOf("3139.70"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("50.00"), - JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3089.70"), JournalEntry.TransactionType.CREDIT)); + Float.valueOf("3139.68"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("50.00"), + JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3089.68"), JournalEntry.TransactionType.CREDIT)); loanStatusHashMap = (HashMap) this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, loanID, "status"); LoanStatusChecker.verifyLoanAccountIsOverPaid(loanStatusHashMap); } @@ -2024,11 +2024,11 @@ public class ClientLoanIntegrationTest { new JournalEntry(Float.valueOf("29.7"), JournalEntry.TransactionType.DEBIT)); System.out.println("----------Make repayment 2------------"); - this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3271.48"), loanID); + this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3271.49"), loanID); this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011", - new JournalEntry(Float.valueOf("3271.48"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("120"), + new JournalEntry(Float.valueOf("3271.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("120"), JournalEntry.TransactionType.CREDIT), - new JournalEntry(Float.valueOf("181.77"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2969.71"), + new JournalEntry(Float.valueOf("181.77"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2969.72"), JournalEntry.TransactionType.CREDIT)); loanSchedule.clear(); @@ -2070,11 +2070,11 @@ public class ClientLoanIntegrationTest { JournalEntry.TransactionType.CREDIT)); System.out.println("----------Make repayment 3 advance------------"); - this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3301.77"), loanID); + this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3301.78"), loanID); this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011", - new JournalEntry(Float.valueOf("3301.77"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("30.29"), + new JournalEntry(Float.valueOf("3301.78"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("30.29"), JournalEntry.TransactionType.CREDIT), - new JournalEntry(Float.valueOf("122.38"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3149.10"), + new JournalEntry(Float.valueOf("122.38"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3149.11"), JournalEntry.TransactionType.CREDIT)); this.loanTransactionHelper.addChargesForLoan(loanID, LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON( String.valueOf(percentagePenaltySpecifiedDueDate), "10 January 2012", "1")); @@ -2082,7 +2082,7 @@ public class ClientLoanIntegrationTest { loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID); HashMap fourthInstallment = loanSchedule.get(4); validateNumberForEqual("120", String.valueOf(fourthInstallment.get("penaltyChargesOutstanding"))); - validateNumberForEqual("3240.60", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); + validateNumberForEqual("3240.58", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); System.out.println("----------Pay applied penalty ------------"); this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("120"), loanID); @@ -2092,13 +2092,13 @@ public class ClientLoanIntegrationTest { loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID); fourthInstallment = loanSchedule.get(4); validateNumberForEqual("0", String.valueOf(fourthInstallment.get("penaltyChargesOutstanding"))); - validateNumberForEqual("3120.60", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); + validateNumberForEqual("3120.58", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); System.out.println("----------Make over payment for repayment 4 ------------"); - this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("3220.60"), loanID); + this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("3220.58"), loanID); this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 January 2012", new JournalEntry( - Float.valueOf("3120.60"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("30.90"), - JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3089.70"), JournalEntry.TransactionType.CREDIT)); + Float.valueOf("3120.58"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("30.90"), + JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3089.68"), JournalEntry.TransactionType.CREDIT)); loanStatusHashMap = (HashMap) this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, loanID, "status"); LoanStatusChecker.verifyLoanAccountIsOverPaid(loanStatusHashMap); } @@ -2230,11 +2230,11 @@ public class ClientLoanIntegrationTest { new JournalEntry(Float.valueOf("31.51"), JournalEntry.TransactionType.DEBIT)); System.out.println("----------Make repayment 2------------"); - this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3277.54"), loanID); + this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3277.55"), loanID); this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011", - new JournalEntry(Float.valueOf("3277.54"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("126.06"), + new JournalEntry(Float.valueOf("3277.55"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("126.06"), JournalEntry.TransactionType.CREDIT), - new JournalEntry(Float.valueOf("181.77"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2969.71"), + new JournalEntry(Float.valueOf("181.77"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2969.72"), JournalEntry.TransactionType.CREDIT)); loanSchedule.clear(); @@ -2278,11 +2278,11 @@ public class ClientLoanIntegrationTest { JournalEntry.TransactionType.CREDIT)); System.out.println("----------Make repayment 3 advance------------"); - this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3302.99"), loanID); + this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3303"), loanID); this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011", - new JournalEntry(Float.valueOf("3302.99"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("31.51"), + new JournalEntry(Float.valueOf("3303"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("31.51"), JournalEntry.TransactionType.CREDIT), - new JournalEntry(Float.valueOf("122.38"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3149.10"), + new JournalEntry(Float.valueOf("122.38"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3149.11"), JournalEntry.TransactionType.CREDIT)); this.loanTransactionHelper.addChargesForLoan( loanID, @@ -2292,7 +2292,7 @@ public class ClientLoanIntegrationTest { loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID); HashMap fourthInstallment = loanSchedule.get(4); validateNumberForEqual("120", String.valueOf(fourthInstallment.get("penaltyChargesOutstanding"))); - validateNumberForEqual("3241.21", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); + validateNumberForEqual("3241.19", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); System.out.println("----------Pay applied penalty ------------"); this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("120"), loanID); @@ -2302,13 +2302,13 @@ public class ClientLoanIntegrationTest { loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID); fourthInstallment = loanSchedule.get(4); validateNumberForEqual("0", String.valueOf(fourthInstallment.get("penaltyChargesOutstanding"))); - validateNumberForEqual("3121.21", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); + validateNumberForEqual("3121.19", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); System.out.println("----------Make over payment for repayment 4 ------------"); this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("3221.61"), loanID); this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 January 2012", new JournalEntry( - Float.valueOf("3121.21"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("31.51"), - JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3089.70"), JournalEntry.TransactionType.CREDIT)); + Float.valueOf("3121.19"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("31.51"), + JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3089.68"), JournalEntry.TransactionType.CREDIT)); loanStatusHashMap = (HashMap) this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, loanID, "status"); LoanStatusChecker.verifyLoanAccountIsOverPaid(loanStatusHashMap); } @@ -2435,11 +2435,11 @@ public class ClientLoanIntegrationTest { checkAccrualTransactions(loanSchedule, loanID); System.out.println("----------Make repayment 2------------"); - this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3251.48"), loanID); + this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3251.49"), loanID); this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011", - new JournalEntry(Float.valueOf("3251.48"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("100.00"), + new JournalEntry(Float.valueOf("3251.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("100.00"), JournalEntry.TransactionType.CREDIT), - new JournalEntry(Float.valueOf("181.77"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2969.71"), + new JournalEntry(Float.valueOf("181.77"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2969.72"), JournalEntry.TransactionType.CREDIT)); loanSchedule.clear(); @@ -2481,11 +2481,11 @@ public class ClientLoanIntegrationTest { JournalEntry.TransactionType.CREDIT)); System.out.println("----------Make repayment 3 advance------------"); - this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3301.48"), loanID); + this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3301.49"), loanID); this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011", - new JournalEntry(Float.valueOf("3301.48"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("50"), + new JournalEntry(Float.valueOf("3301.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("50"), JournalEntry.TransactionType.CREDIT), - new JournalEntry(Float.valueOf("122.38"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3129.10"), + new JournalEntry(Float.valueOf("122.38"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3129.11"), JournalEntry.TransactionType.CREDIT)); this.loanTransactionHelper.addChargesForLoan(loanID, LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON( @@ -2494,7 +2494,7 @@ public class ClientLoanIntegrationTest { loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID); HashMap fourthInstallment = loanSchedule.get(4); validateNumberForEqual("100", String.valueOf(fourthInstallment.get("penaltyChargesOutstanding"))); - validateNumberForEqual("3239.70", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); + validateNumberForEqual("3239.68", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); System.out.println("----------Pay applied penalty ------------"); this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("100"), loanID); @@ -2504,13 +2504,13 @@ public class ClientLoanIntegrationTest { loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID); fourthInstallment = loanSchedule.get(4); validateNumberForEqual("0", String.valueOf(fourthInstallment.get("penaltyChargesOutstanding"))); - validateNumberForEqual("3139.70", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); + validateNumberForEqual("3139.68", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); System.out.println("----------Make repayment 4 ------------"); - this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("3139.70"), loanID); + this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("3139.68"), loanID); this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 January 2012", new JournalEntry( - Float.valueOf("3139.70"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("50.00"), - JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3089.70"), JournalEntry.TransactionType.CREDIT)); + Float.valueOf("3139.68"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("50.00"), + JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3089.68"), JournalEntry.TransactionType.CREDIT)); loanStatusHashMap = (HashMap) this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, loanID, "status"); LoanStatusChecker.verifyLoanAccountIsClosed(loanStatusHashMap); } @@ -2641,11 +2641,11 @@ public class ClientLoanIntegrationTest { checkAccrualTransactions(loanSchedule, loanID); System.out.println("----------Make repayment 2------------"); - this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3271.48"), loanID); + this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3271.49"), loanID); this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011", - new JournalEntry(Float.valueOf("3271.48"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("120"), + new JournalEntry(Float.valueOf("3271.49"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("120"), JournalEntry.TransactionType.CREDIT), - new JournalEntry(Float.valueOf("181.77"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2969.71"), + new JournalEntry(Float.valueOf("181.77"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2969.72"), JournalEntry.TransactionType.CREDIT)); loanSchedule.clear(); @@ -2687,11 +2687,11 @@ public class ClientLoanIntegrationTest { JournalEntry.TransactionType.CREDIT)); System.out.println("----------Make repayment 3 advance------------"); - this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3301.77"), loanID); + this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3301.78"), loanID); this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011", - new JournalEntry(Float.valueOf("3301.77"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("30.29"), + new JournalEntry(Float.valueOf("3301.78"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("30.29"), JournalEntry.TransactionType.CREDIT), - new JournalEntry(Float.valueOf("122.38"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3149.1"), + new JournalEntry(Float.valueOf("122.38"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3149.11"), JournalEntry.TransactionType.CREDIT)); this.loanTransactionHelper.addChargesForLoan(loanID, LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON( @@ -2700,7 +2700,7 @@ public class ClientLoanIntegrationTest { loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID); HashMap fourthInstallment = loanSchedule.get(4); validateNumberForEqual("120", String.valueOf(fourthInstallment.get("penaltyChargesOutstanding"))); - validateNumberForEqual("3240.60", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); + validateNumberForEqual("3240.58", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); System.out.println("----------Pay applied penalty ------------"); this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("120"), loanID); @@ -2710,13 +2710,13 @@ public class ClientLoanIntegrationTest { loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID); fourthInstallment = loanSchedule.get(4); validateNumberForEqual("0", String.valueOf(fourthInstallment.get("penaltyChargesOutstanding"))); - validateNumberForEqual("3120.60", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); + validateNumberForEqual("3120.58", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); System.out.println("----------Make repayment 4 ------------"); - this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("3120.60"), loanID); + this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("3120.58"), loanID); this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 January 2012", new JournalEntry( - Float.valueOf("3120.60"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("30.90"), - JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3089.70"), JournalEntry.TransactionType.CREDIT)); + Float.valueOf("3120.58"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("30.90"), + JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3089.68"), JournalEntry.TransactionType.CREDIT)); loanStatusHashMap = (HashMap) this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, loanID, "status"); LoanStatusChecker.verifyLoanAccountIsClosed(loanStatusHashMap); } @@ -2851,11 +2851,11 @@ public class ClientLoanIntegrationTest { checkAccrualTransactions(loanSchedule, loanID); System.out.println("----------Make repayment 2------------"); - this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3277.54"), loanID); + this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3277.55"), loanID); this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011", - new JournalEntry(Float.valueOf("3277.54"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("126.06"), + new JournalEntry(Float.valueOf("3277.55"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("126.06"), JournalEntry.TransactionType.CREDIT), - new JournalEntry(Float.valueOf("181.77"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2969.71"), + new JournalEntry(Float.valueOf("181.77"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("2969.72"), JournalEntry.TransactionType.CREDIT)); loanSchedule.clear(); @@ -2899,11 +2899,11 @@ public class ClientLoanIntegrationTest { JournalEntry.TransactionType.CREDIT)); System.out.println("----------Make repayment 3 advance------------"); - this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3302.99"), loanID); + this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3303"), loanID); this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 November 2011", - new JournalEntry(Float.valueOf("3302.99"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("31.51"), + new JournalEntry(Float.valueOf("3303"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("31.51"), JournalEntry.TransactionType.CREDIT), - new JournalEntry(Float.valueOf("122.38"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3149.1"), + new JournalEntry(Float.valueOf("122.38"), JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3149.11"), JournalEntry.TransactionType.CREDIT)); this.loanTransactionHelper.addChargesForLoan( @@ -2914,7 +2914,7 @@ public class ClientLoanIntegrationTest { loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID); HashMap fourthInstallment = loanSchedule.get(4); validateNumberForEqual("120", String.valueOf(fourthInstallment.get("penaltyChargesOutstanding"))); - validateNumberForEqual("3241.21", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); + validateNumberForEqual("3241.19", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); System.out.println("----------Pay applied penalty ------------"); this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("120"), loanID); @@ -2924,13 +2924,13 @@ public class ClientLoanIntegrationTest { loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID); fourthInstallment = loanSchedule.get(4); validateNumberForEqual("0", String.valueOf(fourthInstallment.get("penaltyChargesOutstanding"))); - validateNumberForEqual("3121.21", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); + validateNumberForEqual("3121.19", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); System.out.println("----------Make repayment 4 ------------"); - this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("3121.21"), loanID); + this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("3121.19"), loanID); this.journalEntryHelper.checkJournalEntryForAssetAccount(assetAccount, "20 January 2012", new JournalEntry( - Float.valueOf("3121.21"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("31.51"), - JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3089.70"), JournalEntry.TransactionType.CREDIT)); + Float.valueOf("3121.19"), JournalEntry.TransactionType.DEBIT), new JournalEntry(Float.valueOf("31.51"), + JournalEntry.TransactionType.CREDIT), new JournalEntry(Float.valueOf("3089.68"), JournalEntry.TransactionType.CREDIT)); loanStatusHashMap = (HashMap) this.loanTransactionHelper.getLoanDetail(this.requestSpec, this.responseSpec, loanID, "status"); LoanStatusChecker.verifyLoanAccountIsClosed(loanStatusHashMap); } @@ -3019,16 +3019,16 @@ public class ClientLoanIntegrationTest { HashMap secondInstallment = loanSchedule.get(2); HashMap thirdInstallment = loanSchedule.get(3); - validateNumberForEqual("3100", String.valueOf(secondInstallment.get("totalOutstandingForPeriod"))); - validateNumberForEqual("3100", String.valueOf(thirdInstallment.get("totalOutstandingForPeriod"))); + validateNumberForEqual("3200", String.valueOf(secondInstallment.get("totalOutstandingForPeriod"))); + validateNumberForEqual("3200", String.valueOf(thirdInstallment.get("totalOutstandingForPeriod"))); - validateNumberForEqual("2900", String.valueOf(secondInstallment.get("principalOutstanding"))); - validateNumberForEqual("3000", String.valueOf(thirdInstallment.get("principalOutstanding"))); + validateNumberForEqual("3000", String.valueOf(secondInstallment.get("principalOutstanding"))); + validateNumberForEqual("3100", String.valueOf(thirdInstallment.get("principalOutstanding"))); /*** * Make payment for installment #2 */ - this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3300"), loanID); + this.loanTransactionHelper.makeRepayment("20 November 2011", Float.valueOf("3200"), loanID); loanSchedule.clear(); loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID); /*** @@ -3046,17 +3046,17 @@ public class ClientLoanIntegrationTest { * with the excess amount */ thirdInstallment = loanSchedule.get(3); - validateNumberForEqual("2900", String.valueOf(thirdInstallment.get("totalOutstandingForPeriod"))); - validateNumberForEqual("2900", String.valueOf(thirdInstallment.get("principalOutstanding"))); - validateNumberForEqual("100", String.valueOf(thirdInstallment.get("principalPaid"))); - validateNumberForEqual("100", String.valueOf(thirdInstallment.get("interestPaid"))); - validateNumberForEqual("0.00", String.valueOf(thirdInstallment.get("interestOutstanding"))); + validateNumberForEqual("3200", String.valueOf(thirdInstallment.get("totalOutstandingForPeriod"))); + validateNumberForEqual("3100", String.valueOf(thirdInstallment.get("principalOutstanding"))); + validateNumberForEqual("0", String.valueOf(thirdInstallment.get("principalPaid"))); + validateNumberForEqual("0", String.valueOf(thirdInstallment.get("interestPaid"))); + validateNumberForEqual("100.00", String.valueOf(thirdInstallment.get("interestOutstanding"))); /*** * Make payment with due amount of 3rd installment on 4th installment * date */ - this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("2900"), loanID); + this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("3200"), loanID); loanSchedule.clear(); loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID); @@ -3070,11 +3070,11 @@ public class ClientLoanIntegrationTest { validateNumberForEqual("100", String.valueOf(thirdInstallment.get("totalOutstandingForPeriod"))); validateNumberForEqual("100", String.valueOf(thirdInstallment.get("principalOutstanding"))); - validateNumberForEqual("3100", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); + validateNumberForEqual("2900", String.valueOf(fourthInstallment.get("totalOutstandingForPeriod"))); validateNumberForEqual("100", String.valueOf(fourthInstallment.get("interestPaid"))); validateNumberForEqual("0.00", String.valueOf(fourthInstallment.get("interestOutstanding"))); - this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("3200"), loanID); + this.loanTransactionHelper.makeRepayment("20 January 2012", Float.valueOf("3000"), loanID); /*** * verify loan is closed as we paid full amount diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/GroupLoanIntegrationTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/GroupLoanIntegrationTest.java index 158e7b3c7..387ffe2b3 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/GroupLoanIntegrationTest.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/GroupLoanIntegrationTest.java @@ -105,17 +105,17 @@ public class GroupLoanIntegrationTest { assertEquals("Checking for Due Date for 2nd Month", new ArrayList<>(Arrays.asList(2011, 11, 20)), loanSchedule.get(2).get("dueDate")); - assertEquals("Checking for Principal Due for 2nd Month", new Float("2969.71"), loanSchedule.get(2).get("principalDue")); + assertEquals("Checking for Principal Due for 2nd Month", new Float("2969.72"), loanSchedule.get(2).get("principalDue")); assertEquals("Checking for Interest Due for 2nd Month", new Float("181.77"), loanSchedule.get(2).get("interestOriginalDue")); assertEquals("Checking for Due Date for 3rd Month", new ArrayList<>(Arrays.asList(2011, 12, 20)), loanSchedule.get(3).get("dueDate")); - assertEquals("Checking for Principal Due for 3rd Month", new Float("3029.1"), loanSchedule.get(3).get("principalDue")); + assertEquals("Checking for Principal Due for 3rd Month", new Float("3029.11"), loanSchedule.get(3).get("principalDue")); assertEquals("Checking for Interest Due for 3rd Month", new Float("122.38"), loanSchedule.get(3).get("interestOriginalDue")); assertEquals("Checking for Due Date for 4th Month", new ArrayList<>(Arrays.asList(2012, 1, 20)), loanSchedule.get(4).get("dueDate")); - assertEquals("Checking for Principal Due for 4th Month", new Float("3089.7"), loanSchedule.get(4).get("principalDue")); + assertEquals("Checking for Principal Due for 4th Month", new Float("3089.68"), loanSchedule.get(4).get("principalDue")); assertEquals("Checking for Interest Due for 4th Month", new Float("61.79"), loanSchedule.get(4).get("interestOriginalDue")); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/resources/sql/migrations/core_db/V227__fixed_emi_changes.sql b/mifosng-provider/src/main/resources/sql/migrations/core_db/V250__fixed_emi_changes.sql old mode 100755 new mode 100644 similarity index 100% rename from mifosng-provider/src/main/resources/sql/migrations/core_db/V227__fixed_emi_changes.sql rename to mifosng-provider/src/main/resources/sql/migrations/core_db/V250__fixed_emi_changes.sql