MIFOSX-246: support for withdrawal fees on savings accounts.

This commit is contained in:
Keith Woodlock
2013-04-26 10:13:39 +01:00
parent 51d63b6db7
commit 44cef96643
28 changed files with 497 additions and 112 deletions
@@ -0,0 +1,12 @@
ALTER TABLE `m_savings_product`
ADD COLUMN `withdrawal_fee_amount` DECIMAL(19,6) NULL DEFAULT NULL AFTER `lockin_period_frequency_enum`,
ADD COLUMN `withdrawal_fee_type_enum` SMALLINT(5) NULL DEFAULT NULL AFTER `withdrawal_fee_amount`;
ALTER TABLE `m_savings_account`
ADD COLUMN `withdrawal_fee_amount` DECIMAL(19,6) NULL DEFAULT NULL AFTER `lockin_period_frequency_enum`,
ADD COLUMN `withdrawal_fee_type_enum` SMALLINT(5) NULL DEFAULT NULL AFTER `withdrawal_fee_amount`;
ALTER TABLE `m_savings_account`
ADD COLUMN `total_withdrawal_fees_derived` DECIMAL(19,6) NULL DEFAULT NULL AFTER `total_withdrawals_derived`;
@@ -0,0 +1,18 @@
/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.infrastructure.core.exception;
/**
* A {@link RuntimeException} thrown when valid api request end up violating
* some domain rule.
*/
public final class GeneralPlatformDomainRuleException extends AbstractPlatformDomainRuleException {
public GeneralPlatformDomainRuleException(final String globalisationMessageCode, final String defaultUserMessage,
final Object... defaultUserMessageArgs) {
super(globalisationMessageCode, defaultUserMessage, defaultUserMessageArgs);
}
}
@@ -16,7 +16,7 @@ public enum ChargeCalculationType {
private final Integer value;
private final String code;
private ChargeCalculationType(Integer value, String code) {
private ChargeCalculationType(final Integer value, final String code) {
this.value = value;
this.code = code;
}
@@ -44,9 +44,6 @@ public enum ChargeCalculationType {
case 4:
chargeCalculationType = PERCENT_OF_INTEREST;
break;
default:
chargeCalculationType = INVALID;
break;
}
return chargeCalculationType;
}
@@ -145,6 +145,7 @@ public class SavingsAccountsApiResource {
Collection<EnumOptionData> interestCalculationTypeOptions = null;
Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = null;
Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
Collection<EnumOptionData> withdrawalFeeTypeOptions = null;
final Set<String> associationParameters = ApiParameterHelper.extractAssociationsForResponseIfProvided(uriInfo.getQueryParameters());
if (!associationParameters.isEmpty()) {
@@ -170,11 +171,12 @@ public class SavingsAccountsApiResource {
interestCompoundingPostingTypeOptions = this.dropdownReadPlatformService.retrieveInterestPostingPeriodTypeOptions();
interestCalculationTypeOptions = this.dropdownReadPlatformService.retrieveInterestCalculationTypeOptions();
lockinPeriodFrequencyTypeOptions = this.dropdownReadPlatformService.retrieveLockinPeriodFrequencyTypeOptions();
withdrawalFeeTypeOptions = this.dropdownReadPlatformService.retrievewithdrawalFeeTypeOptions();
}
return SavingsAccountData.withTemplateOptions(savingsAccount, productOptions, interestCompoundingPeriodTypeOptions,
interestCompoundingPostingTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
lockinPeriodFrequencyTypeOptions, transactions);
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, transactions);
}
@PUT
@@ -39,6 +39,8 @@ public class SavingsApiConstants {
public static final String minRequiredOpeningBalanceParamName = "minRequiredOpeningBalance";
public static final String lockinPeriodFrequencyParamName = "lockinPeriodFrequency";
public static final String lockinPeriodFrequencyTypeParamName = "lockinPeriodFrequencyType";
public static final String withdrawalFeeAmountParamName = "withdrawalFeeAmount";
public static final String withdrawalFeeTypeParamName = "withdrawalFeeType";
// transaction parameters
public static final String transactionDateParamName = "transactionDate";
@@ -48,7 +50,7 @@ public class SavingsApiConstants {
nameParamName, descriptionParamName, currencyCodeParamName, digitsAfterDecimalParamName, nominalAnnualInterestRateParamName,
interestCompoundingPeriodTypeParamName, interestPostingPeriodTypeParamName, interestCalculationTypeParamName,
interestCalculationDaysInYearTypeParamName, minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName,
lockinPeriodFrequencyTypeParamName));
lockinPeriodFrequencyTypeParamName, withdrawalFeeAmountParamName, withdrawalFeeTypeParamName));
/**
* These parameters will match the class level parameters of
@@ -59,15 +61,16 @@ public class SavingsApiConstants {
nameParamName, descriptionParamName, "currency", digitsAfterDecimalParamName, nominalAnnualInterestRateParamName,
interestCompoundingPeriodTypeParamName, interestPostingPeriodTypeParamName, interestCalculationTypeParamName,
interestCalculationDaysInYearTypeParamName, minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName,
lockinPeriodFrequencyTypeParamName, "currencyOptions", "interestCompoundingPeriodTypeOptions",
"interestPostingPeriodTypeOptions", "interestCalculationTypeOptions", "interestCalculationDaysInYearTypeOptions",
"lockinPeriodFrequencyTypeOptions"));
lockinPeriodFrequencyTypeParamName, withdrawalFeeAmountParamName, withdrawalFeeTypeParamName, "currencyOptions",
"interestCompoundingPeriodTypeOptions", "interestPostingPeriodTypeOptions", "interestCalculationTypeOptions",
"interestCalculationDaysInYearTypeOptions", "lockinPeriodFrequencyTypeOptions", "withdrawalFeeTypeOptions"));
public static final Set<String> SAVINGS_ACCOUNT_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
dateFormatParamName, accountNoParamName, externalIdParamName, clientIdParamName, groupIdParamName, productIdParamName,
activeParamName, activationDateParamName, nominalAnnualInterestRateParamName, interestCompoundingPeriodTypeParamName,
interestPostingPeriodTypeParamName, interestCalculationTypeParamName, interestCalculationDaysInYearTypeParamName,
minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName));
minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName,
withdrawalFeeAmountParamName, withdrawalFeeTypeParamName));
/**
* These parameters will match the class level parameters of
@@ -78,9 +81,10 @@ public class SavingsApiConstants {
accountNoParamName, externalIdParamName, statusParamName, activationDateParamName, clientIdParamName, "clientName",
groupIdParamName, "groupName", "savingsProductId", "savingsProductName", "currency", nominalAnnualInterestRateParamName,
interestCompoundingPeriodTypeParamName, interestCalculationTypeParamName, interestCalculationDaysInYearTypeParamName,
minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName, "summary",
"transactions", "productOptions", "interestCompoundingPeriodTypeOptions", "interestPostingPeriodTypeOptions",
"interestCalculationTypeOptions", "interestCalculationDaysInYearTypeOptions", "lockinPeriodFrequencyTypeOptions"));
minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName,
withdrawalFeeAmountParamName, withdrawalFeeTypeParamName, "summary", "transactions", "productOptions",
"interestCompoundingPeriodTypeOptions", "interestPostingPeriodTypeOptions", "interestCalculationTypeOptions",
"interestCalculationDaysInYearTypeOptions", "lockinPeriodFrequencyTypeOptions", "withdrawalFeeTypeOptions"));
public static final Set<String> SAVINGS_ACCOUNT_TRANSACTION_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(
localeParamName, dateFormatParamName, transactionDateParamName, transactionAmountParamName));
@@ -180,16 +180,18 @@ public class SavingsProductsApiResource {
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = this.dropdownReadPlatformService
.retrieveLockinPeriodFrequencyTypeOptions();
final Collection<EnumOptionData> withdrawalFeeTypeOptions = this.dropdownReadPlatformService.retrievewithdrawalFeeTypeOptions();
SavingsProductData savingsProductToReturn = null;
if (savingsProduct != null) {
savingsProductToReturn = SavingsProductData.withTemplate(savingsProduct, currencyOptions, interestCompoundingPeriodTypeOptions,
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
lockinPeriodFrequencyTypeOptions);
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions);
} else {
savingsProductToReturn = SavingsProductData.template(currency, interestCompoundingPeriodType, interestPostingPeriodType,
interestCalculationType, interestCalculationDaysInYearType, currencyOptions, interestCompoundingPeriodTypeOptions,
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
lockinPeriodFrequencyTypeOptions);
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions);
}
return savingsProductToReturn;
@@ -37,6 +37,8 @@ public class SavingsAccountData {
private final BigDecimal minRequiredOpeningBalance;
private final Integer lockinPeriodFrequency;
private final EnumOptionData lockinPeriodFrequencyType;
private final BigDecimal withdrawalFeeAmount;
private final EnumOptionData withdrawalFeeType;
// associations
private final SavingsAccountSummaryData summary;
@@ -56,6 +58,8 @@ public class SavingsAccountData {
private final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions;
@SuppressWarnings("unused")
private final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions;
@SuppressWarnings("unused")
private final Collection<EnumOptionData> withdrawalFeeTypeOptions;
public static SavingsAccountData instance(final Long id, final String accountNo, final String externalId,
final SavingsAccountStatusEnumData status, final LocalDate activationDate, final Long groupId, final String groupName,
@@ -63,7 +67,8 @@ public class SavingsAccountData {
final BigDecimal interestRate, final EnumOptionData interestCompoundingPeriodType,
final EnumOptionData interestPostingPeriodType, final EnumOptionData interestCalculationType,
final EnumOptionData interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType, final SavingsAccountSummaryData summary) {
final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType, final BigDecimal withdrawalFeeAmount,
final EnumOptionData withdrawalFeeType, final SavingsAccountSummaryData summary) {
final Collection<SavingsProductData> productOptions = null;
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
@@ -71,13 +76,16 @@ public class SavingsAccountData {
final Collection<EnumOptionData> interestCalculationTypeOptions = null;
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = null;
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
final Collection<EnumOptionData> withdrawalFeeTypeOptions = null;
final Collection<SavingsAccountTransactionData> transactions = null;
return new SavingsAccountData(id, accountNo, externalId, status, activationDate, groupId, groupName, clientId, clientName,
productId, productName, currency, interestRate, interestCompoundingPeriodType, interestPostingPeriodType,
interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency,
lockinPeriodFrequencyType, summary, productOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, transactions);
lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, summary, transactions, productOptions,
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions);
}
public static SavingsAccountData withTemplateOptions(final SavingsAccountData account,
@@ -85,15 +93,17 @@ public class SavingsAccountData {
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
final Collection<EnumOptionData> interestCalculationTypeOptions,
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<SavingsAccountTransactionData> transactions) {
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
final Collection<SavingsAccountTransactionData> transactions) {
return new SavingsAccountData(account.id, account.accountNo, account.externalId, account.status, account.activationDate,
account.groupId, account.groupName, account.clientId, account.clientName, account.savingsProductId,
account.savingsProductName, account.currency, account.nominalAnnualInterestRate, account.interestCompoundingPeriodType,
account.interestPostingPeriodType, account.interestCalculationType, account.interestCalculationDaysInYearType,
account.minRequiredOpeningBalance, account.lockinPeriodFrequency, account.lockinPeriodFrequencyType, account.summary,
productOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, transactions);
account.minRequiredOpeningBalance, account.lockinPeriodFrequency, account.lockinPeriodFrequencyType,
account.withdrawalFeeAmount, account.withdrawalFeeType, account.summary, transactions, productOptions,
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions);
}
public static SavingsAccountData withClientTemplate(final Long clientId, final String clientName, final Long groupId,
@@ -115,20 +125,26 @@ public class SavingsAccountData {
final BigDecimal minRequiredOpeningBalance = null;
final Integer lockinPeriodFrequency = null;
final EnumOptionData lockinPeriodFrequencyType = null;
final BigDecimal withdrawalFeeAmount = null;
final EnumOptionData withdrawalFeeType = null;
final SavingsAccountSummaryData summary = null;
final Collection<SavingsAccountTransactionData> transactions = null;
final Collection<SavingsProductData> productOptions = null;
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
final Collection<EnumOptionData> interestPostingPeriodTypeOptions = null;
final Collection<EnumOptionData> interestCalculationTypeOptions = null;
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = null;
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
final Collection<SavingsAccountTransactionData> transactions = null;
final Collection<EnumOptionData> withdrawalFeeTypeOptions = null;
return new SavingsAccountData(id, accountNo, externalId, status, activationDate, groupId, groupName, clientId, clientName,
productId, productName, currency, nominalAnnualInterestRate, interestPeriodType, interestPostingPeriodType,
interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency,
lockinPeriodFrequencyType, summary, productOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, transactions);
lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, summary, transactions, productOptions,
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions);
}
private SavingsAccountData(final Long id, final String accountNo, final String externalId, final SavingsAccountStatusEnumData status,
@@ -137,12 +153,13 @@ public class SavingsAccountData {
final EnumOptionData interestPeriodType, final EnumOptionData interestPostingPeriodType,
final EnumOptionData interestCalculationType, final EnumOptionData interestCalculationDaysInYearType,
final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency,
final EnumOptionData lockinPeriodFrequencyType, final SavingsAccountSummaryData summary,
final EnumOptionData lockinPeriodFrequencyType, final BigDecimal withdrawalFeeAmount, final EnumOptionData withdrawalFeeType,
final SavingsAccountSummaryData summary, final Collection<SavingsAccountTransactionData> transactions,
final Collection<SavingsProductData> productOptions, final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
final Collection<EnumOptionData> interestCalculationTypeOptions,
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<SavingsAccountTransactionData> transactions) {
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions) {
this.id = id;
this.accountNo = accountNo;
this.externalId = externalId;
@@ -163,7 +180,11 @@ public class SavingsAccountData {
this.minRequiredOpeningBalance = minRequiredOpeningBalance;
this.lockinPeriodFrequency = lockinPeriodFrequency;
this.lockinPeriodFrequencyType = lockinPeriodFrequencyType;
this.withdrawalFeeAmount = withdrawalFeeAmount;
this.withdrawalFeeType = withdrawalFeeType;
this.summary = summary;
this.transactions = transactions;
this.productOptions = productOptions;
this.interestCompoundingPeriodTypeOptions = interestCompoundingPeriodTypeOptions;
@@ -171,6 +192,6 @@ public class SavingsAccountData {
this.interestCalculationTypeOptions = interestCalculationTypeOptions;
this.interestCalculationDaysInYearTypeOptions = interestCalculationDaysInYearTypeOptions;
this.lockinPeriodFrequencyTypeOptions = lockinPeriodFrequencyTypeOptions;
this.transactions = transactions;
this.withdrawalFeeTypeOptions = withdrawalFeeTypeOptions;
}
}
@@ -15,6 +15,8 @@ import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockin
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.minRequiredOpeningBalanceParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.nominalAnnualInterestRateParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.productIdParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.withdrawalFeeAmountParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.withdrawalFeeTypeParamName;
import java.lang.reflect.Type;
import java.math.BigDecimal;
@@ -159,6 +161,18 @@ public class SavingsAccountDataValidator {
}
}
if (this.fromApiJsonHelper.parameterExists(withdrawalFeeAmountParamName, element)) {
final BigDecimal withdrawalFeeAmount = fromApiJsonHelper
.extractBigDecimalWithLocaleNamed(withdrawalFeeAmountParamName, element);
baseDataValidator.reset().parameter(withdrawalFeeAmountParamName).value(withdrawalFeeAmount).positiveAmount();
}
if (this.fromApiJsonHelper.parameterExists(withdrawalFeeTypeParamName, element)) {
final Integer withdrawalFeeType = fromApiJsonHelper.extractIntegerSansLocaleNamed(withdrawalFeeTypeParamName, element);
baseDataValidator.reset().parameter(withdrawalFeeTypeParamName).value(withdrawalFeeType).isOneOfTheseValues(1, 2);
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
@@ -290,6 +304,18 @@ public class SavingsAccountDataValidator {
}
}
if (this.fromApiJsonHelper.parameterExists(withdrawalFeeAmountParamName, element)) {
final BigDecimal withdrawalFeeAmount = fromApiJsonHelper
.extractBigDecimalWithLocaleNamed(withdrawalFeeAmountParamName, element);
baseDataValidator.reset().parameter(withdrawalFeeAmountParamName).value(withdrawalFeeAmount).notNull().positiveAmount();
}
if (this.fromApiJsonHelper.parameterExists(withdrawalFeeTypeParamName, element)) {
final Integer withdrawalFeeType = fromApiJsonHelper.extractIntegerSansLocaleNamed(withdrawalFeeTypeParamName, element);
baseDataValidator.reset().parameter(withdrawalFeeTypeParamName).value(withdrawalFeeType).isOneOfTheseValues(1, 2);
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
@@ -18,15 +18,18 @@ public class SavingsAccountSummaryData {
private final CurrencyData currency;
private final BigDecimal totalDeposits;
private final BigDecimal totalWithdrawals;
private final BigDecimal totalWithdrawalFees;
private final BigDecimal totalInterestEarned;
private final BigDecimal totalInterestPosted;
private final BigDecimal accountBalance;
public SavingsAccountSummaryData(final CurrencyData currency, final BigDecimal totalDeposits, final BigDecimal totalWithdrawals,
final BigDecimal totalInterestEarned, final BigDecimal totalInterestPosted, final BigDecimal accountBalance) {
final BigDecimal totalWithdrawalFees, final BigDecimal totalInterestEarned, final BigDecimal totalInterestPosted,
final BigDecimal accountBalance) {
this.currency = currency;
this.totalDeposits = totalDeposits;
this.totalWithdrawals = totalWithdrawals;
this.totalWithdrawalFees = totalWithdrawalFees;
this.totalInterestEarned = totalInterestEarned;
this.totalInterestPosted = totalInterestPosted;
this.accountBalance = accountBalance;
@@ -28,6 +28,8 @@ public class SavingsProductData {
private final BigDecimal minRequiredOpeningBalance;
private final Integer lockinPeriodFrequency;
private final EnumOptionData lockinPeriodFrequencyType;
private final BigDecimal withdrawalFeeAmount;
private final EnumOptionData withdrawalFeeType;
// template
@SuppressWarnings("unused")
@@ -42,6 +44,8 @@ public class SavingsProductData {
private final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions;
@SuppressWarnings("unused")
private final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions;
@SuppressWarnings("unused")
private final Collection<EnumOptionData> withdrawalFeeTypeOptions;
public static SavingsProductData template(final CurrencyData currency, final EnumOptionData interestCompoundingPeriodType,
final EnumOptionData interestPostingPeriodType, final EnumOptionData interestCalculationType,
@@ -50,7 +54,7 @@ public class SavingsProductData {
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
final Collection<EnumOptionData> interestCalculationTypeOptions,
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions) {
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions) {
final Long id = null;
final String name = null;
@@ -59,12 +63,14 @@ public class SavingsProductData {
final BigDecimal minRequiredOpeningBalance = null;
final Integer lockinPeriodFrequency = null;
final EnumOptionData lockinPeriodFrequencyType = null;
final BigDecimal withdrawalFeeAmount = null;
final EnumOptionData withdrawalFeeType = null;
return new SavingsProductData(id, name, description, currency, nominalAnnualInterestRate, interestCompoundingPeriodType,
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
lockinPeriodFrequency, lockinPeriodFrequencyType, currencyOptions, interestCompoundingPeriodTypeOptions,
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
lockinPeriodFrequencyTypeOptions);
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, currencyOptions,
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions);
}
/**
@@ -76,22 +82,24 @@ public class SavingsProductData {
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
final Collection<EnumOptionData> interestCalculationTypeOptions,
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions) {
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions) {
return new SavingsProductData(existingProduct.id, existingProduct.name, existingProduct.description, existingProduct.currency,
existingProduct.nominalAnnualInterestRate, existingProduct.interestCompoundingPeriodType,
existingProduct.interestPostingPeriodType, existingProduct.interestCalculationType,
existingProduct.interestCalculationDaysInYearType, existingProduct.minRequiredOpeningBalance,
existingProduct.lockinPeriodFrequency, existingProduct.lockinPeriodFrequencyType, currencyOptions,
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions);
existingProduct.lockinPeriodFrequency, existingProduct.lockinPeriodFrequencyType, existingProduct.withdrawalFeeAmount,
existingProduct.withdrawalFeeType, currencyOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
withdrawalFeeTypeOptions);
}
public static SavingsProductData instance(final Long id, final String name, final String description, final CurrencyData currency,
final BigDecimal nominalAnnualInterestRate, final EnumOptionData interestCompoundingPeriodType,
final EnumOptionData interestPostingPeriodType, final EnumOptionData interestCalculationType,
final EnumOptionData interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType) {
final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType, final BigDecimal withdrawalFeeAmount,
final EnumOptionData withdrawalFeeType) {
final Collection<CurrencyData> currencyOptions = null;
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
@@ -99,12 +107,13 @@ public class SavingsProductData {
final Collection<EnumOptionData> interestCalculationTypeOptions = null;
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = null;
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
final Collection<EnumOptionData> withdrawalFeeTypeOptions = null;
return new SavingsProductData(id, name, description, currency, nominalAnnualInterestRate, interestCompoundingPeriodType,
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
lockinPeriodFrequency, lockinPeriodFrequencyType, currencyOptions, interestCompoundingPeriodTypeOptions,
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
lockinPeriodFrequencyTypeOptions);
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, currencyOptions,
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions);
}
public static SavingsProductData lookup(final Long id, final String name) {
@@ -119,6 +128,8 @@ public class SavingsProductData {
final BigDecimal minRequiredOpeningBalance = null;
final Integer lockinPeriodFrequency = null;
final EnumOptionData lockinPeriodFrequencyType = null;
final BigDecimal withdrawalFeeAmount = null;
final EnumOptionData withdrawalFeeType = null;
final Collection<CurrencyData> currencyOptions = null;
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions = null;
@@ -126,24 +137,27 @@ public class SavingsProductData {
final Collection<EnumOptionData> interestCalculationTypeOptions = null;
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = null;
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
final Collection<EnumOptionData> withdrawalFeeTypeOptions = null;
return new SavingsProductData(id, name, description, currency, nominalAnnualInterestRate, interestCompoundingPeriodType,
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
lockinPeriodFrequency, lockinPeriodFrequencyType, currencyOptions, interestCompoundingPeriodTypeOptions,
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
lockinPeriodFrequencyTypeOptions);
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, currencyOptions,
interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions,
interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions);
}
private SavingsProductData(final Long id, final String name, final String description, final CurrencyData currency,
final BigDecimal nominalAnnualInterestRate, final EnumOptionData interestCompoundingPeriodType,
final EnumOptionData interestPostingPeriodType, final EnumOptionData interestCalculationType,
final EnumOptionData interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType,
final Collection<CurrencyData> currencyOptions, final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType,
final BigDecimal withdrawalFeeAmount, final EnumOptionData withdrawalFeeType,
final Collection<CurrencyData> currencyOptions,
final Collection<EnumOptionData> interestCompoundingPeriodTypeOptions,
final Collection<EnumOptionData> interestPostingPeriodTypeOptions,
final Collection<EnumOptionData> interestCalculationTypeOptions,
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions,
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions) {
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions) {
this.id = id;
this.name = name;
this.description = description;
@@ -156,6 +170,8 @@ public class SavingsProductData {
this.minRequiredOpeningBalance = minRequiredOpeningBalance;
this.lockinPeriodFrequency = lockinPeriodFrequency;
this.lockinPeriodFrequencyType = lockinPeriodFrequencyType;
this.withdrawalFeeAmount = withdrawalFeeAmount;
this.withdrawalFeeType = withdrawalFeeType;
this.currencyOptions = currencyOptions;
this.interestCompoundingPeriodTypeOptions = interestCompoundingPeriodTypeOptions;
@@ -163,5 +179,6 @@ public class SavingsProductData {
this.interestCalculationTypeOptions = interestCalculationTypeOptions;
this.interestCalculationDaysInYearTypeOptions = interestCalculationDaysInYearTypeOptions;
this.lockinPeriodFrequencyTypeOptions = lockinPeriodFrequencyTypeOptions;
this.withdrawalFeeTypeOptions = withdrawalFeeTypeOptions;
}
}
@@ -14,6 +14,8 @@ import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockin
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.minRequiredOpeningBalanceParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.nameParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.nominalAnnualInterestRateParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.withdrawalFeeAmountParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.withdrawalFeeTypeParamName;
import java.lang.reflect.Type;
import java.math.BigDecimal;
@@ -67,8 +69,10 @@ public class SavingsProductDataValidator {
final Integer digitsAfterDecimal = fromApiJsonHelper.extractIntegerSansLocaleNamed(digitsAfterDecimalParamName, element);
baseDataValidator.reset().parameter(digitsAfterDecimalParamName).value(digitsAfterDecimal).notNull().inMinMaxRange(0, 6);
final BigDecimal nominalAnnualInterestRate = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(nominalAnnualInterestRateParamName, element);
baseDataValidator.reset().parameter(nominalAnnualInterestRateParamName).value(nominalAnnualInterestRate).notNull().zeroOrPositiveAmount();
final BigDecimal nominalAnnualInterestRate = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(nominalAnnualInterestRateParamName,
element);
baseDataValidator.reset().parameter(nominalAnnualInterestRateParamName).value(nominalAnnualInterestRate).notNull()
.zeroOrPositiveAmount();
final Integer interestCompoundingPeriodType = fromApiJsonHelper.extractIntegerSansLocaleNamed(
interestCompoundingPeriodTypeParamName, element);
@@ -121,6 +125,17 @@ public class SavingsProductDataValidator {
}
}
if (this.fromApiJsonHelper.parameterExists(withdrawalFeeTypeParamName, element)) {
final Integer withdrawalFeeType = fromApiJsonHelper.extractIntegerSansLocaleNamed(withdrawalFeeTypeParamName, element);
baseDataValidator.reset().parameter(withdrawalFeeTypeParamName).value(withdrawalFeeType).isOneOfTheseValues(1, 2);
if (withdrawalFeeType != null) {
final BigDecimal withdrawalFeeAmount = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(withdrawalFeeAmountParamName,
element);
baseDataValidator.reset().parameter(withdrawalFeeAmountParamName).value(withdrawalFeeAmount).notNull().positiveAmount();
}
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
@@ -195,14 +210,22 @@ public class SavingsProductDataValidator {
baseDataValidator.reset().parameter(lockinPeriodFrequencyTypeParamName).value(lockinPeriodFrequencyType).inMinMaxRange(1, 3);
}
if (this.fromApiJsonHelper.parameterExists(withdrawalFeeAmountParamName, element)) {
final BigDecimal withdrawalFeeAmount = fromApiJsonHelper
.extractBigDecimalWithLocaleNamed(withdrawalFeeAmountParamName, element);
baseDataValidator.reset().parameter(withdrawalFeeAmountParamName).value(withdrawalFeeAmount).ignoreIfNull().positiveAmount();
}
if (this.fromApiJsonHelper.parameterExists(withdrawalFeeTypeParamName, element)) {
final Integer withdrawalFeeType = fromApiJsonHelper.extractIntegerSansLocaleNamed(withdrawalFeeTypeParamName, element);
baseDataValidator.reset().parameter(withdrawalFeeTypeParamName).value(withdrawalFeeType).ignoreIfNull()
.isOneOfTheseValues(1, 2);
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
if (!dataValidationErrors.isEmpty()) {
//
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors);
}
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException(dataValidationErrors); }
}
}
@@ -136,6 +136,12 @@ public class SavingsAccount extends AbstractPersistable<Long> {
@Column(name = "lockedin_until_date_derived", nullable = true)
private Date lockedInUntilDate;
@Column(name = "withdrawal_fee_amount", scale = 6, precision = 19, nullable = true)
private BigDecimal withdrawalFeeAmount;
@Column(name = "withdrawal_fee_type_enum", nullable = true)
private Integer withdrawalFeeType;
@Embedded
private SavingsAccountSummary summary;
@@ -158,13 +164,14 @@ public class SavingsAccount extends AbstractPersistable<Long> {
final SavingsCompoundingInterestPeriodType interestCompoundingPeriodType,
final SavingsInterestPostingPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType,
final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType) {
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType,
final BigDecimal withdrawalFeeAmount, final SavingsWithdrawalFeesType withdrawalFeeType) {
final SavingsAccountStatusType status = SavingsAccountStatusType.UNACTIVATED;
final LocalDate activationDate = null;
return new SavingsAccount(client, group, product, accountNo, externalId, status, activationDate, interestRate,
interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType,
minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType);
minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType);
}
private SavingsAccount(final Client client, final Group group, final SavingsProduct product, final String accountNo,
@@ -172,7 +179,8 @@ public class SavingsAccount extends AbstractPersistable<Long> {
final BigDecimal nominalAnnualInterestRate, final SavingsCompoundingInterestPeriodType interestCompoundingPeriodType,
final SavingsInterestPostingPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType,
final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType) {
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType,
final BigDecimal withdrawalFeeAmount, final SavingsWithdrawalFeesType withdrawalFeeType) {
this.client = client;
this.group = group;
this.product = product;
@@ -198,6 +206,10 @@ public class SavingsAccount extends AbstractPersistable<Long> {
if (lockinPeriodFrequencyType != null) {
this.lockinPeriodFrequencyType = lockinPeriodFrequencyType.getValue();
}
this.withdrawalFeeAmount = withdrawalFeeAmount;
if (withdrawalFeeType != null) {
this.withdrawalFeeType = withdrawalFeeType.getValue();
}
this.summary = new SavingsAccountSummary();
}
@@ -313,7 +325,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
}
}
}
if (recalucateDailyBalanceDetails) {
// no openingBalance concept supported yet but probably will to
// allow
@@ -411,6 +423,8 @@ public class SavingsAccount extends AbstractPersistable<Long> {
this.summary.updateFromInterestPeriodSummaries(currency, compoundingPeriods);
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
return compoundingPeriods;
}
@@ -788,16 +802,38 @@ public class SavingsAccount extends AbstractPersistable<Long> {
throw new PlatformApiDataValidationException(dataValidationErrors);
}
final Money amount = Money.of(this.currency, transactionAmount);
final Money transactionAmountMoney = Money.of(this.currency, transactionAmount);
if (isNotEnoughFundsToWithdraw(amount)) {
if (isNotEnoughFundsToWithdraw(transactionAmountMoney)) {
//
throw new InsufficientAccountBalanceException("transactionAmount", getAccountBalance(), transactionAmount);
}
final SavingsAccountTransaction transaction = SavingsAccountTransaction.withdrawal(this, transactionDate, amount);
final SavingsAccountTransaction transaction = SavingsAccountTransaction.withdrawal(this, transactionDate, transactionAmountMoney);
this.transactions.add(transaction);
if (isAutomaticWithdrawalFee()) {
SavingsAccountTransaction withdrawalFeeTransaction = null;
Money feeAmount = null;
switch (SavingsWithdrawalFeesType.fromInt(this.withdrawalFeeType)) {
case INVALID:
break;
case FLAT:
feeAmount = Money.of(this.currency, this.withdrawalFeeAmount);
withdrawalFeeTransaction = SavingsAccountTransaction.fee(this, transactionDate, feeAmount);
this.transactions.add(withdrawalFeeTransaction);
break;
case PERCENT_OF_AMOUNT:
final BigDecimal feeAmountDecimal = transactionAmount.multiply(this.withdrawalFeeAmount).divide(
BigDecimal.valueOf(100l));
feeAmount = Money.of(this.currency, feeAmountDecimal);
withdrawalFeeTransaction = SavingsAccountTransaction.fee(this, transactionDate, feeAmount);
this.transactions.add(withdrawalFeeTransaction);
break;
}
}
this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions);
final LocalDate today = DateUtils.getLocalDateOfTenant();
@@ -806,6 +842,10 @@ public class SavingsAccount extends AbstractPersistable<Long> {
return transaction;
}
private boolean isAutomaticWithdrawalFee() {
return this.withdrawalFeeType != null;
}
private boolean isAccountLocked(final LocalDate transactionDate) {
boolean isLocked = false;
final boolean accountHasLockedInSetting = this.lockedInUntilDate != null;
@@ -15,6 +15,8 @@ import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockin
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockinPeriodFrequencyTypeParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.minRequiredOpeningBalanceParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.nominalAnnualInterestRateParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.withdrawalFeeAmountParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.withdrawalFeeTypeParamName;
import java.math.BigDecimal;
import java.util.Locale;
@@ -153,9 +155,27 @@ public class SavingsAccountAssembler {
lockinPeriodFrequencyType = product.lockinPeriodFrequencyType();
}
BigDecimal withdrawalFeeAmount = null;
if (command.parameterExists(withdrawalFeeAmountParamName)) {
withdrawalFeeAmount = command.bigDecimalValueOfParameterNamed(withdrawalFeeAmountParamName);
} else {
withdrawalFeeAmount = product.withdrawalFeeAmount();
}
SavingsWithdrawalFeesType withdrawalFeeType = null;
if (command.parameterExists(withdrawalFeeAmountParamName)) {
final Integer withdrawalFeeTypeValue = command.integerValueOfParameterNamed(withdrawalFeeTypeParamName);
if (withdrawalFeeTypeValue != null) {
withdrawalFeeType = SavingsWithdrawalFeesType.fromInt(withdrawalFeeTypeValue);
}
} else {
withdrawalFeeType = product.withdrawalFeeType();
}
final SavingsAccount account = SavingsAccount.createNewAccount(client, group, product, accountNo, externalId, interestRate,
interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType,
minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType);
minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType);
account.setHelpers(this.savingsAccountTransactionSummaryWrapper);
if (active) {
@@ -29,6 +29,9 @@ public final class SavingsAccountSummary {
@Column(name = "total_interest_posted_derived", scale = 6, precision = 19)
private BigDecimal totalInterestPosted;
@Column(name = "total_withdrawal_fees_derived", scale = 6, precision = 19)
private BigDecimal totalWithdrawalFees;
@Column(name = "account_balance_derived", scale = 6, precision = 19)
private BigDecimal accountBalance = BigDecimal.ZERO;
@@ -42,9 +45,10 @@ public final class SavingsAccountSummary {
this.totalDeposits = wrapper.calculateTotalDeposits(currency, transactions);
this.totalWithdrawals = wrapper.calculateTotalWithdrawals(currency, transactions);
this.totalInterestPosted = wrapper.calculateTotalInterestPosted(currency, transactions);
this.totalWithdrawalFees = wrapper.calculateTotalWithdrawalFees(currency, transactions);
this.accountBalance = Money.of(currency, this.totalDeposits).plus(this.totalInterestPosted).minus(this.totalWithdrawals)
.getAmount();
.minus(this.totalWithdrawalFees).getAmount();
}
public void updateFromInterestPeriodSummaries(final MonetaryCurrency currency,
@@ -82,6 +82,12 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
isReversed);
}
public static SavingsAccountTransaction fee(final SavingsAccount savingsAccount, final LocalDate date, final Money amount) {
final boolean isReversed = false;
return new SavingsAccountTransaction(savingsAccount, SavingsAccountTransactionType.WITHDRAWAL_FEE.getValue(), date, amount,
isReversed);
}
private SavingsAccountTransaction(final SavingsAccount savingsAccount, final Integer typeOf, final LocalDate transactionLocalDate,
final Money amount, final boolean isReversed) {
this.savingsAccount = savingsAccount;
@@ -115,6 +121,10 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
return SavingsAccountTransactionType.fromInt(this.typeOf).isInterestPosting() && isNotReversed();
}
public boolean isWithdrawalFee() {
return SavingsAccountTransactionType.fromInt(this.typeOf).isWithdrawalFee() && isNotReversed();
}
public boolean isNotReversed() {
return !isReversed();
}
@@ -43,4 +43,14 @@ public final class SavingsAccountTransactionSummaryWrapper {
}
return total.getAmountDefaultedToNullIfZero();
}
public BigDecimal calculateTotalWithdrawalFees(final MonetaryCurrency currency, final List<SavingsAccountTransaction> transactions) {
Money total = Money.zero(currency);
for (SavingsAccountTransaction transaction : transactions) {
if (transaction.isWithdrawalFee() && transaction.isNotReversed()) {
total = total.plus(transaction.getAmount(currency));
}
}
return total.getAmountDefaultedToNullIfZero();
}
}
@@ -14,7 +14,8 @@ public enum SavingsAccountTransactionType {
INVALID(0, "savingsAccountTransactionType.invalid"), //
DEPOSIT(1, "savingsAccountTransactionType.deposit"), //
WITHDRAWAL(2, "savingsAccountTransactionType.withdrawal"), //
INTEREST_POSTING(3, "savingsAccountTransactionType.interestPosting");
INTEREST_POSTING(3, "savingsAccountTransactionType.interestPosting"), //
WITHDRAWAL_FEE(4, "savingsAccountTransactionType.withdrawalFee");
private final Integer value;
private final String code;
@@ -47,6 +48,9 @@ public enum SavingsAccountTransactionType {
case 3:
loanTransactionType = SavingsAccountTransactionType.INTEREST_POSTING;
break;
case 4:
loanTransactionType = SavingsAccountTransactionType.WITHDRAWAL_FEE;
break;
}
return loanTransactionType;
}
@@ -62,4 +66,8 @@ public enum SavingsAccountTransactionType {
public boolean isInterestPosting() {
return this.value.equals(SavingsAccountTransactionType.INTEREST_POSTING.getValue());
}
public boolean isWithdrawalFee() {
return this.value.equals(SavingsAccountTransactionType.WITHDRAWAL_FEE.getValue());
}
}
@@ -18,6 +18,8 @@ import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockin
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.minRequiredOpeningBalanceParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.nameParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.nominalAnnualInterestRateParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.withdrawalFeeAmountParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.withdrawalFeeTypeParamName;
import java.math.BigDecimal;
import java.util.LinkedHashMap;
@@ -29,9 +31,9 @@ import javax.persistence.Entity;
import javax.persistence.Table;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.exception.GeneralPlatformDomainRuleException;
import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency;
import org.mifosplatform.organisation.monetary.domain.Money;
import org.mifosplatform.portfolio.savings.exception.InvalidSavingsProductSettingsException;
import org.springframework.data.jpa.domain.AbstractPersistable;
@Entity
@@ -88,15 +90,22 @@ public class SavingsProduct extends AbstractPersistable<Long> {
@Column(name = "lockin_period_frequency_enum", nullable = true)
private Integer lockinPeriodFrequencyType;
@Column(name = "withdrawal_fee_amount", scale = 6, precision = 19, nullable = true)
private BigDecimal withdrawalFeeAmount;
@Column(name = "withdrawal_fee_type_enum", nullable = true)
private Integer withdrawalFeeType;
public static SavingsProduct createNew(final String name, final String description, final MonetaryCurrency currency,
final BigDecimal interestRate, final SavingsCompoundingInterestPeriodType interestCompoundingPeriodType,
final SavingsInterestPostingPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType,
final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType) {
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType,
final BigDecimal withdrawalFeeAmount, final SavingsWithdrawalFeesType withdrawalFeeType) {
return new SavingsProduct(name, description, currency, interestRate, interestCompoundingPeriodType, interestPostingPeriodType,
interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency,
lockinPeriodFrequencyType);
lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType);
}
protected SavingsProduct() {
@@ -108,7 +117,8 @@ public class SavingsProduct extends AbstractPersistable<Long> {
final SavingsCompoundingInterestPeriodType interestCompoundingPeriodType,
final SavingsInterestPostingPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType,
final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType) {
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType,
final BigDecimal withdrawalFeeAmount, final SavingsWithdrawalFeesType withdrawalFeeType) {
this.name = name;
this.description = description;
@@ -129,7 +139,13 @@ public class SavingsProduct extends AbstractPersistable<Long> {
this.lockinPeriodFrequencyType = lockinPeriodFrequencyType.getValue();
}
this.withdrawalFeeAmount = withdrawalFeeAmount;
if (withdrawalFeeType != null) {
this.withdrawalFeeType = withdrawalFeeType.getValue();
}
validateLockinDetails();
validateWithdrawalFeeDetails();
}
public MonetaryCurrency currency() {
@@ -172,6 +188,18 @@ public class SavingsProduct extends AbstractPersistable<Long> {
return type;
}
public BigDecimal withdrawalFeeAmount() {
return this.withdrawalFeeAmount;
}
public SavingsWithdrawalFeesType withdrawalFeeType() {
SavingsWithdrawalFeesType type = null;
if (this.withdrawalFeeType != null) {
type = SavingsWithdrawalFeesType.fromInt(this.withdrawalFeeType);
}
return type;
}
public Map<String, Object> update(final JsonCommand command) {
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(10);
@@ -258,16 +286,43 @@ public class SavingsProduct extends AbstractPersistable<Long> {
this.lockinPeriodFrequencyType = SavingsPeriodFrequencyType.fromInt(newValue).getValue();
}
if (command.isChangeInBigDecimalParameterNamed(withdrawalFeeAmountParamName, this.withdrawalFeeAmount)) {
final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(withdrawalFeeAmountParamName);
actualChanges.put(withdrawalFeeAmountParamName, newValue);
actualChanges.put(localeParamName, localeAsInput);
this.withdrawalFeeAmount = newValue;
}
if (command.isChangeInIntegerParameterNamed(withdrawalFeeTypeParamName, this.withdrawalFeeType)) {
final Integer newValue = command.integerValueOfParameterNamed(withdrawalFeeTypeParamName);
actualChanges.put(withdrawalFeeTypeParamName, newValue);
this.withdrawalFeeType = SavingsWithdrawalFeesType.fromInt(newValue).getValue();
}
validateLockinDetails();
validateWithdrawalFeeDetails();
return actualChanges;
}
private void validateWithdrawalFeeDetails() {
if (isInvalidConfigurationOfWithdrawalFeeSettings()) {
Object[] defaultUserMessageArgs = new Object[] { withdrawalFeeAmountParamName };
throw new GeneralPlatformDomainRuleException("error.msg.product.savings.invalid.withdrawalfee.settings",
"Invalid configuration of withdrawal fee settings.", defaultUserMessageArgs);
}
}
private boolean isInvalidConfigurationOfWithdrawalFeeSettings() {
return (this.withdrawalFeeAmount == null && this.withdrawalFeeType != null)
|| (this.withdrawalFeeType == null && this.withdrawalFeeAmount != null);
}
private void validateLockinDetails() {
if (isInvalidConfigurationOfLockinSettings()) {
//
throw new InvalidSavingsProductSettingsException("error.msg.product.savings.invalid.lockin.settings",
"Invalid configuration of lock in settings.", lockinPeriodFrequencyParamName);
Object[] defaultUserMessageArgs = new Object[] { lockinPeriodFrequencyParamName };
throw new GeneralPlatformDomainRuleException("error.msg.product.savings.invalid.lockin.settings",
"Invalid configuration of lock in settings.", defaultUserMessageArgs);
}
}
@@ -12,6 +12,8 @@ import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockin
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.minRequiredOpeningBalanceParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.nameParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.nominalAnnualInterestRateParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.withdrawalFeeAmountParamName;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.withdrawalFeeTypeParamName;
import java.math.BigDecimal;
@@ -67,8 +69,15 @@ public class SavingsProductAssembler {
lockinPeriodFrequencyType = SavingsPeriodFrequencyType.fromInt(lockinPeriodFrequencyTypeValue);
}
final BigDecimal withdrawalFeeAmount = command.bigDecimalValueOfParameterNamed(withdrawalFeeAmountParamName);
SavingsWithdrawalFeesType withdrawalFeeType = null;
final Integer withdrawalFeeTypeValue = command.integerValueOfParameterNamed(withdrawalFeeTypeParamName);
if (withdrawalFeeTypeValue != null) {
withdrawalFeeType = SavingsWithdrawalFeesType.fromInt(withdrawalFeeTypeValue);
}
return SavingsProduct.createNew(name, description, currency, interestRate, interestCompoundingPeriodType,
interestPostingPeriodType, interestCalculationType,
interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType);
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType);
}
}
@@ -0,0 +1,43 @@
/**
* 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;
public enum SavingsWithdrawalFeesType {
INVALID(0, "savingsWithdrawalFeesType.invalid"), //
FLAT(1, "savingsWithdrawalFeesType.flat"), //
PERCENT_OF_AMOUNT(2, "savingsWithdrawalFeesType.percent.of.amount");
private final Integer value;
private final String code;
private SavingsWithdrawalFeesType(final Integer value, final String code) {
this.value = value;
this.code = code;
}
public Integer getValue() {
return this.value;
}
public String getCode() {
return code;
}
public static SavingsWithdrawalFeesType fromInt(final Integer type) {
SavingsWithdrawalFeesType withdrawalFeeType = SavingsWithdrawalFeesType.INVALID;
switch (type) {
case 1:
withdrawalFeeType = FLAT;
break;
case 2:
withdrawalFeeType = PERCENT_OF_AMOUNT;
break;
}
return withdrawalFeeType;
}
}
@@ -1,10 +0,0 @@
package org.mifosplatform.portfolio.savings.exception;
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
public class InvalidSavingsProductSettingsException extends AbstractPlatformDomainRuleException {
public InvalidSavingsProductSettingsException(final String errorCode, final String defaultMessage, final String paramName) {
super(errorCode, defaultMessage, paramName);
}
}
@@ -112,8 +112,11 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
sqlBuilder.append("sa.min_required_opening_balance as minRequiredOpeningBalance, ");
sqlBuilder.append("sa.lockin_period_frequency as lockinPeriodFrequency,");
sqlBuilder.append("sa.lockin_period_frequency_enum as lockinPeriodFrequencyType, ");
sqlBuilder.append("sa.withdrawal_fee_amount as withdrawalFeeAmount,");
sqlBuilder.append("sa.withdrawal_fee_type_enum as withdrawalFeeTypeEnum, ");
sqlBuilder.append("sa.total_deposits_derived as totalDeposits, ");
sqlBuilder.append("sa.total_withdrawals_derived as totalWithdrawals, ");
sqlBuilder.append("sa.total_withdrawal_fees_derived as totalWithdrawalFees, ");
sqlBuilder.append("sa.total_interest_earned_derived as totalInterestEarned, ");
sqlBuilder.append("sa.total_interest_posted_derived as totalInterestPosted, ");
sqlBuilder.append("sa.account_balance_derived as accountBalance ");
@@ -184,19 +187,29 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
lockinPeriodFrequencyType = SavingsEnumerations.lockinPeriodFrequencyType(lockinPeriodType);
}
final BigDecimal withdrawalFeeAmount = rs.getBigDecimal("withdrawalFeeAmount");
EnumOptionData withdrawalFeeType = null;
final Integer withdrawalFeeTypeValue = JdbcSupport.getInteger(rs, "withdrawalFeeTypeEnum");
if (withdrawalFeeTypeValue != null) {
withdrawalFeeType = SavingsEnumerations.withdrawalFeeType(withdrawalFeeTypeValue);
}
final BigDecimal totalDeposits = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "totalDeposits");
final BigDecimal totalWithdrawals = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "totalWithdrawals");
final BigDecimal totalWithdrawalFees = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "totalWithdrawalFees");
final BigDecimal totalInterestEarned = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "totalInterestEarned");
final BigDecimal totalInterestPosted = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "totalInterestPosted");
final BigDecimal accountBalance = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "accountBalance");
final SavingsAccountSummaryData summary = new SavingsAccountSummaryData(currency, totalDeposits, totalWithdrawals,
totalInterestEarned, totalInterestPosted, accountBalance);
totalWithdrawalFees, totalInterestEarned, totalInterestPosted, accountBalance);
return SavingsAccountData.instance(id, accountNo, externalId, status, activationDate, groupId, groupName, clientId, clientName,
productId, productName, currency, nominalAnnualInterestRate, interestCompoundingPeriodType, interestPostingPeriodType,
interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency,
lockinPeriodFrequencyType, summary);
lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, summary);
}
}
@@ -238,11 +251,14 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = this.dropdownReadPlatformService
.retrieveLockinPeriodFrequencyTypeOptions();
final Collection<EnumOptionData> withdrawalFeeTypeOptions = this.dropdownReadPlatformService.retrievewithdrawalFeeTypeOptions();
final Collection<SavingsAccountTransactionData> transactions = null;
template = SavingsAccountData.withTemplateOptions(template, productOptions, interestCompoundingPeriodTypeOptions,
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
lockinPeriodFrequencyTypeOptions, transactions);
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, transactions);
} else {
String clientName = null;
@@ -262,11 +278,13 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
final Collection<EnumOptionData> interestCalculationTypeOptions = null;
final Collection<EnumOptionData> interestCalculationDaysInYearTypeOptions = null;
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions = null;
final Collection<EnumOptionData> withdrawalFeeTypeOptions = null;
final Collection<SavingsAccountTransactionData> transactions = null;
template = SavingsAccountData.withTemplateOptions(template, productOptions, interestCompoundingPeriodTypeOptions,
interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions,
lockinPeriodFrequencyTypeOptions, transactions);
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, transactions);
}
return template;
@@ -404,8 +422,10 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
sqlBuilder.append("sp.interest_calculation_type_enum as interestCalculationType, ");
sqlBuilder.append("sp.interest_calculation_days_in_year_type_enum as interestCalculationDaysInYearType, ");
sqlBuilder.append("sp.min_required_opening_balance as minRequiredOpeningBalance, ");
sqlBuilder.append("sp.lockin_period_frequency as lockinPeriodFrequency, ");
sqlBuilder.append("sp.lockin_period_frequency_enum as lockinPeriodFrequencyType ");
sqlBuilder.append("sp.lockin_period_frequency as lockinPeriodFrequency,");
sqlBuilder.append("sp.lockin_period_frequency_enum as lockinPeriodFrequencyType, ");
sqlBuilder.append("sp.withdrawal_fee_amount as withdrawalFeeAmount,");
sqlBuilder.append("sp.withdrawal_fee_type_enum as withdrawalFeeTypeEnum ");
sqlBuilder.append("from m_savings_product sp ");
sqlBuilder.append("join m_currency curr on curr.code = sp.currency_code ");
@@ -456,6 +476,14 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
lockinPeriodFrequencyType = SavingsEnumerations.lockinPeriodFrequencyType(lockinPeriodType);
}
final BigDecimal withdrawalFeeAmount = rs.getBigDecimal("withdrawalFeeAmount");
EnumOptionData withdrawalFeeType = null;
final Integer withdrawalFeeTypeValue = JdbcSupport.getInteger(rs, "withdrawalFeeTypeEnum");
if (withdrawalFeeTypeValue != null) {
withdrawalFeeType = SavingsEnumerations.withdrawalFeeType(withdrawalFeeTypeValue);
}
Long clientId = null;
String clientName = null;
if (client != null) {
@@ -476,7 +504,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
return SavingsAccountData.instance(null, null, null, status, activationDate, groupId, groupName, clientId, clientName,
productId, productName, currency, nominalAnnualIterestRate, interestCompoundingPeriodType, interestPostingPeriodType,
interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency,
lockinPeriodFrequencyType, summary);
lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType, summary);
}
}
}
@@ -137,7 +137,7 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
.build();
} catch (DataAccessException dve) {
handleDataIntegrityIssues(command, dve);
return new CommandProcessingResult(Long.valueOf(-1));
return CommandProcessingResult.empty();
}
}
@@ -15,4 +15,6 @@ public interface SavingsDropdownReadPlatformService {
Collection<EnumOptionData> retrieveInterestCalculationTypeOptions();
Collection<EnumOptionData> retrieveInterestCalculationDaysInYearTypeOptions();
Collection<EnumOptionData> retrievewithdrawalFeeTypeOptions();
}
@@ -10,11 +10,22 @@ import org.mifosplatform.portfolio.savings.domain.SavingsInterestCalculationDays
import org.mifosplatform.portfolio.savings.domain.SavingsInterestCalculationType;
import org.mifosplatform.portfolio.savings.domain.SavingsInterestPostingPeriodType;
import org.mifosplatform.portfolio.savings.domain.SavingsPeriodFrequencyType;
import org.mifosplatform.portfolio.savings.domain.SavingsWithdrawalFeesType;
import org.springframework.stereotype.Service;
@Service
public class SavingsDropdownReadPlatformServiceImpl implements SavingsDropdownReadPlatformService {
@Override
public Collection<EnumOptionData> retrievewithdrawalFeeTypeOptions() {
List<EnumOptionData> allowedOptions = Arrays.asList( //
SavingsEnumerations.withdrawalFeeType(SavingsWithdrawalFeesType.FLAT), //
SavingsEnumerations.withdrawalFeeType(SavingsWithdrawalFeesType.PERCENT_OF_AMOUNT) //
);
return allowedOptions;
}
@Override
public List<EnumOptionData> retrieveLockinPeriodFrequencyTypeOptions() {
List<EnumOptionData> allowedLockinPeriodFrequencyTypeOptions = Arrays.asList( //
@@ -15,6 +15,7 @@ import org.mifosplatform.portfolio.savings.domain.SavingsInterestCalculationDays
import org.mifosplatform.portfolio.savings.domain.SavingsInterestCalculationType;
import org.mifosplatform.portfolio.savings.domain.SavingsInterestPostingPeriodType;
import org.mifosplatform.portfolio.savings.domain.SavingsPeriodFrequencyType;
import org.mifosplatform.portfolio.savings.domain.SavingsWithdrawalFeesType;
public class SavingsEnumerations {
@@ -75,6 +76,11 @@ public class SavingsEnumerations {
optionData = new SavingsAccountTransactionEnumData(SavingsAccountTransactionType.INTEREST_POSTING.getValue().longValue(),
SavingsAccountTransactionType.INTEREST_POSTING.getCode(), "Interest posting");
break;
case WITHDRAWAL_FEE:
optionData = new SavingsAccountTransactionEnumData(SavingsAccountTransactionType.WITHDRAWAL_FEE.getValue().longValue(),
SavingsAccountTransactionType.WITHDRAWAL_FEE.getCode(), "Withdrawal fee");
break;
}
return optionData;
}
@@ -144,7 +150,7 @@ public class SavingsEnumerations {
return optionData;
}
public static EnumOptionData interestPeriodType(final Integer type) {
public static EnumOptionData compoundingInterestPeriodType(final Integer type) {
return compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.fromInt(type));
}
@@ -243,4 +249,28 @@ public class SavingsEnumerations {
return optionData;
}
public static EnumOptionData withdrawalFeeType(final Integer type) {
return withdrawalFeeType(SavingsWithdrawalFeesType.fromInt(type));
}
public static EnumOptionData withdrawalFeeType(final SavingsWithdrawalFeesType type) {
EnumOptionData optionData = new EnumOptionData(SavingsWithdrawalFeesType.INVALID.getValue().longValue(),
SavingsWithdrawalFeesType.INVALID.getCode(), "Invalid");
switch (type) {
case INVALID:
break;
case FLAT:
optionData = new EnumOptionData(SavingsWithdrawalFeesType.FLAT.getValue().longValue(),
SavingsWithdrawalFeesType.FLAT.getCode(), "Flat");
break;
case PERCENT_OF_AMOUNT:
optionData = new EnumOptionData(SavingsWithdrawalFeesType.PERCENT_OF_AMOUNT.getValue().longValue(),
SavingsWithdrawalFeesType.PERCENT_OF_AMOUNT.getCode(), "% of Amount");
break;
}
return optionData;
}
}
@@ -16,11 +16,6 @@ import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSourc
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.organisation.monetary.data.CurrencyData;
import org.mifosplatform.portfolio.savings.data.SavingsProductData;
import org.mifosplatform.portfolio.savings.domain.SavingsCompoundingInterestPeriodType;
import org.mifosplatform.portfolio.savings.domain.SavingsInterestCalculationDaysInYearType;
import org.mifosplatform.portfolio.savings.domain.SavingsInterestCalculationType;
import org.mifosplatform.portfolio.savings.domain.SavingsInterestPostingPeriodType;
import org.mifosplatform.portfolio.savings.domain.SavingsPeriodFrequencyType;
import org.mifosplatform.portfolio.savings.exception.SavingsProductNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.EmptyResultDataAccessException;
@@ -88,7 +83,9 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
sqlBuilder.append("sp.interest_calculation_days_in_year_type_enum as interestCalculationDaysInYearType, ");
sqlBuilder.append("sp.min_required_opening_balance as minRequiredOpeningBalance, ");
sqlBuilder.append("sp.lockin_period_frequency as lockinPeriodFrequency,");
sqlBuilder.append("sp.lockin_period_frequency_enum as lockinPeriodFrequencyType ");
sqlBuilder.append("sp.lockin_period_frequency_enum as lockinPeriodFrequencyType, ");
sqlBuilder.append("sp.withdrawal_fee_amount as withdrawalFeeAmount,");
sqlBuilder.append("sp.withdrawal_fee_type_enum as withdrawalFeeTypeEnum ");
sqlBuilder.append("from m_savings_product sp ");
sqlBuilder.append("join m_currency curr on curr.code = sp.currency_code ");
@@ -116,23 +113,21 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
currencyNameCode);
final BigDecimal nominalAnnualInterestRate = rs.getBigDecimal("nominalAnnualInterestRate");
final Integer compoundingInterestPeriodTypeValue = JdbcSupport.getInteger(rs, "compoundingInterestPeriodType");
EnumOptionData compoundingInterestPeriodType = SavingsEnumerations
.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.fromInt(JdbcSupport.getInteger(rs,
"compoundingInterestPeriodType")));
.compoundingInterestPeriodType(compoundingInterestPeriodTypeValue);
SavingsInterestPostingPeriodType interestPostingPeriod = SavingsInterestPostingPeriodType.fromInt(JdbcSupport.getInteger(rs,
"interestPostingPeriodType"));
EnumOptionData interestPostingPeriodType = SavingsEnumerations.interestPostingPeriodType(interestPostingPeriod);
final Integer interestPostingPeriodTypeValue = JdbcSupport.getInteger(rs, "interestPostingPeriodType");
EnumOptionData interestPostingPeriodType = SavingsEnumerations.interestPostingPeriodType(interestPostingPeriodTypeValue);
EnumOptionData interestCalculationType = SavingsEnumerations.interestCalculationType(SavingsInterestCalculationType
.fromInt(JdbcSupport.getInteger(rs, "interestCalculationType")));
final Integer interestCalculationTypeValue = JdbcSupport.getInteger(rs, "interestCalculationType");
EnumOptionData interestCalculationType = SavingsEnumerations.interestCalculationType(interestCalculationTypeValue);
EnumOptionData interestCalculationDaysInYearType = null;
final Integer interestCalculationDaysInYearTypeValue = JdbcSupport.getInteger(rs, "interestCalculationDaysInYearType");
if (interestCalculationDaysInYearTypeValue != null) {
interestCalculationDaysInYearType = SavingsEnumerations
.interestCalculationDaysInYearType(SavingsInterestCalculationDaysInYearType
.fromInt(interestCalculationDaysInYearTypeValue));
.interestCalculationDaysInYearType(interestCalculationDaysInYearTypeValue);
}
final BigDecimal minRequiredOpeningBalance = rs.getBigDecimal("minRequiredOpeningBalance");
@@ -141,13 +136,20 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
EnumOptionData lockinPeriodFrequencyType = null;
final Integer lockinPeriodFrequencyTypeValue = JdbcSupport.getInteger(rs, "lockinPeriodFrequencyType");
if (lockinPeriodFrequencyTypeValue != null) {
lockinPeriodFrequencyType = SavingsEnumerations.lockinPeriodFrequencyType(SavingsPeriodFrequencyType
.fromInt(lockinPeriodFrequencyTypeValue));
lockinPeriodFrequencyType = SavingsEnumerations.lockinPeriodFrequencyType(lockinPeriodFrequencyTypeValue);
}
final BigDecimal withdrawalFeeAmount = rs.getBigDecimal("withdrawalFeeAmount");
EnumOptionData withdrawalFeeType = null;
final Integer withdrawalFeeTypeValue = JdbcSupport.getInteger(rs, "withdrawalFeeTypeEnum");
if (withdrawalFeeTypeValue != null) {
withdrawalFeeType = SavingsEnumerations.withdrawalFeeType(withdrawalFeeTypeValue);
}
return SavingsProductData.instance(id, name, description, currency, nominalAnnualInterestRate, compoundingInterestPeriodType,
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
lockinPeriodFrequency, lockinPeriodFrequencyType);
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeAmount, withdrawalFeeType);
}
}
@@ -72,8 +72,6 @@ public class SavingsProductWritePlatformServiceJpaRepositoryImpl implements Savi
public CommandProcessingResult create(final JsonCommand command) {
try {
this.context.authenticatedUser();
this.fromApiJsonDataValidator.validateForCreate(command.json());
final SavingsProduct product = this.savingsProductAssembler.assemble(command);