Added Overdraft Interest Feature
This commit is contained in:
+3
-3
@@ -82,10 +82,10 @@ public enum SavingsAccountTransactionType {
|
||||
case 15:
|
||||
savingsAccountTransactionType = SavingsAccountTransactionType.REJECT_TRANSFER;
|
||||
break;
|
||||
case 18:
|
||||
case 16:
|
||||
savingsAccountTransactionType = SavingsAccountTransactionType.WRITTEN_OFF;
|
||||
break;
|
||||
case 19:
|
||||
case 17:
|
||||
savingsAccountTransactionType = SavingsAccountTransactionType.OVERDRAFT_INTEREST;
|
||||
break;
|
||||
}
|
||||
@@ -149,7 +149,7 @@ public enum SavingsAccountTransactionType {
|
||||
}
|
||||
|
||||
public boolean isDebit() {
|
||||
return isWithdrawal() || isWithdrawalFee() || isAnnualFee() || isPayCharge();
|
||||
return isWithdrawal() || isWithdrawalFee() || isAnnualFee() || isPayCharge() || isIncomeFromInterest();
|
||||
}
|
||||
|
||||
public boolean isCredit() {
|
||||
|
||||
+9
-3
@@ -97,6 +97,8 @@ public class SavingsApiConstants {
|
||||
public static final String bankNumberParamName = "bankNumber";
|
||||
public static final String allowOverdraftParamName = "allowOverdraft";
|
||||
public static final String overdraftLimitParamName = "overdraftLimit";
|
||||
public static final String nominalAnnualInterestRateOverdraftParamName = "nominalAnnualInterestRateOverdraft";
|
||||
public static final String minOverdraftForInterestCalculationParamName = "minOverdraftForInterestCalculation";
|
||||
public static final String minRequiredBalanceParamName = "minRequiredBalance";
|
||||
public static final String enforceMinRequiredBalanceParamName = "enforceMinRequiredBalance";
|
||||
public static final String minBalanceForInterestCalculationParamName = "minBalanceForInterestCalculation";
|
||||
@@ -162,6 +164,7 @@ public class SavingsApiConstants {
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.OVERDRAFT_PORTFOLIO_CONTROL.getValue(),
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.LOSSES_WRITTEN_OFF.getValue(),
|
||||
SAVINGS_PRODUCT_ACCOUNTING_PARAMS.INCOME_FROM_INTEREST.getValue(), allowOverdraftParamName, overdraftLimitParamName,
|
||||
nominalAnnualInterestRateOverdraftParamName, minOverdraftForInterestCalculationParamName,
|
||||
minRequiredBalanceParamName, enforceMinRequiredBalanceParamName, minBalanceForInterestCalculationParamName));
|
||||
|
||||
/**
|
||||
@@ -176,7 +179,8 @@ public class SavingsApiConstants {
|
||||
lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName, withdrawalFeeAmountParamName, withdrawalFeeTypeParamName,
|
||||
withdrawalFeeForTransfersParamName, feeAmountParamName, feeOnMonthDayParamName, "currencyOptions",
|
||||
"interestCompoundingPeriodTypeOptions", "interestPostingPeriodTypeOptions", "interestCalculationTypeOptions",
|
||||
"interestCalculationDaysInYearTypeOptions", "lockinPeriodFrequencyTypeOptions", "withdrawalFeeTypeOptions"));
|
||||
"interestCalculationDaysInYearTypeOptions", "lockinPeriodFrequencyTypeOptions", "withdrawalFeeTypeOptions",
|
||||
nominalAnnualInterestRateOverdraftParamName, minOverdraftForInterestCalculationParamName));
|
||||
|
||||
public static final Set<String> SAVINGS_ACCOUNT_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName,
|
||||
dateFormatParamName, monthDayFormatParamName, staffIdParamName, accountNoParamName, externalIdParamName, clientIdParamName,
|
||||
@@ -186,7 +190,8 @@ public class SavingsApiConstants {
|
||||
lockinPeriodFrequencyTypeParamName,
|
||||
// withdrawalFeeAmountParamName, withdrawalFeeTypeParamName,
|
||||
withdrawalFeeForTransfersParamName, feeAmountParamName, feeOnMonthDayParamName, chargesParamName, allowOverdraftParamName,
|
||||
overdraftLimitParamName, minRequiredBalanceParamName, enforceMinRequiredBalanceParamName));
|
||||
overdraftLimitParamName, minRequiredBalanceParamName, enforceMinRequiredBalanceParamName,
|
||||
nominalAnnualInterestRateOverdraftParamName, minOverdraftForInterestCalculationParamName));
|
||||
|
||||
/**
|
||||
* These parameters will match the class level parameters of
|
||||
@@ -201,7 +206,8 @@ public class SavingsApiConstants {
|
||||
withdrawalFeeAmountParamName, withdrawalFeeTypeParamName, withdrawalFeeForTransfersParamName, feeAmountParamName,
|
||||
feeOnMonthDayParamName, "summary", "transactions", "productOptions", "interestCompoundingPeriodTypeOptions",
|
||||
"interestPostingPeriodTypeOptions", "interestCalculationTypeOptions", "interestCalculationDaysInYearTypeOptions",
|
||||
"lockinPeriodFrequencyTypeOptions", "withdrawalFeeTypeOptions", "withdrawalFee", "annualFee", onHoldFundsParamName));
|
||||
"lockinPeriodFrequencyTypeOptions", "withdrawalFeeTypeOptions", "withdrawalFee", "annualFee", onHoldFundsParamName,
|
||||
nominalAnnualInterestRateOverdraftParamName, minOverdraftForInterestCalculationParamName));
|
||||
|
||||
public static final Set<String> SAVINGS_ACCOUNT_TRANSACTION_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(localeParamName,
|
||||
dateFormatParamName, transactionDateParamName, transactionAmountParamName, paymentTypeIdParamName,
|
||||
|
||||
+24
-8
@@ -74,6 +74,8 @@ public class SavingsAccountData {
|
||||
private final SavingsAccountChargeData withdrawalFee;
|
||||
@SuppressWarnings("unused")
|
||||
private final SavingsAccountChargeData annualFee;
|
||||
private final BigDecimal nominalAnnualInterestRateOverdraft;
|
||||
private final BigDecimal minOverdraftForInterestCalculation;
|
||||
|
||||
public static SavingsAccountData instance(final Long id, final String accountNo, final EnumOptionData depositType,
|
||||
final String externalId, final Long groupId, final String groupName, final Long clientId, final String clientName,
|
||||
@@ -85,7 +87,8 @@ public class SavingsAccountData {
|
||||
final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType, final boolean withdrawalFeeForTransfers,
|
||||
final SavingsAccountSummaryData summary, final boolean allowOverdraft, final BigDecimal overdraftLimit,
|
||||
final BigDecimal minRequiredBalance, final boolean enforceMinRequiredBalance,
|
||||
final BigDecimal minBalanceForInterestCalculation, final BigDecimal onHoldFunds) {
|
||||
final BigDecimal minBalanceForInterestCalculation, final BigDecimal onHoldFunds,
|
||||
final BigDecimal nominalAnnualInterestRateOverdraft, final BigDecimal minOverdraftForInterestCalculation) {
|
||||
|
||||
final Collection<SavingsProductData> productOptions = null;
|
||||
final Collection<StaffData> fieldOfficerOptions = null;
|
||||
@@ -107,7 +110,8 @@ public class SavingsAccountData {
|
||||
fieldOfficerOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions, charges, chargeOptions, allowOverdraft, overdraftLimit, minRequiredBalance,
|
||||
enforceMinRequiredBalance, minBalanceForInterestCalculation, onHoldFunds);
|
||||
enforceMinRequiredBalance, minBalanceForInterestCalculation, onHoldFunds,
|
||||
nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation);
|
||||
}
|
||||
|
||||
public static SavingsAccountData lookup(final Long accountId, final String accountNo, final EnumOptionData depositType) {
|
||||
@@ -140,6 +144,8 @@ public class SavingsAccountData {
|
||||
// final LocalDate annualFeeNextDueDate = null;
|
||||
final boolean allowOverdraft = false;
|
||||
final BigDecimal overdraftLimit = null;
|
||||
final BigDecimal nominalAnnualInterestRateOverdraft = null;
|
||||
final BigDecimal minOverdraftForInterestCalculation = null;
|
||||
final BigDecimal minRequiredBalance = null;
|
||||
final boolean enforceMinRequiredBalance = false;
|
||||
final BigDecimal minBalanceForInterestCalculation = null;
|
||||
@@ -167,7 +173,8 @@ public class SavingsAccountData {
|
||||
fieldOfficerOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions, charges, chargeOptions, allowOverdraft, overdraftLimit, minRequiredBalance,
|
||||
enforceMinRequiredBalance, minBalanceForInterestCalculation, onHoldFunds);
|
||||
enforceMinRequiredBalance, minBalanceForInterestCalculation, onHoldFunds,
|
||||
nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation);
|
||||
}
|
||||
|
||||
public static SavingsAccountData lookupWithProductDetails(final Long accountId, final String accountNo,
|
||||
@@ -198,6 +205,8 @@ public class SavingsAccountData {
|
||||
// final LocalDate annualFeeNextDueDate = null;
|
||||
final boolean allowOverdraft = false;
|
||||
final BigDecimal overdraftLimit = null;
|
||||
final BigDecimal nominalAnnualInterestRateOverdraft = null;
|
||||
final BigDecimal minOverdraftForInterestCalculation = null;
|
||||
final BigDecimal minRequiredBalance = null;
|
||||
final boolean enforceMinRequiredBalance = false;
|
||||
final BigDecimal minBalanceForInterestCalculation = null;
|
||||
@@ -225,7 +234,8 @@ public class SavingsAccountData {
|
||||
fieldOfficerOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions, charges, chargeOptions, allowOverdraft, overdraftLimit, minRequiredBalance,
|
||||
enforceMinRequiredBalance, minBalanceForInterestCalculation, onHoldFunds);
|
||||
enforceMinRequiredBalance, minBalanceForInterestCalculation, onHoldFunds,
|
||||
nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation);
|
||||
}
|
||||
|
||||
public static SavingsAccountData withTemplateOptions(final SavingsAccountData account, final SavingsAccountData template,
|
||||
@@ -258,7 +268,7 @@ public class SavingsAccountData {
|
||||
template.interestCalculationDaysInYearTypeOptions, template.lockinPeriodFrequencyTypeOptions,
|
||||
template.withdrawalFeeTypeOptions, charges, template.chargeOptions, account.allowOverdraft, account.overdraftLimit,
|
||||
account.minRequiredBalance, account.enforceMinRequiredBalance, account.minBalanceForInterestCalculation,
|
||||
account.onHoldFunds);
|
||||
account.onHoldFunds, account.nominalAnnualInterestRateOverdraft, account.minOverdraftForInterestCalculation);
|
||||
}
|
||||
|
||||
public static SavingsAccountData withTemplateOptions(final SavingsAccountData account,
|
||||
@@ -281,7 +291,7 @@ public class SavingsAccountData {
|
||||
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions, charges, chargeOptions, account.allowOverdraft, account.overdraftLimit,
|
||||
account.minRequiredBalance, account.enforceMinRequiredBalance, account.minBalanceForInterestCalculation,
|
||||
account.onHoldFunds);
|
||||
account.onHoldFunds, account.nominalAnnualInterestRateOverdraft, account.minOverdraftForInterestCalculation);
|
||||
}
|
||||
|
||||
public static SavingsAccountData withClientTemplate(final Long clientId, final String clientName, final Long groupId,
|
||||
@@ -314,6 +324,8 @@ public class SavingsAccountData {
|
||||
// final LocalDate annualFeeNextDueDate = null;
|
||||
final boolean allowOverdraft = false;
|
||||
final BigDecimal overdraftLimit = null;
|
||||
final BigDecimal nominalAnnualInterestRateOverdraft = null;
|
||||
final BigDecimal minOverdraftForInterestCalculation = null;
|
||||
final BigDecimal minRequiredBalance = null;
|
||||
final boolean enforceMinRequiredBalance = false;
|
||||
final BigDecimal minBalanceForInterestCalculation = null;
|
||||
@@ -341,7 +353,8 @@ public class SavingsAccountData {
|
||||
fieldOfficerOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions,
|
||||
interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions,
|
||||
withdrawalFeeTypeOptions, charges, chargeOptions, allowOverdraft, overdraftLimit, minRequiredBalance,
|
||||
enforceMinRequiredBalance, minBalanceForInterestCalculation, onHoldFunds);
|
||||
enforceMinRequiredBalance, minBalanceForInterestCalculation, onHoldFunds,
|
||||
nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation);
|
||||
}
|
||||
|
||||
private SavingsAccountData(final Long id, final String accountNo, final EnumOptionData depositType, final String externalId,
|
||||
@@ -361,7 +374,8 @@ public class SavingsAccountData {
|
||||
final Collection<EnumOptionData> lockinPeriodFrequencyTypeOptions, final Collection<EnumOptionData> withdrawalFeeTypeOptions,
|
||||
final Collection<SavingsAccountChargeData> charges, final Collection<ChargeData> chargeOptions, final boolean allowOverdraft,
|
||||
final BigDecimal overdraftLimit, final BigDecimal minRequiredBalance, final boolean enforceMinRequiredBalance,
|
||||
final BigDecimal minBalanceForInterestCalculation, final BigDecimal onHoldFunds) {
|
||||
final BigDecimal minBalanceForInterestCalculation, final BigDecimal onHoldFunds,
|
||||
final BigDecimal nominalAnnualInterestRateOverdraft, final BigDecimal minOverdraftForInterestCalculation) {
|
||||
this.id = id;
|
||||
this.accountNo = accountNo;
|
||||
this.depositType = depositType;
|
||||
@@ -413,6 +427,8 @@ public class SavingsAccountData {
|
||||
this.annualFee = getAnnualFee();
|
||||
this.allowOverdraft = allowOverdraft;
|
||||
this.overdraftLimit = overdraftLimit;
|
||||
this.nominalAnnualInterestRateOverdraft = nominalAnnualInterestRateOverdraft;
|
||||
this.minOverdraftForInterestCalculation = minOverdraftForInterestCalculation;
|
||||
this.minRequiredBalance = minRequiredBalance;
|
||||
this.enforceMinRequiredBalance = enforceMinRequiredBalance;
|
||||
this.minBalanceForInterestCalculation = minBalanceForInterestCalculation;
|
||||
|
||||
+12
@@ -25,6 +25,8 @@ import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeri
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.minRequiredOpeningBalanceParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.overdraftLimitParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateOverdraftParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.minOverdraftForInterestCalculationParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.productIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.submittedOnDateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName;
|
||||
@@ -389,6 +391,16 @@ public class SavingsAccountDataValidator {
|
||||
baseDataValidator.reset().parameter(overdraftLimitParamName).value(overdraftLimit).ignoreIfNull().zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(nominalAnnualInterestRateOverdraftParamName, element)) {
|
||||
final BigDecimal nominalAnnualInterestRateOverdraft = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(nominalAnnualInterestRateOverdraftParamName, element);
|
||||
baseDataValidator.reset().parameter(nominalAnnualInterestRateOverdraftParamName).value(nominalAnnualInterestRateOverdraft).ignoreIfNull().zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(minOverdraftForInterestCalculationParamName, element)) {
|
||||
final BigDecimal minOverdraftForInterestCalculation = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minOverdraftForInterestCalculationParamName, element);
|
||||
baseDataValidator.reset().parameter(minOverdraftForInterestCalculationParamName).value(minOverdraftForInterestCalculation).ignoreIfNull().zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void validateForAssignSavingsOfficer(final String json) {
|
||||
|
||||
+3
-1
@@ -25,11 +25,12 @@ public class SavingsAccountSummaryData {
|
||||
private final BigDecimal accountBalance;
|
||||
private final BigDecimal totalFeeCharge;
|
||||
private final BigDecimal totalPenaltyCharge;
|
||||
private final BigDecimal totalOverdraftInterestDerived;
|
||||
|
||||
public SavingsAccountSummaryData(final CurrencyData currency, final BigDecimal totalDeposits, final BigDecimal totalWithdrawals,
|
||||
final BigDecimal totalWithdrawalFees, final BigDecimal totalAnnualFees, final BigDecimal totalInterestEarned,
|
||||
final BigDecimal totalInterestPosted, final BigDecimal accountBalance, final BigDecimal totalFeeCharge,
|
||||
final BigDecimal totalPenaltyCharge) {
|
||||
final BigDecimal totalPenaltyCharge, final BigDecimal totalOverdraftInterestDerived) {
|
||||
this.currency = currency;
|
||||
this.totalDeposits = totalDeposits;
|
||||
this.totalWithdrawals = totalWithdrawals;
|
||||
@@ -40,5 +41,6 @@ public class SavingsAccountSummaryData {
|
||||
this.accountBalance = accountBalance;
|
||||
this.totalFeeCharge = totalFeeCharge;
|
||||
this.totalPenaltyCharge = totalPenaltyCharge;
|
||||
this.totalOverdraftInterestDerived = totalOverdraftInterestDerived;
|
||||
}
|
||||
}
|
||||
+22
-8
@@ -67,6 +67,8 @@ public class SavingsProductData {
|
||||
private final Map<String, List<GLAccountData>> accountingMappingOptions;
|
||||
private final Collection<ChargeData> chargeOptions;
|
||||
private final Collection<ChargeData> penaltyOptions;
|
||||
private final BigDecimal nominalAnnualInterestRateOverdraft;
|
||||
private final BigDecimal minOverdraftForInterestCalculation;
|
||||
|
||||
public static SavingsProductData template(final CurrencyData currency, final EnumOptionData interestCompoundingPeriodType,
|
||||
final EnumOptionData interestPostingPeriodType, final EnumOptionData interestCalculationType,
|
||||
@@ -99,6 +101,9 @@ public class SavingsProductData {
|
||||
final BigDecimal minRequiredBalance = null;
|
||||
final boolean enforceMinRequiredBalance = false;
|
||||
final BigDecimal minBalanceForInterestCalculation = null;
|
||||
final BigDecimal nominalAnnualInterestRateOverdraft = null;
|
||||
final BigDecimal minOverdraftForInterestCalculation = null;
|
||||
|
||||
|
||||
return new SavingsProductData(id, name, shortName, description, currency, nominalAnnualInterestRate, interestCompoundingPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
@@ -108,7 +113,7 @@ public class SavingsProductData {
|
||||
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions, accountingRuleOptions,
|
||||
accountingMappingOptions, charges, chargeOptions, penaltyOptions, feeToIncomeAccountMappings,
|
||||
penaltyToIncomeAccountMappings, allowOverdraft, overdraftLimit, minRequiredBalance, enforceMinRequiredBalance,
|
||||
minBalanceForInterestCalculation);
|
||||
minBalanceForInterestCalculation, nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation);
|
||||
}
|
||||
|
||||
public static SavingsProductData withCharges(final SavingsProductData product, final Collection<ChargeData> charges) {
|
||||
@@ -122,7 +127,8 @@ public class SavingsProductData {
|
||||
product.lockinPeriodFrequencyTypeOptions, product.withdrawalFeeTypeOptions, product.paymentTypeOptions,
|
||||
product.accountingRuleOptions, product.accountingMappingOptions, charges, product.chargeOptions, product.penaltyOptions,
|
||||
product.feeToIncomeAccountMappings, product.penaltyToIncomeAccountMappings, product.allowOverdraft, product.overdraftLimit,
|
||||
product.minRequiredBalance, product.enforceMinRequiredBalance, product.minBalanceForInterestCalculation);
|
||||
product.minRequiredBalance, product.enforceMinRequiredBalance, product.minBalanceForInterestCalculation,
|
||||
product.nominalAnnualInterestRateOverdraft, product.minOverdraftForInterestCalculation);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -151,7 +157,8 @@ public class SavingsProductData {
|
||||
accountingMappingOptions, existingProduct.charges, chargeOptions, penaltyOptions,
|
||||
existingProduct.feeToIncomeAccountMappings, existingProduct.penaltyToIncomeAccountMappings, existingProduct.allowOverdraft,
|
||||
existingProduct.overdraftLimit, existingProduct.minRequiredBalance, existingProduct.enforceMinRequiredBalance,
|
||||
existingProduct.minBalanceForInterestCalculation);
|
||||
existingProduct.minBalanceForInterestCalculation, existingProduct.nominalAnnualInterestRateOverdraft,
|
||||
existingProduct.minOverdraftForInterestCalculation);
|
||||
}
|
||||
|
||||
public static SavingsProductData withAccountingDetails(final SavingsProductData existingProduct,
|
||||
@@ -185,7 +192,8 @@ public class SavingsProductData {
|
||||
accountingMappingOptions, existingProduct.charges, chargeOptions, penaltyOptions, feeToIncomeAccountMappings,
|
||||
penaltyToIncomeAccountMappings, existingProduct.allowOverdraft, existingProduct.overdraftLimit,
|
||||
existingProduct.minRequiredBalance, existingProduct.enforceMinRequiredBalance,
|
||||
existingProduct.minBalanceForInterestCalculation);
|
||||
existingProduct.minBalanceForInterestCalculation, existingProduct.nominalAnnualInterestRateOverdraft,
|
||||
existingProduct.minOverdraftForInterestCalculation);
|
||||
}
|
||||
|
||||
public static SavingsProductData instance(final Long id, final String name, final String shortName, final String description,
|
||||
@@ -194,7 +202,8 @@ public class SavingsProductData {
|
||||
final EnumOptionData interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance,
|
||||
final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType, final boolean withdrawalFeeForTransfers,
|
||||
final EnumOptionData accountingType, final boolean allowOverdraft, final BigDecimal overdraftLimit,
|
||||
final BigDecimal minRequiredBalance, final boolean enforceMinRequiredBalance, final BigDecimal minBalanceForInterestCalculation) {
|
||||
final BigDecimal minRequiredBalance, final boolean enforceMinRequiredBalance, final BigDecimal minBalanceForInterestCalculation,
|
||||
final BigDecimal nominalAnnualInterestRateOverdraft, final BigDecimal minOverdraftForInterestCalculation) {
|
||||
|
||||
final Map<String, Object> accountingMappings = null;
|
||||
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings = null;
|
||||
@@ -223,7 +232,7 @@ public class SavingsProductData {
|
||||
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions, accountingRuleOptions,
|
||||
accountingMappingOptions, charges, chargeOptions, penaltyOptions, feeToIncomeAccountMappings,
|
||||
penaltyToIncomeAccountMappings, allowOverdraft, overdraftLimit, minRequiredBalance, enforceMinRequiredBalance,
|
||||
minBalanceForInterestCalculation);
|
||||
minBalanceForInterestCalculation, nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation);
|
||||
}
|
||||
|
||||
public static SavingsProductData lookup(final Long id, final String name) {
|
||||
@@ -245,6 +254,8 @@ public class SavingsProductData {
|
||||
final Collection<PaymentTypeToGLAccountMapper> paymentChannelToFundSourceMappings = null;
|
||||
final boolean allowOverdraft = false;
|
||||
final BigDecimal overdraftLimit = null;
|
||||
final BigDecimal nominalAnnualInterestRateOverdraft = null;
|
||||
final BigDecimal minOverdraftForInterestCalculation = null;
|
||||
final BigDecimal minRequiredBalance = null;
|
||||
final boolean enforceMinRequiredBalance = false;
|
||||
final BigDecimal minBalanceForInterestCalculation = null;
|
||||
@@ -273,7 +284,7 @@ public class SavingsProductData {
|
||||
lockinPeriodFrequencyTypeOptions, withdrawalFeeTypeOptions, paymentTypeOptions, accountingRuleOptions,
|
||||
accountingMappingOptions, charges, chargeOptions, penaltyOptions, feeToIncomeAccountMappings,
|
||||
penaltyToIncomeAccountMappings, allowOverdraft, overdraftLimit, minRequiredBalance, enforceMinRequiredBalance,
|
||||
minBalanceForInterestCalculation);
|
||||
minBalanceForInterestCalculation, nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation);
|
||||
}
|
||||
|
||||
private SavingsProductData(final Long id, final String name, final String shortName, final String description,
|
||||
@@ -294,7 +305,8 @@ public class SavingsProductData {
|
||||
final Collection<ChargeToGLAccountMapper> feeToIncomeAccountMappings,
|
||||
final Collection<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings, final boolean allowOverdraft,
|
||||
final BigDecimal overdraftLimit, final BigDecimal minRequiredBalance, final boolean enforceMinRequiredBalance,
|
||||
final BigDecimal minBalanceForInterestCalculation) {
|
||||
final BigDecimal minBalanceForInterestCalculation,
|
||||
final BigDecimal nominalAnnualInterestRateOverdraft, final BigDecimal minOverdraftForInterestCalculation) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.shortName = shortName;
|
||||
@@ -342,6 +354,8 @@ public class SavingsProductData {
|
||||
this.minRequiredBalance = minRequiredBalance;
|
||||
this.enforceMinRequiredBalance = enforceMinRequiredBalance;
|
||||
this.minBalanceForInterestCalculation = minBalanceForInterestCalculation;
|
||||
this.nominalAnnualInterestRateOverdraft = nominalAnnualInterestRateOverdraft;
|
||||
this.minOverdraftForInterestCalculation = minOverdraftForInterestCalculation;
|
||||
}
|
||||
|
||||
public boolean hasAccountingEnabled() {
|
||||
|
||||
+12
@@ -25,6 +25,8 @@ import static org.mifosplatform.portfolio.savings.SavingsApiConstants.minRequire
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nameParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.overdraftLimitParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateOverdraftParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.minOverdraftForInterestCalculationParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.shortNameParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName;
|
||||
|
||||
@@ -537,6 +539,16 @@ public class SavingsProductDataValidator {
|
||||
baseDataValidator.reset().parameter(overdraftLimitParamName).value(overdraftLimit).ignoreIfNull().zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(nominalAnnualInterestRateOverdraftParamName, element)) {
|
||||
final BigDecimal nominalAnnualInterestRateOverdraft = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(nominalAnnualInterestRateOverdraftParamName, element);
|
||||
baseDataValidator.reset().parameter(nominalAnnualInterestRateOverdraftParamName).value(nominalAnnualInterestRateOverdraft).ignoreIfNull().zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
if (this.fromApiJsonHelper.parameterExists(minOverdraftForInterestCalculationParamName, element)) {
|
||||
final BigDecimal minOverdraftForInterestCalculation = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minOverdraftForInterestCalculationParamName, element);
|
||||
baseDataValidator.reset().parameter(minOverdraftForInterestCalculationParamName).value(minOverdraftForInterestCalculation).ignoreIfNull().zeroOrPositiveAmount();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+124
-62
@@ -5,7 +5,54 @@
|
||||
*/
|
||||
package org.mifosplatform.portfolio.savings.domain;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.allowOverdraftParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.dueAsOfDateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.enforceMinRequiredBalanceParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.localeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.minRequiredBalanceParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.overdraftLimitParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateOverdraftParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.minOverdraftForInterestCalculationParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.DiscriminatorColumn;
|
||||
import javax.persistence.DiscriminatorType;
|
||||
import javax.persistence.DiscriminatorValue;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Inheritance;
|
||||
import javax.persistence.InheritanceType;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.OrderBy;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
import javax.persistence.Transient;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
import javax.persistence.Version;
|
||||
|
||||
import org.apache.commons.lang.ObjectUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.hibernate.annotations.LazyCollection;
|
||||
@@ -51,50 +98,7 @@ import org.mifosplatform.useradministration.domain.AppUser;
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.DiscriminatorColumn;
|
||||
import javax.persistence.DiscriminatorType;
|
||||
import javax.persistence.DiscriminatorValue;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Inheritance;
|
||||
import javax.persistence.InheritanceType;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.OrderBy;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
import javax.persistence.Transient;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
import javax.persistence.Version;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.SAVINGS_ACCOUNT_RESOURCE_NAME;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.allowOverdraftParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.dueAsOfDateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.enforceMinRequiredBalanceParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.localeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.lockinPeriodFrequencyTypeParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.minRequiredBalanceParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.overdraftLimitParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName;
|
||||
import com.google.gson.JsonArray;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_savings_account", uniqueConstraints = { @UniqueConstraint(columnNames = { "account_no" }, name = "sa_account_no_UNIQUE"),
|
||||
@@ -245,6 +249,12 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
@Column(name = "overdraft_limit", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal overdraftLimit;
|
||||
|
||||
@Column(name = "nominal_annual_interest_rate_overdraft", scale = 6, precision = 19, nullable = true)
|
||||
protected BigDecimal nominalAnnualInterestRateOverdraft;
|
||||
|
||||
@Column(name = "min_overdraft_for_interest_calculation", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal minOverdraftForInterestCalculation;
|
||||
|
||||
@Column(name = "enforce_min_required_balance")
|
||||
private boolean enforceMinRequiredBalance;
|
||||
|
||||
@@ -300,14 +310,15 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType,
|
||||
final boolean withdrawalFeeApplicableForTransfer, final Set<SavingsAccountCharge> savingsAccountCharges,
|
||||
final boolean allowOverdraft, final BigDecimal overdraftLimit, final boolean enforceMinRequiredBalance,
|
||||
final BigDecimal minRequiredBalance) {
|
||||
final BigDecimal minRequiredBalance, final BigDecimal nominalAnnualInterestRateOverdraft,
|
||||
final BigDecimal minOverdraftForInterestCalculation) {
|
||||
|
||||
final SavingsAccountStatusType status = SavingsAccountStatusType.SUBMITTED_AND_PENDING_APPROVAL;
|
||||
return new SavingsAccount(client, group, product, fieldOfficer, accountNo, externalId, status, accountType, submittedOnDate,
|
||||
submittedBy, interestRate, interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType,
|
||||
interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType,
|
||||
withdrawalFeeApplicableForTransfer, savingsAccountCharges, allowOverdraft, overdraftLimit, enforceMinRequiredBalance,
|
||||
minRequiredBalance);
|
||||
minRequiredBalance, nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation);
|
||||
}
|
||||
|
||||
protected SavingsAccount(final Client client, final Group group, final SavingsProduct product, final Staff fieldOfficer,
|
||||
@@ -322,7 +333,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
this(client, group, product, fieldOfficer, accountNo, externalId, status, accountType, submittedOnDate, submittedBy,
|
||||
nominalAnnualInterestRate, interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType,
|
||||
interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType,
|
||||
withdrawalFeeApplicableForTransfer, savingsAccountCharges, allowOverdraft, overdraftLimit, false, null);
|
||||
withdrawalFeeApplicableForTransfer, savingsAccountCharges, allowOverdraft, overdraftLimit, false, null, null, null);
|
||||
}
|
||||
|
||||
protected SavingsAccount(final Client client, final Group group, final SavingsProduct product, final Staff savingsOfficer,
|
||||
@@ -334,7 +345,8 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType,
|
||||
final boolean withdrawalFeeApplicableForTransfer, final Set<SavingsAccountCharge> savingsAccountCharges,
|
||||
final boolean allowOverdraft, final BigDecimal overdraftLimit, final boolean enforceMinRequiredBalance,
|
||||
final BigDecimal minRequiredBalance) {
|
||||
final BigDecimal minRequiredBalance, final BigDecimal nominalAnnualInterestRateOverdraft,
|
||||
final BigDecimal minOverdraftForInterestCalculation) {
|
||||
this.client = client;
|
||||
this.group = group;
|
||||
this.product = product;
|
||||
@@ -371,6 +383,8 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
this.summary = new SavingsAccountSummary();
|
||||
this.allowOverdraft = allowOverdraft;
|
||||
this.overdraftLimit = overdraftLimit;
|
||||
this.nominalAnnualInterestRateOverdraft = nominalAnnualInterestRateOverdraft;
|
||||
this.minOverdraftForInterestCalculation = minOverdraftForInterestCalculation;
|
||||
esnureOverdraftLimitsSetForOverdraftAccounts();
|
||||
|
||||
this.enforceMinRequiredBalance = enforceMinRequiredBalance;
|
||||
@@ -443,16 +457,33 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
|
||||
final SavingsAccountTransaction postingTransaction = findInterestPostingTransactionFor(interestPostingTransactionDate);
|
||||
if (postingTransaction == null) {
|
||||
final SavingsAccountTransaction newPostingTransaction = SavingsAccountTransaction.interestPosting(this, office(),
|
||||
interestPostingTransactionDate, interestEarnedToBePostedForPeriod);
|
||||
SavingsAccountTransaction newPostingTransaction;
|
||||
if(interestEarnedToBePostedForPeriod.isGreaterThanOrEqualTo(Money.zero(currency))){
|
||||
newPostingTransaction = SavingsAccountTransaction.interestPosting(this, office(),
|
||||
interestPostingTransactionDate, interestEarnedToBePostedForPeriod);
|
||||
}else{
|
||||
newPostingTransaction = SavingsAccountTransaction.overdraftInterest(this, office(),
|
||||
interestPostingTransactionDate, interestEarnedToBePostedForPeriod.negated());
|
||||
}
|
||||
this.transactions.add(newPostingTransaction);
|
||||
recalucateDailyBalanceDetails = true;
|
||||
} else {
|
||||
final boolean correctionRequired = postingTransaction.hasNotAmount(interestEarnedToBePostedForPeriod);
|
||||
boolean correctionRequired = false;
|
||||
if(postingTransaction.isInterestPostingAndNotReversed()){
|
||||
correctionRequired = postingTransaction.hasNotAmount(interestEarnedToBePostedForPeriod);
|
||||
}else{
|
||||
correctionRequired = postingTransaction.hasNotAmount(interestEarnedToBePostedForPeriod.negated());
|
||||
}
|
||||
if (correctionRequired) {
|
||||
postingTransaction.reverse();
|
||||
final SavingsAccountTransaction newPostingTransaction = SavingsAccountTransaction.interestPosting(this, office(),
|
||||
interestPostingTransactionDate, interestEarnedToBePostedForPeriod);
|
||||
SavingsAccountTransaction newPostingTransaction;
|
||||
if(interestEarnedToBePostedForPeriod.isGreaterThanOrEqualTo(Money.zero(currency))){
|
||||
newPostingTransaction = SavingsAccountTransaction.interestPosting(this, office(),
|
||||
interestPostingTransactionDate, interestEarnedToBePostedForPeriod);
|
||||
}else{
|
||||
newPostingTransaction = SavingsAccountTransaction.overdraftInterest(this, office(),
|
||||
interestPostingTransactionDate, interestEarnedToBePostedForPeriod.negated());
|
||||
}
|
||||
this.transactions.add(newPostingTransaction);
|
||||
recalucateDailyBalanceDetails = true;
|
||||
}
|
||||
@@ -479,7 +510,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
SavingsAccountTransaction postingTransation = null;
|
||||
|
||||
for (final SavingsAccountTransaction transaction : this.transactions) {
|
||||
if (transaction.isInterestPostingAndNotReversed() && transaction.occursOn(postingDate)) {
|
||||
if ((transaction.isInterestPostingAndNotReversed() || transaction.isOverdraftInterestAndNotReversed()) && transaction.occursOn(postingDate)) {
|
||||
postingTransation = transaction;
|
||||
break;
|
||||
}
|
||||
@@ -575,15 +606,18 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
|
||||
final SavingsInterestCalculationType interestCalculationType = SavingsInterestCalculationType.fromInt(this.interestCalculationType);
|
||||
final BigDecimal interestRateAsFraction = getEffectiveInterestRateAsFraction(mc, upToInterestCalculationDate);
|
||||
final BigDecimal overdraftInterestRateAsFraction = getEffectiveOverdraftInterestRateAsFraction(mc);
|
||||
final Collection<Long> interestPostTransactions = this.savingsHelper.fetchPostInterestTransactionIds(getId());
|
||||
final Money minBalanceForInterestCalculation = Money.of(getCurrency(), minBalanceForInterestCalculation());
|
||||
final Money minOverdraftForInterestCalculation = Money.of(getCurrency(), this.minOverdraftForInterestCalculation);
|
||||
|
||||
for (final LocalDateInterval periodInterval : postingPeriodIntervals) {
|
||||
|
||||
final PostingPeriod postingPeriod = PostingPeriod.createFrom(periodInterval, periodStartingBalance,
|
||||
retreiveOrderedNonInterestPostingTransactions(), this.currency, compoundingPeriodType, interestCalculationType,
|
||||
interestRateAsFraction, daysInYearType.getValue(), upToInterestCalculationDate, interestPostTransactions,
|
||||
isInterestTransfer, minBalanceForInterestCalculation, isSavingsInterestPostingAtCurrentPeriodEnd);
|
||||
isInterestTransfer, minBalanceForInterestCalculation, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
overdraftInterestRateAsFraction, minOverdraftForInterestCalculation);
|
||||
|
||||
periodStartingBalance = postingPeriod.closingBalance();
|
||||
|
||||
@@ -599,7 +633,11 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
return allPostingPeriods;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private BigDecimal getEffectiveOverdraftInterestRateAsFraction(MathContext mc) {
|
||||
return this.nominalAnnualInterestRateOverdraft.divide(BigDecimal.valueOf(100l), mc);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
protected BigDecimal getEffectiveInterestRateAsFraction(final MathContext mc, final LocalDate upToInterestCalculationDate) {
|
||||
return this.nominalAnnualInterestRate.divide(BigDecimal.valueOf(100l), mc);
|
||||
}
|
||||
@@ -610,7 +648,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
final List<SavingsAccountTransaction> orderedNonInterestPostingTransactions = new ArrayList<>();
|
||||
|
||||
for (final SavingsAccountTransaction transaction : listOfTransactionsSorted) {
|
||||
if (!transaction.isInterestPostingAndNotReversed() && transaction.isNotReversed()) {
|
||||
if (!(transaction.isInterestPostingAndNotReversed() || transaction.isOverdraftInterestAndNotReversed()) && transaction.isNotReversed()) {
|
||||
orderedNonInterestPostingTransactions.add(transaction);
|
||||
}
|
||||
}
|
||||
@@ -689,7 +727,9 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
LocalDate endOfBalanceDate = interestPostingUpToDate;
|
||||
for (int i = accountTransactionsSorted.size() - 1; i >= 0; i--) {
|
||||
final SavingsAccountTransaction transaction = accountTransactionsSorted.get(i);
|
||||
if (transaction.isNotReversed() && !transaction.isInterestPostingAndNotReversed()) {
|
||||
if (transaction.isNotReversed()
|
||||
&& !(transaction.isInterestPostingAndNotReversed()
|
||||
|| transaction.isOverdraftInterestAndNotReversed())) {
|
||||
transaction.updateCumulativeBalanceAndDates(this.currency, endOfBalanceDate);
|
||||
// this transactions transaction date is end of balance date for
|
||||
// previous transaction.
|
||||
@@ -848,7 +888,7 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
boolean transactionBeforeLastInterestPosting = false;
|
||||
|
||||
for (final SavingsAccountTransaction transaction : retreiveListOfTransactions()) {
|
||||
if (transaction.isInterestPostingAndNotReversed() && transaction.isAfter(transactionDate)) {
|
||||
if ((transaction.isInterestPostingAndNotReversed() || transaction.isOverdraftInterestAndNotReversed()) && transaction.isAfter(transactionDate)) {
|
||||
transactionBeforeLastInterestPosting = true;
|
||||
break;
|
||||
}
|
||||
@@ -1132,8 +1172,24 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
this.overdraftLimit = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInBigDecimalParameterNamedDefaultingZeroToNull(nominalAnnualInterestRateOverdraftParamName, this.nominalAnnualInterestRateOverdraft)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(nominalAnnualInterestRateOverdraftParamName);
|
||||
actualChanges.put(nominalAnnualInterestRateOverdraftParamName, newValue);
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
this.nominalAnnualInterestRateOverdraft = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInBigDecimalParameterNamedDefaultingZeroToNull(minOverdraftForInterestCalculationParamName, this.minOverdraftForInterestCalculation)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(minOverdraftForInterestCalculationParamName);
|
||||
actualChanges.put(minOverdraftForInterestCalculationParamName, newValue);
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
this.minOverdraftForInterestCalculation = newValue;
|
||||
}
|
||||
|
||||
if (!this.allowOverdraft) {
|
||||
this.overdraftLimit = null;
|
||||
this.nominalAnnualInterestRateOverdraft = null;
|
||||
this.minOverdraftForInterestCalculation = null;
|
||||
}
|
||||
|
||||
if (command.isChangeInBooleanParameterNamed(enforceMinRequiredBalanceParamName, this.enforceMinRequiredBalance)) {
|
||||
@@ -1159,8 +1215,10 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
**/
|
||||
private void esnureOverdraftLimitsSetForOverdraftAccounts() {
|
||||
|
||||
if (this.allowOverdraft && this.overdraftLimit == null) {
|
||||
this.overdraftLimit = BigDecimal.ZERO;
|
||||
if (this.allowOverdraft) {
|
||||
this.overdraftLimit = this.overdraftLimit == null? BigDecimal.ZERO : this.overdraftLimit;
|
||||
this.nominalAnnualInterestRateOverdraft = this.nominalAnnualInterestRateOverdraft == null? BigDecimal.ZERO : this.nominalAnnualInterestRateOverdraft;
|
||||
this.minOverdraftForInterestCalculation = this.minOverdraftForInterestCalculation == null? BigDecimal.ZERO : this.minOverdraftForInterestCalculation;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1531,6 +1589,10 @@ public class SavingsAccount extends AbstractPersistable<Long> {
|
||||
return this.nominalAnnualInterestRate;
|
||||
}
|
||||
|
||||
public BigDecimal getNominalAnnualInterestRateOverdraft() {
|
||||
return this.nominalAnnualInterestRateOverdraft;
|
||||
}
|
||||
|
||||
public Map<String, Object> approveApplication(final AppUser currentUser, final JsonCommand command, final LocalDate tenantsTodayDate) {
|
||||
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<>();
|
||||
|
||||
+20
-2
@@ -23,6 +23,8 @@ import static org.mifosplatform.portfolio.savings.SavingsApiConstants.minRequire
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.minRequiredOpeningBalanceParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.overdraftLimitParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateOverdraftParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.minOverdraftForInterestCalculationParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.productIdParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.submittedOnDateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName;
|
||||
@@ -223,6 +225,20 @@ public class SavingsAccountAssembler {
|
||||
overdraftLimit = product.overdraftLimit();
|
||||
}
|
||||
|
||||
BigDecimal nominalAnnualInterestRateOverdraft = BigDecimal.ZERO;
|
||||
if (command.parameterExists(nominalAnnualInterestRateOverdraftParamName)) {
|
||||
nominalAnnualInterestRateOverdraft = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(nominalAnnualInterestRateOverdraftParamName);
|
||||
} else {
|
||||
nominalAnnualInterestRateOverdraft = product.nominalAnnualInterestRateOverdraft();
|
||||
}
|
||||
|
||||
BigDecimal minOverdraftForInterestCalculation = BigDecimal.ZERO;
|
||||
if (command.parameterExists(minOverdraftForInterestCalculationParamName)) {
|
||||
minOverdraftForInterestCalculation = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(minOverdraftForInterestCalculationParamName);
|
||||
} else {
|
||||
minOverdraftForInterestCalculation = product.minOverdraftForInterestCalculation();
|
||||
}
|
||||
|
||||
boolean enforceMinRequiredBalance = false;
|
||||
if (command.parameterExists(enforceMinRequiredBalanceParamName)) {
|
||||
enforceMinRequiredBalance = command.booleanPrimitiveValueOfParameterNamed(enforceMinRequiredBalanceParamName);
|
||||
@@ -241,7 +257,8 @@ public class SavingsAccountAssembler {
|
||||
externalId, accountType, submittedOnDate, submittedBy, interestRate, interestCompoundingPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, iswithdrawalFeeApplicableForTransfer, charges, allowOverdraft,
|
||||
overdraftLimit, enforceMinRequiredBalance, minRequiredBalance);
|
||||
overdraftLimit, enforceMinRequiredBalance, minRequiredBalance,
|
||||
nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation);
|
||||
account.setHelpers(this.savingsAccountTransactionSummaryWrapper, this.savingsHelper);
|
||||
|
||||
account.validateNewApplicationState(DateUtils.getLocalDateOfTenant(), SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||
@@ -295,7 +312,8 @@ public class SavingsAccountAssembler {
|
||||
product.interestPostingPeriodType(), product.interestCalculationType(), product.interestCalculationDaysInYearType(),
|
||||
product.minRequiredOpeningBalance(), product.lockinPeriodFrequency(), product.lockinPeriodFrequencyType(),
|
||||
product.isWithdrawalFeeApplicableForTransfer(), charges, product.isAllowOverdraft(), product.overdraftLimit(),
|
||||
product.isMinRequiredBalanceEnforced(), product.minRequiredBalance());
|
||||
product.isMinRequiredBalanceEnforced(), product.minRequiredBalance(), product.nominalAnnualInterestRateOverdraft(),
|
||||
product.minOverdraftForInterestCalculation());
|
||||
account.setHelpers(this.savingsAccountTransactionSummaryWrapper, this.savingsHelper);
|
||||
|
||||
account.validateNewApplicationState(DateUtils.getLocalDateOfTenant(), SAVINGS_ACCOUNT_RESOURCE_NAME);
|
||||
|
||||
+5
-1
@@ -57,6 +57,9 @@ public final class SavingsAccountSummary {
|
||||
@Transient
|
||||
private BigDecimal totalPenaltyChargesWaived = BigDecimal.ZERO;
|
||||
|
||||
@Column(name = "total_overdraft_interest_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalOverdraftInterestDerived;
|
||||
|
||||
protected SavingsAccountSummary() {
|
||||
//
|
||||
}
|
||||
@@ -73,10 +76,11 @@ public final class SavingsAccountSummary {
|
||||
this.totalPenaltyCharge = wrapper.calculateTotalPenaltyCharge(currency, transactions);
|
||||
this.totalFeeChargesWaived = wrapper.calculateTotalFeesChargeWaived(currency, transactions);
|
||||
this.totalPenaltyChargesWaived = wrapper.calculateTotalPenaltyChargeWaived(currency, transactions);
|
||||
this.totalOverdraftInterestDerived = wrapper.calculateTotalOverdraftInterest(currency, transactions);
|
||||
|
||||
this.accountBalance = Money.of(currency, this.totalDeposits).plus(this.totalInterestPosted).minus(this.totalWithdrawals)
|
||||
.minus(this.totalWithdrawalFees).minus(this.totalAnnualFees).minus(this.totalFeeCharge).minus(this.totalPenaltyCharge)
|
||||
.getAmount();
|
||||
.minus(totalOverdraftInterestDerived).getAmount();
|
||||
}
|
||||
|
||||
public void updateFromInterestPeriodSummaries(final MonetaryCurrency currency, final List<PostingPeriod> allPostingPeriods) {
|
||||
|
||||
+19
-3
@@ -129,7 +129,14 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
|
||||
amount, isReversed, null);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction withdrawalFee(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
|
||||
public static SavingsAccountTransaction overdraftInterest(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
|
||||
final Money amount) {
|
||||
final boolean isReversed = false;
|
||||
return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.OVERDRAFT_INTEREST.getValue(), date,
|
||||
amount, isReversed, null);
|
||||
}
|
||||
|
||||
public static SavingsAccountTransaction withdrawalFee(final SavingsAccount savingsAccount, final Office office, final LocalDate date,
|
||||
final Money amount, final AppUser appUser) {
|
||||
final boolean isReversed = false;
|
||||
return new SavingsAccountTransaction(savingsAccount, office, SavingsAccountTransactionType.WITHDRAWAL_FEE.getValue(), date, amount,
|
||||
@@ -505,10 +512,18 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
public boolean isDebit() {
|
||||
return isWithdrawal() || isWithdrawalFeeAndNotReversed() || isAnnualFeeAndNotReversed() || isPayCharge();
|
||||
return isWithdrawal()
|
||||
|| isWithdrawalFeeAndNotReversed()
|
||||
|| isAnnualFeeAndNotReversed()
|
||||
|| isPayCharge()
|
||||
|| isOverdraftInterestAndNotReversed();
|
||||
}
|
||||
|
||||
public boolean isPayCharge() {
|
||||
public boolean isOverdraftInterestAndNotReversed() {
|
||||
return SavingsAccountTransactionType.fromInt(this.typeOf).isIncomeFromInterest() && isNotReversed();
|
||||
}
|
||||
|
||||
public boolean isPayCharge() {
|
||||
return SavingsAccountTransactionType.fromInt(this.typeOf).isPayCharge();
|
||||
}
|
||||
|
||||
@@ -608,4 +623,5 @@ public final class SavingsAccountTransaction extends AbstractPersistable<Long> {
|
||||
public BigDecimal getAmount() {
|
||||
return this.amount;
|
||||
}
|
||||
|
||||
}
|
||||
+11
@@ -109,4 +109,15 @@ public final class SavingsAccountTransactionSummaryWrapper {
|
||||
return total.getAmountDefaultedToNullIfZero();
|
||||
}
|
||||
|
||||
public BigDecimal calculateTotalOverdraftInterest(MonetaryCurrency currency,
|
||||
List<SavingsAccountTransaction> transactions) {
|
||||
Money total = Money.zero(currency);
|
||||
for (final SavingsAccountTransaction transaction : transactions) {
|
||||
if (transaction.isOverdraftInterestAndNotReversed()) {
|
||||
total = total.plus(transaction.getAmount(currency));
|
||||
}
|
||||
}
|
||||
return total.getAmountDefaultedToNullIfZero();
|
||||
}
|
||||
|
||||
}
|
||||
+46
-6
@@ -27,6 +27,8 @@ import static org.mifosplatform.portfolio.savings.SavingsApiConstants.minRequire
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nameParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.overdraftLimitParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateOverdraftParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.minOverdraftForInterestCalculationParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.shortNameParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName;
|
||||
|
||||
@@ -150,6 +152,12 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
@Column(name = "overdraft_limit", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal overdraftLimit;
|
||||
|
||||
@Column(name = "nominal_annual_interest_rate_overdraft", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal nominalAnnualInterestRateOverdraft;
|
||||
|
||||
@Column(name = "min_overdraft_for_interest_calculation", scale = 6, precision = 19, nullable = true)
|
||||
private BigDecimal minOverdraftForInterestCalculation;
|
||||
|
||||
@Column(name = "enforce_min_required_balance")
|
||||
private boolean enforceMinRequiredBalance;
|
||||
|
||||
@@ -167,12 +175,14 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType,
|
||||
final boolean withdrawalFeeApplicableForTransfer, final AccountingRuleType accountingRuleType, final Set<Charge> charges,
|
||||
final boolean allowOverdraft, final BigDecimal overdraftLimit, final boolean enforceMinRequiredBalance,
|
||||
final BigDecimal minRequiredBalance, final BigDecimal minBalanceForInterestCalculation) {
|
||||
final BigDecimal minRequiredBalance, final BigDecimal minBalanceForInterestCalculation,
|
||||
final BigDecimal nominalAnnualInterestRateOverdraft, final BigDecimal minOverdraftForInterestCalculation) {
|
||||
|
||||
return new SavingsProduct(name, shortName, description, currency, interestRate, interestCompoundingPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeApplicableForTransfer, accountingRuleType, charges,
|
||||
allowOverdraft, overdraftLimit, enforceMinRequiredBalance, minRequiredBalance, minBalanceForInterestCalculation);
|
||||
allowOverdraft, overdraftLimit, enforceMinRequiredBalance, minRequiredBalance, minBalanceForInterestCalculation,
|
||||
nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation);
|
||||
}
|
||||
|
||||
protected SavingsProduct() {
|
||||
@@ -190,7 +200,7 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
this(name, shortName, description, currency, interestRate, interestCompoundingPeriodType, interestPostingPeriodType,
|
||||
interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency,
|
||||
lockinPeriodFrequencyType, withdrawalFeeApplicableForTransfer, accountingRuleType, charges, allowOverdraft, overdraftLimit,
|
||||
false, null, minBalanceForInterestCalculation);
|
||||
false, null, minBalanceForInterestCalculation, null, null);
|
||||
}
|
||||
|
||||
protected SavingsProduct(final String name, final String shortName, final String description, final MonetaryCurrency currency,
|
||||
@@ -200,7 +210,8 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType,
|
||||
final boolean withdrawalFeeApplicableForTransfer, final AccountingRuleType accountingRuleType, final Set<Charge> charges,
|
||||
final boolean allowOverdraft, final BigDecimal overdraftLimit, final boolean enforceMinRequiredBalance,
|
||||
final BigDecimal minRequiredBalance, BigDecimal minBalanceForInterestCalculation) {
|
||||
final BigDecimal minRequiredBalance, BigDecimal minBalanceForInterestCalculation,
|
||||
final BigDecimal nominalAnnualInterestRateOverdraft, final BigDecimal minOverdraftForInterestCalculation) {
|
||||
|
||||
this.name = name;
|
||||
this.shortName = shortName;
|
||||
@@ -235,6 +246,8 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
validateLockinDetails();
|
||||
this.allowOverdraft = allowOverdraft;
|
||||
this.overdraftLimit = overdraftLimit;
|
||||
this.nominalAnnualInterestRateOverdraft = nominalAnnualInterestRateOverdraft;
|
||||
this.minOverdraftForInterestCalculation = minOverdraftForInterestCalculation;
|
||||
|
||||
esnureOverdraftLimitsSetForOverdraftAccounts();
|
||||
|
||||
@@ -249,8 +262,10 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
**/
|
||||
private void esnureOverdraftLimitsSetForOverdraftAccounts() {
|
||||
|
||||
if (this.allowOverdraft && this.overdraftLimit() == null) {
|
||||
this.overdraftLimit = BigDecimal.ZERO;
|
||||
if (this.allowOverdraft) {
|
||||
this.overdraftLimit = this.overdraftLimit == null? BigDecimal.ZERO : this.overdraftLimit;
|
||||
this.nominalAnnualInterestRateOverdraft = this.nominalAnnualInterestRateOverdraft == null? BigDecimal.ZERO : this.nominalAnnualInterestRateOverdraft;
|
||||
this.minOverdraftForInterestCalculation = this.minOverdraftForInterestCalculation == null? BigDecimal.ZERO : this.minOverdraftForInterestCalculation;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -434,8 +449,25 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
this.overdraftLimit = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInBigDecimalParameterNamedDefaultingZeroToNull(nominalAnnualInterestRateOverdraftParamName, this.nominalAnnualInterestRateOverdraft)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(nominalAnnualInterestRateOverdraftParamName);
|
||||
actualChanges.put(nominalAnnualInterestRateOverdraftParamName, newValue);
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
this.nominalAnnualInterestRateOverdraft = newValue;
|
||||
}
|
||||
|
||||
if (command.isChangeInBigDecimalParameterNamedDefaultingZeroToNull(minOverdraftForInterestCalculationParamName, this.minOverdraftForInterestCalculation)) {
|
||||
final BigDecimal newValue = command.bigDecimalValueOfParameterNamedDefaultToNullIfZero(minOverdraftForInterestCalculationParamName);
|
||||
actualChanges.put(minOverdraftForInterestCalculationParamName, newValue);
|
||||
actualChanges.put(localeParamName, localeAsInput);
|
||||
this.minOverdraftForInterestCalculation = newValue;
|
||||
}
|
||||
|
||||
if (!this.allowOverdraft) {
|
||||
this.overdraftLimit = null;
|
||||
this.nominalAnnualInterestRateOverdraft = null;
|
||||
this.minOverdraftForInterestCalculation = null;
|
||||
}
|
||||
|
||||
if (command.isChangeInBooleanParameterNamed(enforceMinRequiredBalanceParamName, this.enforceMinRequiredBalance)) {
|
||||
@@ -571,4 +603,12 @@ public class SavingsProduct extends AbstractPersistable<Long> {
|
||||
return this.shortName;
|
||||
}
|
||||
|
||||
public BigDecimal nominalAnnualInterestRateOverdraft() {
|
||||
return this.nominalAnnualInterestRateOverdraft;
|
||||
}
|
||||
|
||||
public BigDecimal minOverdraftForInterestCalculation() {
|
||||
return this.minOverdraftForInterestCalculation;
|
||||
}
|
||||
|
||||
}
|
||||
+14
-1
@@ -25,6 +25,8 @@ import static org.mifosplatform.portfolio.savings.SavingsApiConstants.minRequire
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nameParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.overdraftLimitParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.nominalAnnualInterestRateOverdraftParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.minOverdraftForInterestCalculationParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.shortNameParamName;
|
||||
import static org.mifosplatform.portfolio.savings.SavingsApiConstants.withdrawalFeeForTransfersParamName;
|
||||
|
||||
@@ -128,6 +130,16 @@ public class SavingsProductAssembler {
|
||||
overdraftLimit = command.bigDecimalValueOfParameterNamed(overdraftLimitParamName);
|
||||
}
|
||||
|
||||
BigDecimal nominalAnnualInterestRateOverdraft = BigDecimal.ZERO;
|
||||
if(command.parameterExists(nominalAnnualInterestRateOverdraftParamName)){
|
||||
nominalAnnualInterestRateOverdraft = command.bigDecimalValueOfParameterNamed(nominalAnnualInterestRateOverdraftParamName);
|
||||
}
|
||||
|
||||
BigDecimal minOverdraftForInterestCalculation = BigDecimal.ZERO;
|
||||
if(command.parameterExists(minOverdraftForInterestCalculationParamName)){
|
||||
minOverdraftForInterestCalculation = command.bigDecimalValueOfParameterNamed(minOverdraftForInterestCalculationParamName);
|
||||
}
|
||||
|
||||
boolean enforceMinRequiredBalance = false;
|
||||
if (command.parameterExists(enforceMinRequiredBalanceParamName)) {
|
||||
enforceMinRequiredBalance = command.booleanPrimitiveValueOfParameterNamed(enforceMinRequiredBalanceParamName);
|
||||
@@ -143,7 +155,8 @@ public class SavingsProductAssembler {
|
||||
return SavingsProduct.createNew(name, shortName, description, currency, interestRate, interestCompoundingPeriodType,
|
||||
interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance,
|
||||
lockinPeriodFrequency, lockinPeriodFrequencyType, iswithdrawalFeeApplicableForTransfer, accountingRuleType, charges,
|
||||
allowOverdraft, overdraftLimit, enforceMinRequiredBalance, minRequiredBalance, minBalanceForInterestCalculation);
|
||||
allowOverdraft, overdraftLimit, enforceMinRequiredBalance, minRequiredBalance, minBalanceForInterestCalculation,
|
||||
nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation);
|
||||
}
|
||||
|
||||
public Set<Charge> assembleListOfSavingsProductCharges(final JsonCommand command, final String savingsProductCurrencyCode) {
|
||||
|
||||
+29
-17
@@ -7,7 +7,6 @@ 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;
|
||||
|
||||
@@ -35,18 +34,19 @@ public class AnnualCompoundingPeriod implements CompoundingPeriod {
|
||||
@Override
|
||||
public BigDecimal calculateInterest(final SavingsCompoundingInterestPeriodType compoundingInterestPeriodType,
|
||||
final SavingsInterestCalculationType interestCalculationType, final BigDecimal interestToCompound,
|
||||
final BigDecimal interestRateAsFraction, final long daysInYear, final BigDecimal minBalanceForInterestCalculation) {
|
||||
final BigDecimal interestRateAsFraction, final long daysInYear, final BigDecimal minBalanceForInterestCalculation,
|
||||
final BigDecimal overdraftInterestRateAsFraction, final BigDecimal minOverdraftForInterestCalculation) {
|
||||
|
||||
BigDecimal interestEarned = BigDecimal.ZERO;
|
||||
|
||||
switch (interestCalculationType) {
|
||||
case DAILY_BALANCE:
|
||||
interestEarned = calculateUsingDailyBalanceMethod(compoundingInterestPeriodType, interestToCompound, interestRateAsFraction,
|
||||
daysInYear, minBalanceForInterestCalculation);
|
||||
daysInYear, minBalanceForInterestCalculation, overdraftInterestRateAsFraction, minOverdraftForInterestCalculation);
|
||||
break;
|
||||
case AVERAGE_DAILY_BALANCE:
|
||||
interestEarned = calculateUsingAverageDailyBalanceMethod(interestToCompound, interestRateAsFraction, daysInYear,
|
||||
minBalanceForInterestCalculation);
|
||||
minBalanceForInterestCalculation, overdraftInterestRateAsFraction, minOverdraftForInterestCalculation);
|
||||
break;
|
||||
case INVALID:
|
||||
break;
|
||||
@@ -56,7 +56,8 @@ public class AnnualCompoundingPeriod implements CompoundingPeriod {
|
||||
}
|
||||
|
||||
private BigDecimal calculateUsingAverageDailyBalanceMethod(final BigDecimal interestToCompound, final BigDecimal interestRateAsFraction,
|
||||
final long daysInYear, final BigDecimal minBalanceForInterestCalculation) {
|
||||
final long daysInYear, final BigDecimal minBalanceForInterestCalculation, final BigDecimal overdraftInterestRateAsFraction,
|
||||
final BigDecimal minOverdraftForInterestCalculation) {
|
||||
|
||||
BigDecimal cumulativeBalance = BigDecimal.ZERO;
|
||||
Integer numberOfDays = Integer.valueOf(0);
|
||||
@@ -74,12 +75,22 @@ public class AnnualCompoundingPeriod implements CompoundingPeriod {
|
||||
final BigDecimal averageDailyBalance = cumulativeBalance.divide(BigDecimal.valueOf(numberOfDays), MathContext.DECIMAL64)
|
||||
.setScale(9, MoneyHelper.getRoundingMode());
|
||||
|
||||
final BigDecimal multiplicand = BigDecimal.ONE.divide(BigDecimal.valueOf(daysInYear), MathContext.DECIMAL64);
|
||||
final BigDecimal dailyInterestRate = interestRateAsFraction.multiply(multiplicand, MathContext.DECIMAL64);
|
||||
final BigDecimal periodicInterestRate = dailyInterestRate.multiply(BigDecimal.valueOf(numberOfDays), MathContext.DECIMAL64);
|
||||
if (averageDailyBalance.compareTo(minBalanceForInterestCalculation) >= 0) {
|
||||
interestEarned = averageDailyBalance.multiply(periodicInterestRate, MathContext.DECIMAL64).setScale(9,
|
||||
MoneyHelper.getRoundingMode());
|
||||
if(averageDailyBalance.compareTo(BigDecimal.ZERO) >= 0){
|
||||
if (averageDailyBalance.compareTo(minBalanceForInterestCalculation) >= 0) {
|
||||
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,
|
||||
MoneyHelper.getRoundingMode());
|
||||
}
|
||||
}else{
|
||||
if (averageDailyBalance.compareTo(minOverdraftForInterestCalculation.negate()) < 0) {
|
||||
final BigDecimal multiplicand = BigDecimal.ONE.divide(BigDecimal.valueOf(daysInYear), MathContext.DECIMAL64);
|
||||
final BigDecimal dailyInterestRate = overdraftInterestRateAsFraction.multiply(multiplicand, MathContext.DECIMAL64);
|
||||
final BigDecimal periodicInterestRate = dailyInterestRate.multiply(BigDecimal.valueOf(numberOfDays), MathContext.DECIMAL64);
|
||||
interestEarned = averageDailyBalance.multiply(periodicInterestRate, MathContext.DECIMAL64).setScale(9,
|
||||
MoneyHelper.getRoundingMode());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +99,8 @@ public class AnnualCompoundingPeriod implements CompoundingPeriod {
|
||||
|
||||
private BigDecimal calculateUsingDailyBalanceMethod(final SavingsCompoundingInterestPeriodType compoundingInterestPeriodType,
|
||||
final BigDecimal interestToCompound, final BigDecimal interestRateAsFraction, final long daysInYear,
|
||||
final BigDecimal minBalanceForInterestCalculation) {
|
||||
final BigDecimal minBalanceForInterestCalculation, final BigDecimal overdraftInterestRateAsFraction,
|
||||
final BigDecimal minOverdraftForInterestCalculation) {
|
||||
|
||||
BigDecimal interestEarned = BigDecimal.ZERO;
|
||||
BigDecimal interestOnBalanceUnrounded = BigDecimal.ZERO;
|
||||
@@ -97,15 +109,15 @@ public class AnnualCompoundingPeriod implements CompoundingPeriod {
|
||||
switch (compoundingInterestPeriodType) {
|
||||
case DAILY:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalanceAndInterest(interestToCompound, interestRateAsFraction,
|
||||
daysInYear, minBalanceForInterestCalculation);
|
||||
daysInYear, minBalanceForInterestCalculation, overdraftInterestRateAsFraction, minOverdraftForInterestCalculation);
|
||||
break;
|
||||
case MONTHLY:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalance(interestToCompound, interestRateAsFraction, daysInYear,
|
||||
minBalanceForInterestCalculation);
|
||||
minBalanceForInterestCalculation, overdraftInterestRateAsFraction, minOverdraftForInterestCalculation);
|
||||
break;
|
||||
case QUATERLY:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalance(interestToCompound, interestRateAsFraction, daysInYear,
|
||||
minBalanceForInterestCalculation);
|
||||
minBalanceForInterestCalculation, overdraftInterestRateAsFraction, minOverdraftForInterestCalculation);
|
||||
break;
|
||||
// case WEEKLY:
|
||||
// break;
|
||||
@@ -113,11 +125,11 @@ public class AnnualCompoundingPeriod implements CompoundingPeriod {
|
||||
// break;
|
||||
case BI_ANNUAL:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalance(interestToCompound, interestRateAsFraction, daysInYear,
|
||||
minBalanceForInterestCalculation);
|
||||
minBalanceForInterestCalculation, overdraftInterestRateAsFraction, minOverdraftForInterestCalculation);
|
||||
break;
|
||||
case ANNUAL:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalance(interestToCompound, interestRateAsFraction, daysInYear,
|
||||
minBalanceForInterestCalculation);
|
||||
minBalanceForInterestCalculation, overdraftInterestRateAsFraction, minOverdraftForInterestCalculation);
|
||||
break;
|
||||
// case NO_COMPOUNDING_SIMPLE_INTEREST:
|
||||
// break;
|
||||
|
||||
+29
-17
@@ -7,7 +7,6 @@ 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;
|
||||
|
||||
@@ -35,18 +34,19 @@ public class BiAnnualCompoundingPeriod implements CompoundingPeriod {
|
||||
@Override
|
||||
public BigDecimal calculateInterest(final SavingsCompoundingInterestPeriodType compoundingInterestPeriodType,
|
||||
final SavingsInterestCalculationType interestCalculationType, final BigDecimal interestToCompound,
|
||||
final BigDecimal interestRateAsFraction, final long daysInYear, final BigDecimal minBalanceForInterestCalculation) {
|
||||
final BigDecimal interestRateAsFraction, final long daysInYear, final BigDecimal minBalanceForInterestCalculation,
|
||||
final BigDecimal overdraftInterestRateAsFraction, final BigDecimal minOverdraftForInterestCalculation) {
|
||||
|
||||
BigDecimal interestEarned = BigDecimal.ZERO;
|
||||
|
||||
switch (interestCalculationType) {
|
||||
case DAILY_BALANCE:
|
||||
interestEarned = calculateUsingDailyBalanceMethod(compoundingInterestPeriodType, interestToCompound, interestRateAsFraction,
|
||||
daysInYear, minBalanceForInterestCalculation);
|
||||
daysInYear, minBalanceForInterestCalculation, overdraftInterestRateAsFraction, minOverdraftForInterestCalculation);
|
||||
break;
|
||||
case AVERAGE_DAILY_BALANCE:
|
||||
interestEarned = calculateUsingAverageDailyBalanceMethod(interestToCompound, interestRateAsFraction, daysInYear,
|
||||
minBalanceForInterestCalculation);
|
||||
minBalanceForInterestCalculation, overdraftInterestRateAsFraction, minOverdraftForInterestCalculation);
|
||||
break;
|
||||
case INVALID:
|
||||
break;
|
||||
@@ -56,7 +56,8 @@ public class BiAnnualCompoundingPeriod implements CompoundingPeriod {
|
||||
}
|
||||
|
||||
private BigDecimal calculateUsingAverageDailyBalanceMethod(final BigDecimal interestToCompound, final BigDecimal interestRateAsFraction,
|
||||
final long daysInYear, final BigDecimal minBalanceForInterestCalculation) {
|
||||
final long daysInYear, final BigDecimal minBalanceForInterestCalculation, final BigDecimal overdraftInterestRateAsFraction,
|
||||
final BigDecimal minOverdraftForInterestCalculation) {
|
||||
|
||||
BigDecimal cumulativeBalance = BigDecimal.ZERO;
|
||||
Integer numberOfDays = Integer.valueOf(0);
|
||||
@@ -74,12 +75,22 @@ public class BiAnnualCompoundingPeriod implements CompoundingPeriod {
|
||||
final BigDecimal averageDailyBalance = cumulativeBalance.divide(BigDecimal.valueOf(numberOfDays), MathContext.DECIMAL64)
|
||||
.setScale(9, MoneyHelper.getRoundingMode());
|
||||
|
||||
final BigDecimal multiplicand = BigDecimal.ONE.divide(BigDecimal.valueOf(daysInYear), MathContext.DECIMAL64);
|
||||
final BigDecimal dailyInterestRate = interestRateAsFraction.multiply(multiplicand, MathContext.DECIMAL64);
|
||||
final BigDecimal periodicInterestRate = dailyInterestRate.multiply(BigDecimal.valueOf(numberOfDays), MathContext.DECIMAL64);
|
||||
if (averageDailyBalance.compareTo(minBalanceForInterestCalculation) >= 0) {
|
||||
interestEarned = averageDailyBalance.multiply(periodicInterestRate, MathContext.DECIMAL64).setScale(9,
|
||||
MoneyHelper.getRoundingMode());
|
||||
if(averageDailyBalance.compareTo(BigDecimal.ZERO) >= 0){
|
||||
if (averageDailyBalance.compareTo(minBalanceForInterestCalculation) >= 0) {
|
||||
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,
|
||||
MoneyHelper.getRoundingMode());
|
||||
}
|
||||
}else{
|
||||
if (averageDailyBalance.compareTo(minOverdraftForInterestCalculation.negate()) < 0) {
|
||||
final BigDecimal multiplicand = BigDecimal.ONE.divide(BigDecimal.valueOf(daysInYear), MathContext.DECIMAL64);
|
||||
final BigDecimal dailyInterestRate = overdraftInterestRateAsFraction.multiply(multiplicand, MathContext.DECIMAL64);
|
||||
final BigDecimal periodicInterestRate = dailyInterestRate.multiply(BigDecimal.valueOf(numberOfDays), MathContext.DECIMAL64);
|
||||
interestEarned = averageDailyBalance.multiply(periodicInterestRate, MathContext.DECIMAL64).setScale(9,
|
||||
MoneyHelper.getRoundingMode());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +99,8 @@ public class BiAnnualCompoundingPeriod implements CompoundingPeriod {
|
||||
|
||||
private BigDecimal calculateUsingDailyBalanceMethod(final SavingsCompoundingInterestPeriodType compoundingInterestPeriodType,
|
||||
final BigDecimal interestToCompound, final BigDecimal interestRateAsFraction, final long daysInYear,
|
||||
final BigDecimal minBalanceForInterestCalculation) {
|
||||
final BigDecimal minBalanceForInterestCalculation, final BigDecimal overdraftInterestRateAsFraction,
|
||||
final BigDecimal minOverdraftForInterestCalculation) {
|
||||
|
||||
BigDecimal interestEarned = BigDecimal.ZERO;
|
||||
BigDecimal interestOnBalanceUnrounded = BigDecimal.ZERO;
|
||||
@@ -97,15 +109,15 @@ public class BiAnnualCompoundingPeriod implements CompoundingPeriod {
|
||||
switch (compoundingInterestPeriodType) {
|
||||
case DAILY:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalanceAndInterest(interestToCompound, interestRateAsFraction,
|
||||
daysInYear, minBalanceForInterestCalculation);
|
||||
daysInYear, minBalanceForInterestCalculation, overdraftInterestRateAsFraction, minOverdraftForInterestCalculation);
|
||||
break;
|
||||
case MONTHLY:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalance(interestToCompound, interestRateAsFraction, daysInYear,
|
||||
minBalanceForInterestCalculation);
|
||||
minBalanceForInterestCalculation, overdraftInterestRateAsFraction, minOverdraftForInterestCalculation);
|
||||
break;
|
||||
case QUATERLY:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalance(interestToCompound, interestRateAsFraction, daysInYear,
|
||||
minBalanceForInterestCalculation);
|
||||
minBalanceForInterestCalculation, overdraftInterestRateAsFraction, minOverdraftForInterestCalculation);
|
||||
break;
|
||||
// case WEEKLY:
|
||||
// break;
|
||||
@@ -113,11 +125,11 @@ public class BiAnnualCompoundingPeriod implements CompoundingPeriod {
|
||||
// break;
|
||||
case BI_ANNUAL:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalance(interestToCompound, interestRateAsFraction, daysInYear,
|
||||
minBalanceForInterestCalculation);
|
||||
minBalanceForInterestCalculation, overdraftInterestRateAsFraction, minOverdraftForInterestCalculation);
|
||||
break;
|
||||
case ANNUAL:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalance(interestToCompound, interestRateAsFraction, daysInYear,
|
||||
minBalanceForInterestCalculation);
|
||||
minBalanceForInterestCalculation, overdraftInterestRateAsFraction, minOverdraftForInterestCalculation);
|
||||
break;
|
||||
// case NO_COMPOUNDING_SIMPLE_INTEREST:
|
||||
// break;
|
||||
|
||||
+2
-1
@@ -14,5 +14,6 @@ public interface CompoundingPeriod {
|
||||
|
||||
BigDecimal calculateInterest(SavingsCompoundingInterestPeriodType compoundingInterestPeriodType,
|
||||
SavingsInterestCalculationType interestCalculationType, BigDecimal interestFromPreviousPostingPeriod,
|
||||
BigDecimal interestRateAsFraction, long daysInYear, BigDecimal minBalanceForInterestCalculation);
|
||||
BigDecimal interestRateAsFraction, long daysInYear, BigDecimal minBalanceForInterestCalculation,
|
||||
BigDecimal overdraftInterestRateAsFraction, BigDecimal minOverdraftForInterestCalculation);
|
||||
}
|
||||
+4
-2
@@ -67,7 +67,8 @@ public class DailyCompoundingPeriod implements CompoundingPeriod {
|
||||
@SuppressWarnings("unused") final SavingsCompoundingInterestPeriodType compoundingInterestPeriodType,
|
||||
@SuppressWarnings("unused") final SavingsInterestCalculationType interestCalculationType,
|
||||
final BigDecimal interestFromPreviousPostingPeriod, final BigDecimal interestRateAsFraction, final long daysInYear,
|
||||
final BigDecimal minBalanceForInterestCalculation) {
|
||||
final BigDecimal minBalanceForInterestCalculation,
|
||||
final BigDecimal overdraftInterestRateAsFraction, final BigDecimal minOverdraftForInterestCalculation) {
|
||||
BigDecimal interestEarned = BigDecimal.ZERO;
|
||||
|
||||
// for daily compounding - each interest calculated from previous daily
|
||||
@@ -75,7 +76,8 @@ public class DailyCompoundingPeriod implements CompoundingPeriod {
|
||||
BigDecimal interestToCompound = interestFromPreviousPostingPeriod;
|
||||
for (final EndOfDayBalance balance : this.endOfDayBalances) {
|
||||
final BigDecimal interestOnBalanceUnrounded = balance.calculateInterestOnBalanceAndInterest(interestToCompound,
|
||||
interestRateAsFraction, daysInYear, minBalanceForInterestCalculation);
|
||||
interestRateAsFraction, daysInYear, minBalanceForInterestCalculation, overdraftInterestRateAsFraction,
|
||||
minOverdraftForInterestCalculation);
|
||||
interestToCompound = interestToCompound.add(interestOnBalanceUnrounded, MathContext.DECIMAL64).setScale(9);
|
||||
interestEarned = interestEarned.add(interestOnBalanceUnrounded);
|
||||
}
|
||||
|
||||
+45
-21
@@ -7,7 +7,6 @@ package org.mifosplatform.portfolio.savings.domain.interest;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.math.RoundingMode;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.domain.LocalDateInterval;
|
||||
@@ -49,17 +48,27 @@ public class EndOfDayBalance {
|
||||
}
|
||||
|
||||
public BigDecimal calculateInterestOnBalance(final BigDecimal interestToCompound, final BigDecimal interestRateAsFraction,
|
||||
final long daysInYear, final BigDecimal minBalanceForInterestCalculation) {
|
||||
final long daysInYear, final BigDecimal minBalanceForInterestCalculation,
|
||||
final BigDecimal overdraftInterestRateAsFraction, final BigDecimal minOverdraftForInterestCalculation) {
|
||||
|
||||
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(this.numberOfDays), MathContext.DECIMAL64);
|
||||
|
||||
final BigDecimal realBalanceForInterestCalculation = this.endOfDayBalance.getAmount().add(interestToCompound);
|
||||
BigDecimal interest = BigDecimal.ZERO.setScale(9, MoneyHelper.getRoundingMode());
|
||||
if (realBalanceForInterestCalculation.compareTo(minBalanceForInterestCalculation) >= 0) {
|
||||
interest = realBalanceForInterestCalculation.multiply(periodicInterestRate, MathContext.DECIMAL64).setScale(9,
|
||||
MoneyHelper.getRoundingMode());
|
||||
final BigDecimal realBalanceForInterestCalculation = this.endOfDayBalance.getAmount().add(interestToCompound);
|
||||
if(realBalanceForInterestCalculation.compareTo(BigDecimal.ZERO) >= 0){
|
||||
if (realBalanceForInterestCalculation.compareTo(minBalanceForInterestCalculation) >= 0) {
|
||||
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(this.numberOfDays), MathContext.DECIMAL64);
|
||||
interest = realBalanceForInterestCalculation.multiply(periodicInterestRate, MathContext.DECIMAL64).setScale(9,
|
||||
MoneyHelper.getRoundingMode());
|
||||
}
|
||||
} else {
|
||||
if (realBalanceForInterestCalculation.compareTo(minOverdraftForInterestCalculation.negate()) < 0) {
|
||||
final BigDecimal multiplicand = BigDecimal.ONE.divide(BigDecimal.valueOf(daysInYear), MathContext.DECIMAL64);
|
||||
final BigDecimal dailyInterestRate = overdraftInterestRateAsFraction.multiply(multiplicand, MathContext.DECIMAL64);
|
||||
final BigDecimal periodicInterestRate = dailyInterestRate.multiply(BigDecimal.valueOf(this.numberOfDays), MathContext.DECIMAL64);
|
||||
interest = realBalanceForInterestCalculation.multiply(periodicInterestRate, MathContext.DECIMAL64).setScale(9,
|
||||
MoneyHelper.getRoundingMode());
|
||||
}
|
||||
}
|
||||
return interest;
|
||||
}
|
||||
@@ -72,22 +81,37 @@ public class EndOfDayBalance {
|
||||
* 1/365 n = number of periods rate is compounded
|
||||
*/
|
||||
public BigDecimal calculateInterestOnBalanceAndInterest(final BigDecimal interestToCompound, final BigDecimal interestRateAsFraction,
|
||||
final long daysInYear, final BigDecimal minBalanceForInterestCalculation) {
|
||||
final long daysInYear, final BigDecimal minBalanceForInterestCalculation, final BigDecimal overdraftInterestRateAsFraction,
|
||||
final BigDecimal minOverdraftForInterestCalculation) {
|
||||
final BigDecimal multiplicand = BigDecimal.ONE.divide(BigDecimal.valueOf(daysInYear), MathContext.DECIMAL64);
|
||||
|
||||
final BigDecimal presentValue = this.endOfDayBalance.getAmount().add(interestToCompound);
|
||||
|
||||
final BigDecimal r = interestRateAsFraction.multiply(multiplicand);
|
||||
|
||||
final BigDecimal interestRateForCompoundingPeriodPlusOne = BigDecimal.ONE.add(r);
|
||||
|
||||
final double interestRateForCompoundingPeriodPowered = Math.pow(interestRateForCompoundingPeriodPlusOne.doubleValue(),
|
||||
Integer.valueOf(this.numberOfDays).doubleValue());
|
||||
BigDecimal futureValue = presentValue.setScale(9, MoneyHelper.getRoundingMode());
|
||||
if (presentValue.compareTo(minBalanceForInterestCalculation) >= 0) {
|
||||
futureValue = presentValue.multiply(BigDecimal.valueOf(interestRateForCompoundingPeriodPowered), MathContext.DECIMAL64)
|
||||
.setScale(9, MoneyHelper.getRoundingMode());
|
||||
|
||||
if(presentValue.compareTo(BigDecimal.ZERO) >= 0){
|
||||
if (presentValue.compareTo(minBalanceForInterestCalculation) >= 0) {
|
||||
final BigDecimal r = interestRateAsFraction.multiply(multiplicand);
|
||||
|
||||
final BigDecimal interestRateForCompoundingPeriodPlusOne = BigDecimal.ONE.add(r);
|
||||
|
||||
final double interestRateForCompoundingPeriodPowered = Math.pow(interestRateForCompoundingPeriodPlusOne.doubleValue(),
|
||||
Integer.valueOf(this.numberOfDays).doubleValue());
|
||||
futureValue = presentValue.multiply(BigDecimal.valueOf(interestRateForCompoundingPeriodPowered), MathContext.DECIMAL64)
|
||||
.setScale(9, MoneyHelper.getRoundingMode());
|
||||
}
|
||||
}else{
|
||||
if (presentValue.compareTo(minOverdraftForInterestCalculation.negate()) < 0) {
|
||||
final BigDecimal r = overdraftInterestRateAsFraction.multiply(multiplicand);
|
||||
|
||||
final BigDecimal interestRateForCompoundingPeriodPlusOne = BigDecimal.ONE.add(r);
|
||||
|
||||
final double interestRateForCompoundingPeriodPowered = Math.pow(interestRateForCompoundingPeriodPlusOne.doubleValue(),
|
||||
Integer.valueOf(this.numberOfDays).doubleValue());
|
||||
futureValue = presentValue.multiply(BigDecimal.valueOf(interestRateForCompoundingPeriodPowered), MathContext.DECIMAL64)
|
||||
.setScale(9, MoneyHelper.getRoundingMode());
|
||||
}
|
||||
}
|
||||
|
||||
return futureValue.subtract(presentValue);
|
||||
}
|
||||
|
||||
|
||||
+26
-14
@@ -7,7 +7,6 @@ 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;
|
||||
|
||||
@@ -35,18 +34,19 @@ public class MonthlyCompoundingPeriod implements CompoundingPeriod {
|
||||
@Override
|
||||
public BigDecimal calculateInterest(final SavingsCompoundingInterestPeriodType compoundingInterestPeriodType,
|
||||
final SavingsInterestCalculationType interestCalculationType, final BigDecimal interestToCompound,
|
||||
final BigDecimal interestRateAsFraction, final long daysInYear, final BigDecimal minBalanceForInterestCalculation) {
|
||||
final BigDecimal interestRateAsFraction, final long daysInYear, final BigDecimal minBalanceForInterestCalculation,
|
||||
final BigDecimal overdraftInterestRateAsFraction, final BigDecimal minOverdraftForInterestCalculation) {
|
||||
|
||||
BigDecimal interestEarned = BigDecimal.ZERO;
|
||||
|
||||
switch (interestCalculationType) {
|
||||
case DAILY_BALANCE:
|
||||
interestEarned = calculateUsingDailyBalanceMethod(compoundingInterestPeriodType, interestToCompound, interestRateAsFraction,
|
||||
daysInYear, minBalanceForInterestCalculation);
|
||||
daysInYear, minBalanceForInterestCalculation, overdraftInterestRateAsFraction, minOverdraftForInterestCalculation);
|
||||
break;
|
||||
case AVERAGE_DAILY_BALANCE:
|
||||
interestEarned = calculateUsingAverageDailyBalanceMethod(interestToCompound, interestRateAsFraction, daysInYear,
|
||||
minBalanceForInterestCalculation);
|
||||
minBalanceForInterestCalculation, overdraftInterestRateAsFraction, minOverdraftForInterestCalculation);
|
||||
break;
|
||||
case INVALID:
|
||||
break;
|
||||
@@ -56,7 +56,8 @@ public class MonthlyCompoundingPeriod implements CompoundingPeriod {
|
||||
}
|
||||
|
||||
private BigDecimal calculateUsingAverageDailyBalanceMethod(final BigDecimal interestToCompound, final BigDecimal interestRateAsFraction,
|
||||
final long daysInYear, final BigDecimal minBalanceForInterestCalculation) {
|
||||
final long daysInYear, final BigDecimal minBalanceForInterestCalculation, final BigDecimal overdraftInterestRateAsFraction,
|
||||
final BigDecimal minOverdraftForInterestCalculation) {
|
||||
|
||||
BigDecimal cumulativeBalance = BigDecimal.ZERO;
|
||||
Integer numberOfDays = Integer.valueOf(0);
|
||||
@@ -74,12 +75,22 @@ public class MonthlyCompoundingPeriod implements CompoundingPeriod {
|
||||
final BigDecimal averageDailyBalance = cumulativeBalance.divide(BigDecimal.valueOf(numberOfDays), MathContext.DECIMAL64)
|
||||
.setScale(9, MoneyHelper.getRoundingMode());
|
||||
|
||||
final BigDecimal multiplicand = BigDecimal.ONE.divide(BigDecimal.valueOf(daysInYear), MathContext.DECIMAL64);
|
||||
final BigDecimal dailyInterestRate = interestRateAsFraction.multiply(multiplicand, MathContext.DECIMAL64);
|
||||
final BigDecimal periodicInterestRate = dailyInterestRate.multiply(BigDecimal.valueOf(numberOfDays), MathContext.DECIMAL64);
|
||||
if (averageDailyBalance.compareTo(minBalanceForInterestCalculation) >= 0) {
|
||||
interestEarned = averageDailyBalance.multiply(periodicInterestRate, MathContext.DECIMAL64).setScale(9,
|
||||
MoneyHelper.getRoundingMode());
|
||||
if(averageDailyBalance.compareTo(BigDecimal.ZERO) >= 0){
|
||||
if (averageDailyBalance.compareTo(minBalanceForInterestCalculation) >= 0) {
|
||||
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,
|
||||
MoneyHelper.getRoundingMode());
|
||||
}
|
||||
}else{
|
||||
if (averageDailyBalance.compareTo(minOverdraftForInterestCalculation.negate()) < 0) {
|
||||
final BigDecimal multiplicand = BigDecimal.ONE.divide(BigDecimal.valueOf(daysInYear), MathContext.DECIMAL64);
|
||||
final BigDecimal dailyInterestRate = overdraftInterestRateAsFraction.multiply(multiplicand, MathContext.DECIMAL64);
|
||||
final BigDecimal periodicInterestRate = dailyInterestRate.multiply(BigDecimal.valueOf(numberOfDays), MathContext.DECIMAL64);
|
||||
interestEarned = averageDailyBalance.multiply(periodicInterestRate, MathContext.DECIMAL64).setScale(9,
|
||||
MoneyHelper.getRoundingMode());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +99,8 @@ public class MonthlyCompoundingPeriod implements CompoundingPeriod {
|
||||
|
||||
private BigDecimal calculateUsingDailyBalanceMethod(final SavingsCompoundingInterestPeriodType compoundingInterestPeriodType,
|
||||
final BigDecimal interestToCompound, final BigDecimal interestRateAsFraction, final long daysInYear,
|
||||
final BigDecimal minBalanceForInterestCalculation) {
|
||||
final BigDecimal minBalanceForInterestCalculation, final BigDecimal overdraftInterestRateAsFraction,
|
||||
final BigDecimal minOverdraftForInterestCalculation) {
|
||||
|
||||
BigDecimal interestEarned = BigDecimal.ZERO;
|
||||
BigDecimal interestOnBalanceUnrounded = BigDecimal.ZERO;
|
||||
@@ -97,11 +109,11 @@ public class MonthlyCompoundingPeriod implements CompoundingPeriod {
|
||||
switch (compoundingInterestPeriodType) {
|
||||
case DAILY:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalanceAndInterest(interestToCompound, interestRateAsFraction,
|
||||
daysInYear, minBalanceForInterestCalculation);
|
||||
daysInYear, minBalanceForInterestCalculation, overdraftInterestRateAsFraction, minOverdraftForInterestCalculation);
|
||||
break;
|
||||
case MONTHLY:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalance(interestToCompound, interestRateAsFraction, daysInYear,
|
||||
minBalanceForInterestCalculation);
|
||||
minBalanceForInterestCalculation, overdraftInterestRateAsFraction, minOverdraftForInterestCalculation);
|
||||
break;
|
||||
// case QUATERLY:
|
||||
// break;
|
||||
|
||||
+29
-4
@@ -44,6 +44,25 @@ public class PostingPeriod {
|
||||
|
||||
// minimum balance for interest calculation
|
||||
private final Money minBalanceForInterestCalculation;
|
||||
private BigDecimal overdraftInterestRateAsFraction;
|
||||
private Money minOverdraftForInterestCalculation;
|
||||
|
||||
public static PostingPeriod createFrom(final LocalDateInterval periodInterval, final Money periodStartingBalance,
|
||||
final List<SavingsAccountTransaction> orderedListOfTransactions, final MonetaryCurrency currency,
|
||||
final SavingsCompoundingInterestPeriodType interestCompoundingPeriodType,
|
||||
final SavingsInterestCalculationType interestCalculationType, final BigDecimal interestRateAsFraction, final long daysInYear,
|
||||
final LocalDate upToInterestCalculationDate, Collection<Long> interestPostTransactions, boolean isInterestTransfer,
|
||||
final Money minBalanceForInterestCalculation, final boolean isSavingsInterestPostingAtCurrentPeriodEnd) {
|
||||
|
||||
final BigDecimal overdraftInterestRateAsFraction = BigDecimal.ZERO;
|
||||
final Money minOverdraftForInterestCalculation = Money.zero(currency);
|
||||
|
||||
return createFrom(periodInterval, periodStartingBalance, orderedListOfTransactions, currency,
|
||||
interestCompoundingPeriodType, interestCalculationType, interestRateAsFraction, daysInYear,
|
||||
upToInterestCalculationDate, interestPostTransactions, isInterestTransfer,
|
||||
minBalanceForInterestCalculation, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
overdraftInterestRateAsFraction, minOverdraftForInterestCalculation);
|
||||
}
|
||||
|
||||
// isInterestTransfer boolean is to identify newly created transaction is
|
||||
// interest transfer
|
||||
@@ -52,7 +71,8 @@ public class PostingPeriod {
|
||||
final SavingsCompoundingInterestPeriodType interestCompoundingPeriodType,
|
||||
final SavingsInterestCalculationType interestCalculationType, final BigDecimal interestRateAsFraction, final long daysInYear,
|
||||
final LocalDate upToInterestCalculationDate, Collection<Long> interestPostTransactions, boolean isInterestTransfer,
|
||||
final Money minBalanceForInterestCalculation, final boolean isSavingsInterestPostingAtCurrentPeriodEnd) {
|
||||
final Money minBalanceForInterestCalculation, final boolean isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
final BigDecimal overdraftInterestRateAsFraction, final Money minOverdraftForInterestCalculation) {
|
||||
|
||||
final List<EndOfDayBalance> accountEndOfDayBalances = new ArrayList<>();
|
||||
boolean interestTransfered = false;
|
||||
@@ -113,14 +133,16 @@ public class PostingPeriod {
|
||||
|
||||
return new PostingPeriod(periodInterval, currency, periodStartingBalance, openingDayBalance, interestCompoundingPeriodType,
|
||||
interestCalculationType, interestRateAsFraction, daysInYear, compoundingPeriods, interestTransfered,
|
||||
minBalanceForInterestCalculation, isSavingsInterestPostingAtCurrentPeriodEnd);
|
||||
minBalanceForInterestCalculation, isSavingsInterestPostingAtCurrentPeriodEnd,
|
||||
overdraftInterestRateAsFraction, minOverdraftForInterestCalculation);
|
||||
}
|
||||
|
||||
private PostingPeriod(final LocalDateInterval periodInterval, final MonetaryCurrency currency, final Money openingBalance,
|
||||
final Money closingBalance, final SavingsCompoundingInterestPeriodType interestCompoundingType,
|
||||
final SavingsInterestCalculationType interestCalculationType, final BigDecimal interestRateAsFraction, final long daysInYear,
|
||||
final List<CompoundingPeriod> compoundingPeriods, boolean interestTransfered, final Money minBalanceForInterestCalculation,
|
||||
final boolean isSavingsInterestPostingAtCurrentPeriodEnd) {
|
||||
final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final BigDecimal overdraftInterestRateAsFraction,
|
||||
final Money minOverdraftForInterestCalculation) {
|
||||
this.periodInterval = periodInterval;
|
||||
this.currency = currency;
|
||||
this.openingBalance = openingBalance;
|
||||
@@ -137,6 +159,8 @@ public class PostingPeriod {
|
||||
this.dateOfPostingTransaction = periodInterval.endDate().plusDays(1);
|
||||
this.interestTransfered = interestTransfered;
|
||||
this.minBalanceForInterestCalculation = minBalanceForInterestCalculation;
|
||||
this.overdraftInterestRateAsFraction = overdraftInterestRateAsFraction;
|
||||
this.minOverdraftForInterestCalculation = minOverdraftForInterestCalculation;
|
||||
}
|
||||
|
||||
public Money interest() {
|
||||
@@ -165,7 +189,8 @@ public class PostingPeriod {
|
||||
|
||||
final BigDecimal interestUnrounded = compoundingPeriod.calculateInterest(this.interestCompoundingType,
|
||||
this.interestCalculationType, interestCompounded, this.interestRateAsFraction, this.daysInYear,
|
||||
this.minBalanceForInterestCalculation.getAmount());
|
||||
this.minBalanceForInterestCalculation.getAmount(), this.overdraftInterestRateAsFraction,
|
||||
this.minOverdraftForInterestCalculation.getAmount());
|
||||
interestCompounded = interestCompounded.add(interestUnrounded);
|
||||
interestEarned = interestEarned.add(interestUnrounded);
|
||||
}
|
||||
|
||||
+29
-17
@@ -7,7 +7,6 @@ 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;
|
||||
|
||||
@@ -35,18 +34,19 @@ public class QuarterlyCompoundingPeriod implements CompoundingPeriod {
|
||||
@Override
|
||||
public BigDecimal calculateInterest(final SavingsCompoundingInterestPeriodType compoundingInterestPeriodType,
|
||||
final SavingsInterestCalculationType interestCalculationType, final BigDecimal interestToCompound,
|
||||
final BigDecimal interestRateAsFraction, final long daysInYear, final BigDecimal minBalanceForInterestCalculation) {
|
||||
final BigDecimal interestRateAsFraction, final long daysInYear, final BigDecimal minBalanceForInterestCalculation,
|
||||
final BigDecimal overdraftInterestRateAsFraction, final BigDecimal minOverdraftForInterestCalculation) {
|
||||
|
||||
BigDecimal interestEarned = BigDecimal.ZERO;
|
||||
|
||||
switch (interestCalculationType) {
|
||||
case DAILY_BALANCE:
|
||||
interestEarned = calculateUsingDailyBalanceMethod(compoundingInterestPeriodType, interestToCompound, interestRateAsFraction,
|
||||
daysInYear, minBalanceForInterestCalculation);
|
||||
daysInYear, minBalanceForInterestCalculation, overdraftInterestRateAsFraction, minOverdraftForInterestCalculation);
|
||||
break;
|
||||
case AVERAGE_DAILY_BALANCE:
|
||||
interestEarned = calculateUsingAverageDailyBalanceMethod(interestToCompound, interestRateAsFraction, daysInYear,
|
||||
minBalanceForInterestCalculation);
|
||||
minBalanceForInterestCalculation, overdraftInterestRateAsFraction, minOverdraftForInterestCalculation);
|
||||
break;
|
||||
case INVALID:
|
||||
break;
|
||||
@@ -56,7 +56,8 @@ public class QuarterlyCompoundingPeriod implements CompoundingPeriod {
|
||||
}
|
||||
|
||||
private BigDecimal calculateUsingAverageDailyBalanceMethod(final BigDecimal interestToCompound, final BigDecimal interestRateAsFraction,
|
||||
final long daysInYear, final BigDecimal minBalanceForInterestCalculation) {
|
||||
final long daysInYear, final BigDecimal minBalanceForInterestCalculation, final BigDecimal overdraftInterestRateAsFraction,
|
||||
final BigDecimal minOverdraftForInterestCalculation) {
|
||||
|
||||
BigDecimal cumulativeBalance = BigDecimal.ZERO;
|
||||
Integer numberOfDays = Integer.valueOf(0);
|
||||
@@ -74,12 +75,22 @@ public class QuarterlyCompoundingPeriod implements CompoundingPeriod {
|
||||
final BigDecimal averageDailyBalance = cumulativeBalance.divide(BigDecimal.valueOf(numberOfDays), MathContext.DECIMAL64)
|
||||
.setScale(9, MoneyHelper.getRoundingMode());
|
||||
|
||||
final BigDecimal multiplicand = BigDecimal.ONE.divide(BigDecimal.valueOf(daysInYear), MathContext.DECIMAL64);
|
||||
final BigDecimal dailyInterestRate = interestRateAsFraction.multiply(multiplicand, MathContext.DECIMAL64);
|
||||
final BigDecimal periodicInterestRate = dailyInterestRate.multiply(BigDecimal.valueOf(numberOfDays), MathContext.DECIMAL64);
|
||||
if (averageDailyBalance.compareTo(minBalanceForInterestCalculation) >= 0) {
|
||||
interestEarned = averageDailyBalance.multiply(periodicInterestRate, MathContext.DECIMAL64).setScale(9,
|
||||
MoneyHelper.getRoundingMode());
|
||||
if(averageDailyBalance.compareTo(BigDecimal.ZERO) >= 0){
|
||||
if (averageDailyBalance.compareTo(minBalanceForInterestCalculation) >= 0) {
|
||||
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,
|
||||
MoneyHelper.getRoundingMode());
|
||||
}
|
||||
}else{
|
||||
if (averageDailyBalance.compareTo(minOverdraftForInterestCalculation.negate()) < 0) {
|
||||
final BigDecimal multiplicand = BigDecimal.ONE.divide(BigDecimal.valueOf(daysInYear), MathContext.DECIMAL64);
|
||||
final BigDecimal dailyInterestRate = overdraftInterestRateAsFraction.multiply(multiplicand, MathContext.DECIMAL64);
|
||||
final BigDecimal periodicInterestRate = dailyInterestRate.multiply(BigDecimal.valueOf(numberOfDays), MathContext.DECIMAL64);
|
||||
interestEarned = averageDailyBalance.multiply(periodicInterestRate, MathContext.DECIMAL64).setScale(9,
|
||||
MoneyHelper.getRoundingMode());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +99,8 @@ public class QuarterlyCompoundingPeriod implements CompoundingPeriod {
|
||||
|
||||
private BigDecimal calculateUsingDailyBalanceMethod(final SavingsCompoundingInterestPeriodType compoundingInterestPeriodType,
|
||||
final BigDecimal interestToCompound, final BigDecimal interestRateAsFraction, final long daysInYear,
|
||||
final BigDecimal minBalanceForInterestCalculation) {
|
||||
final BigDecimal minBalanceForInterestCalculation, final BigDecimal overdraftInterestRateAsFraction,
|
||||
final BigDecimal minOverdraftForInterestCalculation) {
|
||||
|
||||
BigDecimal interestEarned = BigDecimal.ZERO;
|
||||
BigDecimal interestOnBalanceUnrounded = BigDecimal.ZERO;
|
||||
@@ -97,15 +109,15 @@ public class QuarterlyCompoundingPeriod implements CompoundingPeriod {
|
||||
switch (compoundingInterestPeriodType) {
|
||||
case DAILY:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalanceAndInterest(interestToCompound, interestRateAsFraction,
|
||||
daysInYear, minBalanceForInterestCalculation);
|
||||
daysInYear, minBalanceForInterestCalculation, overdraftInterestRateAsFraction, minOverdraftForInterestCalculation);
|
||||
break;
|
||||
case MONTHLY:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalance(interestToCompound, interestRateAsFraction, daysInYear,
|
||||
minBalanceForInterestCalculation);
|
||||
minBalanceForInterestCalculation, overdraftInterestRateAsFraction, minOverdraftForInterestCalculation);
|
||||
break;
|
||||
case QUATERLY:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalance(interestToCompound, interestRateAsFraction, daysInYear,
|
||||
minBalanceForInterestCalculation);
|
||||
minBalanceForInterestCalculation, overdraftInterestRateAsFraction, minOverdraftForInterestCalculation);
|
||||
break;
|
||||
// case WEEKLY:
|
||||
// break;
|
||||
@@ -113,11 +125,11 @@ public class QuarterlyCompoundingPeriod implements CompoundingPeriod {
|
||||
// break;
|
||||
case BI_ANNUAL:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalance(interestToCompound, interestRateAsFraction, daysInYear,
|
||||
minBalanceForInterestCalculation);
|
||||
minBalanceForInterestCalculation, overdraftInterestRateAsFraction, minOverdraftForInterestCalculation);
|
||||
break;
|
||||
case ANNUAL:
|
||||
interestOnBalanceUnrounded = balance.calculateInterestOnBalance(interestToCompound, interestRateAsFraction, daysInYear,
|
||||
minBalanceForInterestCalculation);
|
||||
minBalanceForInterestCalculation, overdraftInterestRateAsFraction, minOverdraftForInterestCalculation);
|
||||
break;
|
||||
// case NO_COMPOUNDING_SIMPLE_INTEREST:
|
||||
// break;
|
||||
|
||||
+2
-1
@@ -709,10 +709,11 @@ public class DepositAccountReadPlatformServiceImpl implements DepositAccountRead
|
||||
final BigDecimal accountBalance = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "accountBalance");
|
||||
final BigDecimal totalFeeCharge = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "totalFeeCharge");
|
||||
final BigDecimal totalPenaltyCharge = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "totalPenaltyCharge");
|
||||
final BigDecimal totalOverdraftInterestDerived = null;
|
||||
|
||||
final SavingsAccountSummaryData summary = new SavingsAccountSummaryData(currency, totalDeposits, totalWithdrawals,
|
||||
totalWithdrawalFees, totalAnnualFees, totalInterestEarned, totalInterestPosted, accountBalance, totalFeeCharge,
|
||||
totalPenaltyCharge);
|
||||
totalPenaltyCharge, totalOverdraftInterestDerived);
|
||||
|
||||
return DepositAccountData.instance(id, accountNo, externalId, groupId, groupName, clientId, clientName, productId, productName,
|
||||
fieldOfficerId, fieldOfficerName, status, timeline, currency, nominalAnnualInterestRate, interestCompoundingPeriodType,
|
||||
|
||||
+14
-3
@@ -237,6 +237,8 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
sqlBuilder.append("sa.withdrawal_fee_for_transfer as withdrawalFeeForTransfers, ");
|
||||
sqlBuilder.append("sa.allow_overdraft as allowOverdraft, ");
|
||||
sqlBuilder.append("sa.overdraft_limit as overdraftLimit, ");
|
||||
sqlBuilder.append("sa.nominal_annual_interest_rate_overdraft as nominalAnnualInterestRateOverdraft, ");
|
||||
sqlBuilder.append("sa.min_overdraft_for_interest_calculation as minOverdraftForInterestCalculation, ");
|
||||
// sqlBuilder.append("sa.annual_fee_amount as annualFeeAmount,");
|
||||
// sqlBuilder.append("sa.annual_fee_on_month as annualFeeOnMonth, ");
|
||||
// sqlBuilder.append("sa.annual_fee_on_day as annualFeeOnDay, ");
|
||||
@@ -247,6 +249,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
sqlBuilder.append("sa.total_annual_fees_derived as totalAnnualFees, ");
|
||||
sqlBuilder.append("sa.total_interest_earned_derived as totalInterestEarned, ");
|
||||
sqlBuilder.append("sa.total_interest_posted_derived as totalInterestPosted, ");
|
||||
sqlBuilder.append("sa.total_overdraft_interest_derived as totalOverdraftInterestDerived, ");
|
||||
sqlBuilder.append("sa.account_balance_derived as accountBalance, ");
|
||||
sqlBuilder.append("sa.total_fees_charge_derived as totalFeeCharge, ");
|
||||
sqlBuilder.append("sa.total_penalty_charge_derived as totalPenaltyCharge, ");
|
||||
@@ -384,6 +387,8 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
|
||||
final boolean allowOverdraft = rs.getBoolean("allowOverdraft");
|
||||
final BigDecimal overdraftLimit = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "overdraftLimit");
|
||||
final BigDecimal nominalAnnualInterestRateOverdraft = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "nominalAnnualInterestRateOverdraft");
|
||||
final BigDecimal minOverdraftForInterestCalculation = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "minOverdraftForInterestCalculation");
|
||||
|
||||
final BigDecimal minRequiredBalance = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "minRequiredBalance");
|
||||
final boolean enforceMinRequiredBalance = rs.getBoolean("enforceMinRequiredBalance");
|
||||
@@ -413,20 +418,22 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
final BigDecimal accountBalance = JdbcSupport.getBigDecimalDefaultToZeroIfNull(rs, "accountBalance");
|
||||
final BigDecimal totalFeeCharge = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "totalFeeCharge");
|
||||
final BigDecimal totalPenaltyCharge = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "totalPenaltyCharge");
|
||||
final BigDecimal totalOverdraftInterestDerived = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "totalOverdraftInterestDerived");
|
||||
|
||||
final BigDecimal minBalanceForInterestCalculation = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs,
|
||||
"minBalanceForInterestCalculation");
|
||||
final BigDecimal onHoldFunds = rs.getBigDecimal("onHoldFunds");
|
||||
|
||||
final SavingsAccountSummaryData summary = new SavingsAccountSummaryData(currency, totalDeposits, totalWithdrawals,
|
||||
totalWithdrawalFees, totalAnnualFees, totalInterestEarned, totalInterestPosted, accountBalance, totalFeeCharge,
|
||||
totalPenaltyCharge);
|
||||
totalPenaltyCharge, totalOverdraftInterestDerived);
|
||||
|
||||
return SavingsAccountData.instance(id, accountNo, depositType, externalId, groupId, groupName, clientId, clientName, productId,
|
||||
productName, fieldOfficerId, fieldOfficerName, status, timeline, currency, nominalAnnualInterestRate,
|
||||
interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType,
|
||||
minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, summary,
|
||||
allowOverdraft, overdraftLimit, minRequiredBalance, enforceMinRequiredBalance, minBalanceForInterestCalculation,
|
||||
onHoldFunds);
|
||||
onHoldFunds, nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -820,6 +827,8 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
sqlBuilder.append("sp.min_balance_for_interest_calculation as minBalanceForInterestCalculation, ");
|
||||
sqlBuilder.append("sp.allow_overdraft as allowOverdraft, ");
|
||||
sqlBuilder.append("sp.overdraft_limit as overdraftLimit, ");
|
||||
sqlBuilder.append("sp.nominal_annual_interest_rate_overdraft as nominalAnnualInterestRateOverdraft, ");
|
||||
sqlBuilder.append("sp.min_overdraft_for_interest_calculation as minOverdraftForInterestCalculation, ");
|
||||
// sqlBuilder.append("sp.annual_fee_amount as annualFeeAmount,");
|
||||
// sqlBuilder.append("sp.annual_fee_on_month as annualFeeOnMonth, ");
|
||||
// sqlBuilder.append("sp.annual_fee_on_day as annualFeeOnDay ");
|
||||
@@ -890,6 +899,8 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
|
||||
final boolean allowOverdraft = rs.getBoolean("allowOverdraft");
|
||||
final BigDecimal overdraftLimit = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "overdraftLimit");
|
||||
final BigDecimal nominalAnnualInterestRateOverdraft = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "nominalAnnualInterestRateOverdraft");
|
||||
final BigDecimal minOverdraftForInterestCalculation = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "minOverdraftForInterestCalculation");
|
||||
|
||||
final BigDecimal minRequiredBalance = JdbcSupport.getBigDecimalDefaultToNullIfZero(rs, "minRequiredBalance");
|
||||
final boolean enforceMinRequiredBalance = rs.getBoolean("enforceMinRequiredBalance");
|
||||
@@ -937,7 +948,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
|
||||
interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType,
|
||||
minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers, summary,
|
||||
allowOverdraft, overdraftLimit, minRequiredBalance, enforceMinRequiredBalance, minBalanceForInterestCalculation,
|
||||
onHoldFunds);
|
||||
onHoldFunds, nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -371,7 +371,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi
|
||||
.isSavingsInterestPostingAtCurrentPeriodEnd();
|
||||
final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth();
|
||||
|
||||
if (account.getNominalAnnualInterestRate().compareTo(BigDecimal.ZERO) == 1) {
|
||||
if (account.getNominalAnnualInterestRate().compareTo(BigDecimal.ZERO) > 0
|
||||
|| (account.allowOverdraft() && account.getNominalAnnualInterestRateOverdraft().compareTo(BigDecimal.ZERO) > 0)) {
|
||||
final Set<Long> existingTransactionIds = new HashSet<>();
|
||||
final Set<Long> existingReversedTransactionIds = new HashSet<>();
|
||||
updateExistingTransactionsDetails(account, existingTransactionIds, existingReversedTransactionIds);
|
||||
|
||||
+5
-1
@@ -114,6 +114,8 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
|
||||
sqlBuilder.append("sp.withdrawal_fee_for_transfer as withdrawalFeeForTransfers, ");
|
||||
sqlBuilder.append("sp.allow_overdraft as allowOverdraft, ");
|
||||
sqlBuilder.append("sp.overdraft_limit as overdraftLimit, ");
|
||||
sqlBuilder.append("sp.nominal_annual_interest_rate_overdraft as nominalAnnualInterestRateOverdraft, ");
|
||||
sqlBuilder.append("sp.min_overdraft_for_interest_calculation as minOverdraftForInterestCalculation, ");
|
||||
sqlBuilder.append("sp.min_required_balance as minRequiredBalance, ");
|
||||
sqlBuilder.append("sp.enforce_min_required_balance as enforceMinRequiredBalance, ");
|
||||
sqlBuilder.append("sp.min_balance_for_interest_calculation as minBalanceForInterestCalculation,");
|
||||
@@ -178,6 +180,8 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
|
||||
final boolean withdrawalFeeForTransfers = rs.getBoolean("withdrawalFeeForTransfers");
|
||||
final boolean allowOverdraft = rs.getBoolean("allowOverdraft");
|
||||
final BigDecimal overdraftLimit = rs.getBigDecimal("overdraftLimit");
|
||||
final BigDecimal nominalAnnualInterestRateOverdraft = rs.getBigDecimal("nominalAnnualInterestRateOverdraft");
|
||||
final BigDecimal minOverdraftForInterestCalculation = rs.getBigDecimal("minOverdraftForInterestCalculation");
|
||||
|
||||
final BigDecimal minRequiredBalance = rs.getBigDecimal("minRequiredBalance");
|
||||
final boolean enforceMinRequiredBalance = rs.getBoolean("enforceMinRequiredBalance");
|
||||
@@ -187,7 +191,7 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead
|
||||
compoundingInterestPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType,
|
||||
minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, withdrawalFeeForTransfers,
|
||||
accountingRuleType, allowOverdraft, overdraftLimit, minRequiredBalance, enforceMinRequiredBalance,
|
||||
minBalanceForInterestCalculation);
|
||||
minBalanceForInterestCalculation, nominalAnnualInterestRateOverdraft, minOverdraftForInterestCalculation);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
ALTER TABLE `m_savings_account`
|
||||
ADD COLUMN `nominal_annual_interest_rate_overdraft` DECIMAL(19,6) NULL DEFAULT NULL AFTER `overdraft_limit`,
|
||||
ADD COLUMN `total_overdraft_interest_derived` DECIMAL(19,6) NULL DEFAULT NULL AFTER `total_interest_posted_derived`,
|
||||
ADD COLUMN `min_overdraft_for_interest_calculation` DECIMAL(19,6) NULL DEFAULT NULL AFTER `nominal_annual_interest_rate_overdraft`;
|
||||
|
||||
ALTER TABLE `m_savings_product`
|
||||
ADD COLUMN `nominal_annual_interest_rate_overdraft` DECIMAL(19,6) NULL DEFAULT NULL AFTER `overdraft_limit`,
|
||||
ADD COLUMN `min_overdraft_for_interest_calculation` DECIMAL(19,6) NULL DEFAULT NULL AFTER `nominal_annual_interest_rate_overdraft`;
|
||||
Reference in New Issue
Block a user