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