Merge pull request #880 from michaeldk-miagstan/michael-miagstan-github
Advanced deposit products and accounts (FD & RD) with interest rate extensions
This commit is contained in:
+4
@@ -210,4 +210,8 @@ public class InterestRateChartSlabFields {
|
||||
}
|
||||
return actualDepositPeriod;
|
||||
}
|
||||
|
||||
public boolean isAmountBetween(final BigDecimal depositAmount){
|
||||
return depositAmount.compareTo(amountRangeFrom) >= 0 && depositAmount.compareTo(amountRangeTo) <= 0;
|
||||
}
|
||||
}
|
||||
+8
-3
@@ -69,6 +69,7 @@ public class DepositsApiConstants {
|
||||
public static final String approvedOnDateParamName = "approvedOnDate";
|
||||
public static final String activatedOnDateParamName = "activatedOnDate";
|
||||
public static final String closedOnDateParamName = "closedOnDate";
|
||||
public static final String expectedFirstDepositOnDateParamName = "expectedFirstDepositOnDate";
|
||||
|
||||
public static final String activeParamName = "active";
|
||||
public static final String nameParamName = "name";
|
||||
@@ -118,6 +119,8 @@ public class DepositsApiConstants {
|
||||
public static final String inMultiplesOfDepositTermType = "inMultiplesOfDepositTermType";
|
||||
|
||||
public static final String depositAmountParamName = "depositAmount";
|
||||
public static final String depositMinAmountParamName = "minDepositAmount";
|
||||
public static final String depositMaxAmountParamName = "maxDepositAmount";
|
||||
public static final String depositPeriodParamName = "depositPeriod";
|
||||
public static final String depositPeriodFrequencyIdParamName = "depositPeriodFrequencyId";
|
||||
|
||||
@@ -211,11 +214,13 @@ public class DepositsApiConstants {
|
||||
|
||||
private static final Set<String> DEPOSIT_TERM_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(minDepositTermParamName,
|
||||
maxDepositTermParamName, minDepositTermTypeIdParamName, maxDepositTermTypeIdParamName, inMultiplesOfDepositTermParamName,
|
||||
inMultiplesOfDepositTermTypeIdParamName));
|
||||
inMultiplesOfDepositTermTypeIdParamName, depositAmountParamName,
|
||||
depositMinAmountParamName, depositMaxAmountParamName));
|
||||
|
||||
private static final Set<String> DEPOSIT_TERM_RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(minDepositTermParamName,
|
||||
maxDepositTermParamName, minDepositTermType, maxDepositTermType, inMultiplesOfDepositTermParamName,
|
||||
inMultiplesOfDepositTermType));
|
||||
inMultiplesOfDepositTermType, depositAmountParamName,
|
||||
depositMinAmountParamName, depositMaxAmountParamName));
|
||||
|
||||
private static final Set<String> RECURRING_DETAILS_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(
|
||||
recurringDepositAmountParamName, recurringDepositTypeIdParamName, recurringDepositFrequencyTypeIdParamName,
|
||||
@@ -277,7 +282,7 @@ public class DepositsApiConstants {
|
||||
interestCompoundingPeriodTypeParamName, interestPostingPeriodTypeParamName, interestCalculationTypeParamName,
|
||||
interestCalculationDaysInYearTypeParamName, lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName,
|
||||
chargesParamName, chartsParamName, depositAmountParamName, depositPeriodParamName, depositPeriodFrequencyIdParamName,
|
||||
savingsAccounts));
|
||||
savingsAccounts, expectedFirstDepositOnDateParamName));
|
||||
|
||||
public static final Set<String> FIXED_DEPOSIT_ACCOUNT_REQUEST_DATA_PARAMETERS = fixedDepositAccountRequestData();
|
||||
public static final Set<String> FIXED_DEPOSIT_ACCOUNT_RESPONSE_DATA_PARAMETERS = fixedDepositAccountResponseData();
|
||||
|
||||
+10
-10
@@ -20,11 +20,11 @@ public enum SavingsCompoundingInterestPeriodType {
|
||||
DAILY(1, "savingsCompoundingInterestPeriodType.daily"), //
|
||||
// WEEKLY(2, "savingsCompoundingInterestPeriodType.weekly"), //
|
||||
// BIWEEKLY(3, "savingsCompoundingInterestPeriodType.biweekly"), //
|
||||
MONTHLY(4, "savingsCompoundingInterestPeriodType.monthly");
|
||||
MONTHLY(4, "savingsCompoundingInterestPeriodType.monthly"),
|
||||
|
||||
// QUATERLY(5, "savingsCompoundingInterestPeriodType.quarterly"), //
|
||||
// BI_ANNUAL(6, "savingsCompoundingInterestPeriodType.biannual"), //
|
||||
// ANNUAL(7, "savingsCompoundingInterestPeriodType.annual"), //
|
||||
QUATERLY(5, "savingsCompoundingInterestPeriodType.quarterly"), //
|
||||
BI_ANNUAL(6, "savingsCompoundingInterestPeriodType.biannual"), //
|
||||
ANNUAL(7, "savingsCompoundingInterestPeriodType.annual"); //
|
||||
// NO_COMPOUNDING_SIMPLE_INTEREST(8,
|
||||
// "savingsCompoundingInterestPeriodType.nocompounding");
|
||||
|
||||
@@ -74,16 +74,16 @@ public enum SavingsCompoundingInterestPeriodType {
|
||||
repaymentFrequencyType = SavingsCompoundingInterestPeriodType.MONTHLY;
|
||||
break;
|
||||
case 5:
|
||||
// repaymentFrequencyType =
|
||||
// SavingsCompoundingInterestPeriodType.QUATERLY;
|
||||
repaymentFrequencyType =
|
||||
SavingsCompoundingInterestPeriodType.QUATERLY;
|
||||
break;
|
||||
case 6:
|
||||
// repaymentFrequencyType =
|
||||
// SavingsCompoundingInterestPeriodType.BI_ANNUAL;
|
||||
repaymentFrequencyType =
|
||||
SavingsCompoundingInterestPeriodType.BI_ANNUAL;
|
||||
break;
|
||||
case 7:
|
||||
// repaymentFrequencyType =
|
||||
// SavingsCompoundingInterestPeriodType.ANNUAL;
|
||||
repaymentFrequencyType =
|
||||
SavingsCompoundingInterestPeriodType.ANNUAL;
|
||||
break;
|
||||
case 8:
|
||||
// repaymentFrequencyType =
|
||||
|
||||
+4
@@ -17,6 +17,7 @@ public enum SavingsPostingInterestPeriodType {
|
||||
INVALID(0, "savingsPostingInterestPeriodType.invalid"), //
|
||||
MONTHLY(4, "savingsPostingInterestPeriodType.monthly"), //
|
||||
QUATERLY(5, "savingsPostingInterestPeriodType.quarterly"), //
|
||||
BIANNUAL(6, "savingsPostingInterestPeriodType.biannual"),
|
||||
ANNUAL(7, "savingsPostingInterestPeriodType.annual");
|
||||
|
||||
private final Integer value;
|
||||
@@ -56,6 +57,9 @@ public enum SavingsPostingInterestPeriodType {
|
||||
case 5:
|
||||
repaymentFrequencyType = SavingsPostingInterestPeriodType.QUATERLY;
|
||||
break;
|
||||
case 6:
|
||||
repaymentFrequencyType = SavingsPostingInterestPeriodType.BIANNUAL;
|
||||
break;
|
||||
case 7:
|
||||
repaymentFrequencyType = SavingsPostingInterestPeriodType.ANNUAL;
|
||||
break;
|
||||
|
||||
+82
@@ -27,6 +27,9 @@ import static org.mifosplatform.portfolio.savings.DepositsApiConstants.preClosur
|
||||
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.recurringDepositFrequencyParamName;
|
||||
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.recurringDepositFrequencyTypeIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.recurringDepositTypeIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.depositAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.depositMinAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.depositMaxAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.currencyCodeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.descriptionParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.digitsAfterDecimalParamName;
|
||||
@@ -48,6 +51,8 @@ import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawal
|
||||
import java.lang.reflect.Type;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
@@ -109,6 +114,8 @@ public class DepositProductDataValidator {
|
||||
validateDepositTermDeatilForCreate(element, baseDataValidator);
|
||||
|
||||
validateChartsData(element, baseDataValidator);
|
||||
|
||||
validateDepositAmountForCreate(element, baseDataValidator);
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
@@ -131,6 +138,8 @@ public class DepositProductDataValidator {
|
||||
validateDepositTermDetailForUpdate(element, baseDataValidator);
|
||||
|
||||
validateChartsData(element, baseDataValidator);
|
||||
|
||||
validateDepositAmountForUpdate(element, baseDataValidator);
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
@@ -156,6 +165,8 @@ public class DepositProductDataValidator {
|
||||
validateRecurringDetailForCreate(element, baseDataValidator);
|
||||
|
||||
validateChartsData(element, baseDataValidator);
|
||||
|
||||
validateDepositAmountForCreate(element, baseDataValidator);
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
@@ -180,6 +191,8 @@ public class DepositProductDataValidator {
|
||||
validateRecurringDepositUpdate(element, baseDataValidator);
|
||||
|
||||
validateChartsData(element, baseDataValidator);
|
||||
|
||||
validateDepositAmountForUpdate(element, baseDataValidator);
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
@@ -733,4 +746,73 @@ public class DepositProductDataValidator {
|
||||
.isOneOfTheseValues(SavingsPeriodFrequencyType.integerValues());
|
||||
}
|
||||
}
|
||||
|
||||
private void validateDepositAmountForCreate(JsonElement element, DataValidatorBuilder baseDataValidator) {
|
||||
final BigDecimal depositAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(depositAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(depositAmountParamName).value(depositAmount).notNull().positiveAmount();
|
||||
|
||||
BigDecimal depositMinAmount = null;
|
||||
if (this.fromApiJsonHelper.parameterExists(depositMinAmountParamName, element)) {
|
||||
depositMinAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(depositMinAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(depositMinAmountParamName).value(depositMinAmount).notNull().positiveAmount();
|
||||
}
|
||||
|
||||
BigDecimal depositMaxAmount = null;
|
||||
if (this.fromApiJsonHelper.parameterExists(depositMaxAmountParamName, element)) {
|
||||
depositMaxAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(depositMaxAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(depositMaxAmountParamName).value(depositMaxAmount).notNull().positiveAmount();
|
||||
}
|
||||
|
||||
if (depositMaxAmount != null && depositMaxAmount.compareTo(BigDecimal.ZERO) != -1) {
|
||||
if (depositMinAmount != null && depositMinAmount.compareTo(BigDecimal.ZERO) != -1) {
|
||||
baseDataValidator.reset().parameter(depositMaxAmountParamName).value(depositMaxAmount).notLessThanMin(depositMinAmount);
|
||||
if (depositMinAmount.compareTo(depositMaxAmount) <= 0) {
|
||||
baseDataValidator.reset().parameter(depositAmountParamName).value(depositAmount)
|
||||
.inMinAndMaxAmountRange(depositMinAmount, depositMaxAmount);
|
||||
}
|
||||
} else {
|
||||
baseDataValidator.reset().parameter(depositAmountParamName).value(depositAmount).notGreaterThanMax(depositMaxAmount);
|
||||
}
|
||||
} else if (depositMinAmount != null && depositMinAmount.compareTo(BigDecimal.ZERO) != -1) {
|
||||
baseDataValidator.reset().parameter(depositAmountParamName).value(depositAmount).notLessThanMin(depositMinAmount);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateDepositAmountForUpdate(JsonElement element, DataValidatorBuilder baseDataValidator) {
|
||||
BigDecimal depositAmount = null;
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(depositAmountParamName, element)) {
|
||||
depositAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(depositAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(depositMinAmountParamName).value(depositAmount).notNull().positiveAmount();
|
||||
}
|
||||
baseDataValidator.reset().parameter(depositAmountParamName).value(depositAmount).notNull().positiveAmount();
|
||||
|
||||
BigDecimal depositMinAmount = null;
|
||||
if (this.fromApiJsonHelper.parameterExists(depositMinAmountParamName, element)) {
|
||||
depositMinAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(depositMinAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(depositMinAmountParamName).value(depositMinAmount).notNull().positiveAmount();
|
||||
}
|
||||
|
||||
BigDecimal depositMaxAmount = null;
|
||||
if (this.fromApiJsonHelper.parameterExists(depositMaxAmountParamName, element)) {
|
||||
depositMaxAmount = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(depositMaxAmountParamName, element);
|
||||
baseDataValidator.reset().parameter(depositMaxAmountParamName).value(depositMaxAmount).notNull().positiveAmount();
|
||||
}
|
||||
|
||||
if(depositAmount != null) {
|
||||
if (depositMaxAmount != null && depositMaxAmount.compareTo(BigDecimal.ZERO) != -1) {
|
||||
if (depositMinAmount != null && depositMinAmount.compareTo(BigDecimal.ZERO) != -1) {
|
||||
baseDataValidator.reset().parameter(depositMaxAmountParamName).value(depositMaxAmount).notLessThanMin(depositMinAmount);
|
||||
if (depositMinAmount.compareTo(depositMaxAmount) <= 0) {
|
||||
baseDataValidator.reset().parameter(depositAmountParamName).value(depositAmount)
|
||||
.inMinAndMaxAmountRange(depositMinAmount, depositMaxAmount);
|
||||
}
|
||||
} else {
|
||||
baseDataValidator.reset().parameter(depositAmountParamName).value(depositAmount).notGreaterThanMax(depositMaxAmount);
|
||||
}
|
||||
} else if (depositMinAmount != null && depositMinAmount.compareTo(BigDecimal.ZERO) != -1) {
|
||||
baseDataValidator.reset().parameter(depositAmountParamName).value(depositAmount).notLessThanMin(depositMinAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+17
-9
@@ -47,6 +47,7 @@ public class RecurringDepositAccountData extends DepositAccountData {
|
||||
private EnumOptionData recurringDepositType;
|
||||
private Integer recurringDepositFrequency;
|
||||
private EnumOptionData recurringDepositFrequencyType;
|
||||
private LocalDate expectedFirstDepositOnDate;
|
||||
|
||||
// used for account close
|
||||
private EnumOptionData onAccountClosure;
|
||||
@@ -73,7 +74,8 @@ public class RecurringDepositAccountData extends DepositAccountData {
|
||||
final BigDecimal maturityAmount, final LocalDate maturityDate, final Integer depositPeriod,
|
||||
final EnumOptionData depositPeriodFrequency, final BigDecimal recurringDepositAmount,
|
||||
final EnumOptionData recurringDepositType, final Integer recurringDepositFrequency,
|
||||
final EnumOptionData recurringDepositFrequencyType, final EnumOptionData onAccountClosure) {
|
||||
final EnumOptionData recurringDepositFrequencyType, final EnumOptionData onAccountClosure,
|
||||
final LocalDate expectedFirstDepositOnDate) {
|
||||
|
||||
final Collection<EnumOptionData> interestFreePeriodTypeOptions = null;
|
||||
final Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions = null;
|
||||
@@ -108,7 +110,7 @@ public class RecurringDepositAccountData extends DepositAccountData {
|
||||
depositPeriod, depositPeriodFrequency, recurringDepositAmount, depositTermTypeOptions, inMultiplesOfDepositTermTypeOptions,
|
||||
recurringDepositType, recurringDepositFrequency, recurringDepositFrequencyType, recurringDepositTypeOptions,
|
||||
recurringDepositFrequencyTypeOptions, depositPeriodFrequencyOptions, depositType, onAccountClosure,
|
||||
onAccountClosureOptions, paymentTypeOptions, savingsAccountDatas);
|
||||
onAccountClosureOptions, paymentTypeOptions, savingsAccountDatas, expectedFirstDepositOnDate);
|
||||
}
|
||||
|
||||
public static RecurringDepositAccountData withInterestChart(final RecurringDepositAccountData account,
|
||||
@@ -132,7 +134,8 @@ public class RecurringDepositAccountData extends DepositAccountData {
|
||||
account.depositTermTypeOptions, account.inMultiplesOfDepositTermTypeOptions, account.recurringDepositType,
|
||||
account.recurringDepositFrequency, account.recurringDepositFrequencyType, account.recurringDepositTypeOptions,
|
||||
account.recurringDepositFrequencyTypeOptions, account.depositPeriodFrequencyOptions, account.depositType,
|
||||
account.onAccountClosure, account.onAccountClosureOptions, account.paymentTypeOptions, account.savingsAccounts);
|
||||
account.onAccountClosure, account.onAccountClosureOptions, account.paymentTypeOptions, account.savingsAccounts,
|
||||
account.expectedFirstDepositOnDate);
|
||||
}
|
||||
|
||||
public static RecurringDepositAccountData withTemplateOptions(final RecurringDepositAccountData account,
|
||||
@@ -186,7 +189,7 @@ public class RecurringDepositAccountData extends DepositAccountData {
|
||||
account.recurringDepositType, account.recurringDepositFrequency, account.recurringDepositFrequencyType,
|
||||
template.recurringDepositTypeOptions, template.recurringDepositFrequencyTypeOptions,
|
||||
template.depositPeriodFrequencyOptions, account.depositType, account.onAccountClosure, account.onAccountClosureOptions,
|
||||
account.paymentTypeOptions, account.savingsAccounts);
|
||||
account.paymentTypeOptions, account.savingsAccounts, account.expectedFirstDepositOnDate);
|
||||
|
||||
}
|
||||
|
||||
@@ -223,7 +226,7 @@ public class RecurringDepositAccountData extends DepositAccountData {
|
||||
depositTermTypeOptions, inMultiplesOfDepositTermTypeOptions, account.recurringDepositType,
|
||||
account.recurringDepositFrequency, account.recurringDepositFrequencyType, recurringDepositTypeOptions,
|
||||
recurringDepositFrequencyTypeOptions, depositPeriodFrequencyOptions, account.depositType, account.onAccountClosure,
|
||||
account.onAccountClosureOptions, account.paymentTypeOptions, account.savingsAccounts);
|
||||
account.onAccountClosureOptions, account.paymentTypeOptions, account.savingsAccounts, account.expectedFirstDepositOnDate);
|
||||
}
|
||||
|
||||
public static RecurringDepositAccountData withClientTemplate(final Long clientId, final String clientName, final Long groupId,
|
||||
@@ -301,6 +304,7 @@ public class RecurringDepositAccountData extends DepositAccountData {
|
||||
final Collection<EnumOptionData> onAccountClosureOptions = null;
|
||||
final Collection<CodeValueData> paymentTypeOptions = null;
|
||||
final Collection<SavingsAccountData> savingsAccountDatas = null;
|
||||
final LocalDate expectedFirstDepositOnDate = null;
|
||||
|
||||
return new RecurringDepositAccountData(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName,
|
||||
fieldOfficerId, fieldOfficerName, status, timeline, currency, nominalAnnualInterestRate, interestPeriodType,
|
||||
@@ -316,7 +320,7 @@ public class RecurringDepositAccountData extends DepositAccountData {
|
||||
depositPeriodFrequency, recurringDepositAmount, depositTermTypeOptions, inMultiplesOfDepositTermTypeOptions,
|
||||
recurringDepositType, recurringDepositFrequency, recurringDepositFrequencyType, recurringDepositTypeOptions,
|
||||
recurringDepositFrequencyTypeOptions, depositPeriodFrequencyOptions, depositType, onAccountClosure,
|
||||
onAccountClosureOptions, paymentTypeOptions, savingsAccountDatas);
|
||||
onAccountClosureOptions, paymentTypeOptions, savingsAccountDatas, expectedFirstDepositOnDate);
|
||||
}
|
||||
|
||||
public static RecurringDepositAccountData preClosureDetails(final Long accountId, BigDecimal maturityAmount,
|
||||
@@ -394,6 +398,7 @@ public class RecurringDepositAccountData extends DepositAccountData {
|
||||
final String groupName = null;
|
||||
final Long clientId = null;
|
||||
final String clientName = null;
|
||||
final LocalDate expectedFirstDepositOnDate = null;
|
||||
|
||||
return new RecurringDepositAccountData(accountId, accountNo, externalId, groupId, groupName, clientId, clientName, productId,
|
||||
productName, fieldOfficerId, fieldOfficerName, status, timeline, currency, nominalAnnualInterestRate, interestPeriodType,
|
||||
@@ -409,7 +414,7 @@ public class RecurringDepositAccountData extends DepositAccountData {
|
||||
depositPeriodFrequency, recurringDepositAmount, depositTermTypeOptions, inMultiplesOfDepositTermTypeOptions,
|
||||
recurringDepositType, recurringDepositFrequency, recurringDepositFrequencyType, recurringDepositTypeOptions,
|
||||
recurringDepositFrequencyTypeOptions, depositPeriodFrequencyOptions, depositType, onAccountClosure,
|
||||
onAccountClosureOptions, paymentTypeOptions, savingsAccountDatas);
|
||||
onAccountClosureOptions, paymentTypeOptions, savingsAccountDatas, expectedFirstDepositOnDate);
|
||||
}
|
||||
|
||||
public static RecurringDepositAccountData withClosureTemplateDetails(final RecurringDepositAccountData account,
|
||||
@@ -434,7 +439,8 @@ public class RecurringDepositAccountData extends DepositAccountData {
|
||||
account.depositTermTypeOptions, account.inMultiplesOfDepositTermTypeOptions, account.recurringDepositType,
|
||||
account.recurringDepositFrequency, account.recurringDepositFrequencyType, account.recurringDepositTypeOptions,
|
||||
account.recurringDepositFrequencyTypeOptions, account.depositPeriodFrequencyOptions, account.depositType,
|
||||
account.onAccountClosure, onAccountClosureOptions, paymentTypeOptions, savingsAccountDatas);
|
||||
account.onAccountClosure, onAccountClosureOptions, paymentTypeOptions, savingsAccountDatas,
|
||||
account.expectedFirstDepositOnDate);
|
||||
}
|
||||
|
||||
private RecurringDepositAccountData(final Long id, final String accountNo, final String externalId, final Long groupId,
|
||||
@@ -469,7 +475,8 @@ public class RecurringDepositAccountData extends DepositAccountData {
|
||||
final Collection<EnumOptionData> recurringDepositFrequencyTypeOptions,
|
||||
final Collection<EnumOptionData> depositPeriodFrequencyOptions, final EnumOptionData depositType,
|
||||
final EnumOptionData onAccountClosure, final Collection<EnumOptionData> onAccountClosureOptions,
|
||||
final Collection<CodeValueData> paymentTypeOptions, final Collection<SavingsAccountData> savingsAccountDatas) {
|
||||
final Collection<CodeValueData> paymentTypeOptions, final Collection<SavingsAccountData> savingsAccountDatas,
|
||||
final LocalDate expectedFirstDepositOnDate) {
|
||||
|
||||
super(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName, fieldofficerId,
|
||||
fieldofficerName, status, timeline, currency, nominalAnnualInterestRate, interestPeriodType, interestPostingPeriodType,
|
||||
@@ -501,6 +508,7 @@ public class RecurringDepositAccountData extends DepositAccountData {
|
||||
this.recurringDepositFrequencyType = recurringDepositFrequencyType;
|
||||
this.recurringDepositFrequency = recurringDepositFrequency;
|
||||
this.recurringDepositType = recurringDepositType;
|
||||
this.expectedFirstDepositOnDate = expectedFirstDepositOnDate;
|
||||
|
||||
// template data
|
||||
this.interestFreePeriodTypeOptions = interestFreePeriodTypeOptions;
|
||||
|
||||
+34
-12
@@ -40,6 +40,9 @@ public class RecurringDepositProductData extends DepositProductData {
|
||||
private EnumOptionData recurringDepositType;
|
||||
private Integer recurringDepositFrequency;
|
||||
private EnumOptionData recurringDepositFrequencyType;
|
||||
private BigDecimal minDepositAmount;
|
||||
private BigDecimal depositAmount;
|
||||
private BigDecimal maxDepositAmount;
|
||||
|
||||
private Collection<EnumOptionData> interestFreePeriodTypeOptions;
|
||||
private Collection<EnumOptionData> preClosurePenalInterestOnTypeOptions;
|
||||
@@ -96,7 +99,10 @@ public class RecurringDepositProductData extends DepositProductData {
|
||||
final EnumOptionData maxDepositTermType = null;
|
||||
final Integer inMultiplesOfDepositTerm = null;
|
||||
final EnumOptionData inMultiplesOfDepositTermType = null;
|
||||
|
||||
final BigDecimal minDepositAmount = null;
|
||||
final BigDecimal depositAmount = null;
|
||||
final BigDecimal maxDepositAmount = null;
|
||||
|
||||
return new RecurringDepositProductData(id, name, shortName, description, currency, nominalAnnualInterestRate,
|
||||
interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, accountingRule, accountingMappings, paymentChannelToFundSourceMappings,
|
||||
@@ -106,9 +112,10 @@ public class RecurringDepositProductData extends DepositProductData {
|
||||
penaltyToIncomeAccountMappings, interestRateCharts, chartTemplate, interestFreePeriodApplicable, interestFreeFromPeriod,
|
||||
interestFreeToPeriod, interestFreePeriodFrequencyType, preClosurePenalApplicable, preClosurePenalInterest,
|
||||
preClosurePenalInterestOnType, interestFreePeriodTypes, preClosurePenalInterestOnTypeOptions, minDepositTerm,
|
||||
maxDepositTerm, minDepositTermType, maxDepositTermType, inMultiplesOfDepositTerm, inMultiplesOfDepositTermType,
|
||||
recurringDepositType, recurringDepositFrequency, recurringDepositFrequencyType, recurringDepositTypeOptions,
|
||||
recurringDepositFrequencyTypeOptions, depositTermTypeOptions, inMultiplesOfDepositTermTypeOptions);
|
||||
maxDepositTerm, minDepositTermType, maxDepositTermType, inMultiplesOfDepositTerm, inMultiplesOfDepositTermType, recurringDepositType,
|
||||
recurringDepositFrequency, recurringDepositFrequencyType, recurringDepositTypeOptions,
|
||||
recurringDepositFrequencyTypeOptions, depositTermTypeOptions, inMultiplesOfDepositTermTypeOptions,
|
||||
minDepositAmount, depositAmount, maxDepositAmount);
|
||||
}
|
||||
|
||||
public static RecurringDepositProductData withCharges(final RecurringDepositProductData existingProduct,
|
||||
@@ -134,7 +141,8 @@ public class RecurringDepositProductData extends DepositProductData {
|
||||
existingProduct.recurringDepositType, existingProduct.recurringDepositFrequency,
|
||||
existingProduct.recurringDepositFrequencyType, existingProduct.recurringDepositTypeOptions,
|
||||
existingProduct.recurringDepositFrequencyTypeOptions, existingProduct.depositTermTypeOptions,
|
||||
existingProduct.inMultiplesOfDepositTermTypeOptions);
|
||||
existingProduct.inMultiplesOfDepositTermTypeOptions, existingProduct.minDepositAmount,
|
||||
existingProduct.depositAmount, existingProduct.maxDepositAmount);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -175,7 +183,8 @@ public class RecurringDepositProductData extends DepositProductData {
|
||||
existingProduct.minDepositTermType, existingProduct.maxDepositTermType, existingProduct.inMultiplesOfDepositTerm,
|
||||
existingProduct.inMultiplesOfDepositTermType, existingProduct.recurringDepositType,
|
||||
existingProduct.recurringDepositFrequency, existingProduct.recurringDepositFrequencyType, recurringDepositTypeOptions,
|
||||
recurringDepositFrequencyTypeOptions, depositTermTypeOptions, inMultiplesOfDepositTermTypeOptions);
|
||||
recurringDepositFrequencyTypeOptions, depositTermTypeOptions, inMultiplesOfDepositTermTypeOptions, existingProduct.minDepositAmount,
|
||||
existingProduct.depositAmount, existingProduct.maxDepositAmount);
|
||||
}
|
||||
|
||||
public static RecurringDepositProductData withAccountingDetails(final RecurringDepositProductData existingProduct,
|
||||
@@ -216,7 +225,8 @@ public class RecurringDepositProductData extends DepositProductData {
|
||||
existingProduct.recurringDepositType, existingProduct.recurringDepositFrequency,
|
||||
existingProduct.recurringDepositFrequencyType, existingProduct.recurringDepositTypeOptions,
|
||||
existingProduct.recurringDepositFrequencyTypeOptions, existingProduct.depositTermTypeOptions,
|
||||
existingProduct.inMultiplesOfDepositTermTypeOptions);
|
||||
existingProduct.inMultiplesOfDepositTermTypeOptions, existingProduct.minDepositAmount,
|
||||
existingProduct.depositAmount, existingProduct.maxDepositAmount);
|
||||
}
|
||||
|
||||
public static RecurringDepositProductData instance(final DepositProductData depositProductData,
|
||||
@@ -226,7 +236,9 @@ public class RecurringDepositProductData extends DepositProductData {
|
||||
final Integer maxDepositTerm, final EnumOptionData minDepositTermType, final EnumOptionData maxDepositTermType,
|
||||
final Integer inMultiplesOfDepositTerm, final EnumOptionData inMultiplesOfDepositTermType,
|
||||
final EnumOptionData recurringDepositType, final Integer recurringDepositFrequency,
|
||||
final EnumOptionData recurringDepositFrequencyType) {
|
||||
final EnumOptionData recurringDepositFrequencyType,
|
||||
final BigDecimal minDepositAmount,final BigDecimal depositAmount,
|
||||
final BigDecimal maxDepositAmount) {
|
||||
|
||||
final Map<String, Object> accountingMappings = null;
|
||||
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings = null;
|
||||
@@ -269,7 +281,8 @@ public class RecurringDepositProductData extends DepositProductData {
|
||||
preClosurePenalInterestOnType, interestFreePeriodTypes, preClosurePenalInterestOnTypeOptions, minDepositTerm,
|
||||
maxDepositTerm, minDepositTermType, maxDepositTermType, inMultiplesOfDepositTerm, inMultiplesOfDepositTermType,
|
||||
recurringDepositType, recurringDepositFrequency, recurringDepositFrequencyType, recurringDepositTypeOptions,
|
||||
recurringDepositFrequencyTypeOptions, depositTermTypeOptions, inMultiplesOfDepositTermTypeOptions);
|
||||
recurringDepositFrequencyTypeOptions, depositTermTypeOptions, inMultiplesOfDepositTermTypeOptions,
|
||||
minDepositAmount, depositAmount, maxDepositAmount);
|
||||
}
|
||||
|
||||
public static RecurringDepositProductData lookup(final Long id, final String name) {
|
||||
@@ -329,6 +342,9 @@ public class RecurringDepositProductData extends DepositProductData {
|
||||
final EnumOptionData inMultiplesOfDepositTermType = null;
|
||||
final Collection<EnumOptionData> depositTermTypeOptions = null;
|
||||
final Collection<EnumOptionData> inMultiplesOfDepositTermTypeOptions = null;
|
||||
final BigDecimal minDepositAmount = null;
|
||||
final BigDecimal depositAmount = null;
|
||||
final BigDecimal maxDepositAmount = null;
|
||||
|
||||
return new RecurringDepositProductData(id, name, shortName, description, currency, nominalAnnualInterestRate,
|
||||
interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType,
|
||||
@@ -341,7 +357,8 @@ public class RecurringDepositProductData extends DepositProductData {
|
||||
preClosurePenalInterestOnType, interestFreePeriodTypes, preClosurePenalInterestOnTypeOptions, minDepositTerm,
|
||||
maxDepositTerm, minDepositTermType, maxDepositTermType, inMultiplesOfDepositTerm, inMultiplesOfDepositTermType,
|
||||
recurringDepositType, recurringDepositFrequency, recurringDepositFrequencyType, recurringDepositTypeOptions,
|
||||
recurringDepositFrequencyTypeOptions, depositTermTypeOptions, inMultiplesOfDepositTermTypeOptions);
|
||||
recurringDepositFrequencyTypeOptions, depositTermTypeOptions, inMultiplesOfDepositTermTypeOptions,
|
||||
minDepositAmount, depositAmount, maxDepositAmount);
|
||||
}
|
||||
|
||||
public static RecurringDepositProductData withInterestChart(final RecurringDepositProductData product,
|
||||
@@ -362,7 +379,8 @@ public class RecurringDepositProductData extends DepositProductData {
|
||||
product.minDepositTerm, product.maxDepositTerm, product.minDepositTermType, product.maxDepositTermType,
|
||||
product.inMultiplesOfDepositTerm, product.inMultiplesOfDepositTermType, product.recurringDepositType,
|
||||
product.recurringDepositFrequency, product.recurringDepositFrequencyType, product.recurringDepositTypeOptions,
|
||||
product.recurringDepositFrequencyTypeOptions, product.depositTermTypeOptions, product.inMultiplesOfDepositTermTypeOptions);
|
||||
product.recurringDepositFrequencyTypeOptions, product.depositTermTypeOptions, product.inMultiplesOfDepositTermTypeOptions, product.minDepositAmount,
|
||||
product.depositAmount, product.maxDepositAmount);
|
||||
}
|
||||
|
||||
private RecurringDepositProductData(final Long id, final String name, final String shortName, final String description,
|
||||
@@ -393,7 +411,8 @@ public class RecurringDepositProductData extends DepositProductData {
|
||||
final EnumOptionData recurringDepositType, final Integer recurringDepositFrequency,
|
||||
final EnumOptionData recurringDepositFrequencyType, final Collection<EnumOptionData> recurringDepositTypeOptions,
|
||||
final Collection<EnumOptionData> recurringDepositFrequencyTypeOptions, final Collection<EnumOptionData> depositTermTypeOptions,
|
||||
final Collection<EnumOptionData> inMultiplesOfDepositTermTypeOptions) {
|
||||
final Collection<EnumOptionData> inMultiplesOfDepositTermTypeOptions,final BigDecimal minDepositAmount,
|
||||
final BigDecimal depositAmount, final BigDecimal maxDepositAmount) {
|
||||
|
||||
super(id, name, shortName, description, currency, nominalAnnualInterestRate, interestCompoundingPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, lockinPeriodFrequency,
|
||||
@@ -419,6 +438,9 @@ public class RecurringDepositProductData extends DepositProductData {
|
||||
this.recurringDepositFrequencyType = recurringDepositFrequencyType;
|
||||
this.recurringDepositFrequency = recurringDepositFrequency;
|
||||
this.recurringDepositType = recurringDepositType;
|
||||
this.minDepositAmount = minDepositAmount;
|
||||
this.depositAmount = depositAmount;
|
||||
this.maxDepositAmount = maxDepositAmount;
|
||||
|
||||
// template data
|
||||
this.interestFreePeriodTypeOptions = interestFreePeriodTypeOptions;
|
||||
|
||||
+3
-1
@@ -13,6 +13,7 @@ import static org.mifosplatform.portfolio.savings.DepositsApiConstants.recurring
|
||||
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.recurringDepositFrequencyParamName;
|
||||
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.recurringDepositFrequencyTypeIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.recurringDepositTypeIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.expectedFirstDepositOnDateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.accountNoParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.clientIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.externalIdParamName;
|
||||
@@ -312,6 +313,7 @@ public class DepositAccountAssembler {
|
||||
final Integer depositPeriodFrequencyId = command.integerValueOfParameterNamed(depositPeriodFrequencyIdParamName);
|
||||
final SavingsPeriodFrequencyType depositPeriodFrequency = SavingsPeriodFrequencyType.fromInt(depositPeriodFrequencyId);
|
||||
final SavingsAccount account = null;
|
||||
final LocalDate expectedFirstDepositOnDate = command.localDateValueOfParameterNamed(expectedFirstDepositOnDateParamName);
|
||||
|
||||
// calculate maturity amount
|
||||
final BigDecimal maturityAmount = null;// calculated and updated in
|
||||
@@ -319,7 +321,7 @@ public class DepositAccountAssembler {
|
||||
final LocalDate maturityDate = null;// calculated and updated in account
|
||||
final DepositAccountOnClosureType accountOnClosureType = null;
|
||||
return DepositAccountTermAndPreClosure.createNew(updatedProductPreClosure, updatedProductTerm, account, depositAmount,
|
||||
maturityAmount, maturityDate, depositPeriod, depositPeriodFrequency, accountOnClosureType);
|
||||
maturityAmount, maturityDate, depositPeriod, depositPeriodFrequency, expectedFirstDepositOnDate, accountOnClosureType);
|
||||
}
|
||||
|
||||
public DepositAccountRecurringDetail assembleAccountRecurringDetail(final JsonCommand command,
|
||||
|
||||
+9
-2
@@ -179,8 +179,15 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi
|
||||
final LocalDate transactionDate = withdrawal.transactionLocalDate();
|
||||
if (rdAccount.isReinvestOnClosure()) {
|
||||
RecurringDepositAccount reinvestedDeposit = rdAccount.reInvest(transactionAmount);
|
||||
final LocalDate transactionStartDate = rdAccount.depositStartDate();
|
||||
rdAccount.updateMaturityDateAndAmount(mc, transactionStartDate);
|
||||
depositAccountAssembler.assignSavingAccountHelpers(reinvestedDeposit);
|
||||
final Locale locale = command.extractLocale();
|
||||
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
|
||||
final LocalDate transactionStartDate = reinvestedDeposit.getActivationLocalDate();
|
||||
final LocalDate nextTransactionStartDate = reinvestedDeposit.nextDepositDate(transactionStartDate);
|
||||
reinvestedDeposit.updateMaturityDateAndAmount(mc, nextTransactionStartDate);
|
||||
reinvestedDeposit.processAccountUponActivation(fmt);
|
||||
reinvestedDeposit.updateMaturityDateAndAmount(mc, nextTransactionStartDate);
|
||||
|
||||
this.savingsAccountRepository.save(reinvestedDeposit);
|
||||
autoGenerateAccountNumber(reinvestedDeposit);
|
||||
} else if (rdAccount.isTransferToSavingsOnClosure()) {
|
||||
|
||||
+2
-2
@@ -119,10 +119,10 @@ public class DepositAccountInterestRateChart extends AbstractPersistable<Long> {
|
||||
this.account = account;
|
||||
}
|
||||
|
||||
public BigDecimal getApplicableInterestRate(@SuppressWarnings("unused") final BigDecimal depositAmount, final LocalDate periodStartDate, final LocalDate periodEndDate){
|
||||
public BigDecimal getApplicableInterestRate(final BigDecimal depositAmount, final LocalDate periodStartDate, final LocalDate periodEndDate){
|
||||
BigDecimal effectiveInterestRate = BigDecimal.ZERO;
|
||||
for (DepositAccountInterestRateChartSlabs slab : setOfChartSlabs()) {
|
||||
if(slab.slabFields().isBetweenPeriod(periodStartDate, periodEndDate)){
|
||||
if(slab.slabFields().isBetweenPeriod(periodStartDate, periodEndDate) && slab.slabFields().isAmountBetween(depositAmount)){
|
||||
effectiveInterestRate = slab.slabFields().annualInterestRate();
|
||||
}
|
||||
}
|
||||
|
||||
+29
-6
@@ -49,6 +49,10 @@ public class DepositAccountTermAndPreClosure extends AbstractPersistable<Long> {
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Column(name = "maturity_date", nullable = true)
|
||||
private Date maturityDate;
|
||||
|
||||
@Temporal(TemporalType.DATE)
|
||||
@Column(name = "expected_firstdepositon_date")
|
||||
private Date expectedFirstDepositOnDate;
|
||||
|
||||
@Column(name = "deposit_period", nullable = true)
|
||||
private Integer depositPeriod;
|
||||
@@ -75,16 +79,16 @@ public class DepositAccountTermAndPreClosure extends AbstractPersistable<Long> {
|
||||
|
||||
public static DepositAccountTermAndPreClosure createNew(DepositPreClosureDetail preClosureDetail, DepositTermDetail depositTermDetail,
|
||||
SavingsAccount account, BigDecimal depositAmount, BigDecimal maturityAmount, final LocalDate maturityDate,
|
||||
Integer depositPeriod, final SavingsPeriodFrequencyType depositPeriodFrequency,
|
||||
Integer depositPeriod, final SavingsPeriodFrequencyType depositPeriodFrequency, final LocalDate expectedFirstDepositOnDate,
|
||||
final DepositAccountOnClosureType accountOnClosureType) {
|
||||
|
||||
return new DepositAccountTermAndPreClosure(preClosureDetail, depositTermDetail, account, depositAmount, maturityAmount,
|
||||
maturityDate, depositPeriod, depositPeriodFrequency, accountOnClosureType);
|
||||
maturityDate, depositPeriod, depositPeriodFrequency, expectedFirstDepositOnDate, accountOnClosureType);
|
||||
}
|
||||
|
||||
private DepositAccountTermAndPreClosure(DepositPreClosureDetail preClosureDetail, DepositTermDetail depositTermDetail,
|
||||
SavingsAccount account, BigDecimal depositAmount, BigDecimal maturityAmount, final LocalDate maturityDate,
|
||||
Integer depositPeriod, final SavingsPeriodFrequencyType depositPeriodFrequency,
|
||||
Integer depositPeriod, final SavingsPeriodFrequencyType depositPeriodFrequency, final LocalDate expectedFirstDepositOnDate,
|
||||
final DepositAccountOnClosureType accountOnClosureType) {
|
||||
this.depositAmount = depositAmount;
|
||||
this.maturityAmount = maturityAmount;
|
||||
@@ -94,6 +98,7 @@ public class DepositAccountTermAndPreClosure extends AbstractPersistable<Long> {
|
||||
this.preClosureDetail = preClosureDetail;
|
||||
this.depositTermDetail = depositTermDetail;
|
||||
this.account = account;
|
||||
this.expectedFirstDepositOnDate = expectedFirstDepositOnDate == null ? null : expectedFirstDepositOnDate.toDate();
|
||||
this.onAccountClosureType = (accountOnClosureType == null) ? null : accountOnClosureType.getValue();
|
||||
}
|
||||
|
||||
@@ -174,6 +179,14 @@ public class DepositAccountTermAndPreClosure extends AbstractPersistable<Long> {
|
||||
}
|
||||
return maturityLocalDate;
|
||||
}
|
||||
|
||||
public LocalDate getExpectedFirstDepositOnDate() {
|
||||
LocalDate expectedFirstDepositOnLocalDate = null;
|
||||
if (this.expectedFirstDepositOnDate != null) {
|
||||
expectedFirstDepositOnLocalDate = new LocalDate(this.expectedFirstDepositOnDate);
|
||||
}
|
||||
return expectedFirstDepositOnLocalDate;
|
||||
}
|
||||
|
||||
public boolean isPreClosurePenalApplicable() {
|
||||
if (this.preClosureDetail != null) { return this.preClosureDetail.preClosurePenalApplicable(); }
|
||||
@@ -181,7 +194,11 @@ public class DepositAccountTermAndPreClosure extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
public Integer getActualDepositPeriod(final LocalDate interestPostingUpToDate, final SavingsPeriodFrequencyType periodFrequencyType) {
|
||||
final LocalDate depositFromDate = this.account.accountSubmittedOrActivationDate();
|
||||
LocalDate depositFromDate = getExpectedFirstDepositOnDate();
|
||||
|
||||
if(depositFromDate == null)
|
||||
depositFromDate = this.account.accountSubmittedOrActivationDate();
|
||||
|
||||
Integer actualDepositPeriod = this.depositPeriod;
|
||||
if (depositFromDate == null || getMaturityLocalDate() == null || interestPostingUpToDate.isEqual(getMaturityLocalDate())) { return actualDepositPeriod; }
|
||||
|
||||
@@ -225,14 +242,20 @@ public class DepositAccountTermAndPreClosure extends AbstractPersistable<Long> {
|
||||
public DepositAccountTermAndPreClosure deepCopy(Money depositAmount) {
|
||||
final SavingsAccount account = null;
|
||||
final BigDecimal maturityAmount = null;
|
||||
final BigDecimal actualDepositAmount = null;
|
||||
final LocalDate maturityDate = null;
|
||||
final Integer depositPeriod = this.depositPeriod;
|
||||
final SavingsPeriodFrequencyType depositPeriodFrequency = SavingsPeriodFrequencyType.fromInt(this.depositPeriodFrequency);
|
||||
final DepositPreClosureDetail preClosureDetail = this.preClosureDetail.copy();
|
||||
final DepositTermDetail depositTermDetail = this.depositTermDetail.copy();
|
||||
final LocalDate expectedFirstDepositOnDate = null;
|
||||
|
||||
final DepositAccountOnClosureType accountOnClosureType = null;
|
||||
return DepositAccountTermAndPreClosure.createNew(preClosureDetail, depositTermDetail, account, depositAmount.getAmount(), maturityAmount,
|
||||
maturityDate, depositPeriod, depositPeriodFrequency, accountOnClosureType);
|
||||
return DepositAccountTermAndPreClosure.createNew(preClosureDetail, depositTermDetail, account, actualDepositAmount, maturityAmount,
|
||||
maturityDate, depositPeriod, depositPeriodFrequency, expectedFirstDepositOnDate, accountOnClosureType);
|
||||
}
|
||||
|
||||
public void updateExpectedFirstDepositDate(final LocalDate expectedFirstDepositOnDate) {
|
||||
this.expectedFirstDepositOnDate = expectedFirstDepositOnDate.toDate();
|
||||
}
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* 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.portfolio.savings.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embeddable;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
|
||||
|
||||
/**
|
||||
* RecurringDepositProductAmountDetails encapsulates all recurring Deposit Amount of a
|
||||
* {@link RecurringDepositProduct}.
|
||||
*/
|
||||
@Embeddable
|
||||
public class DepositProductAmountDetails {
|
||||
|
||||
@Column(name = "min_deposit_amount", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal minDepositAmount;
|
||||
|
||||
@Column(name = "max_deposit_amount", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal maxDepositAmount;
|
||||
|
||||
@Column(name = "deposit_amount", scale = 6, precision = 19, nullable = false)
|
||||
private BigDecimal depositAmount;
|
||||
|
||||
|
||||
|
||||
public static DepositProductAmountDetails createFrom(final BigDecimal minDepositAmount,
|
||||
final BigDecimal depositAmount, final BigDecimal maxDepositAmount) {
|
||||
|
||||
return new DepositProductAmountDetails(minDepositAmount, depositAmount, maxDepositAmount);
|
||||
}
|
||||
|
||||
protected DepositProductAmountDetails() {
|
||||
//
|
||||
}
|
||||
|
||||
public DepositProductAmountDetails(final BigDecimal minDepositAmount, final BigDecimal depositAmount, final BigDecimal maxDepositAmount) {
|
||||
this.minDepositAmount = minDepositAmount;
|
||||
this.depositAmount = depositAmount;
|
||||
this.maxDepositAmount = maxDepositAmount;
|
||||
}
|
||||
|
||||
public Map<String, Object> update(final JsonCommand command, final DataValidatorBuilder baseDataValidator) {
|
||||
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(20);
|
||||
|
||||
final String localeAsInput = command.locale();
|
||||
|
||||
final String minDepositAmountParamName = "minDepositAmount";
|
||||
if (command.isChangeInBigDecimalParameterNamedWithNullCheck(minDepositAmountParamName, this.minDepositAmount)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(minDepositAmountParamName);
|
||||
actualChanges.put(minDepositAmountParamName, newValue);
|
||||
actualChanges.put("locale", localeAsInput);
|
||||
this.minDepositAmount = newValue;
|
||||
}
|
||||
|
||||
final String maxDepositAmountParamName = "maxDepositAmount";
|
||||
if (command.isChangeInBigDecimalParameterNamedWithNullCheck(maxDepositAmountParamName, this.maxDepositAmount)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(maxDepositAmountParamName);
|
||||
actualChanges.put(maxDepositAmountParamName, newValue);
|
||||
actualChanges.put("locale", localeAsInput);
|
||||
this.maxDepositAmount = newValue;
|
||||
}
|
||||
|
||||
final String depositAmountParamName = "depositAmount";
|
||||
if (command.isChangeInBigDecimalParameterNamedWithNullCheck(depositAmountParamName, this.depositAmount)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(depositAmountParamName);
|
||||
actualChanges.put(depositAmountParamName, newValue);
|
||||
actualChanges.put("locale", localeAsInput);
|
||||
this.depositAmount = newValue;
|
||||
}
|
||||
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
public BigDecimal getMinDepositAmount() {
|
||||
return this.minDepositAmount;
|
||||
}
|
||||
|
||||
public BigDecimal getMaxDepositAmount() {
|
||||
return this.maxDepositAmount;
|
||||
}
|
||||
|
||||
public BigDecimal getDepositAmount() {
|
||||
return this.depositAmount;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+32
-3
@@ -24,6 +24,9 @@ import static org.mifosplatform.portfolio.savings.DepositsApiConstants.preClosur
|
||||
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.recurringDepositFrequencyParamName;
|
||||
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.recurringDepositFrequencyTypeIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.recurringDepositTypeIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.depositAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.depositMinAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.DepositsApiConstants.depositMaxAmountParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.chargesParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.currencyCodeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.descriptionParamName;
|
||||
@@ -133,8 +136,9 @@ public class DepositProductAssembler {
|
||||
|
||||
final DepositPreClosureDetail preClosureDetail = this.assemblePreClosureDetail(command);
|
||||
final DepositTermDetail depositTermDetail = this.assembleDepositTermDetail(command);
|
||||
final DepositProductAmountDetails depositProductAmountDetails = this.assembleDepositAmountDetails(command);
|
||||
final DepositProductTermAndPreClosure productTermAndPreClosure = DepositProductTermAndPreClosure.createNew(preClosureDetail,
|
||||
depositTermDetail, null);
|
||||
depositTermDetail, depositProductAmountDetails, null);
|
||||
|
||||
// Savings product charges
|
||||
final Set<Charge> charges = assembleListOfSavingsProductCharges(command, currencyCode);
|
||||
@@ -167,7 +171,7 @@ public class DepositProductAssembler {
|
||||
.failWithCodeNoParameterAddedToErrorCode("max.term.lessthan.min.term");
|
||||
}
|
||||
fixedDepositProduct.validateCharts(baseDataValidator);
|
||||
|
||||
fixedDepositProduct.validateInterestPostingAndCompoundingPeriodTypes(baseDataValidator);
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
|
||||
@@ -220,8 +224,9 @@ public class DepositProductAssembler {
|
||||
|
||||
final DepositPreClosureDetail preClosureDetail = this.assemblePreClosureDetail(command);
|
||||
final DepositTermDetail depositTermDetail = this.assembleDepositTermDetail(command);
|
||||
final DepositProductAmountDetails depositProductAmountDetails = this.assembleDepositAmountDetails(command);
|
||||
final DepositProductTermAndPreClosure productTermAndPreClosure = DepositProductTermAndPreClosure.createNew(preClosureDetail,
|
||||
depositTermDetail, null);
|
||||
depositTermDetail, depositProductAmountDetails, null);
|
||||
final DepositRecurringDetail recurringDetail = this.assembleRecurringDetail(command);
|
||||
final DepositProductRecurringDetail productRecurringDetail = DepositProductRecurringDetail.createNew(recurringDetail, null);
|
||||
|
||||
@@ -260,6 +265,7 @@ public class DepositProductAssembler {
|
||||
.failWithCodeNoParameterAddedToErrorCode("max.term.lessthan.min.term");
|
||||
}
|
||||
recurringDepositProduct.validateCharts(baseDataValidator);
|
||||
recurringDepositProduct.validateInterestPostingAndCompoundingPeriodTypes(baseDataValidator);
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
}
|
||||
@@ -535,4 +541,27 @@ public class DepositProductAssembler {
|
||||
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
||||
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
|
||||
}
|
||||
|
||||
public DepositProductAmountDetails assembleDepositAmountDetails(final JsonCommand command) {
|
||||
|
||||
BigDecimal minDepositAmount = null;
|
||||
if(command.parameterExists(depositMinAmountParamName)) {
|
||||
minDepositAmount = command.bigDecimalValueOfParameterNamed(depositMinAmountParamName);
|
||||
}
|
||||
|
||||
BigDecimal maxDepositAmount = null;
|
||||
if(command.parameterExists(depositMaxAmountParamName)) {
|
||||
maxDepositAmount = command.bigDecimalValueOfParameterNamed(depositMaxAmountParamName);
|
||||
}
|
||||
|
||||
BigDecimal depositAmount = null;
|
||||
if(command.parameterExists(depositAmountParamName)) {
|
||||
depositAmount = command.bigDecimalValueOfParameterNamed(depositAmountParamName);
|
||||
}
|
||||
|
||||
final DepositProductAmountDetails depositRecurringDetail = new DepositProductAmountDetails(minDepositAmount,
|
||||
depositAmount, maxDepositAmount);
|
||||
|
||||
return depositRecurringDetail;
|
||||
}
|
||||
}
|
||||
+15
-2
@@ -31,21 +31,26 @@ public class DepositProductTermAndPreClosure extends AbstractPersistable<Long> {
|
||||
@OneToOne
|
||||
@JoinColumn(name = "savings_product_id", nullable = false)
|
||||
private FixedDepositProduct product;
|
||||
|
||||
@Embedded
|
||||
private DepositProductAmountDetails depositProductAmountDetails;
|
||||
|
||||
protected DepositProductTermAndPreClosure() {
|
||||
super();
|
||||
}
|
||||
|
||||
public static DepositProductTermAndPreClosure createNew(DepositPreClosureDetail preClosureDetail, DepositTermDetail depositTermDetail,
|
||||
DepositProductAmountDetails depositProductMinMaxAmountDetails,
|
||||
SavingsProduct product) {
|
||||
|
||||
return new DepositProductTermAndPreClosure(preClosureDetail, depositTermDetail, product);
|
||||
return new DepositProductTermAndPreClosure(preClosureDetail, depositTermDetail, depositProductMinMaxAmountDetails, product);
|
||||
}
|
||||
|
||||
private DepositProductTermAndPreClosure(DepositPreClosureDetail preClosureDetail, DepositTermDetail depositTermDetail,
|
||||
SavingsProduct product) {
|
||||
DepositProductAmountDetails depositProductMinMaxAmountDetails, SavingsProduct product) {
|
||||
this.preClosureDetail = preClosureDetail;
|
||||
this.depositTermDetail = depositTermDetail;
|
||||
this.depositProductAmountDetails = depositProductMinMaxAmountDetails;
|
||||
this.product = (FixedDepositProduct)product;
|
||||
}
|
||||
|
||||
@@ -58,6 +63,10 @@ public class DepositProductTermAndPreClosure extends AbstractPersistable<Long> {
|
||||
if (this.depositTermDetail != null) {
|
||||
actualChanges.putAll(this.depositTermDetail.update(command, baseDataValidator));
|
||||
}
|
||||
|
||||
if(this.depositProductAmountDetails != null) {
|
||||
actualChanges.putAll(this.depositProductAmountDetails.update(command, baseDataValidator));
|
||||
}
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
@@ -69,6 +78,10 @@ public class DepositProductTermAndPreClosure extends AbstractPersistable<Long> {
|
||||
return this.depositTermDetail;
|
||||
}
|
||||
|
||||
public DepositProductAmountDetails depositProductAmountDetails() {
|
||||
return this.depositProductAmountDetails;
|
||||
}
|
||||
|
||||
public void updateProductReference(final SavingsProduct product){
|
||||
this.product = (FixedDepositProduct)product;
|
||||
}
|
||||
|
||||
+33
@@ -11,6 +11,7 @@ import static org.mifosplatform.portfolio.savings.DepositsApiConstants.FIXED_DEP
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -260,5 +261,37 @@ public class FixedDepositProduct extends SavingsProduct {
|
||||
public DepositProductTermAndPreClosure depositProductTermAndPreClosure() {
|
||||
return this.productTermAndPreClosure;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void validateInterestPostingAndCompoundingPeriodTypes(final DataValidatorBuilder baseDataValidator) {
|
||||
Map<SavingsPostingInterestPeriodType, List<SavingsCompoundingInterestPeriodType>> postingtoCompoundMap =
|
||||
new HashMap<SavingsPostingInterestPeriodType, List<SavingsCompoundingInterestPeriodType>>();
|
||||
postingtoCompoundMap.put(SavingsPostingInterestPeriodType.MONTHLY,
|
||||
Arrays.asList(new SavingsCompoundingInterestPeriodType[]{SavingsCompoundingInterestPeriodType.DAILY,SavingsCompoundingInterestPeriodType.MONTHLY}));
|
||||
|
||||
postingtoCompoundMap.put(SavingsPostingInterestPeriodType.QUATERLY,
|
||||
Arrays.asList(new SavingsCompoundingInterestPeriodType[]{SavingsCompoundingInterestPeriodType.DAILY
|
||||
,SavingsCompoundingInterestPeriodType.MONTHLY,SavingsCompoundingInterestPeriodType.QUATERLY}));
|
||||
|
||||
postingtoCompoundMap.put(SavingsPostingInterestPeriodType.BIANNUAL,
|
||||
Arrays.asList(new SavingsCompoundingInterestPeriodType[]{SavingsCompoundingInterestPeriodType.DAILY,
|
||||
SavingsCompoundingInterestPeriodType.MONTHLY,SavingsCompoundingInterestPeriodType.QUATERLY,SavingsCompoundingInterestPeriodType.BI_ANNUAL}));
|
||||
|
||||
postingtoCompoundMap.put(SavingsPostingInterestPeriodType.ANNUAL,
|
||||
Arrays.asList(new SavingsCompoundingInterestPeriodType[]{SavingsCompoundingInterestPeriodType.DAILY,
|
||||
SavingsCompoundingInterestPeriodType.MONTHLY,SavingsCompoundingInterestPeriodType.QUATERLY
|
||||
,SavingsCompoundingInterestPeriodType.BI_ANNUAL,SavingsCompoundingInterestPeriodType.ANNUAL}));
|
||||
|
||||
SavingsPostingInterestPeriodType savingsPostingInterestPeriodType = SavingsPostingInterestPeriodType.fromInt(interestPostingPeriodType);
|
||||
SavingsCompoundingInterestPeriodType savingsCompoundingInterestPeriodType = SavingsCompoundingInterestPeriodType.fromInt(interestCompoundingPeriodType);
|
||||
|
||||
if(postingtoCompoundMap.get(savingsPostingInterestPeriodType) == null ||
|
||||
!postingtoCompoundMap.get(savingsPostingInterestPeriodType).contains(savingsCompoundingInterestPeriodType)) {
|
||||
baseDataValidator.failWithCodeNoParameterAddedToErrorCode("posting.period.type.is.less.than.compound.period.type",
|
||||
savingsPostingInterestPeriodType.name(),savingsCompoundingInterestPeriodType.name());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+120
-15
@@ -99,6 +99,28 @@ public class RecurringDepositAccount extends SavingsAccount {
|
||||
lockinPeriodFrequencyType, withdrawalFeeApplicableForTransfer, savingsAccountCharges, accountTermAndPreClosure,
|
||||
recurringDetail, chart, allowOverdraft, overdraftLimit);
|
||||
}
|
||||
|
||||
public static RecurringDepositAccount createNewActivatedAccount(final Client client, final Group group,
|
||||
final SavingsProduct product, final Staff fieldOfficer, final String accountNo, final String externalId,
|
||||
final AccountType accountType, final LocalDate submittedOnDate, final AppUser submittedBy, final BigDecimal interestRate,
|
||||
final SavingsCompoundingInterestPeriodType interestCompoundingPeriodType,
|
||||
final SavingsPostingInterestPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType,
|
||||
final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
|
||||
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType,
|
||||
final boolean withdrawalFeeApplicableForTransfer, final Set<SavingsAccountCharge> savingsAccountCharges,
|
||||
final DepositAccountTermAndPreClosure accountTermAndPreClosure, final DepositAccountRecurringDetail recurringDetail,
|
||||
final DepositAccountInterestRateChart chart) {
|
||||
|
||||
final boolean allowOverdraft = false;
|
||||
final BigDecimal overdraftLimit = new BigDecimal(0);
|
||||
|
||||
final SavingsAccountStatusType status = SavingsAccountStatusType.ACTIVE;
|
||||
return new RecurringDepositAccount(client, group, product, fieldOfficer, accountNo, externalId, status, accountType,
|
||||
submittedOnDate, submittedBy, interestRate, interestCompoundingPeriodType, interestPostingPeriodType,
|
||||
interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency,
|
||||
lockinPeriodFrequencyType, withdrawalFeeApplicableForTransfer, savingsAccountCharges, accountTermAndPreClosure,
|
||||
recurringDetail, chart, allowOverdraft, overdraftLimit);
|
||||
}
|
||||
|
||||
private RecurringDepositAccount(final Client client, final Group group, final SavingsProduct product, final Staff fieldOfficer,
|
||||
final String accountNo, final String externalId, final SavingsAccountStatusType status, final AccountType accountType,
|
||||
@@ -159,7 +181,7 @@ public class RecurringDepositAccount extends SavingsAccount {
|
||||
}
|
||||
}
|
||||
|
||||
final BigDecimal depositAmount = accountTermAndPreClosure.depositAmount();
|
||||
final BigDecimal depositAmount = recurringDetail.recurringDepositAmount();
|
||||
|
||||
BigDecimal applicableInterestRate = this.chart.getApplicableInterestRate(depositAmount, depositStartDate(), depositCloseDate);
|
||||
|
||||
@@ -251,7 +273,7 @@ public class RecurringDepositAccount extends SavingsAccount {
|
||||
.fromInt(this.interestCalculationDaysInYearType);
|
||||
|
||||
final List<LocalDateInterval> postingPeriodIntervals = this.savingsHelper.determineInterestPostingPeriods(
|
||||
accountSubmittedOrActivationDate(), maturityDate, postingPeriodType);
|
||||
depositStartDate(), maturityDate, postingPeriodType);
|
||||
|
||||
final List<PostingPeriod> allPostingPeriods = new ArrayList<PostingPeriod>();
|
||||
|
||||
@@ -321,7 +343,7 @@ public class RecurringDepositAccount extends SavingsAccount {
|
||||
return allTransactions;
|
||||
}
|
||||
|
||||
private LocalDate nextDepositDate(LocalDate depositDate) {
|
||||
public LocalDate nextDepositDate(LocalDate depositDate) {
|
||||
final LocalDate depositStartDate = depositStartDate();
|
||||
LocalDate nextDepositDate = depositStartDate;
|
||||
while (!depositDate.isBefore(nextDepositDate)) {
|
||||
@@ -357,7 +379,9 @@ public class RecurringDepositAccount extends SavingsAccount {
|
||||
public LocalDate depositStartDate() {
|
||||
// TODO: Support to add deposit start date which can be a date after
|
||||
// account activation date.
|
||||
final LocalDate depositStartDate = accountSubmittedOrActivationDate();
|
||||
final LocalDate depositStartDate = accountTermAndPreClosure.getExpectedFirstDepositOnDate();
|
||||
if(depositStartDate == null)
|
||||
return accountSubmittedOrActivationDate();
|
||||
return depositStartDate;
|
||||
}
|
||||
|
||||
@@ -436,18 +460,19 @@ public class RecurringDepositAccount extends SavingsAccount {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void processAccountUponActivation(final DateTimeFormatter fmt) {
|
||||
final Money recurringDepositAmount = Money.of(this.currency, this.recurringDetail.recurringDepositAmount());
|
||||
if (recurringDepositAmount.isGreaterThanZero()) {
|
||||
|
||||
protected void processAccountUponActivation(final DateTimeFormatter fmt) {
|
||||
final Money minRequiredOpeningBalance = Money.of(this.currency, this.minRequiredOpeningBalance);
|
||||
|
||||
if (minRequiredOpeningBalance.isGreaterThanZero()) {
|
||||
final SavingsAccountTransactionDTO transactionDTO = new SavingsAccountTransactionDTO(fmt, getActivationLocalDate(),
|
||||
recurringDepositAmount.getAmount(), null, new Date());
|
||||
minRequiredOpeningBalance.getAmount(), null, new Date());
|
||||
deposit(transactionDTO);
|
||||
final LocalDate interestPostingUpToDate = interestPostingUpToDate(DateUtils.getLocalDateOfTenant());
|
||||
|
||||
// update existing transactions so derived balance fields are
|
||||
// correct.
|
||||
recalculateDailyBalances(Money.zero(this.currency), interestPostingUpToDate);
|
||||
recalculateDailyBalances(Money.zero(this.currency), DateUtils.getLocalDateOfTenant());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public SavingsAccountTransaction close(final AppUser currentUser, final JsonCommand command, final LocalDate tenantsTodayDate,
|
||||
@@ -778,6 +803,25 @@ public class RecurringDepositAccount extends SavingsAccount {
|
||||
if (!chartInterval.contains(accountSubmittedOrActivationDate())) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("no.valid.interest.rate.slab.available.for.date.range");
|
||||
}
|
||||
|
||||
final boolean firstDepositDateBeforeMaturityAndOnOrAfterActivationDate = firstDepositDateBeforeMaturityAndOnOrAfterActivationDate();
|
||||
|
||||
if(!firstDepositDateBeforeMaturityAndOnOrAfterActivationDate) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("expected.first.deposit.date.is.not.between.maturity.date.and.activation.or.submitted.date");
|
||||
}
|
||||
|
||||
final BigDecimal recurringDepositAmount = recurringDetail.recurringDepositAmount();
|
||||
BigDecimal applicableInterestRate = this.chart.getApplicableInterestRate(recurringDepositAmount, depositStartDate(), calculateMaturityDate());
|
||||
|
||||
if(applicableInterestRate.equals(BigDecimal.ZERO)) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("no.applicable.interest.rate.is.found.based.on.amount.and.deposit.period");
|
||||
}
|
||||
|
||||
final boolean recurringFrequencyBeforeDepositPeriod = recurringFrequencyBeforeDepositPeriod();
|
||||
|
||||
if(!recurringFrequencyBeforeDepositPeriod) {
|
||||
baseDataValidator.reset().failWithCodeNoParameterAddedToErrorCode("recurring.frequency.not.before.deposit.period");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isReinvestOnClosure() {
|
||||
@@ -795,7 +839,7 @@ public class RecurringDepositAccount extends SavingsAccount {
|
||||
final SavingsProduct product = this.product;
|
||||
final InterestRateChart productChart = product.applicableChart(getClosedOnDate());
|
||||
final DepositAccountInterestRateChart newChart = DepositAccountInterestRateChart.from(productChart);
|
||||
final String accountNumber = this.accountNumber;
|
||||
final String accountNumber = null;
|
||||
final String externalId = this.externalId;
|
||||
final AccountType accountType = AccountType.fromInt(this.accountType);
|
||||
final SavingsPostingInterestPeriodType postingPeriodType = SavingsPostingInterestPeriodType.fromInt(this.interestPostingPeriodType);
|
||||
@@ -804,17 +848,78 @@ public class RecurringDepositAccount extends SavingsAccount {
|
||||
final SavingsInterestCalculationType interestCalculationType = SavingsInterestCalculationType.fromInt(this.interestCalculationType);
|
||||
final SavingsInterestCalculationDaysInYearType daysInYearType = SavingsInterestCalculationDaysInYearType
|
||||
.fromInt(this.interestCalculationDaysInYearType);
|
||||
final BigDecimal minRequiredOpeningBalance = null;
|
||||
final BigDecimal interestRate = null;
|
||||
final BigDecimal minRequiredOpeningBalance = depositAmount.getAmount();
|
||||
final BigDecimal interestRate = BigDecimal.ZERO;
|
||||
final Set<SavingsAccountCharge> savingsAccountCharges = null;
|
||||
final SavingsPeriodFrequencyType lockinPeriodFrequencyType = SavingsPeriodFrequencyType.fromInt(this.lockinPeriodFrequencyType);
|
||||
final Integer lockinPeriodFrequency = this.lockinPeriodFrequency;
|
||||
final boolean withdrawalFeeApplicableForTransfer = false;
|
||||
|
||||
LocalDate now = LocalDate.now();
|
||||
|
||||
newAccountTermAndPreClosure.updateExpectedFirstDepositDate(now);
|
||||
|
||||
return RecurringDepositAccount.createNewApplicationForSubmittal(client, group, product, fieldOfficer, accountNumber, externalId,
|
||||
RecurringDepositAccount rdAccount = RecurringDepositAccount.createNewActivatedAccount(client, group, product, fieldOfficer, accountNumber, externalId,
|
||||
accountType, getClosedOnDate(), closedBy, interestRate, compoundingPeriodType, postingPeriodType, interestCalculationType,
|
||||
daysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType,
|
||||
withdrawalFeeApplicableForTransfer, savingsAccountCharges, newAccountTermAndPreClosure, recurringDetail, newChart);
|
||||
|
||||
rdAccount.setDatesFrom(now);
|
||||
newAccountTermAndPreClosure.updateAccountReference(rdAccount);
|
||||
recurringDetail.updateAccountReference(rdAccount);
|
||||
|
||||
return rdAccount;
|
||||
|
||||
}
|
||||
|
||||
private boolean firstDepositDateBeforeMaturityAndOnOrAfterActivationDate() {
|
||||
LocalDate expectedFirstDepositLocalDate = accountTermAndPreClosure.getExpectedFirstDepositOnDate();
|
||||
LocalDate maturityLocalDate = calculateMaturityDate();
|
||||
LocalDate activateOnSubmittedLocalDate = accountSubmittedOrActivationDate();
|
||||
|
||||
return expectedFirstDepositLocalDate.isBefore(maturityLocalDate) &&
|
||||
(activateOnSubmittedLocalDate.isEqual(expectedFirstDepositLocalDate) || activateOnSubmittedLocalDate.isBefore(expectedFirstDepositLocalDate));
|
||||
}
|
||||
|
||||
public void setDatesFrom(final LocalDate now) {
|
||||
this.rejectedOnDate = null;
|
||||
this.rejectedBy = null;
|
||||
this.withdrawnOnDate = null;
|
||||
this.withdrawnBy = null;
|
||||
this.closedOnDate = null;
|
||||
this.closedBy = null;
|
||||
|
||||
this.activatedBy = null;
|
||||
this.lockedInUntilDate = null;
|
||||
|
||||
this.activatedOnDate = now.toDate();
|
||||
}
|
||||
|
||||
private boolean recurringFrequencyBeforeDepositPeriod() {
|
||||
final int recurringFrequency = recurringDetail.recurringDepositFrequency();
|
||||
final SavingsPeriodFrequencyType recurringfrequencyType = recurringDetail.recurringDepositFrequencyType();
|
||||
|
||||
LocalDate depositStartDate = accountTermAndPreClosure.getExpectedFirstDepositOnDate();
|
||||
|
||||
LocalDate endDateWithFirstRecurringFrequency = null;
|
||||
|
||||
switch (recurringfrequencyType) {
|
||||
case DAYS:
|
||||
endDateWithFirstRecurringFrequency = depositStartDate.plusDays(recurringFrequency);
|
||||
break;
|
||||
case MONTHS:
|
||||
endDateWithFirstRecurringFrequency = depositStartDate.plusMonths(recurringFrequency);
|
||||
break;
|
||||
case WEEKS:
|
||||
endDateWithFirstRecurringFrequency = depositStartDate.plusWeeks(recurringFrequency);
|
||||
break;
|
||||
case YEARS:
|
||||
endDateWithFirstRecurringFrequency = depositStartDate.plusYears(recurringFrequency);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return endDateWithFirstRecurringFrequency != null && endDateWithFirstRecurringFrequency.isBefore(calculateMaturityDate());
|
||||
}
|
||||
}
|
||||
+9
@@ -69,6 +69,15 @@ public final class SavingsHelper {
|
||||
periodEndDate = new DateTime().withDate(year, 12, 31).toLocalDate();
|
||||
}
|
||||
break;
|
||||
case BIANNUAL:
|
||||
final int byear = periodStartDate.getYearOfEra();
|
||||
final int bmonthofYear = periodStartDate.getMonthOfYear();
|
||||
if (bmonthofYear <= 6) {
|
||||
periodEndDate = new DateTime().withDate(byear, 6, 30).toLocalDate();
|
||||
} else if (bmonthofYear <= 12) {
|
||||
periodEndDate = new DateTime().withDate(byear, 12, 31).toLocalDate();
|
||||
}
|
||||
break;
|
||||
case ANNUAL:
|
||||
periodEndDate = periodStartDate.monthOfYear().withMaximumValue();
|
||||
periodEndDate = periodEndDate.dayOfMonth().withMaximumValue();
|
||||
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
package org.mifosplatform.portfolio.savings.domain.interest;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.domain.LocalDateInterval;
|
||||
import org.mifosplatform.portfolio.savings.SavingsCompoundingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationType;
|
||||
|
||||
public class AnnualCompoundingPeriod implements CompoundingPeriod {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final LocalDateInterval periodInterval;
|
||||
private final List<EndOfDayBalance> endOfDayBalances;
|
||||
|
||||
public static AnnualCompoundingPeriod create(final LocalDateInterval periodInterval, final List<EndOfDayBalance> allEndOfDayBalances, final LocalDate upToInterestCalculationDate) {
|
||||
|
||||
final List<EndOfDayBalance> endOfDayBalancesWithinPeriod = endOfDayBalancesWithinPeriodInterval(periodInterval, allEndOfDayBalances, upToInterestCalculationDate);
|
||||
|
||||
return new AnnualCompoundingPeriod(periodInterval, endOfDayBalancesWithinPeriod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal calculateInterest(final BigDecimal interestRateAsFraction, final long daysInYear) {
|
||||
|
||||
BigDecimal interestEarned = BigDecimal.ZERO;
|
||||
|
||||
for (final EndOfDayBalance balance : this.endOfDayBalances) {
|
||||
final BigDecimal interestOnBalanceUnrounded = balance.calculateInterestOnBalance(BigDecimal.ZERO, interestRateAsFraction,
|
||||
daysInYear);
|
||||
interestEarned = interestEarned.add(interestOnBalanceUnrounded);
|
||||
}
|
||||
|
||||
return interestEarned;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal calculateInterest(final SavingsCompoundingInterestPeriodType compoundingInterestPeriodType,
|
||||
final SavingsInterestCalculationType interestCalculationType, final BigDecimal interestToCompound,
|
||||
final BigDecimal interestRateAsFraction, final long daysInYear) {
|
||||
|
||||
BigDecimal interestEarned = BigDecimal.ZERO;
|
||||
|
||||
switch (interestCalculationType) {
|
||||
case DAILY_BALANCE:
|
||||
interestEarned = calculateUsingDailyBalanceMethod(compoundingInterestPeriodType, interestToCompound,
|
||||
interestRateAsFraction, daysInYear);
|
||||
break;
|
||||
case AVERAGE_DAILY_BALANCE:
|
||||
interestEarned = calculateUsingAverageDailyBalanceMethod(interestToCompound, interestRateAsFraction, daysInYear);
|
||||
break;
|
||||
case INVALID:
|
||||
break;
|
||||
}
|
||||
|
||||
return interestEarned;
|
||||
}
|
||||
|
||||
private BigDecimal calculateUsingAverageDailyBalanceMethod(final BigDecimal interestToCompound,
|
||||
final BigDecimal interestRateAsFraction, final long daysInYear) {
|
||||
|
||||
BigDecimal cumulativeBalance = BigDecimal.ZERO;
|
||||
Integer numberOfDays = Integer.valueOf(0);
|
||||
|
||||
for (final EndOfDayBalance balance : this.endOfDayBalances) {
|
||||
final BigDecimal endOfDayCumulativeBalance = balance.cumulativeBalance(interestToCompound);
|
||||
cumulativeBalance = cumulativeBalance.add(endOfDayCumulativeBalance);
|
||||
|
||||
final Integer balanceExistsForNumberOfDays = balance.getNumberOfDays();
|
||||
numberOfDays = numberOfDays + balanceExistsForNumberOfDays;
|
||||
}
|
||||
|
||||
BigDecimal interestEarned = BigDecimal.ZERO;
|
||||
if (cumulativeBalance.compareTo(BigDecimal.ZERO) != 0 && numberOfDays > 0) {
|
||||
final BigDecimal averageDailyBalance = cumulativeBalance.divide(BigDecimal.valueOf(numberOfDays), MathContext.DECIMAL64)
|
||||
.setScale(9, RoundingMode.HALF_EVEN);
|
||||
|
||||
final BigDecimal multiplicand = BigDecimal.ONE.divide(BigDecimal.valueOf(daysInYear), MathContext.DECIMAL64);
|
||||
final BigDecimal dailyInterestRate = interestRateAsFraction.multiply(multiplicand, MathContext.DECIMAL64);
|
||||
final BigDecimal periodicInterestRate = dailyInterestRate.multiply(BigDecimal.valueOf(numberOfDays), MathContext.DECIMAL64);
|
||||
|
||||
interestEarned = averageDailyBalance.multiply(periodicInterestRate, MathContext.DECIMAL64).setScale(9, RoundingMode.HALF_EVEN);
|
||||
}
|
||||
|
||||
return interestEarned;
|
||||
}
|
||||
|
||||
private BigDecimal calculateUsingDailyBalanceMethod(final SavingsCompoundingInterestPeriodType compoundingInterestPeriodType,
|
||||
final BigDecimal interestToCompound, final BigDecimal interestRateAsFraction, final long daysInYear) {
|
||||
|
||||
BigDecimal interestEarned = BigDecimal.ZERO;
|
||||
BigDecimal interestOnBalanceUnrounded = BigDecimal.ZERO;
|
||||
for (final EndOfDayBalance balance : this.endOfDayBalances) {
|
||||
|
||||
switch (compoundingInterestPeriodType) {
|
||||
case DAILY:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalanceAndInterest(interestToCompound, interestRateAsFraction,
|
||||
daysInYear);
|
||||
break;
|
||||
case MONTHLY:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalance(interestToCompound, interestRateAsFraction, daysInYear);
|
||||
break;
|
||||
case QUATERLY:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalance(interestToCompound, interestRateAsFraction, daysInYear);
|
||||
break;
|
||||
// case WEEKLY:
|
||||
// break;
|
||||
// case BIWEEKLY:
|
||||
// break;
|
||||
case BI_ANNUAL:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalance(interestToCompound, interestRateAsFraction, daysInYear);
|
||||
break;
|
||||
case ANNUAL:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalance(interestToCompound, interestRateAsFraction, daysInYear);
|
||||
break;
|
||||
// case NO_COMPOUNDING_SIMPLE_INTEREST:
|
||||
// break;
|
||||
case INVALID:
|
||||
break;
|
||||
}
|
||||
|
||||
interestEarned = interestEarned.add(interestOnBalanceUnrounded);
|
||||
}
|
||||
return interestEarned;
|
||||
}
|
||||
|
||||
private static List<EndOfDayBalance> endOfDayBalancesWithinPeriodInterval(final LocalDateInterval compoundingPeriodInterval,
|
||||
final List<EndOfDayBalance> allEndOfDayBalances, final LocalDate upToInterestCalculationDate) {
|
||||
|
||||
final List<EndOfDayBalance> endOfDayBalancesForPeriodInterval = new ArrayList<EndOfDayBalance>();
|
||||
|
||||
for (final EndOfDayBalance endOfDayBalance : allEndOfDayBalances) {
|
||||
|
||||
if (compoundingPeriodInterval.contains(endOfDayBalance.date())) {
|
||||
final EndOfDayBalance cappedToPeriodEndDate = endOfDayBalance.upTo(compoundingPeriodInterval, upToInterestCalculationDate);
|
||||
endOfDayBalancesForPeriodInterval.add(cappedToPeriodEndDate);
|
||||
} else if (endOfDayBalance.contains(compoundingPeriodInterval)) {
|
||||
final EndOfDayBalance cappedToPeriodEndDate = endOfDayBalance.upTo(compoundingPeriodInterval, upToInterestCalculationDate);
|
||||
endOfDayBalancesForPeriodInterval.add(cappedToPeriodEndDate);
|
||||
}
|
||||
}
|
||||
|
||||
return endOfDayBalancesForPeriodInterval;
|
||||
}
|
||||
|
||||
private AnnualCompoundingPeriod(final LocalDateInterval periodInterval, final List<EndOfDayBalance> endOfDayBalances) {
|
||||
this.periodInterval = periodInterval;
|
||||
this.endOfDayBalances = endOfDayBalances;
|
||||
}
|
||||
}
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
package org.mifosplatform.portfolio.savings.domain.interest;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.domain.LocalDateInterval;
|
||||
import org.mifosplatform.portfolio.savings.SavingsCompoundingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationType;
|
||||
|
||||
public class BiAnnualCompoundingPeriod implements CompoundingPeriod {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final LocalDateInterval periodInterval;
|
||||
private final List<EndOfDayBalance> endOfDayBalances;
|
||||
|
||||
public static BiAnnualCompoundingPeriod create(final LocalDateInterval periodInterval, final List<EndOfDayBalance> allEndOfDayBalances, final LocalDate upToInterestCalculationDate) {
|
||||
|
||||
final List<EndOfDayBalance> endOfDayBalancesWithinPeriod = endOfDayBalancesWithinPeriodInterval(periodInterval, allEndOfDayBalances, upToInterestCalculationDate);
|
||||
|
||||
return new BiAnnualCompoundingPeriod(periodInterval, endOfDayBalancesWithinPeriod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal calculateInterest(final BigDecimal interestRateAsFraction, final long daysInYear) {
|
||||
|
||||
BigDecimal interestEarned = BigDecimal.ZERO;
|
||||
|
||||
for (final EndOfDayBalance balance : this.endOfDayBalances) {
|
||||
final BigDecimal interestOnBalanceUnrounded = balance.calculateInterestOnBalance(BigDecimal.ZERO, interestRateAsFraction,
|
||||
daysInYear);
|
||||
interestEarned = interestEarned.add(interestOnBalanceUnrounded);
|
||||
}
|
||||
|
||||
return interestEarned;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal calculateInterest(final SavingsCompoundingInterestPeriodType compoundingInterestPeriodType,
|
||||
final SavingsInterestCalculationType interestCalculationType, final BigDecimal interestToCompound,
|
||||
final BigDecimal interestRateAsFraction, final long daysInYear) {
|
||||
|
||||
BigDecimal interestEarned = BigDecimal.ZERO;
|
||||
|
||||
switch (interestCalculationType) {
|
||||
case DAILY_BALANCE:
|
||||
interestEarned = calculateUsingDailyBalanceMethod(compoundingInterestPeriodType, interestToCompound,
|
||||
interestRateAsFraction, daysInYear);
|
||||
break;
|
||||
case AVERAGE_DAILY_BALANCE:
|
||||
interestEarned = calculateUsingAverageDailyBalanceMethod(interestToCompound, interestRateAsFraction, daysInYear);
|
||||
break;
|
||||
case INVALID:
|
||||
break;
|
||||
}
|
||||
|
||||
return interestEarned;
|
||||
}
|
||||
|
||||
private BigDecimal calculateUsingAverageDailyBalanceMethod(final BigDecimal interestToCompound,
|
||||
final BigDecimal interestRateAsFraction, final long daysInYear) {
|
||||
|
||||
BigDecimal cumulativeBalance = BigDecimal.ZERO;
|
||||
Integer numberOfDays = Integer.valueOf(0);
|
||||
|
||||
for (final EndOfDayBalance balance : this.endOfDayBalances) {
|
||||
final BigDecimal endOfDayCumulativeBalance = balance.cumulativeBalance(interestToCompound);
|
||||
cumulativeBalance = cumulativeBalance.add(endOfDayCumulativeBalance);
|
||||
|
||||
final Integer balanceExistsForNumberOfDays = balance.getNumberOfDays();
|
||||
numberOfDays = numberOfDays + balanceExistsForNumberOfDays;
|
||||
}
|
||||
|
||||
BigDecimal interestEarned = BigDecimal.ZERO;
|
||||
if (cumulativeBalance.compareTo(BigDecimal.ZERO) != 0 && numberOfDays > 0) {
|
||||
final BigDecimal averageDailyBalance = cumulativeBalance.divide(BigDecimal.valueOf(numberOfDays), MathContext.DECIMAL64)
|
||||
.setScale(9, RoundingMode.HALF_EVEN);
|
||||
|
||||
final BigDecimal multiplicand = BigDecimal.ONE.divide(BigDecimal.valueOf(daysInYear), MathContext.DECIMAL64);
|
||||
final BigDecimal dailyInterestRate = interestRateAsFraction.multiply(multiplicand, MathContext.DECIMAL64);
|
||||
final BigDecimal periodicInterestRate = dailyInterestRate.multiply(BigDecimal.valueOf(numberOfDays), MathContext.DECIMAL64);
|
||||
|
||||
interestEarned = averageDailyBalance.multiply(periodicInterestRate, MathContext.DECIMAL64).setScale(9, RoundingMode.HALF_EVEN);
|
||||
}
|
||||
|
||||
return interestEarned;
|
||||
}
|
||||
|
||||
private BigDecimal calculateUsingDailyBalanceMethod(final SavingsCompoundingInterestPeriodType compoundingInterestPeriodType,
|
||||
final BigDecimal interestToCompound, final BigDecimal interestRateAsFraction, final long daysInYear) {
|
||||
|
||||
BigDecimal interestEarned = BigDecimal.ZERO;
|
||||
BigDecimal interestOnBalanceUnrounded = BigDecimal.ZERO;
|
||||
for (final EndOfDayBalance balance : this.endOfDayBalances) {
|
||||
|
||||
switch (compoundingInterestPeriodType) {
|
||||
case DAILY:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalanceAndInterest(interestToCompound, interestRateAsFraction,
|
||||
daysInYear);
|
||||
break;
|
||||
case MONTHLY:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalance(interestToCompound, interestRateAsFraction, daysInYear);
|
||||
break;
|
||||
case QUATERLY:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalance(interestToCompound, interestRateAsFraction, daysInYear);
|
||||
break;
|
||||
// case WEEKLY:
|
||||
// break;
|
||||
// case BIWEEKLY:
|
||||
// break;
|
||||
case BI_ANNUAL:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalance(interestToCompound, interestRateAsFraction, daysInYear);
|
||||
break;
|
||||
case ANNUAL:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalance(interestToCompound, interestRateAsFraction, daysInYear);
|
||||
break;
|
||||
// case NO_COMPOUNDING_SIMPLE_INTEREST:
|
||||
// break;
|
||||
case INVALID:
|
||||
break;
|
||||
}
|
||||
|
||||
interestEarned = interestEarned.add(interestOnBalanceUnrounded);
|
||||
}
|
||||
return interestEarned;
|
||||
}
|
||||
|
||||
private static List<EndOfDayBalance> endOfDayBalancesWithinPeriodInterval(final LocalDateInterval compoundingPeriodInterval,
|
||||
final List<EndOfDayBalance> allEndOfDayBalances, final LocalDate upToInterestCalculationDate) {
|
||||
|
||||
final List<EndOfDayBalance> endOfDayBalancesForPeriodInterval = new ArrayList<EndOfDayBalance>();
|
||||
|
||||
for (final EndOfDayBalance endOfDayBalance : allEndOfDayBalances) {
|
||||
|
||||
if (compoundingPeriodInterval.contains(endOfDayBalance.date())) {
|
||||
final EndOfDayBalance cappedToPeriodEndDate = endOfDayBalance.upTo(compoundingPeriodInterval, upToInterestCalculationDate);
|
||||
endOfDayBalancesForPeriodInterval.add(cappedToPeriodEndDate);
|
||||
} else if (endOfDayBalance.contains(compoundingPeriodInterval)) {
|
||||
final EndOfDayBalance cappedToPeriodEndDate = endOfDayBalance.upTo(compoundingPeriodInterval, upToInterestCalculationDate);
|
||||
endOfDayBalancesForPeriodInterval.add(cappedToPeriodEndDate);
|
||||
}
|
||||
}
|
||||
|
||||
return endOfDayBalancesForPeriodInterval;
|
||||
}
|
||||
|
||||
private BiAnnualCompoundingPeriod(final LocalDateInterval periodInterval, final List<EndOfDayBalance> endOfDayBalances) {
|
||||
this.periodInterval = periodInterval;
|
||||
this.endOfDayBalances = endOfDayBalances;
|
||||
}
|
||||
}
|
||||
+9
-3
@@ -6,6 +6,7 @@ import java.math.RoundingMode;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.domain.LocalDateInterval;
|
||||
import org.mifosplatform.infrastructure.core.service.DateUtils;
|
||||
import org.mifosplatform.organisation.monetary.domain.Money;
|
||||
|
||||
public class EndOfDayBalance {
|
||||
@@ -89,14 +90,19 @@ public class EndOfDayBalance {
|
||||
|
||||
Money startingBalance = this.openingBalance;
|
||||
LocalDate balanceStartDate = this.date;
|
||||
|
||||
LocalDate oldBalanceEndDate = this.date.plusDays(this.numberOfDays - 1);
|
||||
|
||||
int daysOfBalance = this.numberOfDays;
|
||||
|
||||
if (this.date.isBefore(compoundingPeriodInterval.startDate())) {
|
||||
balanceStartDate = compoundingPeriodInterval.startDate();
|
||||
startingBalance = this.endOfDayBalance;
|
||||
final LocalDateInterval balancePeriodInterval = LocalDateInterval.create(balanceStartDate, oldBalanceEndDate);
|
||||
daysOfBalance = balancePeriodInterval.daysInPeriodInclusiveOfEndDate();
|
||||
}
|
||||
|
||||
int daysOfBalance = this.numberOfDays;
|
||||
LocalDate balanceEndDate = balanceStartDate.plusDays(this.numberOfDays);
|
||||
LocalDate balanceEndDate = balanceStartDate.plusDays(daysOfBalance - 1);
|
||||
if (balanceEndDate.isAfter(compoundingPeriodInterval.endDate())) {
|
||||
balanceEndDate = compoundingPeriodInterval.endDate();
|
||||
final LocalDateInterval balancePeriodInterval = LocalDateInterval.create(balanceStartDate, balanceEndDate);
|
||||
@@ -113,7 +119,7 @@ public class EndOfDayBalance {
|
||||
|
||||
public boolean contains(final LocalDateInterval compoundingPeriodInterval) {
|
||||
|
||||
final LocalDate balanceUpToDate = this.date.plusDays(this.numberOfDays);
|
||||
final LocalDate balanceUpToDate = this.date.plusDays(this.numberOfDays - 1);
|
||||
|
||||
final LocalDateInterval balanceInterval = LocalDateInterval.create(this.date, balanceUpToDate);
|
||||
return balanceInterval.containsPortionOf(compoundingPeriodInterval);
|
||||
|
||||
+113
-41
@@ -4,6 +4,7 @@ import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.domain.LocalDateInterval;
|
||||
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
|
||||
@@ -185,14 +186,83 @@ public class PostingPeriod {
|
||||
// break;
|
||||
// case BIWEEKLY:
|
||||
// break;
|
||||
// case QUATERLY:
|
||||
// break;
|
||||
// case BI_ANNUAL:
|
||||
// break;
|
||||
// case ANNUAL:
|
||||
// break;
|
||||
// case NO_COMPOUNDING_SIMPLE_INTEREST:
|
||||
// break;
|
||||
case QUATERLY:
|
||||
final LocalDate qPostingPeriodEndDate = postingPeriodInterval.endDate();
|
||||
|
||||
periodStartDate = postingPeriodInterval.startDate();
|
||||
periodEndDate = periodStartDate;
|
||||
|
||||
while (!periodStartDate.isAfter(qPostingPeriodEndDate) && !periodEndDate.isAfter(qPostingPeriodEndDate)) {
|
||||
|
||||
periodEndDate = determineInterestPeriodEndDateFrom(periodStartDate, interestPeriodType, upToInterestCalculationDate);
|
||||
if (periodEndDate.isAfter(qPostingPeriodEndDate)) {
|
||||
periodEndDate = qPostingPeriodEndDate;
|
||||
}
|
||||
|
||||
final LocalDateInterval compoundingPeriodInterval = LocalDateInterval.create(periodStartDate, periodEndDate);
|
||||
if (postingPeriodInterval.contains(compoundingPeriodInterval)) {
|
||||
|
||||
compoundingPeriod = QuarterlyCompoundingPeriod.create(compoundingPeriodInterval, allEndOfDayBalances,
|
||||
upToInterestCalculationDate);
|
||||
compoundingPeriods.add(compoundingPeriod);
|
||||
}
|
||||
|
||||
// move periodStartDate forward to day after this period
|
||||
periodStartDate = periodEndDate.plusDays(1);
|
||||
}
|
||||
break;
|
||||
case BI_ANNUAL:
|
||||
final LocalDate bPostingPeriodEndDate = postingPeriodInterval.endDate();
|
||||
|
||||
periodStartDate = postingPeriodInterval.startDate();
|
||||
periodEndDate = periodStartDate;
|
||||
|
||||
while (!periodStartDate.isAfter(bPostingPeriodEndDate) && !periodEndDate.isAfter(bPostingPeriodEndDate)) {
|
||||
|
||||
periodEndDate = determineInterestPeriodEndDateFrom(periodStartDate, interestPeriodType, upToInterestCalculationDate);
|
||||
if (periodEndDate.isAfter(bPostingPeriodEndDate)) {
|
||||
periodEndDate = bPostingPeriodEndDate;
|
||||
}
|
||||
|
||||
final LocalDateInterval compoundingPeriodInterval = LocalDateInterval.create(periodStartDate, periodEndDate);
|
||||
if (postingPeriodInterval.contains(compoundingPeriodInterval)) {
|
||||
|
||||
compoundingPeriod = BiAnnualCompoundingPeriod.create(compoundingPeriodInterval, allEndOfDayBalances,
|
||||
upToInterestCalculationDate);
|
||||
compoundingPeriods.add(compoundingPeriod);
|
||||
}
|
||||
|
||||
// move periodStartDate forward to day after this period
|
||||
periodStartDate = periodEndDate.plusDays(1);
|
||||
}
|
||||
break;
|
||||
case ANNUAL:
|
||||
final LocalDate aPostingPeriodEndDate = postingPeriodInterval.endDate();
|
||||
|
||||
periodStartDate = postingPeriodInterval.startDate();
|
||||
periodEndDate = periodStartDate;
|
||||
|
||||
while (!periodStartDate.isAfter(aPostingPeriodEndDate) && !periodEndDate.isAfter(aPostingPeriodEndDate)) {
|
||||
|
||||
periodEndDate = determineInterestPeriodEndDateFrom(periodStartDate, interestPeriodType, upToInterestCalculationDate);
|
||||
if (periodEndDate.isAfter(aPostingPeriodEndDate)) {
|
||||
periodEndDate = aPostingPeriodEndDate;
|
||||
}
|
||||
|
||||
final LocalDateInterval compoundingPeriodInterval = LocalDateInterval.create(periodStartDate, periodEndDate);
|
||||
if (postingPeriodInterval.contains(compoundingPeriodInterval)) {
|
||||
|
||||
compoundingPeriod = AnnualCompoundingPeriod.create(compoundingPeriodInterval, allEndOfDayBalances,
|
||||
upToInterestCalculationDate);
|
||||
compoundingPeriods.add(compoundingPeriod);
|
||||
}
|
||||
|
||||
// move periodStartDate forward to day after this period
|
||||
periodStartDate = periodEndDate.plusDays(1);
|
||||
}
|
||||
break;
|
||||
// case NO_COMPOUNDING_SIMPLE_INTEREST:
|
||||
// break;
|
||||
}
|
||||
|
||||
return compoundingPeriods;
|
||||
@@ -221,39 +291,41 @@ public class PostingPeriod {
|
||||
// produce period end date on last day of current month
|
||||
periodEndDate = periodStartDate.dayOfMonth().withMaximumValue();
|
||||
break;
|
||||
// case QUATERLY:
|
||||
// // jan 1st to mar 31st, 1st apr to jun 30, jul 1st to sept 30,
|
||||
// // oct 1st to dec 31
|
||||
// int year = periodStartDate.getYearOfEra();
|
||||
// int monthofYear = periodStartDate.getMonthOfYear();
|
||||
// if (monthofYear <= 3) {
|
||||
// periodEndDate = new DateTime().withDate(year, 3, 31).toLocalDate();
|
||||
// } else if (monthofYear <= 6) {
|
||||
// periodEndDate = new DateTime().withDate(year, 6, 30).toLocalDate();
|
||||
// } else if (monthofYear <= 9) {
|
||||
// periodEndDate = new DateTime().withDate(year, 9, 30).toLocalDate();
|
||||
// } else if (monthofYear <= 12) {
|
||||
// periodEndDate = new DateTime().withDate(year, 12, 31).toLocalDate();
|
||||
// }
|
||||
// break;
|
||||
// case BI_ANNUAL:
|
||||
// // jan 1st to 30, jul 1st to dec 31
|
||||
// year = periodStartDate.getYearOfEra();
|
||||
// monthofYear = periodStartDate.getMonthOfYear();
|
||||
// if (monthofYear <= 6) {
|
||||
// periodEndDate = new DateTime().withDate(year, 6, 30).toLocalDate();
|
||||
// } else if (monthofYear <= 12) {
|
||||
// periodEndDate = new DateTime().withDate(year, 12, 31).toLocalDate();
|
||||
// }
|
||||
// break;
|
||||
// case ANNUAL:
|
||||
// periodEndDate = periodStartDate.monthOfYear().withMaximumValue();
|
||||
// periodEndDate = periodEndDate.dayOfMonth().withMaximumValue();
|
||||
// break;
|
||||
// case NO_COMPOUNDING_SIMPLE_INTEREST:
|
||||
// periodEndDate = periodStartDate.monthOfYear().withMaximumValue();
|
||||
// periodEndDate = periodEndDate.dayOfMonth().withMaximumValue();
|
||||
// break;
|
||||
case QUATERLY:
|
||||
// // jan 1st to mar 31st, 1st apr to jun 30, jul 1st to sept
|
||||
// 30,
|
||||
// // oct 1st to dec 31
|
||||
int year = periodStartDate.getYearOfEra();
|
||||
int monthofYear = periodStartDate.getMonthOfYear();
|
||||
if (monthofYear <= 3) {
|
||||
periodEndDate = new DateTime().withDate(year, 3, 31).toLocalDate();
|
||||
} else if (monthofYear <= 6) {
|
||||
periodEndDate = new DateTime().withDate(year, 6, 30).toLocalDate();
|
||||
} else if (monthofYear <= 9) {
|
||||
periodEndDate = new DateTime().withDate(year, 9, 30).toLocalDate();
|
||||
} else if (monthofYear <= 12) {
|
||||
periodEndDate = new DateTime().withDate(year, 12, 31).toLocalDate();
|
||||
}
|
||||
break;
|
||||
case BI_ANNUAL:
|
||||
// // jan 1st to 30, jul 1st to dec 31
|
||||
year = periodStartDate.getYearOfEra();
|
||||
monthofYear = periodStartDate.getMonthOfYear();
|
||||
if (monthofYear <= 6) {
|
||||
periodEndDate = new DateTime().withDate(year, 6, 30).toLocalDate();
|
||||
} else if (monthofYear <= 12) {
|
||||
periodEndDate = new DateTime().withDate(year, 12, 31).toLocalDate();
|
||||
}
|
||||
break;
|
||||
case ANNUAL:
|
||||
periodEndDate = periodStartDate.monthOfYear().withMaximumValue();
|
||||
periodEndDate = periodEndDate.dayOfMonth().withMaximumValue();
|
||||
break;
|
||||
|
||||
// case NO_COMPOUNDING_SIMPLE_INTEREST:
|
||||
// periodEndDate = periodStartDate.monthOfYear().withMaximumValue();
|
||||
// periodEndDate = periodEndDate.dayOfMonth().withMaximumValue();
|
||||
// break;
|
||||
}
|
||||
|
||||
return periodEndDate;
|
||||
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
package org.mifosplatform.portfolio.savings.domain.interest;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.domain.LocalDateInterval;
|
||||
import org.mifosplatform.portfolio.savings.SavingsCompoundingInterestPeriodType;
|
||||
import org.mifosplatform.portfolio.savings.SavingsInterestCalculationType;
|
||||
|
||||
public class QuarterlyCompoundingPeriod implements CompoundingPeriod {
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final LocalDateInterval periodInterval;
|
||||
private final List<EndOfDayBalance> endOfDayBalances;
|
||||
|
||||
public static QuarterlyCompoundingPeriod create(final LocalDateInterval periodInterval, final List<EndOfDayBalance> allEndOfDayBalances, final LocalDate upToInterestCalculationDate) {
|
||||
|
||||
final List<EndOfDayBalance> endOfDayBalancesWithinPeriod = endOfDayBalancesWithinPeriodInterval(periodInterval, allEndOfDayBalances, upToInterestCalculationDate);
|
||||
|
||||
return new QuarterlyCompoundingPeriod(periodInterval, endOfDayBalancesWithinPeriod);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal calculateInterest(final BigDecimal interestRateAsFraction, final long daysInYear) {
|
||||
|
||||
BigDecimal interestEarned = BigDecimal.ZERO;
|
||||
|
||||
for (final EndOfDayBalance balance : this.endOfDayBalances) {
|
||||
final BigDecimal interestOnBalanceUnrounded = balance.calculateInterestOnBalance(BigDecimal.ZERO, interestRateAsFraction,
|
||||
daysInYear);
|
||||
interestEarned = interestEarned.add(interestOnBalanceUnrounded);
|
||||
}
|
||||
|
||||
return interestEarned;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal calculateInterest(final SavingsCompoundingInterestPeriodType compoundingInterestPeriodType,
|
||||
final SavingsInterestCalculationType interestCalculationType, final BigDecimal interestToCompound,
|
||||
final BigDecimal interestRateAsFraction, final long daysInYear) {
|
||||
|
||||
BigDecimal interestEarned = BigDecimal.ZERO;
|
||||
|
||||
switch (interestCalculationType) {
|
||||
case DAILY_BALANCE:
|
||||
interestEarned = calculateUsingDailyBalanceMethod(compoundingInterestPeriodType, interestToCompound,
|
||||
interestRateAsFraction, daysInYear);
|
||||
break;
|
||||
case AVERAGE_DAILY_BALANCE:
|
||||
interestEarned = calculateUsingAverageDailyBalanceMethod(interestToCompound, interestRateAsFraction, daysInYear);
|
||||
break;
|
||||
case INVALID:
|
||||
break;
|
||||
}
|
||||
|
||||
return interestEarned;
|
||||
}
|
||||
|
||||
private BigDecimal calculateUsingAverageDailyBalanceMethod(final BigDecimal interestToCompound,
|
||||
final BigDecimal interestRateAsFraction, final long daysInYear) {
|
||||
|
||||
BigDecimal cumulativeBalance = BigDecimal.ZERO;
|
||||
Integer numberOfDays = Integer.valueOf(0);
|
||||
|
||||
for (final EndOfDayBalance balance : this.endOfDayBalances) {
|
||||
final BigDecimal endOfDayCumulativeBalance = balance.cumulativeBalance(interestToCompound);
|
||||
cumulativeBalance = cumulativeBalance.add(endOfDayCumulativeBalance);
|
||||
|
||||
final Integer balanceExistsForNumberOfDays = balance.getNumberOfDays();
|
||||
numberOfDays = numberOfDays + balanceExistsForNumberOfDays;
|
||||
}
|
||||
|
||||
BigDecimal interestEarned = BigDecimal.ZERO;
|
||||
if (cumulativeBalance.compareTo(BigDecimal.ZERO) != 0 && numberOfDays > 0) {
|
||||
final BigDecimal averageDailyBalance = cumulativeBalance.divide(BigDecimal.valueOf(numberOfDays), MathContext.DECIMAL64)
|
||||
.setScale(9, RoundingMode.HALF_EVEN);
|
||||
|
||||
final BigDecimal multiplicand = BigDecimal.ONE.divide(BigDecimal.valueOf(daysInYear), MathContext.DECIMAL64);
|
||||
final BigDecimal dailyInterestRate = interestRateAsFraction.multiply(multiplicand, MathContext.DECIMAL64);
|
||||
final BigDecimal periodicInterestRate = dailyInterestRate.multiply(BigDecimal.valueOf(numberOfDays), MathContext.DECIMAL64);
|
||||
|
||||
interestEarned = averageDailyBalance.multiply(periodicInterestRate, MathContext.DECIMAL64).setScale(9, RoundingMode.HALF_EVEN);
|
||||
}
|
||||
|
||||
return interestEarned;
|
||||
}
|
||||
|
||||
private BigDecimal calculateUsingDailyBalanceMethod(final SavingsCompoundingInterestPeriodType compoundingInterestPeriodType,
|
||||
final BigDecimal interestToCompound, final BigDecimal interestRateAsFraction, final long daysInYear) {
|
||||
|
||||
BigDecimal interestEarned = BigDecimal.ZERO;
|
||||
BigDecimal interestOnBalanceUnrounded = BigDecimal.ZERO;
|
||||
for (final EndOfDayBalance balance : this.endOfDayBalances) {
|
||||
|
||||
switch (compoundingInterestPeriodType) {
|
||||
case DAILY:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalanceAndInterest(interestToCompound, interestRateAsFraction,
|
||||
daysInYear);
|
||||
break;
|
||||
case MONTHLY:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalance(interestToCompound, interestRateAsFraction, daysInYear);
|
||||
break;
|
||||
case QUATERLY:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalance(interestToCompound, interestRateAsFraction, daysInYear);
|
||||
break;
|
||||
// case WEEKLY:
|
||||
// break;
|
||||
// case BIWEEKLY:
|
||||
// break;
|
||||
case BI_ANNUAL:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalance(interestToCompound, interestRateAsFraction, daysInYear);
|
||||
break;
|
||||
case ANNUAL:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalance(interestToCompound, interestRateAsFraction, daysInYear);
|
||||
break;
|
||||
// case NO_COMPOUNDING_SIMPLE_INTEREST:
|
||||
// break;
|
||||
case INVALID:
|
||||
break;
|
||||
}
|
||||
|
||||
interestEarned = interestEarned.add(interestOnBalanceUnrounded);
|
||||
}
|
||||
return interestEarned;
|
||||
}
|
||||
|
||||
private static List<EndOfDayBalance> endOfDayBalancesWithinPeriodInterval(final LocalDateInterval compoundingPeriodInterval,
|
||||
final List<EndOfDayBalance> allEndOfDayBalances, final LocalDate upToInterestCalculationDate) {
|
||||
|
||||
final List<EndOfDayBalance> endOfDayBalancesForPeriodInterval = new ArrayList<EndOfDayBalance>();
|
||||
|
||||
for (final EndOfDayBalance endOfDayBalance : allEndOfDayBalances) {
|
||||
|
||||
if (compoundingPeriodInterval.contains(endOfDayBalance.date())) {
|
||||
final EndOfDayBalance cappedToPeriodEndDate = endOfDayBalance.upTo(compoundingPeriodInterval, upToInterestCalculationDate);
|
||||
endOfDayBalancesForPeriodInterval.add(cappedToPeriodEndDate);
|
||||
} else if (endOfDayBalance.contains(compoundingPeriodInterval)) {
|
||||
final EndOfDayBalance cappedToPeriodEndDate = endOfDayBalance.upTo(compoundingPeriodInterval, upToInterestCalculationDate);
|
||||
endOfDayBalancesForPeriodInterval.add(cappedToPeriodEndDate);
|
||||
}
|
||||
}
|
||||
|
||||
return endOfDayBalancesForPeriodInterval;
|
||||
}
|
||||
|
||||
private QuarterlyCompoundingPeriod(final LocalDateInterval periodInterval, final List<EndOfDayBalance> endOfDayBalances) {
|
||||
this.periodInterval = periodInterval;
|
||||
this.endOfDayBalances = endOfDayBalances;
|
||||
}
|
||||
}
|
||||
+5
-2
@@ -783,6 +783,7 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
|
||||
sqlBuilder.append("datp.in_multiples_of_deposit_term_type_enum as inMultiplesOfDepositTermTypeId, ");
|
||||
sqlBuilder.append("datp.deposit_amount as depositAmount, ");
|
||||
sqlBuilder.append("datp.maturity_amount as maturityAmount, ");
|
||||
sqlBuilder.append("datp.expected_firstdepositon_date as expectedFirstDepositOnDate, ");
|
||||
sqlBuilder.append("datp.maturity_date as maturityDate, ");
|
||||
sqlBuilder.append("datp.deposit_period as depositPeriod, ");
|
||||
sqlBuilder.append("datp.deposit_period_frequency_enum as depositPeriodFrequencyTypeId, ");
|
||||
@@ -847,12 +848,13 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
|
||||
final Integer onAccountClosureId = JdbcSupport.getInteger(rs, "onAccountClosureId");
|
||||
final EnumOptionData onAccountClosureType = (onAccountClosureId == null) ? null : SavingsEnumerations
|
||||
.depositAccountOnClosureType(onAccountClosureId);
|
||||
final LocalDate expectedFirstDepositOnDate = JdbcSupport.getLocalDate(rs, "expectedFirstDepositOnDate");
|
||||
return RecurringDepositAccountData.instance(depositAccountData, interestFreePeriodApplicable, interestFreeFromPeriod,
|
||||
interestFreeToPeriod, interestFreePeriodFrequencyType, preClosurePenalApplicable, preClosurePenalInterest,
|
||||
preClosurePenalInterestOnType, minDepositTerm, maxDepositTerm, minDepositTermType, maxDepositTermType,
|
||||
inMultiplesOfDepositTerm, inMultiplesOfDepositTermType, depositAmount, maturityAmount, maturityDate, depositPeriod,
|
||||
depositPeriodFrequencyType, recurringDepositAmount, recurringDepositType, recurringDepositFrequency,
|
||||
recurringDepositFrequencyType, onAccountClosureType);
|
||||
recurringDepositFrequencyType, onAccountClosureType, expectedFirstDepositOnDate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1266,13 +1268,14 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
|
||||
final Integer depositPeriod = null;
|
||||
final EnumOptionData depositPeriodFrequencyType = null;
|
||||
final BigDecimal recurringDepositAmount = null;
|
||||
final LocalDate expectedFirstDepositOnDate = null;
|
||||
final EnumOptionData onAccountClosureType = null;
|
||||
return RecurringDepositAccountData.instance(depositAccountData, interestFreePeriodApplicable, interestFreeFromPeriod,
|
||||
interestFreeToPeriod, interestFreePeriodFrequencyType, preClosurePenalApplicable, preClosurePenalInterest,
|
||||
preClosurePenalInterestOnType, minDepositTerm, maxDepositTerm, minDepositTermType, maxDepositTermType,
|
||||
inMultiplesOfDepositTerm, inMultiplesOfDepositTermType, depositAmount, maturityAmount, maturityDate, depositPeriod,
|
||||
depositPeriodFrequencyType, recurringDepositAmount, recurringDepositType, recurringDepositFrequency,
|
||||
recurringDepositFrequencyType, onAccountClosureType);
|
||||
recurringDepositFrequencyType, onAccountClosureType, expectedFirstDepositOnDate);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -151,7 +151,7 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
((FixedDepositAccount) account).updateMaturityDateAndAmountBeforeAccountActivation(mc);
|
||||
this.fixedDepositAccountRepository.saveAndFlush((FixedDepositAccount) account);
|
||||
} else if (depositAccountType.isRecurringDeposit()) {
|
||||
final LocalDate transactionStartDate = account.accountSubmittedOrActivationDate();
|
||||
final LocalDate transactionStartDate = ((RecurringDepositAccount) account).depositStartDate();
|
||||
((RecurringDepositAccount) account).updateMaturityDateAndAmount(mc, transactionStartDate);
|
||||
this.recurringDepositAccountRepository.save((RecurringDepositAccount) account);
|
||||
}
|
||||
@@ -254,7 +254,7 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl
|
||||
if (depositAccountType.isFixedDeposit()) {
|
||||
((FixedDepositAccount) account).updateMaturityDateAndAmountBeforeAccountActivation(mc);
|
||||
} else if (depositAccountType.isRecurringDeposit()) {
|
||||
final LocalDate transactionStartDate = account.accountSubmittedOrActivationDate();
|
||||
final LocalDate transactionStartDate = ((RecurringDepositAccount) account).depositStartDate();
|
||||
((RecurringDepositAccount) account).updateMaturityDateAndAmount(mc, transactionStartDate);
|
||||
}
|
||||
|
||||
|
||||
+8
-1
@@ -275,6 +275,9 @@ public class DepositProductReadPlatformServiceImpl implements DepositProductRead
|
||||
sqlBuilder.append("dprd.recurring_deposit_type_enum as recurringDepositTypeId, ");
|
||||
sqlBuilder.append("dprd.recurring_deposit_frequency as recurringDepositFrequency, ");
|
||||
sqlBuilder.append("dprd.recurring_deposit_frequency_type_enum as recurringDepositFrequencyTypeId, ");
|
||||
sqlBuilder.append("dptp.min_deposit_amount as minDepositAmount, ");
|
||||
sqlBuilder.append("dptp.deposit_amount as depositAmount, ");
|
||||
sqlBuilder.append("dptp.max_deposit_amount as maxDepositAmount, ");
|
||||
sqlBuilder.append("dptp.min_deposit_term as minDepositTerm, ");
|
||||
sqlBuilder.append("dptp.max_deposit_term as maxDepositTerm, ");
|
||||
sqlBuilder.append("dptp.min_deposit_term_type_enum as minDepositTermTypeId, ");
|
||||
@@ -315,6 +318,9 @@ public class DepositProductReadPlatformServiceImpl implements DepositProductRead
|
||||
.recurringDepositType(recurringDepositTypeId);
|
||||
final Integer recurringDepositFrequency = JdbcSupport.getInteger(rs, "recurringDepositFrequency");
|
||||
final Integer recurringDepositFrequencyTypeId = JdbcSupport.getInteger(rs, "recurringDepositFrequencyTypeId");
|
||||
final BigDecimal minDepositAmount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "minDepositAmount");
|
||||
final BigDecimal depositAmount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "depositAmount");
|
||||
final BigDecimal maxDepositAmount = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "maxDepositAmount");
|
||||
final EnumOptionData recurringDepositFrequencyType = (recurringDepositFrequencyTypeId == null) ? null : SavingsEnumerations
|
||||
.recurringDepositFrequencyType(recurringDepositFrequencyTypeId);
|
||||
|
||||
@@ -334,7 +340,8 @@ public class DepositProductReadPlatformServiceImpl implements DepositProductRead
|
||||
return RecurringDepositProductData.instance(depositProductData, interestFreePeriodApplicable, interestFreeFromPeriod,
|
||||
interestFreeToPeriod, interestFreePeriodFrequencyType, preClosurePenalApplicable, preClosurePenalInterest,
|
||||
preClosurePenalInterestOnType, minDepositTerm, maxDepositTerm, minDepositTermType, maxDepositTermType, inMultiplesOfDepositTerm,
|
||||
inMultiplesOfDepositTermType, recurringDepositType, recurringDepositFrequency, recurringDepositFrequencyType);
|
||||
inMultiplesOfDepositTermType, recurringDepositType, recurringDepositFrequency, recurringDepositFrequencyType,
|
||||
minDepositAmount, depositAmount, maxDepositAmount);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-6
@@ -51,12 +51,10 @@ public class SavingsDropdownReadPlatformServiceImpl implements SavingsDropdownRe
|
||||
// //
|
||||
// SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.BIWEEKLY),
|
||||
// //
|
||||
SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.MONTHLY)
|
||||
// SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.QUATERLY),
|
||||
// //
|
||||
// SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.BI_ANNUAL),
|
||||
// //
|
||||
// SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.ANNUAL),
|
||||
SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.MONTHLY),
|
||||
SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.QUATERLY),
|
||||
SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.BI_ANNUAL),
|
||||
SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.ANNUAL)
|
||||
// //
|
||||
// SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.NO_COMPOUNDING_SIMPLE_INTEREST)
|
||||
// //
|
||||
@@ -70,6 +68,7 @@ public class SavingsDropdownReadPlatformServiceImpl implements SavingsDropdownRe
|
||||
final List<EnumOptionData> allowedOptions = Arrays.asList( //
|
||||
SavingsEnumerations.interestPostingPeriodType(SavingsPostingInterestPeriodType.MONTHLY), //
|
||||
SavingsEnumerations.interestPostingPeriodType(SavingsPostingInterestPeriodType.QUATERLY), //
|
||||
SavingsEnumerations.interestPostingPeriodType(SavingsPostingInterestPeriodType.BIANNUAL), //
|
||||
SavingsEnumerations.interestPostingPeriodType(SavingsPostingInterestPeriodType.ANNUAL) //
|
||||
);
|
||||
|
||||
|
||||
+16
-20
@@ -232,6 +232,10 @@ public class SavingsEnumerations {
|
||||
optionData = new EnumOptionData(SavingsPostingInterestPeriodType.QUATERLY.getValue().longValue(), codePrefix
|
||||
+ SavingsPostingInterestPeriodType.QUATERLY.getCode(), "Quarterly");
|
||||
break;
|
||||
case BIANNUAL:
|
||||
optionData = new EnumOptionData(SavingsPostingInterestPeriodType.BIANNUAL.getValue().longValue(), codePrefix
|
||||
+ SavingsPostingInterestPeriodType.BIANNUAL.getCode(), "BiAnnual");
|
||||
break;
|
||||
case ANNUAL:
|
||||
optionData = new EnumOptionData(SavingsPostingInterestPeriodType.ANNUAL.getValue().longValue(), codePrefix
|
||||
+ SavingsPostingInterestPeriodType.ANNUAL.getCode(), "Annually");
|
||||
@@ -276,26 +280,18 @@ public class SavingsEnumerations {
|
||||
optionData = new EnumOptionData(SavingsCompoundingInterestPeriodType.MONTHLY.getValue().longValue(), codePrefix
|
||||
+ SavingsCompoundingInterestPeriodType.MONTHLY.getCode(), "Monthly");
|
||||
break;
|
||||
// case QUATERLY:
|
||||
// optionData = new
|
||||
// EnumOptionData(SavingsCompoundingInterestPeriodType.QUATERLY.getValue().longValue(),
|
||||
// codePrefix
|
||||
// + SavingsCompoundingInterestPeriodType.QUATERLY.getCode(),
|
||||
// "Quarterly");
|
||||
// break;
|
||||
// case BI_ANNUAL:
|
||||
// optionData = new
|
||||
// EnumOptionData(SavingsCompoundingInterestPeriodType.BI_ANNUAL.getValue().longValue(),
|
||||
// codePrefix
|
||||
// + SavingsCompoundingInterestPeriodType.BI_ANNUAL.getCode(),
|
||||
// "Semi-Annual");
|
||||
// break;
|
||||
// case ANNUAL:
|
||||
// optionData = new
|
||||
// EnumOptionData(SavingsCompoundingInterestPeriodType.ANNUAL.getValue().longValue(),
|
||||
// codePrefix
|
||||
// + SavingsCompoundingInterestPeriodType.ANNUAL.getCode(), "Annually");
|
||||
// break;
|
||||
case QUATERLY:
|
||||
optionData = new EnumOptionData(SavingsCompoundingInterestPeriodType.QUATERLY.getValue().longValue(), codePrefix
|
||||
+ SavingsCompoundingInterestPeriodType.QUATERLY.getCode(), "Quarterly");
|
||||
break;
|
||||
case BI_ANNUAL:
|
||||
optionData = new EnumOptionData(SavingsCompoundingInterestPeriodType.BI_ANNUAL.getValue().longValue(), codePrefix
|
||||
+ SavingsCompoundingInterestPeriodType.BI_ANNUAL.getCode(), "Semi-Annual");
|
||||
break;
|
||||
case ANNUAL:
|
||||
optionData = new EnumOptionData(SavingsCompoundingInterestPeriodType.ANNUAL.getValue().longValue(), codePrefix
|
||||
+ SavingsCompoundingInterestPeriodType.ANNUAL.getCode(), "Annually");
|
||||
break;
|
||||
// case NO_COMPOUNDING_SIMPLE_INTEREST:
|
||||
// optionData = new
|
||||
// EnumOptionData(SavingsCompoundingInterestPeriodType.NO_COMPOUNDING_SIMPLE_INTEREST.getValue().longValue(),
|
||||
|
||||
Reference in New Issue
Block a user