MIFOSX-2148: Make Rounding Mode as configurable throughout Mifos
This commit is contained in:
+3
-4
@@ -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;
|
||||
|
||||
+2
@@ -47,4 +47,6 @@ public interface ConfigurationDomainService {
|
||||
|
||||
boolean isMeetingMandatoryForJLGLoans();
|
||||
|
||||
int getRoundingMode();
|
||||
|
||||
}
|
||||
+12
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+20
-14
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
+17
@@ -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});
|
||||
}
|
||||
|
||||
}
|
||||
+14
-14
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+36
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+75
-68
@@ -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()); }
|
||||
|
||||
}
|
||||
|
||||
|
||||
+25
-24
@@ -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;
|
||||
}
|
||||
|
||||
+17
-15
@@ -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();
|
||||
}
|
||||
|
||||
+15
-11
@@ -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)) {
|
||||
|
||||
+34
-33
@@ -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); }
|
||||
}
|
||||
}
|
||||
+8
-7
@@ -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());
|
||||
|
||||
+14
-13
@@ -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());
|
||||
|
||||
+2
-1
@@ -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();
|
||||
|
||||
+2
-1
@@ -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);
|
||||
}
|
||||
|
||||
+9
-8
@@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+9
-8
@@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-8
@@ -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);
|
||||
}
|
||||
|
||||
+9
-8
@@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-10
@@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-3
@@ -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;
|
||||
|
||||
+5
-5
@@ -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
|
||||
|
||||
+4
@@ -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');
|
||||
+6
-1
@@ -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();
|
||||
|
||||
+6
-1
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user