MIFOSX-2148: Make Rounding Mode as configurable throughout Mifos

This commit is contained in:
shahrahul1985
2015-08-26 16:25:43 +05:30
committed by pramod
parent f0252a1747
commit fd5ef09360
27 changed files with 373 additions and 260 deletions
@@ -21,8 +21,7 @@ public class GlobalConfigurationPropertyData {
@SuppressWarnings("unused")
private final String description;
public GlobalConfigurationPropertyData(final String name, final boolean enabled, final Long value,
final String description) {
public GlobalConfigurationPropertyData(final String name, final boolean enabled, final Long value, final String description) {
this.name = name;
this.enabled = enabled;
this.value = value;
@@ -30,8 +29,8 @@ public class GlobalConfigurationPropertyData {
this.description = description;
}
public GlobalConfigurationPropertyData(final String name, final boolean enabled, final Long value,
final Long id, final String description) {
public GlobalConfigurationPropertyData(final String name, final boolean enabled, final Long value, final Long id,
final String description) {
this.name = name;
this.enabled = enabled;
this.value = value;
@@ -47,4 +47,6 @@ public interface ConfigurationDomainService {
boolean isMeetingMandatoryForJLGLoans();
int getRoundingMode();
}
@@ -180,4 +180,16 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService
return property.isEnabled();
}
public int getRoundingMode() {
final String propertyName = "rounding-mode";
int defaultValue = 6; // 6 Stands for HALF-EVEN
final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByNameWithNotFoundDetection(propertyName);
if (property.isEnabled()) {
int value = property.getValue().intValue();
if (value < 0 || value > 6) { return defaultValue; }
return value;
}
return defaultValue;
}
}
@@ -12,6 +12,8 @@ import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
import org.mifosplatform.infrastructure.configuration.exception.GlobalConfigurationPropertyCannotBeModfied;
import org.mifosplatform.infrastructure.configuration.exception.GlobalConfigurationPropertyNotFoundException;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.security.exception.ForcePasswordResetException;
import org.springframework.data.jpa.domain.AbstractPersistable;
@@ -28,23 +30,28 @@ public class GlobalConfigurationProperty extends AbstractPersistable<Long> {
@Column(name = "value", nullable = true)
private Long value;
@Column(name = "description", nullable = true)
private final String description;
@Column(name = "is_trap_door", nullable = false)
private boolean isTrapDoor;
protected GlobalConfigurationProperty() {
this.name = null;
this.enabled = false;
this.value = null;
this.description = null;
this.isTrapDoor = false;
}
public GlobalConfigurationProperty(final String name, final boolean enabled, final Long value,
final String description) {
public GlobalConfigurationProperty(final String name, final boolean enabled, final Long value, final String description,
final boolean isTrapDoor) {
this.name = name;
this.enabled = enabled;
this.value = value;
this.description = description;
this.isTrapDoor = isTrapDoor;
}
public boolean isEnabled() {
@@ -65,6 +72,8 @@ public class GlobalConfigurationProperty extends AbstractPersistable<Long> {
final Map<String, Object> actualChanges = new LinkedHashMap<>(7);
if (this.isTrapDoor == true) { throw new GlobalConfigurationPropertyCannotBeModfied(this.getId()); }
final String enabledParamName = "enabled";
if (command.isChangeInBooleanParameterNamed(enabledParamName, this.enabled)) {
final Boolean newValue = command.booleanPrimitiveValueOfParameterNamed(enabledParamName);
@@ -79,22 +88,19 @@ public class GlobalConfigurationProperty extends AbstractPersistable<Long> {
actualChanges.put(valueParamName, newValue);
this.value = newValue;
}
final String passwordPropertyName = "force-password-reset-days";
if(this.name.equalsIgnoreCase(passwordPropertyName)){
if(this.enabled == true && command.hasParameter(valueParamName) && this.value == 0 ||
this.enabled == true && !command.hasParameter(valueParamName) && previousValue == 0){
throw new ForcePasswordResetException();
}
}
if (this.name.equalsIgnoreCase(passwordPropertyName)) {
if (this.enabled == true && command.hasParameter(valueParamName) && this.value == 0 || this.enabled == true
&& !command.hasParameter(valueParamName) && previousValue == 0) { throw new ForcePasswordResetException(); }
}
return actualChanges;
}
public static GlobalConfigurationProperty newSurveyConfiguration(final String name)
{
return new GlobalConfigurationProperty(name, false, null, null);
public static GlobalConfigurationProperty newSurveyConfiguration(final String name) {
return new GlobalConfigurationProperty(name, false, null, null, false);
}
}
@@ -0,0 +1,17 @@
/**
* 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.infrastructure.configuration.exception;
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
public class GlobalConfigurationPropertyCannotBeModfied extends AbstractPlatformDomainRuleException{
public GlobalConfigurationPropertyCannotBeModfied(final Long configId) {
super("error.msg.configuration.id.not.modifiable", "Configuration identifier `" + configId + "` cannot be modified", new Object[] {configId});
}
}
@@ -39,13 +39,14 @@ public class ConfigurationReadPlatformServiceImpl implements ConfigurationReadPl
this.context.authenticatedUser();
String sql = "SELECT c.id, c.name, c.enabled, c.value, c.description FROM c_configuration c ";
String sql = "SELECT c.id, c.name, c.enabled, c.value, c.description, c.is_trap_door FROM c_configuration c ";
if(survey)
{
sql += " JOIN x_registered_table on x_registered_table.registered_table_name = c.name ";
sql += " WHERE x_registered_table.category ="+DataTableApiConstant.CATEGORY_PPI;
if (survey) {
sql += " JOIN x_registered_table on x_registered_table.registered_table_name = c.name ";
sql += " WHERE x_registered_table.category =" + DataTableApiConstant.CATEGORY_PPI + " and c.is_trap_door=0";
} else {
sql += " WHERE c.is_trap_door=0";
}
sql += " order by c.id";
@@ -53,33 +54,32 @@ public class ConfigurationReadPlatformServiceImpl implements ConfigurationReadPl
return new GlobalConfigurationData(globalConfiguration);
}
@Override
public GlobalConfigurationPropertyData retrieveGlobalConfiguration(Long configId) {
this.context.authenticatedUser();
final String sql = "SELECT c.id, c.name, c.enabled, c.value, c.description FROM "
+ "c_configuration c where c.id=? order by c.id";
final GlobalConfigurationPropertyData globalConfiguration = this.jdbcTemplate.queryForObject(sql, this.rm, new Object[] {configId});
final String sql = "SELECT c.id, c.name, c.enabled, c.value, c.description, c.is_trap_door FROM "
+ "c_configuration c where c.id=? and c.is_trap_door = 0 order by c.id";
final GlobalConfigurationPropertyData globalConfiguration = this.jdbcTemplate.queryForObject(sql, this.rm,
new Object[] { configId });
return globalConfiguration;
}
private static final class GlobalConfigurationRowMapper implements RowMapper<GlobalConfigurationPropertyData> {
@Override
public GlobalConfigurationPropertyData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
public GlobalConfigurationPropertyData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum)
throws SQLException {
final String name = rs.getString("name");
final boolean enabled = rs.getBoolean("enabled");
final Long value = rs.getLong("value");
final String description = rs.getString("description");
final Long id = rs.getLong("id");
final boolean isTrapDoor = rs.getBoolean("is_trap_door");
return new GlobalConfigurationPropertyData(name, enabled, value, id, description);
}
}
@@ -76,7 +76,7 @@ public class Money implements Comparable<Money> {
final double existingVal = amountScaled.doubleValue();
amountScaled = BigDecimal.valueOf(roundToMultiplesOf(existingVal, inMultiplesOf));
}
this.amount = amountScaled.setScale(this.currencyDigitsAfterDecimal, RoundingMode.HALF_EVEN);
this.amount = amountScaled.setScale(this.currencyDigitsAfterDecimal, RoundingMode.valueOf(MoneyHelper.getRoundingMode()));
}
public static double roundToMultiplesOf(final double existingVal, final Integer inMultiplesOf) {
@@ -227,8 +227,8 @@ public class Money implements Comparable<Money> {
@Override
public int compareTo(final Money other) {
final Money otherMoney = other;
if (this.currencyCode.equals(otherMoney.currencyCode) == false) { throw new UnsupportedOperationException(
"currencies arent different"); }
if (this.currencyCode
.equals(otherMoney.currencyCode) == false) { throw new UnsupportedOperationException("currencies arent different"); }
return this.amount.compareTo(otherMoney.amount);
}
@@ -0,0 +1,36 @@
/**
* 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.organisation.monetary.domain;
import javax.annotation.PostConstruct;
import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class MoneyHelper {
private static int roundingModeIntValue = -1;
private static ConfigurationDomainService staticConfigurationDomainService;
@Autowired
private ConfigurationDomainService configurationDomainService;
@PostConstruct
public void someFunction () {
staticConfigurationDomainService = configurationDomainService;
}
public static int getRoundingMode() {
if (roundingModeIntValue == -1) {
roundingModeIntValue = staticConfigurationDomainService.getRoundingMode();
}
return roundingModeIntValue;
}
}
@@ -21,6 +21,7 @@ import org.joda.time.LocalDateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.mifosplatform.infrastructure.codes.domain.CodeValue;
import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
@@ -33,6 +34,7 @@ import org.mifosplatform.organisation.monetary.data.CurrencyData;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.organisation.monetary.domain.MoneyHelper;
import org.mifosplatform.organisation.office.domain.Office;
import org.mifosplatform.organisation.staff.domain.Staff;
import org.mifosplatform.organisation.workingdays.domain.WorkingDays;
@@ -64,13 +66,16 @@ import org.mifosplatform.portfolio.loanproduct.LoanProductConstants;
import org.mifosplatform.portfolio.loanproduct.domain.*;
import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations;
import org.mifosplatform.useradministration.domain.AppUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.AbstractPersistable;
import org.springframework.stereotype.Component;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
@Entity
@Component
@Table(name = "m_loan", uniqueConstraints = { @UniqueConstraint(columnNames = { "account_no" }, name = "loan_account_no_UNIQUE"),
@UniqueConstraint(columnNames = { "external_id" }, name = "loan_externalid_UNIQUE") })
public class Loan extends AbstractPersistable<Long> {
@@ -573,8 +578,8 @@ public class Loan extends AbstractPersistable<Long> {
final LoanTransaction applyLoanChargeTransaction = LoanTransaction.accrueLoanCharge(this, getOffice(), chargeAmount,
transactionDate, feeCharges, penaltyCharges, DateUtils.getLocalDateTimeOfTenant(), currentUser);
Integer installmentNumber = null;
final LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(applyLoanChargeTransaction, loanCharge, loanCharge.getAmount(
getCurrency()).getAmount(), installmentNumber);
final LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(applyLoanChargeTransaction, loanCharge,
loanCharge.getAmount(getCurrency()).getAmount(), installmentNumber);
applyLoanChargeTransaction.getLoanChargesPaid().add(loanChargePaidBy);
this.loanTransactions.add(applyLoanChargeTransaction);
return applyLoanChargeTransaction;
@@ -583,8 +588,8 @@ public class Loan extends AbstractPersistable<Long> {
private void handleChargePaidTransaction(final LoanCharge charge, final LoanTransaction chargesPayment,
final LoanLifecycleStateMachine loanLifecycleStateMachine, final Integer installmentNumber) {
chargesPayment.updateLoan(this);
final LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(chargesPayment, charge, chargesPayment.getAmount(getCurrency())
.getAmount(), installmentNumber);
final LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(chargesPayment, charge,
chargesPayment.getAmount(getCurrency()).getAmount(), installmentNumber);
chargesPayment.getLoanChargesPaid().add(loanChargePaidBy);
this.loanTransactions.add(chargesPayment);
final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.LOAN_CHARGE_PAYMENT,
@@ -622,7 +627,8 @@ public class Loan extends AbstractPersistable<Long> {
private void validateLoanChargeIsNotWaived(final LoanCharge loanCharge) {
if (loanCharge.isWaived()) {
final String defaultUserMessage = "This loan charge cannot be removed as the charge as already been waived.";
throw new LoanChargeCannotBeAddedException("loanCharge", "loanCharge.is.waived", defaultUserMessage, getId(), loanCharge.name());
throw new LoanChargeCannotBeAddedException("loanCharge", "loanCharge.is.waived", defaultUserMessage, getId(),
loanCharge.name());
}
}
@@ -862,11 +868,10 @@ public class Loan extends AbstractPersistable<Long> {
existingTransactionIds.addAll(findExistingTransactionIds());
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
final LoanTransaction waiveLoanChargeTransaction = LoanTransaction.waiveLoanCharge(this, getOffice(), amountWaived,
transactionDate, feeChargesWaived, penaltyChargesWaived, unrecognizedIncome, DateUtils.getLocalDateTimeOfTenant(),
currentUser);
final LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(waiveLoanChargeTransaction, loanCharge, waiveLoanChargeTransaction
.getAmount(getCurrency()).getAmount(), loanInstallmentNumber);
final LoanTransaction waiveLoanChargeTransaction = LoanTransaction.waiveLoanCharge(this, getOffice(), amountWaived, transactionDate,
feeChargesWaived, penaltyChargesWaived, unrecognizedIncome, DateUtils.getLocalDateTimeOfTenant(), currentUser);
final LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(waiveLoanChargeTransaction, loanCharge,
waiveLoanChargeTransaction.getAmount(getCurrency()).getAmount(), loanInstallmentNumber);
waiveLoanChargeTransaction.getLoanChargesPaid().add(loanChargePaidBy);
this.loanTransactions.add(waiveLoanChargeTransaction);
@@ -1409,13 +1414,13 @@ public class Loan extends AbstractPersistable<Long> {
}
if (this.loanInterestRecalculationDetails == null) {
actualChanges.put(LoanProductConstants.isInterestRecalculationEnabledParameterName, true);
this.loanInterestRecalculationDetails = LoanInterestRecalculationDetails.createFrom(this.loanProduct
.getProductInterestRecalculationDetails().getInterestRecalculationCompoundingMethod(), this.loanProduct
.getProductInterestRecalculationDetails().getRescheduleStrategyMethod(), this.loanProduct
.getProductInterestRecalculationDetails().getRestFrequencyType().getValue(), this.loanProduct
.getProductInterestRecalculationDetails().getRestInterval(), restFrequencyDate, this.loanProduct
.getProductInterestRecalculationDetails().getCompoundingFrequencyType().getValue(), this.loanProduct
.getProductInterestRecalculationDetails().getCompoundingInterval(), compoundingFrequencyDate);
this.loanInterestRecalculationDetails = LoanInterestRecalculationDetails.createFrom(
this.loanProduct.getProductInterestRecalculationDetails().getInterestRecalculationCompoundingMethod(),
this.loanProduct.getProductInterestRecalculationDetails().getRescheduleStrategyMethod(),
this.loanProduct.getProductInterestRecalculationDetails().getRestFrequencyType().getValue(),
this.loanProduct.getProductInterestRecalculationDetails().getRestInterval(), restFrequencyDate,
this.loanProduct.getProductInterestRecalculationDetails().getCompoundingFrequencyType().getValue(),
this.loanProduct.getProductInterestRecalculationDetails().getCompoundingInterval(), compoundingFrequencyDate);
this.loanInterestRecalculationDetails.updateLoan(this);
} else {
@@ -1549,9 +1554,8 @@ public class Loan extends AbstractPersistable<Long> {
expectedDisbursementDate = date.toDate();
}
if (jsonObject.get(LoanApiConstants.disbursementPrincipalParameterName).isJsonPrimitive()
&& StringUtils.isNotBlank((jsonObject.get(LoanApiConstants.disbursementPrincipalParameterName)
.getAsString()))) {
if (jsonObject.get(LoanApiConstants.disbursementPrincipalParameterName).isJsonPrimitive() && StringUtils
.isNotBlank((jsonObject.get(LoanApiConstants.disbursementPrincipalParameterName).getAsString()))) {
principal = jsonObject.getAsJsonPrimitive(LoanApiConstants.disbursementPrincipalParameterName)
.getAsBigDecimal();
}
@@ -1694,7 +1698,8 @@ public class Loan extends AbstractPersistable<Long> {
if (this.client != null && this.client.isActivatedAfter(submittedOn)) {
final String errorMessage = "The date on which a loan is submitted cannot be earlier than client's activation date.";
throw new InvalidLoanStateTransitionException("submittal", "cannot.be.before.client.activation.date", errorMessage, submittedOn);
throw new InvalidLoanStateTransitionException("submittal", "cannot.be.before.client.activation.date", errorMessage,
submittedOn);
}
validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.LOAN_CREATED, submittedOn);
@@ -1737,13 +1742,13 @@ public class Loan extends AbstractPersistable<Long> {
if (recalculationCompoundingFrequencyDate != null) {
compoundingFrequencyDate = recalculationCompoundingFrequencyDate.toDate();
}
this.loanInterestRecalculationDetails = LoanInterestRecalculationDetails.createFrom(this.loanProduct
.getProductInterestRecalculationDetails().getInterestRecalculationCompoundingMethod(), this.loanProduct
.getProductInterestRecalculationDetails().getRescheduleStrategyMethod(), this.loanProduct
.getProductInterestRecalculationDetails().getRestFrequencyType().getValue(), this.loanProduct
.getProductInterestRecalculationDetails().getRestInterval(), restFrequencyDate, this.loanProduct
.getProductInterestRecalculationDetails().getCompoundingFrequencyType().getValue(), this.loanProduct
.getProductInterestRecalculationDetails().getCompoundingInterval(), compoundingFrequencyDate);
this.loanInterestRecalculationDetails = LoanInterestRecalculationDetails.createFrom(
this.loanProduct.getProductInterestRecalculationDetails().getInterestRecalculationCompoundingMethod(),
this.loanProduct.getProductInterestRecalculationDetails().getRescheduleStrategyMethod(),
this.loanProduct.getProductInterestRecalculationDetails().getRestFrequencyType().getValue(),
this.loanProduct.getProductInterestRecalculationDetails().getRestInterval(), restFrequencyDate,
this.loanProduct.getProductInterestRecalculationDetails().getCompoundingFrequencyType().getValue(),
this.loanProduct.getProductInterestRecalculationDetails().getCompoundingInterval(), compoundingFrequencyDate);
this.loanInterestRecalculationDetails.updateLoan(this);
}
@@ -2228,7 +2233,8 @@ public class Loan extends AbstractPersistable<Long> {
if (date != null) {
for (LoanDisbursementDetails disbursementDetail : this.disbursementDetails) {
if (disbursementDetail.actualDisbursementDate() != null) {
if (disbursementDetail.actualDisbursementDate().after(date) || disbursementDetail.actualDisbursementDate().equals(date)) {
if (disbursementDetail.actualDisbursementDate().after(date)
|| disbursementDetail.actualDisbursementDate().equals(date)) {
date = disbursementDetail.actualDisbursementDate();
details = disbursementDetail;
}
@@ -2317,7 +2323,7 @@ public class Loan extends AbstractPersistable<Long> {
final InterestMethod interestMethod = this.loanRepaymentScheduleDetail.getInterestMethod();
final LoanScheduleGenerator loanScheduleGenerator = scheduleGeneratorDTO.getLoanScheduleFactory().create(interestMethod);
final RoundingMode roundingMode = RoundingMode.HALF_EVEN;
final RoundingMode roundingMode = RoundingMode.valueOf(MoneyHelper.getRoundingMode());
final MathContext mc = new MathContext(8, roundingMode);
final Integer loanTermFrequency = this.termFrequency;
@@ -2731,8 +2737,8 @@ public class Loan extends AbstractPersistable<Long> {
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
.determineProcessor(this.transactionProcessingStrategy);
final LoanRepaymentScheduleInstallment currentInstallment = fetchLoanRepaymentScheduleInstallment(loanTransaction
.getTransactionDate());
final LoanRepaymentScheduleInstallment currentInstallment = fetchLoanRepaymentScheduleInstallment(
loanTransaction.getTransactionDate());
boolean reprocess = true;
if (isTransactionChronologicallyLatest && adjustedTransaction == null
@@ -2750,8 +2756,8 @@ public class Loan extends AbstractPersistable<Long> {
if (currentInstallment == null || currentInstallment.isNotFullyPaidOff()) {
reprocess = true;
} else {
final LoanRepaymentScheduleInstallment nextInstallment = fetchRepaymentScheduleInstallment(currentInstallment
.getInstallmentNumber() + 1);
final LoanRepaymentScheduleInstallment nextInstallment = fetchRepaymentScheduleInstallment(
currentInstallment.getInstallmentNumber() + 1);
if (nextInstallment != null && nextInstallment.getTotalPaidInAdvance(getCurrency()).isGreaterThanZero()) {
reprocess = true;
}
@@ -2939,7 +2945,8 @@ public class Loan extends AbstractPersistable<Long> {
return isAfterLatRepayment;
}
private boolean isChronologicallyLatestTransaction(final LoanTransaction loanTransaction, final List<LoanTransaction> loanTransactions) {
private boolean isChronologicallyLatestTransaction(final LoanTransaction loanTransaction,
final List<LoanTransaction> loanTransactions) {
boolean isChronologicallyLatestRepaymentOrWaiver = true;
@@ -3066,8 +3073,8 @@ public class Loan extends AbstractPersistable<Long> {
return changedTransactionDetail;
}
public ChangedTransactionDetail undoWrittenOff(final List<Long> existingTransactionIds,
final List<Long> existingReversedTransactionIds, final ScheduleGeneratorDTO scheduleGeneratorDTO, final AppUser currentUser) {
public ChangedTransactionDetail undoWrittenOff(final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds,
final ScheduleGeneratorDTO scheduleGeneratorDTO, final AppUser currentUser) {
validateAccountStatus(LoanEvent.WRITE_OFF_OUTSTANDING_UNDO);
existingTransactionIds.addAll(findExistingTransactionIds());
@@ -3710,8 +3717,8 @@ public class Loan extends AbstractPersistable<Long> {
final String errorMessage = "The Loan officer Unassign date(" + unassignDate + ") cannot be before its assignment date ("
+ latestHistoryRecord.getStartDate() + ").";
throw new LoanOfficerUnassignmentDateException("cannot.be.before.assignment.date", errorMessage, getId(), getLoanOfficer()
.getId(), latestHistoryRecord.getStartDate(), unassignDate);
throw new LoanOfficerUnassignmentDateException("cannot.be.before.assignment.date", errorMessage, getId(),
getLoanOfficer().getId(), latestHistoryRecord.getStartDate(), unassignDate);
} else if (unassignDate.isAfter(today)) {
@@ -3986,8 +3993,8 @@ public class Loan extends AbstractPersistable<Long> {
loanRepaymentInterval, tmpFromDate);
if (newRepaymentDate.isAfter(maxDateLimitForNewRepayment)) {
newRepaymentDate = CalendarUtils.getNextRepaymentMeetingDate(recuringRule, seedDate, tmpFromDate,
loanRepaymentInterval, frequency, workingDays);
newRepaymentDate = CalendarUtils.getNextRepaymentMeetingDate(recuringRule, seedDate, tmpFromDate, loanRepaymentInterval,
frequency, workingDays);
}
if (isHolidayEnabled) {
@@ -4240,7 +4247,8 @@ public class Loan extends AbstractPersistable<Long> {
}
private void validateActivityNotBeforeLastTransactionDate(final LoanEvent event, final LocalDate activityDate) {
if (!(this.repaymentScheduleDetail().isInterestRecalculationEnabled() || this.loanProduct().isHoldGuaranteeFundsEnabled())) { return; }
if (!(this.repaymentScheduleDetail().isInterestRecalculationEnabled()
|| this.loanProduct().isHoldGuaranteeFundsEnabled())) { return; }
LocalDate lastTransactionDate = getLastUserTransactionDate();
final LocalDate clientOfficeJoiningDate = this.client.getOfficeJoiningLocalDate();
if (lastTransactionDate.isAfter(activityDate)) {
@@ -4330,8 +4338,8 @@ public class Loan extends AbstractPersistable<Long> {
case LOAN_APPROVED:
if (!isSubmittedAndPendingApproval()) {
final String defaultUserMessage = "Loan Account Approval is not allowed. Loan Account is not in submitted and pending approval state.";
final ApiParameterError error = ApiParameterError.generalError(
"error.msg.loan.approve.account.is.not.submitted.and.pending.state", defaultUserMessage);
final ApiParameterError error = ApiParameterError
.generalError("error.msg.loan.approve.account.is.not.submitted.and.pending.state", defaultUserMessage);
dataValidationErrors.add(error);
}
break;
@@ -4347,8 +4355,8 @@ public class Loan extends AbstractPersistable<Long> {
if ((!(isApproved() && isNotDisbursed()) && !this.loanProduct.isMultiDisburseLoan())
|| (this.loanProduct.isMultiDisburseLoan() && !isAllTranchesNotDisbursed())) {
final String defaultUserMessage = "Loan Disbursal is not allowed. Loan Account is not in approved and not disbursed state.";
final ApiParameterError error = ApiParameterError.generalError(
"error.msg.loan.disbursal.account.is.not.approve.not.disbursed.state", defaultUserMessage);
final ApiParameterError error = ApiParameterError
.generalError("error.msg.loan.disbursal.account.is.not.approve.not.disbursed.state", defaultUserMessage);
dataValidationErrors.add(error);
}
break;
@@ -4363,24 +4371,24 @@ public class Loan extends AbstractPersistable<Long> {
case LOAN_REPAYMENT_OR_WAIVER:
if (!isOpen()) {
final String defaultUserMessage = "Loan Repayment or Waiver is not allowed. Loan Account is not active.";
final ApiParameterError error = ApiParameterError.generalError(
"error.msg.loan.repayment.or.waiver.account.is.not.active", defaultUserMessage);
final ApiParameterError error = ApiParameterError
.generalError("error.msg.loan.repayment.or.waiver.account.is.not.active", defaultUserMessage);
dataValidationErrors.add(error);
}
break;
case LOAN_REJECTED:
if (!isSubmittedAndPendingApproval()) {
final String defaultUserMessage = "Loan application cannot be rejected. Loan Account is not in Submitted and Pending approval state.";
final ApiParameterError error = ApiParameterError.generalError(
"error.msg.loan.reject.account.is.not.submitted.pending.approval.state", defaultUserMessage);
final ApiParameterError error = ApiParameterError
.generalError("error.msg.loan.reject.account.is.not.submitted.pending.approval.state", defaultUserMessage);
dataValidationErrors.add(error);
}
break;
case LOAN_WITHDRAWN:
if (!isSubmittedAndPendingApproval()) {
final String defaultUserMessage = "Loan application cannot be withdrawn. Loan Account is not in Submitted and Pending approval state.";
final ApiParameterError error = ApiParameterError.generalError(
"error.msg.loan.withdrawn.account.is.not.submitted.pending.approval.state", defaultUserMessage);
final ApiParameterError error = ApiParameterError
.generalError("error.msg.loan.withdrawn.account.is.not.submitted.pending.approval.state", defaultUserMessage);
dataValidationErrors.add(error);
}
break;
@@ -4395,8 +4403,8 @@ public class Loan extends AbstractPersistable<Long> {
case WRITE_OFF_OUTSTANDING_UNDO:
if (!isClosedWrittenOff()) {
final String defaultUserMessage = "Loan Undo Written off is not allowed. Loan Account is not Written off.";
final ApiParameterError error = ApiParameterError.generalError(
"error.msg.loan.undo.writtenoff.account.is.not.written.off", defaultUserMessage);
final ApiParameterError error = ApiParameterError
.generalError("error.msg.loan.undo.writtenoff.account.is.not.written.off", defaultUserMessage);
dataValidationErrors.add(error);
}
break;
@@ -4421,8 +4429,8 @@ public class Loan extends AbstractPersistable<Long> {
case LOAN_EDIT_MULTI_DISBURSE_DATE:
if (isClosed()) {
final String defaultUserMessage = "Edit disbursement is not allowed. Loan Account is not active.";
final ApiParameterError error = ApiParameterError.generalError(
"error.msg.loan.edit.disbursement.account.is.not.active", defaultUserMessage);
final ApiParameterError error = ApiParameterError.generalError("error.msg.loan.edit.disbursement.account.is.not.active",
defaultUserMessage);
dataValidationErrors.add(error);
}
break;
@@ -4674,7 +4682,7 @@ public class Loan extends AbstractPersistable<Long> {
final InterestMethod interestMethod = this.loanRepaymentScheduleDetail.getInterestMethod();
final LoanScheduleGenerator loanScheduleGenerator = generatorDTO.getLoanScheduleFactory().create(interestMethod);
final RoundingMode roundingMode = RoundingMode.HALF_EVEN;
final RoundingMode roundingMode = RoundingMode.valueOf(MoneyHelper.getRoundingMode());
final MathContext mc = new MathContext(8, roundingMode);
final LoanApplicationTerms loanApplicationTerms = constructLoanApplicationTerms(generatorDTO.getApplicationCurrency(),
@@ -4719,12 +4727,11 @@ public class Loan extends AbstractPersistable<Long> {
RecalculationFrequencyType compoundingFrequencyType = this.loanInterestRecalculationDetails().getCompoundingFrequencyType();
final LoanApplicationTerms loanApplicationTerms = LoanApplicationTerms.assembleFrom(applicationCurrency, loanTermFrequency,
loanTermPeriodFrequencyType, getDisbursementDate(), getExpectedFirstRepaymentOnDate(),
calculatedRepaymentsStartingFromDate, getInArrearsTolerance(), this.loanRepaymentScheduleDetail,
this.loanProduct.isMultiDisburseLoan(), this.fixedEmiAmount, disbursementData, this.maxOutstandingLoanBalance,
loanVariationTermsData, getInterestChargedFromDate(), this.loanInterestRecalculationDetails,
calendarInstanceForInterestRecalculation, recalculationFrequencyType, compoundingCalendarInstance,
compoundingFrequencyType, this.loanProduct.getPrincipalThresholdForLastInstallment(),
loanTermPeriodFrequencyType, getDisbursementDate(), getExpectedFirstRepaymentOnDate(), calculatedRepaymentsStartingFromDate,
getInArrearsTolerance(), this.loanRepaymentScheduleDetail, this.loanProduct.isMultiDisburseLoan(), this.fixedEmiAmount,
disbursementData, this.maxOutstandingLoanBalance, loanVariationTermsData, getInterestChargedFromDate(),
this.loanInterestRecalculationDetails, calendarInstanceForInterestRecalculation, recalculationFrequencyType,
compoundingCalendarInstance, compoundingFrequencyType, this.loanProduct.getPrincipalThresholdForLastInstallment(),
this.loanProduct.getInstallmentAmountInMultiplesOf(), this.loanProduct.preCloseInterestCalculationStrategy());
return loanApplicationTerms;
}
@@ -4738,7 +4745,7 @@ public class Loan extends AbstractPersistable<Long> {
final InterestMethod interestMethod = this.loanRepaymentScheduleDetail.getInterestMethod();
final LoanScheduleGenerator loanScheduleGenerator = loanScheduleFactory.create(interestMethod);
final RoundingMode roundingMode = RoundingMode.HALF_EVEN;
final RoundingMode roundingMode = RoundingMode.valueOf(MoneyHelper.getRoundingMode());
final MathContext mc = new MathContext(8, roundingMode);
final Integer loanTermFrequency = this.termFrequency;
@@ -4988,8 +4995,8 @@ public class Loan extends AbstractPersistable<Long> {
final List<DisbursementData> disbursementData = getDisbursmentData();
final List<LoanTermVariationsData> loanVariationTermsData = new ArrayList<LoanTermVariationsData>();
LoanTermVariationsData data = new LoanTermVariationsData(null,
LoanEnumerations.loanvariationType(LoanTermVariationType.EMI_AMOUNT), expectedDisbursementDate, emiAmount);
LoanTermVariationsData data = new LoanTermVariationsData(null, LoanEnumerations.loanvariationType(LoanTermVariationType.EMI_AMOUNT),
expectedDisbursementDate, emiAmount);
loanVariationTermsData.add(data);
RecalculationFrequencyType recalculationFrequencyType = null;
@@ -5131,8 +5138,8 @@ public class Loan extends AbstractPersistable<Long> {
private void validateRefundDateIsAfterLastRepayment(final LocalDate refundTransactionDate) {
final LocalDate possibleNextRefundDate = possibleNextRefundDate();
if (possibleNextRefundDate == null || refundTransactionDate.isBefore(possibleNextRefundDate)) { throw new InvalidRefundDateException(
refundTransactionDate.toString()); }
if (possibleNextRefundDate == null || refundTransactionDate
.isBefore(possibleNextRefundDate)) { throw new InvalidRefundDateException(refundTransactionDate.toString()); }
}
@@ -37,6 +37,7 @@ import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.organisation.monetary.domain.MoneyHelper;
import org.mifosplatform.portfolio.charge.domain.Charge;
import org.mifosplatform.portfolio.charge.domain.ChargeCalculationType;
import org.mifosplatform.portfolio.charge.domain.ChargePaymentMode;
@@ -143,8 +144,8 @@ public class LoanCharge extends AbstractPersistable<Long> {
break;
case PERCENT_OF_AMOUNT_AND_INTEREST:
if (command.hasParameter("principal") && command.hasParameter("interest")) {
amountPercentageAppliedTo = command.bigDecimalValueOfParameterNamed("principal").add(
command.bigDecimalValueOfParameterNamed("interest"));
amountPercentageAppliedTo = command.bigDecimalValueOfParameterNamed("principal")
.add(command.bigDecimalValueOfParameterNamed("interest"));
} else {
amountPercentageAppliedTo = loan.getPrincpal().getAmount().add(loan.getTotalInterest());
}
@@ -552,7 +553,7 @@ public class LoanCharge extends AbstractPersistable<Long> {
BigDecimal percentageOf = BigDecimal.ZERO;
if (isGreaterThanZero(value)) {
final MathContext mc = new MathContext(8, RoundingMode.HALF_EVEN);
final MathContext mc = new MathContext(8, RoundingMode.valueOf(MoneyHelper.getRoundingMode()));
final BigDecimal multiplicand = percentage.divide(BigDecimal.valueOf(100l), mc);
percentageOf = value.multiply(multiplicand, mc);
}
@@ -763,9 +764,8 @@ public class LoanCharge extends AbstractPersistable<Long> {
public LoanInstallmentCharge getUnpaidInstallmentLoanCharge() {
LoanInstallmentCharge unpaidChargePerInstallment = null;
for (final LoanInstallmentCharge loanChargePerInstallment : this.loanInstallmentCharge) {
if (loanChargePerInstallment.isPending()
&& (unpaidChargePerInstallment == null || unpaidChargePerInstallment.getRepaymentInstallment().getDueDate()
.isAfter(loanChargePerInstallment.getRepaymentInstallment().getDueDate()))) {
if (loanChargePerInstallment.isPending() && (unpaidChargePerInstallment == null || unpaidChargePerInstallment
.getRepaymentInstallment().getDueDate().isAfter(loanChargePerInstallment.getRepaymentInstallment().getDueDate()))) {
unpaidChargePerInstallment = loanChargePerInstallment;
}
}
@@ -781,7 +781,8 @@ public class LoanCharge extends AbstractPersistable<Long> {
public LoanInstallmentCharge getInstallmentLoanCharge(final Integer installmentNumber) {
for (final LoanInstallmentCharge loanChargePerInstallment : this.loanInstallmentCharge) {
if (installmentNumber.equals(loanChargePerInstallment.getRepaymentInstallment().getInstallmentNumber().intValue())) { return loanChargePerInstallment; }
if (installmentNumber.equals(loanChargePerInstallment.getRepaymentInstallment().getInstallmentNumber()
.intValue())) { return loanChargePerInstallment; }
}
return null;
}
@@ -883,52 +884,52 @@ public class LoanCharge extends AbstractPersistable<Long> {
public LoanOverdueInstallmentCharge getOverdueInstallmentCharge() {
return this.overdueInstallmentCharge;
}
public Money undoPaidOrPartiallyAmountBy(final Money incrementBy,final Integer installmentNumber, final Money feeAmount) {
public Money undoPaidOrPartiallyAmountBy(final Money incrementBy, final Integer installmentNumber, final Money feeAmount) {
Money processAmount = Money.zero(incrementBy.getCurrency());
if(isInstalmentFee()){
if(installmentNumber == null){
processAmount = getLastPaidOrPartiallyPaidInstallmentLoanCharge(incrementBy.getCurrency()).undoPaidAmountBy(incrementBy, feeAmount);
}else{
if (isInstalmentFee()) {
if (installmentNumber == null) {
processAmount = getLastPaidOrPartiallyPaidInstallmentLoanCharge(incrementBy.getCurrency()).undoPaidAmountBy(incrementBy,
feeAmount);
} else {
processAmount = getInstallmentLoanCharge(installmentNumber).undoPaidAmountBy(incrementBy, feeAmount);
}
}else{
} else {
processAmount = incrementBy;
}
Money amountPaidToDate = Money.of(processAmount.getCurrency(), this.amountPaid);
Money amountDeductedOnThisCharge = Money.zero(processAmount.getCurrency());
if (processAmount.isGreaterThanOrEqualTo(amountPaidToDate)) {
amountDeductedOnThisCharge = amountPaidToDate;
amountDeductedOnThisCharge = amountPaidToDate;
amountPaidToDate = Money.zero(processAmount.getCurrency());
this.amountPaid = amountPaidToDate.getAmount();
this.amountOutstanding = this.amount;
this.paid = false;
} else {
amountDeductedOnThisCharge = processAmount;
amountDeductedOnThisCharge = processAmount;
amountPaidToDate = amountPaidToDate.minus(processAmount);
this.amountPaid = amountPaidToDate.getAmount();
this.amountOutstanding = calculateAmountOutstanding(incrementBy.getCurrency());
}
return amountDeductedOnThisCharge;
}
public LoanInstallmentCharge getLastPaidOrPartiallyPaidInstallmentLoanCharge(MonetaryCurrency currency) {
LoanInstallmentCharge paidChargePerInstallment = null;
for (final LoanInstallmentCharge loanChargePerInstallment : this.loanInstallmentCharge) {
Money outstanding = Money.of(currency, loanChargePerInstallment.getAmountOutstanding());
final boolean partiallyPaid = outstanding.isGreaterThanZero() && outstanding.isLessThan(loanChargePerInstallment.getAmount(currency));
if ((partiallyPaid || loanChargePerInstallment.isPaid())
&& (paidChargePerInstallment == null || paidChargePerInstallment.getRepaymentInstallment().getDueDate()
.isBefore(loanChargePerInstallment.getRepaymentInstallment().getDueDate()))) {
Money outstanding = Money.of(currency, loanChargePerInstallment.getAmountOutstanding());
final boolean partiallyPaid = outstanding.isGreaterThanZero()
&& outstanding.isLessThan(loanChargePerInstallment.getAmount(currency));
if ((partiallyPaid || loanChargePerInstallment.isPaid()) && (paidChargePerInstallment == null || paidChargePerInstallment
.getRepaymentInstallment().getDueDate().isBefore(loanChargePerInstallment.getRepaymentInstallment().getDueDate()))) {
paidChargePerInstallment = loanChargePerInstallment;
}
}
return paidChargePerInstallment;
}
public Loan getLoan() {
return this.loan;
}
@@ -21,6 +21,7 @@ import org.joda.time.format.DateTimeFormatter;
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
import org.mifosplatform.organisation.monetary.domain.MoneyHelper;
import org.mifosplatform.portfolio.account.PortfolioAccountType;
import org.mifosplatform.portfolio.account.data.AccountTransferDTO;
import org.mifosplatform.portfolio.account.domain.AccountTransferDetails;
@@ -59,7 +60,7 @@ public class GuarantorDomainServiceImpl implements GuarantorDomainService {
private final BusinessEventNotifierService businessEventNotifierService;
private final DepositAccountOnHoldTransactionRepository depositAccountOnHoldTransactionRepository;
private final Map<Long, Long> releaseLoanIds = new HashMap<>(2);
private final RoundingMode roundingMode = RoundingMode.HALF_EVEN;
@Autowired
public GuarantorDomainServiceImpl(final GuarantorRepository guarantorRepository,
@@ -101,8 +102,8 @@ public class GuarantorDomainServiceImpl implements GuarantorDomainService {
final List<Guarantor> existGuarantorList = this.guarantorRepository.findByLoan(loan);
BigDecimal mandatoryAmount = principal.multiply(guaranteeData.getMandatoryGuarantee()).divide(BigDecimal.valueOf(100));
BigDecimal minSelfAmount = principal.multiply(guaranteeData.getMinimumGuaranteeFromOwnFunds()).divide(BigDecimal.valueOf(100));
BigDecimal minExtGuarantee = principal.multiply(guaranteeData.getMinimumGuaranteeFromGuarantor()).divide(
BigDecimal.valueOf(100));
BigDecimal minExtGuarantee = principal.multiply(guaranteeData.getMinimumGuaranteeFromGuarantor())
.divide(BigDecimal.valueOf(100));
BigDecimal actualAmount = BigDecimal.ZERO;
BigDecimal actualSelfAmount = BigDecimal.ZERO;
@@ -113,11 +114,11 @@ public class GuarantorDomainServiceImpl implements GuarantorDomainService {
if (guarantorFundingDetails.getStatus().isActive() || guarantorFundingDetails.getStatus().isWithdrawn()
|| guarantorFundingDetails.getStatus().isCompleted()) {
if (guarantor.isSelfGuarantee()) {
actualSelfAmount = actualSelfAmount.add(guarantorFundingDetails.getAmount()).subtract(
guarantorFundingDetails.getAmountTransfered());
actualSelfAmount = actualSelfAmount.add(guarantorFundingDetails.getAmount())
.subtract(guarantorFundingDetails.getAmountTransfered());
} else {
actualExtGuarantee = actualExtGuarantee.add(guarantorFundingDetails.getAmount()).subtract(
guarantorFundingDetails.getAmountTransfered());
actualExtGuarantee = actualExtGuarantee.add(guarantorFundingDetails.getAmount())
.subtract(guarantorFundingDetails.getAmountTransfered());
}
}
}
@@ -238,12 +239,13 @@ public class GuarantorDomainServiceImpl implements GuarantorDomainService {
BigDecimal remainingAmount = guarantorFundingDetails.getAmountRemaining();
if (loan.getGuaranteeAmount().compareTo(loan.getPrincpal().getAmount()) == 1) {
remainingAmount = remainingAmount.multiply(loan.getPrincpal().getAmount()).divide(loan.getGuaranteeAmount(),
roundingMode);
RoundingMode.valueOf(MoneyHelper.getRoundingMode()));
}
AccountTransferDTO accountTransferDTO = new AccountTransferDTO(transactionDate, remainingAmount, fromAccountType,
toAccountType, fromAccountId, toAccountId, description, locale, fmt, paymentDetail, fromTransferType,
toTransferType, chargeId, loanInstallmentNumber, transferType, accountTransferDetails, noteText,
txnExternalId, loan, toSavingsAccount, fromSavingsAccount, isRegularTransaction, isExceptionForBalanceCheck);
txnExternalId, loan, toSavingsAccount, fromSavingsAccount, isRegularTransaction,
isExceptionForBalanceCheck);
transferAmount(accountTransferDTO);
} finally {
releaseLoanIds.remove(loanId);
@@ -378,16 +380,16 @@ public class GuarantorDomainServiceImpl implements GuarantorDomainService {
BigDecimal amountForRelease = loanTransaction.getPrincipalPortion();
BigDecimal totalGuaranteeAmount = loan.getGuaranteeAmount();
BigDecimal principal = loan.getPrincpal().getAmount();
if((amountForRelease!=null)&&(totalGuaranteeAmount!=null))
{
amountForRelease = amountForRelease.multiply(totalGuaranteeAmount).divide(principal,this.roundingMode);
if ((amountForRelease != null) && (totalGuaranteeAmount != null)) {
amountForRelease = amountForRelease.multiply(totalGuaranteeAmount).divide(principal, RoundingMode.valueOf(MoneyHelper.getRoundingMode()));
List<DepositAccountOnHoldTransaction> accountOnHoldTransactions = new ArrayList<>();
BigDecimal amountLeft = calculateAndRelaseGuarantorFunds(externalGuarantorList, guarantorGuarantee, amountForRelease,
loanTransaction, accountOnHoldTransactions);
loanTransaction, accountOnHoldTransactions);
if (amountLeft.compareTo(BigDecimal.ZERO) == 1) {
calculateAndRelaseGuarantorFunds(selfGuarantorList, selfGuarantee, amountLeft, loanTransaction, accountOnHoldTransactions);
calculateAndRelaseGuarantorFunds(selfGuarantorList, selfGuarantee, amountLeft, loanTransaction,
accountOnHoldTransactions);
externalGuarantorList.addAll(selfGuarantorList);
}
@@ -465,7 +467,7 @@ public class GuarantorDomainServiceImpl implements GuarantorDomainService {
BigDecimal amountLeft = amountForRelease;
for (GuarantorFundingDetails fundingDetails : guarantorList) {
BigDecimal guarantorAmount = amountForRelease.multiply(fundingDetails.getAmountRemaining()).divide(totalGuaranteeAmount,
roundingMode);
RoundingMode.valueOf(MoneyHelper.getRoundingMode()));
if (fundingDetails.getAmountRemaining().compareTo(guarantorAmount) < 1) {
guarantorAmount = fundingDetails.getAmountRemaining();
}
@@ -18,6 +18,7 @@ import org.joda.time.PeriodType;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.organisation.monetary.domain.MoneyHelper;
import org.mifosplatform.portfolio.calendar.domain.Calendar;
import org.mifosplatform.portfolio.calendar.domain.CalendarInstance;
import org.mifosplatform.portfolio.common.domain.DayOfWeekType;
@@ -402,7 +403,7 @@ public final class LoanApplicationTerms {
} else if (this.actualFixedEmiAmount != null) {
final Money difference = this.principal.minus(totalCumulativePrincipalToDate);
final Money principalThreshold = principalForPeriod.multipliedBy(this.principalThresholdForLastInstalment).dividedBy(100,
RoundingMode.HALF_EVEN);
RoundingMode.valueOf(MoneyHelper.getRoundingMode()));
if (difference.isLessThan(principalThreshold)) {
adjusted = principalForPeriod.plus(difference.abs());
}
@@ -486,7 +487,8 @@ public final class LoanApplicationTerms {
case DECLINING_BALANCE:
switch (this.amortizationMethod) {
case EQUAL_INSTALLMENTS:
Money totalPmtForThisInstallment = pmtForInstallment(calculator, daysInPeriod, outstandingBalance, periodNumber, mc);
Money totalPmtForThisInstallment = pmtForInstallment(calculator, daysInPeriod, outstandingBalance, periodNumber,
mc);
principalForInstallment = calculatePrincipalDueForInstallment(periodNumber, totalPmtForThisInstallment,
interestForThisInstallment);
break;
@@ -551,9 +553,9 @@ public final class LoanApplicationTerms {
final Money interestForThisInstallmentBeforeGrace = calculateDecliningInterestDueForInstallmentBeforeApplyingGrace(
calculator, mc, daysInPeriodApplicableForInterest, outstandingBalance);
final Money interestForThisInstallmentAfterGrace = calculateDecliningInterestDueForInstallmentAfterApplyingGrace(
calculator, interestCalculationGraceOnRepaymentPeriodFraction, mc, daysInPeriodApplicableForInterest,
outstandingBalance, periodNumber);
final Money interestForThisInstallmentAfterGrace = calculateDecliningInterestDueForInstallmentAfterApplyingGrace(calculator,
interestCalculationGraceOnRepaymentPeriodFraction, mc, daysInPeriodApplicableForInterest, outstandingBalance,
periodNumber);
interestForInstallment = interestForThisInstallmentAfterGrace;
if (interestForThisInstallmentAfterGrace.isGreaterThanZero()) {
@@ -646,7 +648,8 @@ public final class LoanApplicationTerms {
this.loanEndDate = loanEndDate;
}
private Money calculateTotalInterestPerInstallmentWithoutGrace(final PaymentPeriodsInOneYearCalculator calculator, final MathContext mc) {
private Money calculateTotalInterestPerInstallmentWithoutGrace(final PaymentPeriodsInOneYearCalculator calculator,
final MathContext mc) {
final Money totalInterestForLoanTerm = calculateTotalFlatInterestDueWithoutGrace(calculator, mc);
@@ -703,8 +706,8 @@ public final class LoanApplicationTerms {
final Integer interestPaymentDuePeriods = calculateNumberOfRepaymentPeriodsWhereInterestPaymentIsDue(this.numberOfRepayments);
interestForInstallment = realTotalInterestForLoan
.dividedBy(BigDecimal.valueOf(interestPaymentDuePeriods), mc.getRoundingMode());
interestForInstallment = realTotalInterestForLoan.dividedBy(BigDecimal.valueOf(interestPaymentDuePeriods),
mc.getRoundingMode());
}
return interestForInstallment;
@@ -786,8 +789,8 @@ public final class LoanApplicationTerms {
final BigDecimal divisor = BigDecimal.valueOf(Double.valueOf("100.0"));
final BigDecimal loanTermPeriodsInYearBigDecimal = BigDecimal.valueOf(loanTermPeriodsInOneYear);
final BigDecimal oneDayOfYearInterestRate = this.annualNominalInterestRate.divide(loanTermPeriodsInYearBigDecimal, mc).divide(
divisor, mc);
final BigDecimal oneDayOfYearInterestRate = this.annualNominalInterestRate.divide(loanTermPeriodsInYearBigDecimal, mc)
.divide(divisor, mc);
BigDecimal interestRate = oneDayOfYearInterestRate.multiply(BigDecimal.valueOf(repaymentEvery), mc);
return outstandingBalance.getAmount().multiply(interestRate, mc);
}
@@ -938,7 +941,8 @@ public final class LoanApplicationTerms {
return principal;
}
private Money calculatePrincipalDueForInstallment(final int periodNumber, final Money totalDuePerInstallment, final Money periodInterest) {
private Money calculatePrincipalDueForInstallment(final int periodNumber, final Money totalDuePerInstallment,
final Money periodInterest) {
Money principal = totalDuePerInstallment.minus(periodInterest);
if (isPrincipalGraceApplicableForThisPeriod(periodNumber)) {
@@ -25,6 +25,7 @@ import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.organisation.monetary.domain.MoneyHelper;
import org.mifosplatform.organisation.workingdays.domain.WorkingDays;
import org.mifosplatform.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
import org.mifosplatform.organisation.workingdays.service.WorkingDaysUtil;
@@ -229,8 +230,8 @@ public class LoanScheduleAssembler {
final Integer graceOnInterestCharged = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("graceOnInterestCharged", element);
final LocalDate interestChargedFromDate = this.fromApiJsonHelper.extractLocalDateNamed("interestChargedFromDate", element);
final Integer graceOnArrearsAgeing = this.fromApiJsonHelper.extractIntegerWithLocaleNamed(
LoanProductConstants.graceOnArrearsAgeingParameterName, element);
final Integer graceOnArrearsAgeing = this.fromApiJsonHelper
.extractIntegerWithLocaleNamed(LoanProductConstants.graceOnArrearsAgeingParameterName, element);
// other
final BigDecimal inArrearsTolerance = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("inArrearsTolerance", element);
@@ -238,14 +239,14 @@ public class LoanScheduleAssembler {
final BigDecimal emiAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(LoanApiConstants.emiAmountParameterName,
element);
final BigDecimal maxOutstandingBalance = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(
LoanApiConstants.maxOutstandingBalanceParameterName, element);
final BigDecimal maxOutstandingBalance = this.fromApiJsonHelper
.extractBigDecimalWithLocaleNamed(LoanApiConstants.maxOutstandingBalanceParameterName, element);
final List<DisbursementData> disbursementDatas = fetchDisbursementData(element.getAsJsonObject());
final List<LoanTermVariationsData> loanVariationTermsData = new ArrayList<>();
LoanTermVariationsData data = new LoanTermVariationsData(null,
LoanEnumerations.loanvariationType(LoanTermVariationType.EMI_AMOUNT), expectedDisbursementDate, emiAmount);
LoanTermVariationsData data = new LoanTermVariationsData(null, LoanEnumerations.loanvariationType(LoanTermVariationType.EMI_AMOUNT),
expectedDisbursementDate, emiAmount);
loanVariationTermsData.add(data);
/**
@@ -265,8 +266,8 @@ public class LoanScheduleAssembler {
.getProductInterestRecalculationDetails();
recalculationFrequencyType = loanProductInterestRecalculationDetails.getRestFrequencyType();
if (!recalculationFrequencyType.isSameAsRepayment()) {
LocalDate calendarStartDate = this.fromApiJsonHelper.extractLocalDateNamed(
LoanProductConstants.recalculationRestFrequencyDateParamName, element);
LocalDate calendarStartDate = this.fromApiJsonHelper
.extractLocalDateNamed(LoanProductConstants.recalculationRestFrequencyDateParamName, element);
if (calendarStartDate == null) {
calendarStartDate = expectedDisbursementDate;
}
@@ -278,8 +279,8 @@ public class LoanScheduleAssembler {
if (compoundingMethod.isCompoundingEnabled()) {
compoundingFrequencyType = loanProductInterestRecalculationDetails.getCompoundingFrequencyType();
if (!compoundingFrequencyType.isSameAsRepayment()) {
LocalDate calendarStartDate = this.fromApiJsonHelper.extractLocalDateNamed(
LoanProductConstants.recalculationCompoundingFrequencyDateParamName, element);
LocalDate calendarStartDate = this.fromApiJsonHelper
.extractLocalDateNamed(LoanProductConstants.recalculationCompoundingFrequencyDateParamName, element);
if (calendarStartDate == null) {
calendarStartDate = expectedDisbursementDate;
}
@@ -344,12 +345,12 @@ public class LoanScheduleAssembler {
BigDecimal principal = null;
if (jsonObject.has(LoanApiConstants.disbursementDateParameterName)) {
expectedDisbursementDate = this.fromApiJsonHelper.extractLocalDateNamed(
LoanApiConstants.disbursementDateParameterName, jsonObject, dateFormat, locale);
expectedDisbursementDate = this.fromApiJsonHelper
.extractLocalDateNamed(LoanApiConstants.disbursementDateParameterName, jsonObject, dateFormat, locale);
}
if (jsonObject.has(LoanApiConstants.disbursementPrincipalParameterName)
&& jsonObject.get(LoanApiConstants.disbursementPrincipalParameterName).isJsonPrimitive()
&& StringUtils.isNotBlank((jsonObject.get(LoanApiConstants.disbursementPrincipalParameterName).getAsString()))) {
&& jsonObject.get(LoanApiConstants.disbursementPrincipalParameterName).isJsonPrimitive() && StringUtils
.isNotBlank((jsonObject.get(LoanApiConstants.disbursementPrincipalParameterName).getAsString()))) {
principal = jsonObject.getAsJsonPrimitive(LoanApiConstants.disbursementPrincipalParameterName).getAsBigDecimal();
}
disbursementDatas.add(new DisbursementData(null, expectedDisbursementDate, null, principal));
@@ -361,9 +362,8 @@ public class LoanScheduleAssembler {
}
private void validateRepaymentsStartDateWithMeetingDates(final LocalDate repaymentsStartingFromDate, final Calendar calendar) {
if (repaymentsStartingFromDate != null
&& !CalendarUtils.isValidRedurringDate(calendar.getRecurrence(), calendar.getStartDateLocalDate(),
repaymentsStartingFromDate)) {
if (repaymentsStartingFromDate != null && !CalendarUtils.isValidRedurringDate(calendar.getRecurrence(),
calendar.getStartDateLocalDate(), repaymentsStartingFromDate)) {
final String errorMessage = "First repayment date '" + repaymentsStartingFromDate + "' do not fall on a meeting date";
throw new LoanApplicationDateException("first.repayment.date.do.not.match.meeting.date", errorMessage,
repaymentsStartingFromDate);
@@ -444,7 +444,7 @@ public class LoanScheduleAssembler {
final LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(loanApplicationTerms.getInterestMethod());
final RoundingMode roundingMode = RoundingMode.HALF_EVEN;
final RoundingMode roundingMode = RoundingMode.valueOf(MoneyHelper.getRoundingMode());
final MathContext mc = new MathContext(8, roundingMode);
HolidayDetailDTO detailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
@@ -455,12 +455,12 @@ public class LoanScheduleAssembler {
public LoanScheduleModel assembleForInterestRecalculation(final LoanApplicationTerms loanApplicationTerms, final Long officeId,
List<LoanTransaction> transactions, final Set<LoanCharge> loanCharges,
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor) {
final RoundingMode roundingMode = RoundingMode.HALF_EVEN;
final RoundingMode roundingMode = RoundingMode.valueOf(MoneyHelper.getRoundingMode());
final MathContext mc = new MathContext(8, roundingMode);
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(officeId, loanApplicationTerms
.getExpectedDisbursementDate().toDate(), HolidayStatusType.ACTIVE.getValue());
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(officeId,
loanApplicationTerms.getExpectedDisbursementDate().toDate(), HolidayStatusType.ACTIVE.getValue());
final WorkingDays workingDays = this.workingDaysRepository.findOne();
final LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(loanApplicationTerms.getInterestMethod());
@@ -474,12 +474,12 @@ public class LoanScheduleAssembler {
final Long officeId, List<LoanTransaction> loanTransactions,
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor) {
final LoanScheduleGenerator loanScheduleGenerator = this.loanScheduleFactory.create(loanApplicationTerms.getInterestMethod());
final RoundingMode roundingMode = RoundingMode.HALF_EVEN;
final RoundingMode roundingMode = RoundingMode.valueOf(MoneyHelper.getRoundingMode());
final MathContext mc = new MathContext(8, roundingMode);
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(officeId, loanApplicationTerms
.getExpectedDisbursementDate().toDate(), HolidayStatusType.ACTIVE.getValue());
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(officeId,
loanApplicationTerms.getExpectedDisbursementDate().toDate(), HolidayStatusType.ACTIVE.getValue());
final WorkingDays workingDays = this.workingDaysRepository.findOne();
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
@@ -521,7 +521,7 @@ public class LoanScheduleAssembler {
refernceDateForCalculatingFirstRepaymentDate, repaymentPeriodFrequencyType,
minimumDaysBetweenDisbursalAndFirstRepayment, calendar);
}/*** Individual or group account, or JLG not linked to a meeting ***/
} /*** Individual or group account, or JLG not linked to a meeting ***/
else {
LocalDate dateBasedOnRepaymentFrequency;
// Derive the first repayment date as greater date among
@@ -534,12 +534,12 @@ public class LoanScheduleAssembler {
dateBasedOnRepaymentFrequency = expectedDisbursementDate.plusWeeks(repaymentEvery);
} else if (repaymentPeriodFrequencyType.isMonthly()) {
dateBasedOnRepaymentFrequency = expectedDisbursementDate.plusMonths(repaymentEvery);
}/** yearly loan **/
} /** yearly loan **/
else {
dateBasedOnRepaymentFrequency = expectedDisbursementDate.plusYears(repaymentEvery);
}
derivedFirstRepayment = dateBasedOnRepaymentFrequency.isAfter(dateBasedOnMinimumDaysBetweenDisbursalAndFirstRepayment) ? dateBasedOnRepaymentFrequency
: dateBasedOnMinimumDaysBetweenDisbursalAndFirstRepayment;
derivedFirstRepayment = dateBasedOnRepaymentFrequency.isAfter(dateBasedOnMinimumDaysBetweenDisbursalAndFirstRepayment)
? dateBasedOnRepaymentFrequency : dateBasedOnMinimumDaysBetweenDisbursalAndFirstRepayment;
}
return derivedFirstRepayment;
@@ -553,16 +553,17 @@ public class LoanScheduleAssembler {
final LocalDate derivedFirstRepayment = CalendarUtils.getFirstRepaymentMeetingDate(calendar,
refernceDateForCalculatingFirstRepaymentDate, repaymentEvery, frequency);
final LocalDate minimumFirstRepaymentDate = expectedDisbursementDate.plusDays(minimumDaysBetweenDisbursalAndFirstRepayment);
return minimumFirstRepaymentDate.isBefore(derivedFirstRepayment) ? derivedFirstRepayment : deriveFirstRepaymentDateForJLGLoans(
repaymentEvery, expectedDisbursementDate, derivedFirstRepayment, repaymentPeriodFrequencyType,
minimumDaysBetweenDisbursalAndFirstRepayment, calendar);
return minimumFirstRepaymentDate.isBefore(derivedFirstRepayment) ? derivedFirstRepayment
: deriveFirstRepaymentDateForJLGLoans(repaymentEvery, expectedDisbursementDate, derivedFirstRepayment,
repaymentPeriodFrequencyType, minimumDaysBetweenDisbursalAndFirstRepayment, calendar);
}
private void validateMinimumDaysBetweenDisbursalAndFirstRepayment(final LocalDate disbursalDate, final LocalDate firstRepaymentDate,
final Integer minimumDaysBetweenDisbursalAndFirstRepayment) {
final LocalDate minimumFirstRepaymentDate = disbursalDate.plusDays(minimumDaysBetweenDisbursalAndFirstRepayment);
if (firstRepaymentDate.isBefore(minimumFirstRepaymentDate)) { throw new MinDaysBetweenDisbursalAndFirstRepaymentViolationException(
disbursalDate, firstRepaymentDate, minimumDaysBetweenDisbursalAndFirstRepayment); }
if (firstRepaymentDate
.isBefore(minimumFirstRepaymentDate)) { throw new MinDaysBetweenDisbursalAndFirstRepaymentViolationException(disbursalDate,
firstRepaymentDate, minimumDaysBetweenDisbursalAndFirstRepayment); }
}
}
@@ -16,6 +16,7 @@ import org.mifosplatform.organisation.holiday.domain.HolidayStatusType;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.MoneyHelper;
import org.mifosplatform.organisation.workingdays.domain.WorkingDays;
import org.mifosplatform.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
import org.mifosplatform.portfolio.calendar.domain.Calendar;
@@ -72,26 +73,26 @@ public class LoanReschedulePreviewPlatformServiceImpl implements LoanRescheduleP
Loan loan = loanRescheduleRequest.getLoan();
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), loan
.getDisbursementDate().toDate(), HolidayStatusType.ACTIVE.getValue());
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(),
loan.getDisbursementDate().toDate(), HolidayStatusType.ACTIVE.getValue());
final WorkingDays workingDays = this.workingDaysRepository.findOne();
final LoanProductMinimumRepaymentScheduleRelatedDetail loanProductRelatedDetail = loan.getLoanRepaymentScheduleDetail();
final MonetaryCurrency currency = loanProductRelatedDetail.getCurrency();
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
final InterestMethod interestMethod = loan.getLoanRepaymentScheduleDetail().getInterestMethod();
final RoundingMode roundingMode = RoundingMode.HALF_EVEN;
final RoundingMode roundingMode = RoundingMode.valueOf(MoneyHelper.getRoundingMode());
final MathContext mathContext = new MathContext(8, roundingMode);
List<LoanRepaymentScheduleHistory> oldPeriods = this.loanScheduleHistoryWritePlatformService.createLoanScheduleArchive(
loan.getRepaymentScheduleInstallments(), loan, loanRescheduleRequest);
List<LoanRepaymentScheduleHistory> oldPeriods = this.loanScheduleHistoryWritePlatformService
.createLoanScheduleArchive(loan.getRepaymentScheduleInstallments(), loan, loanRescheduleRequest);
HolidayDetailDTO holidayDetailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
CalendarInstance restCalendarInstance = null;
CalendarInstance compoundingCalendarInstance = null;
if (loan.repaymentScheduleDetail().isInterestRecalculationEnabled()) {
restCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
CalendarEntityType.LOAN_RECALCULATION_REST_DETAIL.getValue());
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(
loan.loanInterestRecalculationDetailId(), CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
compoundingCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.loanInterestRecalculationDetailId(),
CalendarEntityType.LOAN_RECALCULATION_COMPOUNDING_DETAIL.getValue());
}
final CalendarInstance loanCalendarInstance = calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(),
CalendarEntityType.LOANS.getValue());
@@ -28,6 +28,7 @@ import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.organisation.monetary.domain.MoneyHelper;
import org.mifosplatform.organisation.workingdays.domain.WorkingDays;
import org.mifosplatform.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
import org.mifosplatform.portfolio.calendar.domain.Calendar;
@@ -270,8 +271,8 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
final Map<String, Object> changes = new LinkedHashMap<>();
LocalDate approvedOnDate = jsonCommand.localDateValueOfParameterNamed("approvedOnDate");
final DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(jsonCommand.dateFormat()).withLocale(
jsonCommand.extractLocale());
final DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(jsonCommand.dateFormat())
.withLocale(jsonCommand.extractLocale());
changes.put("locale", jsonCommand.locale());
changes.put("dateFormat", jsonCommand.dateFormat());
@@ -283,15 +284,15 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
final LoanSummary loanSummary = loan.getSummary();
final boolean isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), loan
.getDisbursementDate().toDate());
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(),
loan.getDisbursementDate().toDate());
final WorkingDays workingDays = this.workingDaysRepository.findOne();
final LoanProductMinimumRepaymentScheduleRelatedDetail loanProductRelatedDetail = loan.getLoanRepaymentScheduleDetail();
final MonetaryCurrency currency = loanProductRelatedDetail.getCurrency();
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
final InterestMethod interestMethod = loan.getLoanRepaymentScheduleDetail().getInterestMethod();
final RoundingMode roundingMode = RoundingMode.HALF_EVEN;
final RoundingMode roundingMode = RoundingMode.valueOf(MoneyHelper.getRoundingMode());
final MathContext mathContext = new MathContext(8, roundingMode);
Collection<LoanRepaymentScheduleHistory> loanRepaymentScheduleHistoryList = this.loanScheduleHistoryWritePlatformService
@@ -454,12 +455,12 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
final CalendarInstance calendarInstance = this.calendarInstanceRepository.findCalendarInstaneByEntityId(loan.getId(),
CalendarEntityType.LOANS.getValue());
calculatedRepaymentsStartingFromDate = this.loanAccountDomainService.getCalculatedRepaymentsStartingFromDate(
loan.getDisbursementDate(), loan, calendarInstance);
calculatedRepaymentsStartingFromDate = this.loanAccountDomainService
.getCalculatedRepaymentsStartingFromDate(loan.getDisbursementDate(), loan, calendarInstance);
isHolidayEnabled = this.configurationDomainService.isRescheduleRepaymentsOnHolidaysEnabled();
holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), loan.getDisbursementDate()
.toDate());
holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(),
loan.getDisbursementDate().toDate());
workingDays = this.workingDaysRepository.findOne();
overdurPenaltyWaitPeriod = this.configurationDomainService.retrievePenaltyWaitPeriod();
}
@@ -471,8 +472,8 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
Money accruedCharge = Money.zero(loan.getCurrency());
if (loan.isPeriodicAccrualAccountingEnabledOnLoanProduct()) {
Collection<LoanChargePaidByData> chargePaidByDatas = this.loanChargeReadPlatformService.retriveLoanChargesPaidBy(
loanCharge.getId(), LoanTransactionType.ACCRUAL, loanInstallmentNumber);
Collection<LoanChargePaidByData> chargePaidByDatas = this.loanChargeReadPlatformService
.retriveLoanChargesPaidBy(loanCharge.getId(), LoanTransactionType.ACCRUAL, loanInstallmentNumber);
for (LoanChargePaidByData chargePaidByData : chargePaidByDatas) {
accruedCharge = accruedCharge.plus(chargePaidByData.getAmount());
}
@@ -522,8 +523,8 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
final Map<String, Object> changes = new LinkedHashMap<>();
LocalDate rejectedOnDate = jsonCommand.localDateValueOfParameterNamed("rejectedOnDate");
final DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(jsonCommand.dateFormat()).withLocale(
jsonCommand.extractLocale());
final DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern(jsonCommand.dateFormat())
.withLocale(jsonCommand.extractLocale());
changes.put("locale", jsonCommand.locale());
changes.put("dateFormat", jsonCommand.dateFormat());
@@ -22,6 +22,7 @@ import org.joda.time.LocalDate;
import org.mifosplatform.accounting.journalentry.service.JournalEntryWritePlatformService;
import org.mifosplatform.infrastructure.core.service.DateUtils;
import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
import org.mifosplatform.organisation.monetary.domain.MoneyHelper;
import org.mifosplatform.portfolio.loanaccount.data.LoanChargeData;
import org.mifosplatform.portfolio.loanaccount.data.LoanInstallmentChargeData;
import org.mifosplatform.portfolio.loanaccount.data.LoanScheduleAccrualData;
@@ -140,7 +141,7 @@ public class LoanAccrualWritePlatformServiceImpl implements LoanAccrualWritePlat
double iterest = interestPerDay * daysToBeAccrued;
interestportion = BigDecimal.valueOf(iterest);
}
interestportion = interestportion.setScale(accrualData.getCurrencyData().decimalPlaces(), RoundingMode.HALF_EVEN);
interestportion = interestportion.setScale(accrualData.getCurrencyData().decimalPlaces(), RoundingMode.valueOf(MoneyHelper.getRoundingMode()));
BigDecimal totalAccInterest = accrualData.getAccruedInterestIncome();
BigDecimal totalAccPenalty = accrualData.getAccruedPenaltyIncome();
@@ -34,6 +34,7 @@ import org.joda.time.MonthDay;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.organisation.monetary.domain.MoneyHelper;
import org.mifosplatform.portfolio.charge.domain.Charge;
import org.mifosplatform.portfolio.charge.domain.ChargeCalculationType;
import org.mifosplatform.portfolio.charge.domain.ChargeTimeType;
@@ -527,7 +528,7 @@ public class SavingsAccountCharge extends AbstractPersistable<Long> {
BigDecimal percentageOf = BigDecimal.ZERO;
if (isGreaterThanZero(value)) {
final MathContext mc = new MathContext(8, RoundingMode.HALF_EVEN);
final MathContext mc = new MathContext(8, RoundingMode.valueOf(MoneyHelper.getRoundingMode()));
final BigDecimal multiplicand = percentage.divide(BigDecimal.valueOf(100l), mc);
percentageOf = value.multiply(multiplicand, mc);
}
@@ -13,6 +13,7 @@ import java.util.List;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.domain.LocalDateInterval;
import org.mifosplatform.organisation.monetary.domain.MoneyHelper;
import org.mifosplatform.portfolio.savings.SavingsCompoundingInterestPeriodType;
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationType;
@@ -25,8 +26,8 @@ public class AnnualCompoundingPeriod implements CompoundingPeriod {
public static AnnualCompoundingPeriod create(final LocalDateInterval periodInterval, final List<EndOfDayBalance> allEndOfDayBalances,
final LocalDate upToInterestCalculationDate) {
final List<EndOfDayBalance> endOfDayBalancesWithinPeriod = endOfDayBalancesWithinPeriodInterval(periodInterval,
allEndOfDayBalances, upToInterestCalculationDate);
final List<EndOfDayBalance> endOfDayBalancesWithinPeriod = endOfDayBalancesWithinPeriodInterval(periodInterval, allEndOfDayBalances,
upToInterestCalculationDate);
return new AnnualCompoundingPeriod(periodInterval, endOfDayBalancesWithinPeriod);
}
@@ -40,8 +41,8 @@ public class AnnualCompoundingPeriod implements CompoundingPeriod {
switch (interestCalculationType) {
case DAILY_BALANCE:
interestEarned = calculateUsingDailyBalanceMethod(compoundingInterestPeriodType, interestToCompound,
interestRateAsFraction, daysInYear, minBalanceForInterestCalculation);
interestEarned = calculateUsingDailyBalanceMethod(compoundingInterestPeriodType, interestToCompound, interestRateAsFraction,
daysInYear, minBalanceForInterestCalculation);
break;
case AVERAGE_DAILY_BALANCE:
interestEarned = calculateUsingAverageDailyBalanceMethod(interestToCompound, interestRateAsFraction, daysInYear,
@@ -54,8 +55,8 @@ public class AnnualCompoundingPeriod implements CompoundingPeriod {
return interestEarned;
}
private BigDecimal calculateUsingAverageDailyBalanceMethod(final BigDecimal interestToCompound,
final BigDecimal interestRateAsFraction, final long daysInYear, final BigDecimal minBalanceForInterestCalculation) {
private BigDecimal calculateUsingAverageDailyBalanceMethod(final BigDecimal interestToCompound, final BigDecimal interestRateAsFraction,
final long daysInYear, final BigDecimal minBalanceForInterestCalculation) {
BigDecimal cumulativeBalance = BigDecimal.ZERO;
Integer numberOfDays = Integer.valueOf(0);
@@ -71,14 +72,14 @@ public class AnnualCompoundingPeriod implements CompoundingPeriod {
BigDecimal interestEarned = BigDecimal.ZERO;
if (cumulativeBalance.compareTo(BigDecimal.ZERO) != 0 && numberOfDays > 0) {
final BigDecimal averageDailyBalance = cumulativeBalance.divide(BigDecimal.valueOf(numberOfDays), MathContext.DECIMAL64)
.setScale(9, RoundingMode.HALF_EVEN);
.setScale(9, RoundingMode.valueOf(MoneyHelper.getRoundingMode()));
final BigDecimal multiplicand = BigDecimal.ONE.divide(BigDecimal.valueOf(daysInYear), MathContext.DECIMAL64);
final BigDecimal dailyInterestRate = interestRateAsFraction.multiply(multiplicand, MathContext.DECIMAL64);
final BigDecimal periodicInterestRate = dailyInterestRate.multiply(BigDecimal.valueOf(numberOfDays), MathContext.DECIMAL64);
if (averageDailyBalance.compareTo(minBalanceForInterestCalculation) >= 0) {
interestEarned = averageDailyBalance.multiply(periodicInterestRate, MathContext.DECIMAL64).setScale(9,
RoundingMode.HALF_EVEN);
RoundingMode.valueOf(MoneyHelper.getRoundingMode()));
}
}
@@ -13,6 +13,7 @@ import java.util.List;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.domain.LocalDateInterval;
import org.mifosplatform.organisation.monetary.domain.MoneyHelper;
import org.mifosplatform.portfolio.savings.SavingsCompoundingInterestPeriodType;
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationType;
@@ -25,8 +26,8 @@ public class BiAnnualCompoundingPeriod implements CompoundingPeriod {
public static BiAnnualCompoundingPeriod create(final LocalDateInterval periodInterval, final List<EndOfDayBalance> allEndOfDayBalances,
final LocalDate upToInterestCalculationDate) {
final List<EndOfDayBalance> endOfDayBalancesWithinPeriod = endOfDayBalancesWithinPeriodInterval(periodInterval,
allEndOfDayBalances, upToInterestCalculationDate);
final List<EndOfDayBalance> endOfDayBalancesWithinPeriod = endOfDayBalancesWithinPeriodInterval(periodInterval, allEndOfDayBalances,
upToInterestCalculationDate);
return new BiAnnualCompoundingPeriod(periodInterval, endOfDayBalancesWithinPeriod);
}
@@ -40,8 +41,8 @@ public class BiAnnualCompoundingPeriod implements CompoundingPeriod {
switch (interestCalculationType) {
case DAILY_BALANCE:
interestEarned = calculateUsingDailyBalanceMethod(compoundingInterestPeriodType, interestToCompound,
interestRateAsFraction, daysInYear, minBalanceForInterestCalculation);
interestEarned = calculateUsingDailyBalanceMethod(compoundingInterestPeriodType, interestToCompound, interestRateAsFraction,
daysInYear, minBalanceForInterestCalculation);
break;
case AVERAGE_DAILY_BALANCE:
interestEarned = calculateUsingAverageDailyBalanceMethod(interestToCompound, interestRateAsFraction, daysInYear,
@@ -54,8 +55,8 @@ public class BiAnnualCompoundingPeriod implements CompoundingPeriod {
return interestEarned;
}
private BigDecimal calculateUsingAverageDailyBalanceMethod(final BigDecimal interestToCompound,
final BigDecimal interestRateAsFraction, final long daysInYear, final BigDecimal minBalanceForInterestCalculation) {
private BigDecimal calculateUsingAverageDailyBalanceMethod(final BigDecimal interestToCompound, final BigDecimal interestRateAsFraction,
final long daysInYear, final BigDecimal minBalanceForInterestCalculation) {
BigDecimal cumulativeBalance = BigDecimal.ZERO;
Integer numberOfDays = Integer.valueOf(0);
@@ -71,14 +72,14 @@ public class BiAnnualCompoundingPeriod implements CompoundingPeriod {
BigDecimal interestEarned = BigDecimal.ZERO;
if (cumulativeBalance.compareTo(BigDecimal.ZERO) != 0 && numberOfDays > 0) {
final BigDecimal averageDailyBalance = cumulativeBalance.divide(BigDecimal.valueOf(numberOfDays), MathContext.DECIMAL64)
.setScale(9, RoundingMode.HALF_EVEN);
.setScale(9, RoundingMode.valueOf(MoneyHelper.getRoundingMode()));
final BigDecimal multiplicand = BigDecimal.ONE.divide(BigDecimal.valueOf(daysInYear), MathContext.DECIMAL64);
final BigDecimal dailyInterestRate = interestRateAsFraction.multiply(multiplicand, MathContext.DECIMAL64);
final BigDecimal periodicInterestRate = dailyInterestRate.multiply(BigDecimal.valueOf(numberOfDays), MathContext.DECIMAL64);
if (averageDailyBalance.compareTo(minBalanceForInterestCalculation) >= 0) {
interestEarned = averageDailyBalance.multiply(periodicInterestRate, MathContext.DECIMAL64).setScale(9,
RoundingMode.HALF_EVEN);
RoundingMode.valueOf(MoneyHelper.getRoundingMode()));
}
}
@@ -12,6 +12,7 @@ import java.math.RoundingMode;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.domain.LocalDateInterval;
import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.organisation.monetary.domain.MoneyHelper;
public class EndOfDayBalance {
@@ -20,7 +21,8 @@ public class EndOfDayBalance {
private final Money endOfDayBalance;
private final int numberOfDays;
public static EndOfDayBalance from(final LocalDate date, final Money openingBalance, final Money endOfDayBalance, final int numberOfDays) {
public static EndOfDayBalance from(final LocalDate date, final Money openingBalance, final Money endOfDayBalance,
final int numberOfDays) {
return new EndOfDayBalance(date, openingBalance, endOfDayBalance, numberOfDays);
}
@@ -42,7 +44,8 @@ public class EndOfDayBalance {
public BigDecimal cumulativeBalance(final BigDecimal interestToCompound) {
final BigDecimal daysAsBigDecimal = BigDecimal.valueOf(this.numberOfDays);
final BigDecimal realBalanceForInterestCalculation = this.endOfDayBalance.getAmount().add(interestToCompound);
return realBalanceForInterestCalculation.multiply(daysAsBigDecimal, MathContext.DECIMAL64).setScale(9, RoundingMode.HALF_EVEN);
return realBalanceForInterestCalculation.multiply(daysAsBigDecimal, MathContext.DECIMAL64).setScale(9,
RoundingMode.valueOf(MoneyHelper.getRoundingMode()));
}
public BigDecimal calculateInterestOnBalance(final BigDecimal interestToCompound, final BigDecimal interestRateAsFraction,
@@ -53,10 +56,10 @@ public class EndOfDayBalance {
final BigDecimal periodicInterestRate = dailyInterestRate.multiply(BigDecimal.valueOf(this.numberOfDays), MathContext.DECIMAL64);
final BigDecimal realBalanceForInterestCalculation = this.endOfDayBalance.getAmount().add(interestToCompound);
BigDecimal interest = BigDecimal.ZERO.setScale(9, RoundingMode.HALF_EVEN);
BigDecimal interest = BigDecimal.ZERO.setScale(9, RoundingMode.valueOf(MoneyHelper.getRoundingMode()));
if (realBalanceForInterestCalculation.compareTo(minBalanceForInterestCalculation) >= 0) {
interest = realBalanceForInterestCalculation.multiply(periodicInterestRate, MathContext.DECIMAL64).setScale(9,
RoundingMode.HALF_EVEN);
RoundingMode.valueOf(MoneyHelper.getRoundingMode()));
}
return interest;
}
@@ -78,12 +81,12 @@ public class EndOfDayBalance {
final BigDecimal interestRateForCompoundingPeriodPlusOne = BigDecimal.ONE.add(r);
final double interestRateForCompoundingPeriodPowered = Math.pow(interestRateForCompoundingPeriodPlusOne.doubleValue(), Integer
.valueOf(this.numberOfDays).doubleValue());
BigDecimal futureValue = presentValue.setScale(9, RoundingMode.HALF_EVEN);
final double interestRateForCompoundingPeriodPowered = Math.pow(interestRateForCompoundingPeriodPlusOne.doubleValue(),
Integer.valueOf(this.numberOfDays).doubleValue());
BigDecimal futureValue = presentValue.setScale(9, RoundingMode.valueOf(MoneyHelper.getRoundingMode()));
if (presentValue.compareTo(minBalanceForInterestCalculation) >= 0) {
futureValue = presentValue.multiply(BigDecimal.valueOf(interestRateForCompoundingPeriodPowered), MathContext.DECIMAL64)
.setScale(9, RoundingMode.HALF_EVEN);
.setScale(9, RoundingMode.valueOf(MoneyHelper.getRoundingMode()));
}
return futureValue.subtract(presentValue);
}
@@ -13,6 +13,7 @@ import java.util.List;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.domain.LocalDateInterval;
import org.mifosplatform.organisation.monetary.domain.MoneyHelper;
import org.mifosplatform.portfolio.savings.SavingsCompoundingInterestPeriodType;
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationType;
@@ -25,8 +26,8 @@ public class MonthlyCompoundingPeriod implements CompoundingPeriod {
public static MonthlyCompoundingPeriod create(final LocalDateInterval periodInterval, final List<EndOfDayBalance> allEndOfDayBalances,
final LocalDate upToInterestCalculationDate) {
final List<EndOfDayBalance> endOfDayBalancesWithinPeriod = endOfDayBalancesWithinPeriodInterval(periodInterval,
allEndOfDayBalances, upToInterestCalculationDate);
final List<EndOfDayBalance> endOfDayBalancesWithinPeriod = endOfDayBalancesWithinPeriodInterval(periodInterval, allEndOfDayBalances,
upToInterestCalculationDate);
return new MonthlyCompoundingPeriod(periodInterval, endOfDayBalancesWithinPeriod);
}
@@ -40,8 +41,8 @@ public class MonthlyCompoundingPeriod implements CompoundingPeriod {
switch (interestCalculationType) {
case DAILY_BALANCE:
interestEarned = calculateUsingDailyBalanceMethod(compoundingInterestPeriodType, interestToCompound,
interestRateAsFraction, daysInYear, minBalanceForInterestCalculation);
interestEarned = calculateUsingDailyBalanceMethod(compoundingInterestPeriodType, interestToCompound, interestRateAsFraction,
daysInYear, minBalanceForInterestCalculation);
break;
case AVERAGE_DAILY_BALANCE:
interestEarned = calculateUsingAverageDailyBalanceMethod(interestToCompound, interestRateAsFraction, daysInYear,
@@ -54,8 +55,8 @@ public class MonthlyCompoundingPeriod implements CompoundingPeriod {
return interestEarned;
}
private BigDecimal calculateUsingAverageDailyBalanceMethod(final BigDecimal interestToCompound,
final BigDecimal interestRateAsFraction, final long daysInYear, final BigDecimal minBalanceForInterestCalculation) {
private BigDecimal calculateUsingAverageDailyBalanceMethod(final BigDecimal interestToCompound, final BigDecimal interestRateAsFraction,
final long daysInYear, final BigDecimal minBalanceForInterestCalculation) {
BigDecimal cumulativeBalance = BigDecimal.ZERO;
Integer numberOfDays = Integer.valueOf(0);
@@ -71,14 +72,14 @@ public class MonthlyCompoundingPeriod implements CompoundingPeriod {
BigDecimal interestEarned = BigDecimal.ZERO;
if (cumulativeBalance.compareTo(BigDecimal.ZERO) != 0 && numberOfDays > 0) {
final BigDecimal averageDailyBalance = cumulativeBalance.divide(BigDecimal.valueOf(numberOfDays), MathContext.DECIMAL64)
.setScale(9, RoundingMode.HALF_EVEN);
.setScale(9, RoundingMode.valueOf(MoneyHelper.getRoundingMode()));
final BigDecimal multiplicand = BigDecimal.ONE.divide(BigDecimal.valueOf(daysInYear), MathContext.DECIMAL64);
final BigDecimal dailyInterestRate = interestRateAsFraction.multiply(multiplicand, MathContext.DECIMAL64);
final BigDecimal periodicInterestRate = dailyInterestRate.multiply(BigDecimal.valueOf(numberOfDays), MathContext.DECIMAL64);
if (averageDailyBalance.compareTo(minBalanceForInterestCalculation) >= 0) {
interestEarned = averageDailyBalance.multiply(periodicInterestRate, MathContext.DECIMAL64).setScale(9,
RoundingMode.HALF_EVEN);
RoundingMode.valueOf(MoneyHelper.getRoundingMode()));
}
}
@@ -13,6 +13,7 @@ import java.util.List;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.domain.LocalDateInterval;
import org.mifosplatform.organisation.monetary.domain.MoneyHelper;
import org.mifosplatform.portfolio.savings.SavingsCompoundingInterestPeriodType;
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationType;
@@ -22,11 +23,11 @@ public class QuarterlyCompoundingPeriod implements CompoundingPeriod {
private final LocalDateInterval periodInterval;
private final List<EndOfDayBalance> endOfDayBalances;
public static QuarterlyCompoundingPeriod create(final LocalDateInterval periodInterval,
final List<EndOfDayBalance> allEndOfDayBalances, final LocalDate upToInterestCalculationDate) {
public static QuarterlyCompoundingPeriod create(final LocalDateInterval periodInterval, final List<EndOfDayBalance> allEndOfDayBalances,
final LocalDate upToInterestCalculationDate) {
final List<EndOfDayBalance> endOfDayBalancesWithinPeriod = endOfDayBalancesWithinPeriodInterval(periodInterval,
allEndOfDayBalances, upToInterestCalculationDate);
final List<EndOfDayBalance> endOfDayBalancesWithinPeriod = endOfDayBalancesWithinPeriodInterval(periodInterval, allEndOfDayBalances,
upToInterestCalculationDate);
return new QuarterlyCompoundingPeriod(periodInterval, endOfDayBalancesWithinPeriod);
}
@@ -40,8 +41,8 @@ public class QuarterlyCompoundingPeriod implements CompoundingPeriod {
switch (interestCalculationType) {
case DAILY_BALANCE:
interestEarned = calculateUsingDailyBalanceMethod(compoundingInterestPeriodType, interestToCompound,
interestRateAsFraction, daysInYear, minBalanceForInterestCalculation);
interestEarned = calculateUsingDailyBalanceMethod(compoundingInterestPeriodType, interestToCompound, interestRateAsFraction,
daysInYear, minBalanceForInterestCalculation);
break;
case AVERAGE_DAILY_BALANCE:
interestEarned = calculateUsingAverageDailyBalanceMethod(interestToCompound, interestRateAsFraction, daysInYear,
@@ -54,8 +55,8 @@ public class QuarterlyCompoundingPeriod implements CompoundingPeriod {
return interestEarned;
}
private BigDecimal calculateUsingAverageDailyBalanceMethod(final BigDecimal interestToCompound,
final BigDecimal interestRateAsFraction, final long daysInYear, final BigDecimal minBalanceForInterestCalculation) {
private BigDecimal calculateUsingAverageDailyBalanceMethod(final BigDecimal interestToCompound, final BigDecimal interestRateAsFraction,
final long daysInYear, final BigDecimal minBalanceForInterestCalculation) {
BigDecimal cumulativeBalance = BigDecimal.ZERO;
Integer numberOfDays = Integer.valueOf(0);
@@ -71,14 +72,14 @@ public class QuarterlyCompoundingPeriod implements CompoundingPeriod {
BigDecimal interestEarned = BigDecimal.ZERO;
if (cumulativeBalance.compareTo(BigDecimal.ZERO) != 0 && numberOfDays > 0) {
final BigDecimal averageDailyBalance = cumulativeBalance.divide(BigDecimal.valueOf(numberOfDays), MathContext.DECIMAL64)
.setScale(9, RoundingMode.HALF_EVEN);
.setScale(9, RoundingMode.valueOf(MoneyHelper.getRoundingMode()));
final BigDecimal multiplicand = BigDecimal.ONE.divide(BigDecimal.valueOf(daysInYear), MathContext.DECIMAL64);
final BigDecimal dailyInterestRate = interestRateAsFraction.multiply(multiplicand, MathContext.DECIMAL64);
final BigDecimal periodicInterestRate = dailyInterestRate.multiply(BigDecimal.valueOf(numberOfDays), MathContext.DECIMAL64);
if (averageDailyBalance.compareTo(minBalanceForInterestCalculation) >= 0) {
interestEarned = averageDailyBalance.multiply(periodicInterestRate, MathContext.DECIMAL64).setScale(9,
RoundingMode.HALF_EVEN);
RoundingMode.valueOf(MoneyHelper.getRoundingMode()));
}
}
@@ -47,6 +47,7 @@ import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.organisation.monetary.domain.MoneyHelper;
import org.mifosplatform.organisation.office.domain.Office;
import org.mifosplatform.organisation.staff.domain.Staff;
import org.mifosplatform.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
@@ -466,7 +467,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
checkClientOrGroupActive(account);
final LocalDate today = DateUtils.getLocalDateOfTenant();
final MathContext mc = new MathContext(15, RoundingMode.HALF_EVEN);
final MathContext mc = new MathContext(15, RoundingMode.valueOf(MoneyHelper.getRoundingMode()));
boolean isInterestTransfer = false;
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
@@ -510,7 +511,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
final Set<Long> existingReversedTransactionIds = new HashSet<>();
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
final LocalDate today = DateUtils.getLocalDateOfTenant();
final MathContext mc = new MathContext(10, RoundingMode.HALF_EVEN);
final MathContext mc = new MathContext(10, RoundingMode.valueOf(MoneyHelper.getRoundingMode()));
boolean isInterestTransfer = false;
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
this.savingAccountRepository.save(account);
@@ -659,7 +660,7 @@ public class DepositAccountWritePlatformServiceJpaRepositoryImpl implements Depo
final Map<String, Object> changes = new LinkedHashMap<>();
final PaymentDetail paymentDetail = this.paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes);
final MathContext mc = new MathContext(10, RoundingMode.HALF_EVEN);
final MathContext mc = new MathContext(10, RoundingMode.valueOf(MoneyHelper.getRoundingMode()));
account.undoTransaction(transactionId);
SavingsAccountTransaction transaction = null;
@@ -43,6 +43,7 @@ import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency;
import org.mifosplatform.organisation.monetary.domain.ApplicationCurrencyRepositoryWrapper;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.organisation.monetary.domain.MoneyHelper;
import org.mifosplatform.organisation.office.domain.Office;
import org.mifosplatform.organisation.staff.domain.Staff;
import org.mifosplatform.organisation.staff.domain.StaffRepositoryWrapper;
@@ -321,7 +322,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
checkClientOrGroupActive(account);
final LocalDate today = DateUtils.getLocalDateOfTenant();
final MathContext mc = new MathContext(15, RoundingMode.HALF_EVEN);
final MathContext mc = new MathContext(15, RoundingMode.valueOf(MoneyHelper.getRoundingMode()));
boolean isInterestTransfer = false;
account.calculateInterestUsing(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd,
financialYearBeginningMonth);
@@ -366,7 +367,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final Set<Long> existingReversedTransactionIds = new HashSet<>();
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
final LocalDate today = DateUtils.getLocalDateOfTenant();
final MathContext mc = new MathContext(10, RoundingMode.HALF_EVEN);
final MathContext mc = new MathContext(10, RoundingMode.valueOf(MoneyHelper.getRoundingMode()));
boolean isInterestTransfer = false;
account.postInterest(mc, today, isInterestTransfer, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth);
@@ -384,7 +385,6 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
}
}
@Override
public CommandProcessingResult undoTransaction(final Long savingsId, final Long transactionId,
final boolean allowAccountTransferModification) {
@@ -415,7 +415,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
"Savings account transaction:" + transactionId + " update not allowed for this savings type", transactionId); }
final LocalDate today = DateUtils.getLocalDateOfTenant();
final MathContext mc = new MathContext(15, RoundingMode.HALF_EVEN);
final MathContext mc = new MathContext(15, RoundingMode.valueOf(MoneyHelper.getRoundingMode()));
if (account.isNotActive()) {
throwValidationForActiveStatus(SavingsApiConstants.undoTransactionAction);
@@ -497,7 +497,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
final Map<String, Object> changes = new LinkedHashMap<>();
final PaymentDetail paymentDetail = this.paymentDetailWritePlatformService.createAndPersistPaymentDetail(command, changes);
final MathContext mc = new MathContext(10, RoundingMode.HALF_EVEN);
final MathContext mc = new MathContext(10, RoundingMode.valueOf(MoneyHelper.getRoundingMode()));
account.undoTransaction(transactionId);
// for undo withdrawal fee
@@ -0,0 +1,4 @@
ALTER TABLE `c_configuration`
ADD COLUMN `is_trap_door` boolean NOT NULL DEFAULT '0' AFTER `enabled`;
insert into c_configuration(name, value, enabled, is_trap_door, description) values('rounding-mode', '6', '1', '1', '0 - UP, 1 - DOWN, 2- CEILING, 3- FLOOR, 4- HALF_UP, 5- HALF_DOWN, 6 - HALF_EVEN');
@@ -5,6 +5,7 @@
*/
package org.mifosplatform.portfolio.loanaccount;
import java.lang.reflect.Field;
import java.util.List;
import org.joda.time.LocalDate;
@@ -12,6 +13,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.MoneyHelper;
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.impl.RBILoanRepaymentScheduleTransactionProcessor;
import org.mockito.runners.MockitoJUnitRunner;
@@ -29,8 +31,11 @@ public class AdhikarLoanRepaymentScheduleTransactionProcessorTest {
private List<LoanRepaymentScheduleInstallment> installments;
@Before
public void setUpForEachTestCase() {
public void setUpForEachTestCase() throws Exception {
Field field = MoneyHelper.class.getDeclaredField("roundingModeIntValue");
field.setAccessible(true);
field.setInt(null, 6);
this.installments = LoanScheduleTestDataHelper.createSimpleLoanSchedule(this.july2nd, this.usDollars);
this.processor = new RBILoanRepaymentScheduleTransactionProcessor();
@@ -5,6 +5,7 @@
*/
package org.mifosplatform.portfolio.loanaccount;
import java.lang.reflect.Field;
import java.util.List;
import org.joda.time.LocalDate;
@@ -12,6 +13,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.MoneyHelper;
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
import org.mifosplatform.portfolio.loanaccount.domain.transactionprocessor.impl.HeavensFamilyLoanRepaymentScheduleTransactionProcessor;
import org.mockito.runners.MockitoJUnitRunner;
@@ -29,8 +31,11 @@ public class HeavensFamilyLoanRepaymentScheduleTransactionProcessorTest {
private List<LoanRepaymentScheduleInstallment> installments;
@Before
public void setUpForEachTestCase() {
public void setUpForEachTestCase() throws Exception {
Field field = MoneyHelper.class.getDeclaredField("roundingModeIntValue");
field.setAccessible(true);
field.setInt(null, 6);
this.installments = LoanScheduleTestDataHelper.createSimpleLoanSchedule(this.july2nd, this.usDollars);
this.processor = new HeavensFamilyLoanRepaymentScheduleTransactionProcessor();