calculate future value of fixed term deposit on opening or creation of deposit account.2
This commit is contained in:
+13
-7
@@ -118,14 +118,19 @@ public class DepositAccount extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
|
|
||||||
public static DepositAccount openNew(
|
public static DepositAccount openNew(
|
||||||
final Client client, final DepositProduct product,
|
final Client client, final DepositProduct product,
|
||||||
final String externalId, final Money deposit, final BigDecimal interestRate, final Integer termInMonths,
|
final String externalId, final Money deposit, final BigDecimal maturityInterestRate, final Integer tenureInMonths,
|
||||||
final Integer interestCompoundedEvery,
|
final Integer interestCompoundedEvery,
|
||||||
final PeriodFrequencyType interestCompoundedFrequencyPeriodType,
|
final PeriodFrequencyType interestCompoundedFrequencyPeriodType,
|
||||||
final LocalDate commencementDate,
|
final LocalDate commencementDate,
|
||||||
final boolean renewalAllowed,
|
final boolean renewalAllowed,
|
||||||
final boolean preClosureAllowed) {
|
final boolean preClosureAllowed,
|
||||||
return new DepositAccount(client, product, externalId, deposit, interestRate, termInMonths,
|
final FixedTermDepositInterestCalculator fixedTermDepositInterestCalculator) {
|
||||||
interestCompoundedEvery, interestCompoundedFrequencyPeriodType, commencementDate, renewalAllowed, preClosureAllowed);
|
|
||||||
|
Money futureValueOnMaturity = fixedTermDepositInterestCalculator.calculateInterestOnMaturityFor(deposit, tenureInMonths,
|
||||||
|
maturityInterestRate, interestCompoundedEvery, interestCompoundedFrequencyPeriodType);
|
||||||
|
|
||||||
|
return new DepositAccount(client, product, externalId, deposit, maturityInterestRate, tenureInMonths,
|
||||||
|
interestCompoundedEvery, interestCompoundedFrequencyPeriodType, commencementDate, renewalAllowed, preClosureAllowed, futureValueOnMaturity);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DepositAccount() {
|
protected DepositAccount() {
|
||||||
@@ -139,7 +144,8 @@ public class DepositAccount extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
final PeriodFrequencyType interestCompoundedFrequencyPeriodType,
|
final PeriodFrequencyType interestCompoundedFrequencyPeriodType,
|
||||||
final LocalDate commencementDate,
|
final LocalDate commencementDate,
|
||||||
final boolean renewalAllowed,
|
final boolean renewalAllowed,
|
||||||
final boolean preClosureAllowed) {
|
final boolean preClosureAllowed,
|
||||||
|
final Money futureValueOnMaturity) {
|
||||||
this.client = client;
|
this.client = client;
|
||||||
this.product = product;
|
this.product = product;
|
||||||
this.externalId = externalId;
|
this.externalId = externalId;
|
||||||
@@ -163,8 +169,8 @@ public class DepositAccount extends AbstractAuditableCustom<AppUser, Long> {
|
|||||||
this.preClosureInterestRate = BigDecimal.ZERO;
|
this.preClosureInterestRate = BigDecimal.ZERO;
|
||||||
|
|
||||||
// derived fields
|
// derived fields
|
||||||
this.projectedInterestAccruedOnMaturity = BigDecimal.ZERO;
|
this.projectedInterestAccruedOnMaturity = futureValueOnMaturity.minus(deposit).getAmount();
|
||||||
this.projectedTotalOnMaturity = BigDecimal.ZERO;
|
this.projectedTotalOnMaturity = futureValueOnMaturity.getAmount();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isDeleted() {
|
public boolean isDeleted() {
|
||||||
|
|||||||
+66
@@ -0,0 +1,66 @@
|
|||||||
|
package org.mifosng.platform.saving.domain;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.MathContext;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
|
||||||
|
import org.mifosng.platform.currency.domain.Money;
|
||||||
|
import org.mifosng.platform.loan.domain.PeriodFrequencyType;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class FixedTermDepositInterestCalculator {
|
||||||
|
|
||||||
|
public Money calculateInterestOnMaturityFor(
|
||||||
|
final Money deposit,
|
||||||
|
final Integer tenureInMonths,
|
||||||
|
final BigDecimal maturityInterestRate,
|
||||||
|
final Integer interestCompoundedEvery,
|
||||||
|
final PeriodFrequencyType interestCompoundedFrequencyPeriodType) {
|
||||||
|
|
||||||
|
// TODO - Can change 'interest compounding' fields into something simpler like interestCompoundedFrequency {None (Simple Interest), Monthly, Quarterly, Half-Yearly, Annually}
|
||||||
|
// - the 'interestCompoundedEvery' would then be inferred form the selected type.
|
||||||
|
// - the special case of 'simple interest' or 'no compounding' would use simple formula rather than 'future value' function.
|
||||||
|
|
||||||
|
// FIXME - assuming only monthly compounding period for now
|
||||||
|
MathContext mc = new MathContext(8, RoundingMode.HALF_EVEN);
|
||||||
|
Integer monthsInYear = 12;
|
||||||
|
|
||||||
|
BigDecimal interestRateAsFraction = maturityInterestRate.divide(BigDecimal.valueOf(100), mc);
|
||||||
|
BigDecimal interestRateForOneMonth = interestRateAsFraction.divide(BigDecimal.valueOf(monthsInYear.doubleValue()), mc);
|
||||||
|
|
||||||
|
BigDecimal ratePerCompoundingPeriod = interestRateForOneMonth.multiply(BigDecimal.valueOf(interestCompoundedEvery.doubleValue()), mc);
|
||||||
|
|
||||||
|
Integer numberOfPeriods = tenureInMonths / interestCompoundedEvery;
|
||||||
|
|
||||||
|
return fv(ratePerCompoundingPeriod, numberOfPeriods, deposit);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Money fv(final BigDecimal ratePerCompoundingPeriod, final Integer numberOfPeriods, final Money presentValue) {
|
||||||
|
|
||||||
|
double pmtPerPeriod = Double.valueOf("0.0");
|
||||||
|
double pv = presentValue.negated().getAmount().doubleValue();
|
||||||
|
|
||||||
|
double futureValue = fv(ratePerCompoundingPeriod.doubleValue(), numberOfPeriods.doubleValue(), pmtPerPeriod, pv, false);
|
||||||
|
|
||||||
|
return Money.of(presentValue.getCurrency(), BigDecimal.valueOf(futureValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Future value of an amount given the number of payments, rate, amount of
|
||||||
|
* individual payment, present value and boolean value indicating whether
|
||||||
|
* payments are due at the beginning of period (false => payments are due at
|
||||||
|
* end of period)
|
||||||
|
*/
|
||||||
|
private static double fv(double ratePeriodCompoundingPeriod, double numberOfCompoundingPeriods, double pmtPerPeriod, double presentValue, boolean type) {
|
||||||
|
double retval = 0;
|
||||||
|
if (ratePeriodCompoundingPeriod == 0) {
|
||||||
|
retval = -1 * (presentValue + (numberOfCompoundingPeriods * pmtPerPeriod));
|
||||||
|
} else {
|
||||||
|
double r1 = ratePeriodCompoundingPeriod + 1;
|
||||||
|
retval = ((1 - Math.pow(r1, numberOfCompoundingPeriods)) * (type ? r1 : 1) * pmtPerPeriod) / ratePeriodCompoundingPeriod - presentValue
|
||||||
|
* Math.pow(r1, numberOfCompoundingPeriods);
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
}
|
||||||
+6
-4
@@ -10,6 +10,7 @@ import org.mifosng.platform.exceptions.ClientNotFoundException;
|
|||||||
import org.mifosng.platform.exceptions.DepositProductNotFoundException;
|
import org.mifosng.platform.exceptions.DepositProductNotFoundException;
|
||||||
import org.mifosng.platform.loan.domain.PeriodFrequencyType;
|
import org.mifosng.platform.loan.domain.PeriodFrequencyType;
|
||||||
import org.mifosng.platform.saving.domain.DepositAccount;
|
import org.mifosng.platform.saving.domain.DepositAccount;
|
||||||
|
import org.mifosng.platform.saving.domain.FixedTermDepositInterestCalculator;
|
||||||
import org.mifosng.platform.savingproduct.domain.DepositProduct;
|
import org.mifosng.platform.savingproduct.domain.DepositProduct;
|
||||||
import org.mifosng.platform.savingproduct.domain.DepositProductRepository;
|
import org.mifosng.platform.savingproduct.domain.DepositProductRepository;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -23,11 +24,14 @@ public class DepositAccountAssembler {
|
|||||||
|
|
||||||
private final ClientRepository clientRepository;
|
private final ClientRepository clientRepository;
|
||||||
private final DepositProductRepository depositProductRepository;
|
private final DepositProductRepository depositProductRepository;
|
||||||
|
private final FixedTermDepositInterestCalculator fixedTermDepositInterestCalculator;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public DepositAccountAssembler(final ClientRepository clientRepository, final DepositProductRepository depositProductRepository) {
|
public DepositAccountAssembler(final ClientRepository clientRepository, final DepositProductRepository depositProductRepository,
|
||||||
|
final FixedTermDepositInterestCalculator fixedTermDepositInterestCalculator) {
|
||||||
this.clientRepository = clientRepository;
|
this.clientRepository = clientRepository;
|
||||||
this.depositProductRepository = depositProductRepository;
|
this.depositProductRepository = depositProductRepository;
|
||||||
|
this.fixedTermDepositInterestCalculator = fixedTermDepositInterestCalculator;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DepositAccount assembleFrom(final DepositAccountCommand command) {
|
public DepositAccount assembleFrom(final DepositAccountCommand command) {
|
||||||
@@ -76,14 +80,12 @@ public class DepositAccountAssembler {
|
|||||||
}
|
}
|
||||||
// end of details allowed to be overriden from product
|
// end of details allowed to be overriden from product
|
||||||
|
|
||||||
// fixed-term interest calculator
|
|
||||||
|
|
||||||
DepositAccount account = DepositAccount.openNew(client, product, command.getExternalId(),
|
DepositAccount account = DepositAccount.openNew(client, product, command.getExternalId(),
|
||||||
deposit,
|
deposit,
|
||||||
maturityInterestRate,
|
maturityInterestRate,
|
||||||
tenureInMonths, compoundingInterestEvery, compoundingInterestFrequency,
|
tenureInMonths, compoundingInterestEvery, compoundingInterestFrequency,
|
||||||
command.getCommencementDate(),
|
command.getCommencementDate(),
|
||||||
renewalAllowed, preClosureAllowed);
|
renewalAllowed, preClosureAllowed, this.fixedTermDepositInterestCalculator);
|
||||||
|
|
||||||
return account;
|
return account;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user