From e8cc870f210c0e6ad9a1dfb6777a67791b886a1a Mon Sep 17 00:00:00 2001 From: Madhukar Date: Tue, 22 Jan 2013 12:47:56 +0530 Subject: [PATCH] Add interest posting functionality for saving accounts rename_patches_after_rebasing remove existed db script file --- ...atch-03_add_note_for_m_saving_account.sql} | 0 ...eate_table_saving_account_transaction.sql} | 0 ...ng,i_p_frequency_for_m_saving_account.sql} | 0 ...est_posting_cols_for_m_saving_account.sql} | 0 ...est_accured_cols_for_m_saving_schedule.sql | 3 + ..._deposit_freq_col_for_m_saving_account.sql | 2 - ...GsonPortfolioApiJsonSerializerService.java | 2 +- ...PortfolioApiDataConversionServiceImpl.java | 5 +- .../api/SavingsAccountApiResource.java | 16 +++- .../CalculateSavingScheduleCommand.java | 14 ++- .../command/SavingAccountCommand.java | 10 +- .../SavingAccountCommandValidator.java | 2 - .../data/SavingAccountData.java | 88 ++++++++++++++++- .../data/SavingAccountTransactionsData.java | 33 +++++++ .../data/SavingScheduleData.java | 18 +++- .../data/SavingSchedulePeriodData.java | 12 ++- .../domain/DepositScheduleDateGenerator.java | 4 +- .../ReccuringDepositInterestCalculator.java | 21 ++-- .../savingsaccount/domain/SavingAccount.java | 92 ++++++++++-------- .../domain/SavingScheduleInstallments.java | 7 +- .../service/CalculateSavingScheduleImpl.java | 32 +++++-- .../DefaultDepositScheduleDateGenerator.java | 25 ++--- .../service/SavingAccountAssembler.java | 35 ++++--- .../SavingAccountReadPlatformService.java | 3 + .../SavingAccountReadPlatformServiceImpl.java | 52 ++++++++-- .../service/SavingScheduleGenerator.java | 95 ++++++++++++++++--- .../domain/TenureTypeEnum.java | 8 ++ 27 files changed, 452 insertions(+), 127 deletions(-) rename mifosng-db/patches/{patch-17_add_note_for_m_saving_account.sql => patch-03_add_note_for_m_saving_account.sql} (100%) rename mifosng-db/patches/{patch-18_create_table_saving_account_transaction.sql => patch-04_create_table_saving_account_transaction.sql} (100%) rename mifosng-db/patches/{patch-19_add_interest_posting,i_p_frequency_for_m_saving_account.sql => patch-05_add_interest_posting,i_p_frequency_for_m_saving_account.sql} (100%) rename mifosng-db/patches/{patch-20_add_interest_posting_cols_for_m_saving_account.sql => patch-06_add_interest_posting_cols_for_m_saving_account.sql} (100%) create mode 100644 mifosng-db/patches/patch-07_add_interest_accured_cols_for_m_saving_schedule.sql delete mode 100644 mifosng-db/patches/patch-10_add_deposit_freq_col_for_m_saving_account.sql create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/data/SavingAccountTransactionsData.java diff --git a/mifosng-db/patches/patch-17_add_note_for_m_saving_account.sql b/mifosng-db/patches/patch-03_add_note_for_m_saving_account.sql similarity index 100% rename from mifosng-db/patches/patch-17_add_note_for_m_saving_account.sql rename to mifosng-db/patches/patch-03_add_note_for_m_saving_account.sql diff --git a/mifosng-db/patches/patch-18_create_table_saving_account_transaction.sql b/mifosng-db/patches/patch-04_create_table_saving_account_transaction.sql similarity index 100% rename from mifosng-db/patches/patch-18_create_table_saving_account_transaction.sql rename to mifosng-db/patches/patch-04_create_table_saving_account_transaction.sql diff --git a/mifosng-db/patches/patch-19_add_interest_posting,i_p_frequency_for_m_saving_account.sql b/mifosng-db/patches/patch-05_add_interest_posting,i_p_frequency_for_m_saving_account.sql similarity index 100% rename from mifosng-db/patches/patch-19_add_interest_posting,i_p_frequency_for_m_saving_account.sql rename to mifosng-db/patches/patch-05_add_interest_posting,i_p_frequency_for_m_saving_account.sql diff --git a/mifosng-db/patches/patch-20_add_interest_posting_cols_for_m_saving_account.sql b/mifosng-db/patches/patch-06_add_interest_posting_cols_for_m_saving_account.sql similarity index 100% rename from mifosng-db/patches/patch-20_add_interest_posting_cols_for_m_saving_account.sql rename to mifosng-db/patches/patch-06_add_interest_posting_cols_for_m_saving_account.sql diff --git a/mifosng-db/patches/patch-07_add_interest_accured_cols_for_m_saving_schedule.sql b/mifosng-db/patches/patch-07_add_interest_accured_cols_for_m_saving_schedule.sql new file mode 100644 index 000000000..e7f7daeb8 --- /dev/null +++ b/mifosng-db/patches/patch-07_add_interest_accured_cols_for_m_saving_schedule.sql @@ -0,0 +1,3 @@ +Alter TABLE `m_saving_schedule` + ADD COLUMN `interest_accured` decimal(21,4) DEFAULT '0.0000' AFTER `deposit_paid` + \ No newline at end of file diff --git a/mifosng-db/patches/patch-10_add_deposit_freq_col_for_m_saving_account.sql b/mifosng-db/patches/patch-10_add_deposit_freq_col_for_m_saving_account.sql deleted file mode 100644 index b9dfbb2d8..000000000 --- a/mifosng-db/patches/patch-10_add_deposit_freq_col_for_m_saving_account.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE m_saving_account - ADD COLUMN `deposit_every` bigint(20) DEFAULT NULL AFTER `tenure_type`; \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/api/GoogleGsonPortfolioApiJsonSerializerService.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/api/GoogleGsonPortfolioApiJsonSerializerService.java index ba5b6621a..f06c22d40 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/api/GoogleGsonPortfolioApiJsonSerializerService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/api/GoogleGsonPortfolioApiJsonSerializerService.java @@ -55,7 +55,7 @@ public class GoogleGsonPortfolioApiJsonSerializerService implements PortfolioApi "preClosureAllowed", "preClosureInterestRate", "withdrawnonDate", "rejectedonDate", "closedonDate", "isLockinPeriodAllowed", "lockinPeriod", "lockinPeriodType", "productOptions", "currencyOptions", "savingsProductTypeOptions", "tenureTypeOptions", "savingFrequencyOptions", "savingsInterestTypeOptions", "lockinPeriodTypeOptions", "interestCalculationOptions","permissions","savingScheduleDatas", - "dueAmount", "savingScheduleData")); + "dueAmount", "savingScheduleData", "transactions","interestPostEvery","interestPostFrequency")); // guarantors private static final Set GUARANTOR_DATA_PARAMETERS = new HashSet(Arrays.asList("externalGuarantor", "existingClientId", diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/api/PortfolioApiDataConversionServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/api/PortfolioApiDataConversionServiceImpl.java index c5bf97e6d..3cb7854d5 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/api/PortfolioApiDataConversionServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/api/PortfolioApiDataConversionServiceImpl.java @@ -817,7 +817,7 @@ public class PortfolioApiDataConversionServiceImpl implements PortfolioApiDataCo Set supportedParams = new HashSet(Arrays.asList("clientId", "productId", "externalId", "currencyCode", "digitsAfterDecimal", "savingsDepositAmountPerPeriod", "recurringInterestRate", "savingInterestRate", "tenure", "commencementDate", "locale", "dateFormat", "isLockinPeriodAllowed", "lockinPeriod", "lockinPeriodType", - "savingProductType", "tenureType", "depositfrequency", "interestType", "interestCalculationMethod", "minimumBalanceForWithdrawal", + "tenureType", "depositfrequency", "interestType", "interestCalculationMethod", "minimumBalanceForWithdrawal", "isPartialDepositAllowed", "depositEvery","interestPostEvery","interestPostFrequency")); checkForUnsupportedParameters(requestMap, supportedParams); Set modifiedParameters = new HashSet(); @@ -837,7 +837,6 @@ public class PortfolioApiDataConversionServiceImpl implements PortfolioApiDataCo Integer lockinPeriodType = extractIntegerParameter("lockinPeriodType", requestMap, modifiedParameters); LocalDate commencementDate = extractLocalDateParameter("commencementDate", requestMap, modifiedParameters); - Integer savingProductType = extractIntegerParameter("savingProductType", requestMap, modifiedParameters); Integer tenureType = extractIntegerParameter("tenureType", requestMap, modifiedParameters); Integer depositfrequency = extractIntegerParameter("depositfrequency", requestMap, modifiedParameters); Integer interestType = extractIntegerParameter("interestType", requestMap, modifiedParameters); @@ -851,7 +850,7 @@ public class PortfolioApiDataConversionServiceImpl implements PortfolioApiDataCo return new SavingAccountCommand(modifiedParameters, resourceIdentifier, clientId, productId, externalId, currencyCode, digitsAfterDecimalValue, savingsDepositAmount, recurringInterestRate, savingInterestRate, tenure, commencementDate, - savingProductType, tenureType, depositfrequency, interestType, minimumBalanceForWithdrawal, interestCalculationMethod, + tenureType, depositfrequency, interestType, minimumBalanceForWithdrawal, interestCalculationMethod, isLockinPeriodAllowed, isPartialDepositAllowed, lockinPeriod, lockinPeriodType, depositEvery, interestPostEvery, interestPostFrequency); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/api/SavingsAccountApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/api/SavingsAccountApiResource.java index 1ad97cd33..c10a9dd39 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/api/SavingsAccountApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/api/SavingsAccountApiResource.java @@ -42,6 +42,7 @@ import org.mifosplatform.portfolio.savingsaccount.command.SavingAccountWithdrawa import org.mifosplatform.portfolio.savingsaccount.command.SavingStateTransitionsCommand; import org.mifosplatform.portfolio.savingsaccount.data.SavingAccountData; import org.mifosplatform.portfolio.savingsaccount.data.SavingAccountForLookup; +import org.mifosplatform.portfolio.savingsaccount.data.SavingAccountTransactionsData; import org.mifosplatform.portfolio.savingsaccount.data.SavingPermissionData; import org.mifosplatform.portfolio.savingsaccount.data.SavingScheduleData; import org.mifosplatform.portfolio.savingsaccount.service.CalculateSavingSchedule; @@ -103,7 +104,7 @@ public class SavingsAccountApiResource { "interestCalculationMethod", "tenure", "tenureType", "projectedCommencementDate", "actualCommencementDate", "maturesOnDate", "projectedInterestAccuredOnMaturity", "actualInterestAccured", "projectedMaturityAmount", "actualMaturityAmount", "preClosureAllowed", "preClosureInterestRate", "withdrawnonDate", "rejectedonDate", "closedonDate", "isLockinPeriodAllowed", - "lockinPeriod", "lockinPeriodType","outstandingAmount","savingScheduleData")); + "lockinPeriod", "lockinPeriodType","outstandingAmount","savingScheduleData","transactions","interestPostEvery","interestPostFrequency")); @POST @Consumes({ MediaType.APPLICATION_JSON }) @@ -173,6 +174,7 @@ public class SavingsAccountApiResource { SavingPermissionData permissions = null; SavingScheduleData savingScheduleData = null; + Collection transactions = null; Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); if (responseParameters.isEmpty()) { @@ -191,8 +193,8 @@ public class SavingsAccountApiResource { Set associationParameters = ApiParameterHelper.extractAssociationsForResponseIfProvided(uriInfo.getQueryParameters()); if (!associationParameters.isEmpty()) { if (associationParameters.contains("all")) { - associationParameters.add("savingScheduleData"); - responseParameters.addAll(Arrays.asList("permissions","savingScheduleData")); + associationParameters.addAll(Arrays.asList("savingScheduleData","transactions")); + responseParameters.addAll(Arrays.asList("permissions","savingScheduleData","transactions")); } else { responseParameters.addAll(associationParameters); } @@ -202,6 +204,10 @@ public class SavingsAccountApiResource { savingScheduleData = this.savingAccountReadPlatformService.retrieveSavingsAccountSchedule(accountId,currencyData); account = new SavingAccountData(account,savingScheduleData); } + if (associationParameters.contains("transactions")) { + transactions = this.savingAccountReadPlatformService.retrieveSavingsAccountTransactions(accountId); + account = new SavingAccountData(account,transactions); + } permissions = this.savingAccountReadPlatformService.retrieveSavingAccountPermissions(account); account = new SavingAccountData(account, permissions); } @@ -258,10 +264,10 @@ public class SavingsAccountApiResource { List lockinPeriodTypeOptions = Arrays.asList(months); EnumOptionData averagebal = SavingProductEnumerations.savingInterestCalculationMethod(SavingInterestCalculationMethod.AVERAGEBAL); - EnumOptionData minbal = SavingProductEnumerations.savingInterestCalculationMethod(SavingInterestCalculationMethod.MINBAL); + // EnumOptionData minbal = SavingProductEnumerations.savingInterestCalculationMethod(SavingInterestCalculationMethod.MINBAL); EnumOptionData monthlyCollection = SavingProductEnumerations .savingInterestCalculationMethod(SavingInterestCalculationMethod.MONTHLYCOLLECTION); - List interestCalculationOptions = Arrays.asList(averagebal, minbal, monthlyCollection); + List interestCalculationOptions = Arrays.asList(averagebal, monthlyCollection); BigDecimal dueAmount = this.savingAccountReadPlatformService.deriveSavingDueAmount(account); return new SavingAccountData(account, productOptions, currencyOptions, savingsProductTypeOptions,tenureTypeOptions,savingFrequencyOptions, savingsInterestTypeOptions,lockinPeriodTypeOptions,interestCalculationOptions, dueAmount); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/command/CalculateSavingScheduleCommand.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/command/CalculateSavingScheduleCommand.java index 67b36dcdb..2834285d2 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/command/CalculateSavingScheduleCommand.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/command/CalculateSavingScheduleCommand.java @@ -13,12 +13,14 @@ public class CalculateSavingScheduleCommand { private final BigDecimal interestRate; private final LocalDate paymentsStartingFromDate; private final Integer tenure; + private final Integer tenureType; private final Integer interestPostEvery; private final Integer interestPostFrequency; + private final Integer interestCalculationMethod; public CalculateSavingScheduleCommand(final Long productId, final BigDecimal deposit, final Integer depositEvery, final Integer paymentFrequencyType, final BigDecimal interestRate, final LocalDate paymentsStartingFromDate, - final Integer tenure,final Integer interestPostEvery, final Integer interestPostFrequency) { + final Integer tenure, final Integer tenureType, final Integer interestPostEvery, final Integer interestPostFrequency, final Integer interestCalculationMethod) { this.productId = productId; this.deposit = deposit; @@ -27,8 +29,10 @@ public class CalculateSavingScheduleCommand { this.interestRate = interestRate; this.paymentsStartingFromDate = paymentsStartingFromDate; this.tenure = tenure; + this.tenureType = tenureType; this.interestPostEvery = interestPostEvery; this.interestPostFrequency = interestPostFrequency; + this.interestCalculationMethod = interestCalculationMethod; } @@ -68,4 +72,12 @@ public class CalculateSavingScheduleCommand { return this.interestPostFrequency; } + public Integer getTenureType() { + return this.tenureType; + } + + public Integer getInterestCalculationMethod() { + return this.interestCalculationMethod; + } + } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/command/SavingAccountCommand.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/command/SavingAccountCommand.java index 3e2b5049f..f5ec18b0f 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/command/SavingAccountCommand.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/command/SavingAccountCommand.java @@ -24,7 +24,6 @@ public class SavingAccountCommand { private final Integer lockinPeriodType; private final LocalDate commencementDate; - private final Integer savingProductType; private final Integer tenureType; private final Integer frequency; private final Integer interestType; @@ -42,7 +41,7 @@ public class SavingAccountCommand { public SavingAccountCommand(final Set modifiedParameters, final Long id, final Long clientId, final Long productId, final String externalId, final String currencyCode, final Integer digitsAfterDecimal, final BigDecimal savingsDepositAmount, final BigDecimal recurringInterestRate, final BigDecimal savingInterestRate, final Integer tenure, - final LocalDate commencementDate, final Integer savingProductType, final Integer tenureType, final Integer frequency, + final LocalDate commencementDate, final Integer tenureType, final Integer frequency, final Integer interestType, final BigDecimal minimumBalanceForWithdrawal, final Integer interestCalculationMethod, final boolean isLockinPeriodAllowed, final boolean isPartialDepositAllowed, final Integer lockInPeriod, final Integer lockinPeriodType, final Integer depositEvery,final Integer interestPostEvery,final Integer interestPostFrequency) { @@ -61,7 +60,6 @@ public class SavingAccountCommand { this.modifiedParameters = modifiedParameters; this.commencementDate = commencementDate; - this.savingProductType = savingProductType; this.tenureType = tenureType; this.frequency = frequency; this.interestType = interestType; @@ -134,10 +132,6 @@ public class SavingAccountCommand { return commencementDate; } - public Integer getSavingProductType() { - return savingProductType; - } - public Integer getTenureType() { return tenureType; } @@ -261,7 +255,7 @@ public class SavingAccountCommand { public CalculateSavingScheduleCommand toCalculateSavingScheduleCommand() { return new CalculateSavingScheduleCommand(productId, savingsDepositAmount, depositEvery, frequency, recurringInterestRate, - commencementDate, tenure, interestPostEvery, interestPostFrequency); + commencementDate, tenure, tenureType, interestPostEvery, interestPostFrequency,interestCalculationMethod); } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/command/SavingAccountCommandValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/command/SavingAccountCommandValidator.java index 031d74cde..60ceef6e8 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/command/SavingAccountCommandValidator.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/command/SavingAccountCommandValidator.java @@ -32,7 +32,6 @@ public class SavingAccountCommandValidator { baseDataValidator.reset().parameter("savingInterestRate").value(command.getSavingInterestRate()).notNull().zeroOrPositiveAmount(); baseDataValidator.reset().parameter("savingInterestRate") .comapareMinAndMaxOfTwoBigDecmimalNos(command.getSavingInterestRate(), command.getRecurringInterestRate()); - baseDataValidator.reset().parameter("savingProductType").value(command.getSavingProductType()).notNull(); baseDataValidator.reset().parameter("tenureType").value(command.getTenureType()).notNull(); baseDataValidator.reset().parameter("tenure").value(command.getTenure()).notNull(); baseDataValidator.reset().parameter("frequency").value(command.getFrequency()).notNull(); @@ -72,7 +71,6 @@ public class SavingAccountCommandValidator { .zeroOrPositiveAmount(); baseDataValidator.reset().parameter("savingInterestRate") .comapareMinAndMaxOfTwoBigDecmimalNos(command.getSavingInterestRate(), command.getRecurringInterestRate()); - baseDataValidator.reset().parameter("savingProductType").value(command.getSavingProductType()).ignoreIfNull(); baseDataValidator.reset().parameter("tenureType").value(command.getTenureType()).ignoreIfNull(); baseDataValidator.reset().parameter("tenure").value(command.getTenure()).ignoreIfNull(); baseDataValidator.reset().parameter("frequency").value(command.getFrequency()).ignoreIfNull(); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/data/SavingAccountData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/data/SavingAccountData.java index 3c50ee16d..fc8e40e3a 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/data/SavingAccountData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/data/SavingAccountData.java @@ -72,6 +72,10 @@ public class SavingAccountData { private final BigDecimal outstandingAmount; private final BigDecimal dueAmount; private final SavingScheduleData savingScheduleData; + private final Collection transactions; + + private final Integer interestPostEvery; + private final EnumOptionData interestPostFrequency; public static SavingAccountData createFrom(final Long clientId, final String clientDisplayName) { return new SavingAccountData(clientId, clientDisplayName); @@ -85,7 +89,7 @@ public class SavingAccountData { BigDecimal projectedInterestAccuredOnMaturity, BigDecimal actualInterestAccured, BigDecimal projectedMaturityAmount, BigDecimal actualMaturityAmount, boolean preClosureAllowed, BigDecimal preClosureInterestRate, LocalDate withdrawnonDate, LocalDate rejectedonDate, LocalDate closedonDate, boolean isLockinPeriodAllowed, Integer lockinPeriod, - EnumOptionData lockinPeriodType, Integer depositEvery, BigDecimal outstandingAmount) { + EnumOptionData lockinPeriodType, Integer depositEvery, BigDecimal outstandingAmount, Integer interestPostEvery, EnumOptionData interestPostFrequency) { this.id = id; this.status = status; this.externalId = externalId; @@ -133,6 +137,9 @@ public class SavingAccountData { this.outstandingAmount = outstandingAmount; this.dueAmount = BigDecimal.ZERO; this.savingScheduleData = null; + this.transactions = null; + this.interestPostEvery = interestPostEvery; + this.interestPostFrequency = interestPostFrequency; } public SavingAccountData(Long clientId, String clientName) { @@ -183,6 +190,9 @@ public class SavingAccountData { this.outstandingAmount = BigDecimal.ZERO; this.dueAmount =BigDecimal.ZERO; this.savingScheduleData = null; + this.transactions = null; + this.interestPostEvery =null; + this.interestPostFrequency = null; } public SavingAccountData(SavingAccountData account, Collection productOptions, List currencyOptions, @@ -238,6 +248,9 @@ public class SavingAccountData { this.permissions = account.permissions; this.outstandingAmount = account.outstandingAmount; this.savingScheduleData = account.savingScheduleData; + this.transactions = account.transactions; + this.interestPostEvery = account.interestPostEvery; + this.interestPostFrequency = account.interestPostFrequency; } // FIXME - Madhukar - unused variables been passed into construction - why? @@ -277,7 +290,7 @@ public class SavingAccountData { this.withdrawnonDate = null; this.rejectedonDate = null; this.closedonDate = null; - this.isLockinPeriodAllowed = false; + this.isLockinPeriodAllowed = lockinPeriodAllowed; this.lockinPeriod = lockinPeriod; this.lockinPeriodType = lockinPeriodType; this.depositEvery = depositEvery; @@ -294,6 +307,9 @@ public class SavingAccountData { this.outstandingAmount = BigDecimal.ZERO; this.dueAmount = BigDecimal.ZERO; this.savingScheduleData = null; + this.transactions = null; + this.interestPostEvery =3; + this.interestPostFrequency = savingsFrequencyType; } public SavingAccountData(SavingAccountData account, SavingPermissionData permissions) { @@ -345,6 +361,9 @@ public class SavingAccountData { this.outstandingAmount = account.outstandingAmount; this.dueAmount = account.dueAmount; this.savingScheduleData = account.savingScheduleData; + this.transactions = account.transactions; + this.interestPostEvery = account.interestPostEvery; + this.interestPostFrequency = account.interestPostFrequency; } public SavingAccountData(SavingAccountData account, SavingScheduleData savingScheduleData) { @@ -396,6 +415,63 @@ public class SavingAccountData { this.outstandingAmount = account.outstandingAmount; this.dueAmount = account.dueAmount; this.savingScheduleData = savingScheduleData; + this.transactions = account.transactions; + this.interestPostEvery = account.interestPostEvery; + this.interestPostFrequency = account.interestPostFrequency; + } + + public SavingAccountData(SavingAccountData account, Collection transactions) { + this.id = account.id; + this.status = account.status; + this.externalId = account.externalId; + this.clientId = account.clientId; + this.clientName = account.clientName; + this.productId = account.productId; + this.productName = account.productName; + this.productType = account.productType; + this.currencyData = account.currencyData; + this.savingsDepositAmountPerPeriod = account.savingsDepositAmountPerPeriod; + this.savingsFrequencyType = account.savingsFrequencyType; + this.totalDepositAmount = account.totalDepositAmount; + this.recurringInterestRate = account.recurringInterestRate; + this.savingInterestRate = account.savingInterestRate; + this.interestType = account.interestType; + this.interestCalculationMethod = account.interestCalculationMethod; + this.tenure = account.tenure; + this.tenureType = account.tenureType; + this.projectedCommencementDate = account.projectedCommencementDate; + this.actualCommencementDate = account.actualCommencementDate; + this.maturesOnDate = account.maturesOnDate; + this.projectedInterestAccuredOnMaturity = account.projectedInterestAccuredOnMaturity; + this.actualInterestAccured = account.actualInterestAccured; + this.projectedMaturityAmount = account.projectedMaturityAmount; + this.actualMaturityAmount = account.actualMaturityAmount; + this.preClosureAllowed = account.preClosureAllowed; + this.preClosureInterestRate = account.preClosureInterestRate; + this.withdrawnonDate = account.withdrawnonDate; + this.rejectedonDate = account.rejectedonDate; + this.closedonDate = account.closedonDate; + this.isLockinPeriodAllowed = account.isLockinPeriodAllowed; + this.lockinPeriod = account.lockinPeriod; + this.lockinPeriodType = account.lockinPeriodType; + this.depositEvery = account.depositEvery; + + this.productOptions = account.productOptions; + this.currencyOptions = account.currencyOptions; + this.savingsProductTypeOptions = account.savingsProductTypeOptions; + this.tenureTypeOptions = account.tenureTypeOptions; + this.savingFrequencyOptions = account.savingFrequencyOptions; + this.savingsInterestTypeOptions = account.savingsInterestTypeOptions; + this.lockinPeriodTypeOptions = account.lockinPeriodTypeOptions; + this.interestCalculationOptions = account.interestCalculationOptions; + this.savingScheduleDatas = account.savingScheduleDatas; + this.permissions = account.permissions; + this.outstandingAmount = account.outstandingAmount; + this.dueAmount = account.dueAmount; + this.savingScheduleData = account.savingScheduleData; + this.transactions = transactions; + this.interestPostEvery = account.interestPostEvery; + this.interestPostFrequency = account.interestPostFrequency; } public Long getId() { @@ -569,5 +645,13 @@ public class SavingAccountData { public BigDecimal getOutstandingAmount() { return this.outstandingAmount; } + + public Integer getInterestPostEvery() { + return this.interestPostEvery; + } + + public EnumOptionData getInterestPostFrequency() { + return this.interestPostFrequency; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/data/SavingAccountTransactionsData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/data/SavingAccountTransactionsData.java new file mode 100644 index 000000000..8fb973a5e --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/data/SavingAccountTransactionsData.java @@ -0,0 +1,33 @@ +package org.mifosplatform.portfolio.savingsaccount.data; + +import java.math.BigDecimal; + +import org.joda.time.LocalDate; +import org.mifosplatform.infrastructure.core.data.EnumOptionData; + +public class SavingAccountTransactionsData { + + @SuppressWarnings("unused") + private final Long id; + @SuppressWarnings("unused") + private final LocalDate transactionDate; + @SuppressWarnings("unused") + private final EnumOptionData transactionType; + @SuppressWarnings("unused") + private final BigDecimal amount; + + public SavingAccountTransactionsData() { + this.id = null; + this.transactionDate = null; + this.transactionType = null; + this.amount = BigDecimal.ZERO; + } + + public SavingAccountTransactionsData(final Long id, final LocalDate transactionDate, EnumOptionData transactionType, BigDecimal amount){ + this.id = id; + this.transactionDate = transactionDate; + this.transactionType = transactionType; + this.amount = amount; + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/data/SavingScheduleData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/data/SavingScheduleData.java index 54cfa60de..62bc2d173 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/data/SavingScheduleData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/data/SavingScheduleData.java @@ -9,12 +9,16 @@ public class SavingScheduleData { private final CurrencyData currency; private final BigDecimal cumulativeDepositDue; + private final BigDecimal cumulativeDepositPaid; + private final BigDecimal cummulativeInterestAccured; private final Collection periods; - public SavingScheduleData(final CurrencyData currency, final BigDecimal cumulativeDepositDue, - final Collection periods) { + public SavingScheduleData(final CurrencyData currency, final BigDecimal cumulativeDepositDue, final BigDecimal cumulativeDepositPaid, + final BigDecimal cummulativeInterestAccured, final Collection periods) { this.currency = currency; this.cumulativeDepositDue = cumulativeDepositDue; + this.cumulativeDepositPaid = cumulativeDepositPaid; + this.cummulativeInterestAccured = cummulativeInterestAccured; this.periods = periods; } @@ -27,7 +31,15 @@ public class SavingScheduleData { return this.cumulativeDepositDue; } - public Collection getPeriods() { + public BigDecimal getCumulativeDepositPaid() { + return this.cumulativeDepositPaid; + } + + public BigDecimal getCummulativeInterestAccured() { + return this.cummulativeInterestAccured; + } + + public Collection getPeriods() { return this.periods; } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/data/SavingSchedulePeriodData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/data/SavingSchedulePeriodData.java index e2d7b3b1d..28f65f76b 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/data/SavingSchedulePeriodData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/data/SavingSchedulePeriodData.java @@ -10,17 +10,19 @@ public class SavingSchedulePeriodData { private final LocalDate dueDate; private final BigDecimal depositDue; private final BigDecimal depositPaid; + private final BigDecimal interestAccured; - public SavingSchedulePeriodData(final Integer period, final LocalDate dueDate, final BigDecimal depositDue, final BigDecimal depositPaid) { + public SavingSchedulePeriodData(final Integer period, final LocalDate dueDate, final BigDecimal depositDue, final BigDecimal depositPaid, final BigDecimal interestAccured) { this.period = period; this.dueDate = dueDate; this.depositDue = depositDue; this.depositPaid = depositPaid; + this.interestAccured = interestAccured; } public static SavingSchedulePeriodData addScheduleInformation(int periodNumber, LocalDate scheduleDate, - BigDecimal depositAmountPerPeriod) { - return new SavingSchedulePeriodData(periodNumber, scheduleDate, depositAmountPerPeriod, BigDecimal.ZERO); + BigDecimal depositAmountPerPeriod, BigDecimal interestAccured) { + return new SavingSchedulePeriodData(periodNumber, scheduleDate, depositAmountPerPeriod, BigDecimal.ZERO, interestAccured); } public Integer getPeriod() { @@ -39,5 +41,7 @@ public class SavingSchedulePeriodData { return this.depositPaid; } - + public BigDecimal getInterestAccured() { + return this.interestAccured; + } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/domain/DepositScheduleDateGenerator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/domain/DepositScheduleDateGenerator.java index 6b2e7b4ca..adfd97d26 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/domain/DepositScheduleDateGenerator.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/domain/DepositScheduleDateGenerator.java @@ -3,11 +3,11 @@ package org.mifosplatform.portfolio.savingsaccount.domain; import java.util.List; import org.joda.time.LocalDate; -import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType; +import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingFrequencyType; public interface DepositScheduleDateGenerator { - List generate(LocalDate startDate, Integer paymentPeriods, Integer depositFrequency, PeriodFrequencyType depositFrequencyType); + List generate(LocalDate startDate, Integer paymentPeriods, Integer depositFrequency, SavingFrequencyType savingFrequencyType); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/domain/ReccuringDepositInterestCalculator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/domain/ReccuringDepositInterestCalculator.java index d81110e25..7222b2301 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/domain/ReccuringDepositInterestCalculator.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/domain/ReccuringDepositInterestCalculator.java @@ -34,27 +34,29 @@ public class ReccuringDepositInterestCalculator { if(savingInterestCalculationMethod.isAverageBalance()){ - BigDecimal totalAmount = BigDecimal.ZERO; BigDecimal termAmount = BigDecimal.ZERO; BigDecimal totalInterest = BigDecimal.ZERO; + BigDecimal closingBalance = BigDecimal.ZERO; BigDecimal amountPerPeriod = savingsDepositPerPeriod.getAmount(); Integer depositEveryOriginalValue = depositEvery; - BigDecimal amountPermonth = amountPerPeriod.divide(BigDecimal.valueOf(depositEvery.doubleValue())); + BigDecimal amountPermonth = BigDecimal.valueOf(amountPerPeriod.doubleValue()/depositEvery.doubleValue()); + while (noOfTimestobeCalculated > 0) { while (depositEvery > 0) { - termAmount = termAmount.add(amountPermonth); - totalAmount = totalAmount.add(termAmount); + closingBalance = closingBalance.add(amountPermonth); + termAmount = termAmount.add(closingBalance); depositEvery--; } - BigDecimal averageAmount = BigDecimal.valueOf(totalAmount.doubleValue()/depositEveryOriginalValue.doubleValue()); + + BigDecimal averageAmount = BigDecimal.valueOf(termAmount.doubleValue()/depositEveryOriginalValue.doubleValue()); BigDecimal interestRatePerTerm = BigDecimal.valueOf(interestRateAsFraction.doubleValue()/monthsInYear.doubleValue()*depositEveryOriginalValue.doubleValue()); BigDecimal interestperTerm = averageAmount.multiply(interestRatePerTerm); totalInterest = totalInterest.add(interestperTerm); depositEvery = depositEveryOriginalValue; - totalAmount = BigDecimal.ZERO; + termAmount = BigDecimal.ZERO; noOfTimestobeCalculated--; } - finalAmount = termAmount.add(totalInterest); + finalAmount = closingBalance.add(totalInterest); } else if(savingInterestCalculationMethod.isMonthlyCollection()){ /* @@ -73,14 +75,15 @@ public class ReccuringDepositInterestCalculator { BigDecimal monthsExpressedInYears; BigDecimal timeforOneCalculationPeriod; BigDecimal amountPerPeriod; - + Integer tempTenure = tenure; while (noOfTimestobeCalculated > 0) { - monthsExpressedInYears = BigDecimal.valueOf(tenure.doubleValue() / monthsInYear.doubleValue()); + monthsExpressedInYears = BigDecimal.valueOf(tempTenure.doubleValue() / monthsInYear.doubleValue()); timeforOneCalculationPeriod = BigDecimal.valueOf(noofTimesInterestCompoundPerYear * monthsExpressedInYears.doubleValue()); amountPerPeriod = savingsDepositPerPeriod.getAmount().multiply( BigDecimal.valueOf(Math.pow(onePlusInterestRatePerPeriod.doubleValue(), timeforOneCalculationPeriod.doubleValue()))); finalAmount = finalAmount.add(amountPerPeriod); noOfTimestobeCalculated--; + tempTenure = tempTenure-depositEvery; } } return Money.of(savingsDepositPerPeriod.getCurrency(), finalAmount); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/domain/SavingAccount.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/domain/SavingAccount.java index 071a4511a..354391786 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/domain/SavingAccount.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/domain/SavingAccount.java @@ -204,12 +204,13 @@ public class SavingAccount extends AbstractAuditableCustom { Integer depositEvery, Integer interestPostEvery, Integer interestPostFrequency) { Money futureValueOnMaturity = null; - if (savingProductType.isReccuring()) { + if (savingProductType.isReccuring() && tenureTypeEnum.isFixedPeriod()) { futureValueOnMaturity = reccuringDepositInterestCalculator.calculateInterestOnMaturityFor(savingsDeposit, tenure, reccuringInterestRate, commencementDate, tenureTypeEnum, savingFrequencyType, savingInterestCalculationMethod,depositEvery); - } else if (savingProductType.isRegular()) { - futureValueOnMaturity = reccuringDepositInterestCalculator.calculateInterestOnMaturityFor(savingsDeposit, tenure, - savingInterestRate, commencementDate, tenureTypeEnum, savingFrequencyType, savingInterestCalculationMethod,depositEvery); + } else if (savingProductType.isReccuring() && tenureTypeEnum.isPerpetual()) { + futureValueOnMaturity = savingsDeposit; + } else { + futureValueOnMaturity = savingsDeposit; } return new SavingAccount(client, externalId, product, savingsDeposit, reccuringInterestRate, savingInterestRate, tenure, @@ -255,8 +256,8 @@ public class SavingAccount extends AbstractAuditableCustom { this.lockinPeriod = lockinPeriod; this.lockinPeriodType = lockinPeriodType.getValue(); this.projectedTotalOnMaturity = futureValueOnMaturity.getAmount(); - this.projectedInterestAccruedOnMaturity = futureValueOnMaturity.getAmount().subtract( - BigDecimal.valueOf(savingsDeposit.getAmount().doubleValue() * tenure.doubleValue() / payEvery)); //presently only for months + BigDecimal projectedInterestForReccuring = futureValueOnMaturity.getAmount().subtract(BigDecimal.valueOf(savingsDeposit.getAmount().doubleValue() * tenure.doubleValue() / payEvery)); //presently only for months + this.projectedInterestAccruedOnMaturity = savingProductType.isReccuring() && tenureTypeEnum.isFixedPeriod() ? projectedInterestForReccuring : BigDecimal.ZERO; this.payEvery = payEvery; this.outstandingAmount = BigDecimal.ZERO; this.interestPostEvery = interestPostEvery; @@ -267,15 +268,17 @@ public class SavingAccount extends AbstractAuditableCustom { BigDecimal savingInterestRate, Integer tenure, LocalDate commencementDate, TenureTypeEnum tenureTypeEnum, SavingProductType savingProductType, SavingFrequencyType savingFrequencyType, SavingInterestCalculationMethod savingInterestCalculationMethod, boolean isLockinPeriodAllowed, Integer lockinPeriod, - PeriodFrequencyType lockinPeriodType, ReccuringDepositInterestCalculator reccuringDepositInterestCalculator,Integer payEvery) { + PeriodFrequencyType lockinPeriodType, ReccuringDepositInterestCalculator reccuringDepositInterestCalculator,Integer payEvery, + SavingsInterestType interestType, Integer interestPostEvery, Integer interestPostFrequency) { - Money futureValueOnMaturity = null; - if (savingProductType.isReccuring()) { + Money futureValueOnMaturity = null; + if (savingProductType.isReccuring() && tenureTypeEnum.isFixedPeriod()) { futureValueOnMaturity = reccuringDepositInterestCalculator.calculateInterestOnMaturityFor(savingsDeposit, tenure, reccuringInterestRate, commencementDate, tenureTypeEnum, savingFrequencyType, savingInterestCalculationMethod,payEvery); - } else if (savingProductType.isRegular()) { - futureValueOnMaturity = reccuringDepositInterestCalculator.calculateInterestOnMaturityFor(savingsDeposit, tenure, - savingInterestRate, commencementDate, tenureTypeEnum, savingFrequencyType, savingInterestCalculationMethod,payEvery); + } else if (savingProductType.isReccuring() && tenureTypeEnum.isPerpetual()) { + futureValueOnMaturity = savingsDeposit; + } else { + futureValueOnMaturity = savingsDeposit; } this.product = product; @@ -288,17 +291,20 @@ public class SavingAccount extends AbstractAuditableCustom { this.tenureType = tenureTypeEnum.getValue(); this.savingProductType = savingProductType.getValue(); this.frequency = savingFrequencyType.getValue(); + this.interestType = interestType.getValue(); this.interestCalculationMethod = savingInterestCalculationMethod.getValue(); this.isLockinPeriodAllowed = isLockinPeriodAllowed; this.lockinPeriod = lockinPeriod; this.lockinPeriodType = lockinPeriodType.getValue(); this.payEvery = payEvery; this.outstandingAmount = BigDecimal.ZERO; + this.interestPostEvery = interestPostEvery; + this.interestPostFrequency=interestPostFrequency; + this.savingScheduleInstallments.clear(); - // FIXME - MADHUKAR - futureValueOnMaturity is possibly null this.projectedTotalOnMaturity = futureValueOnMaturity.getAmount(); - this.projectedInterestAccruedOnMaturity = futureValueOnMaturity.getAmount().subtract( - BigDecimal.valueOf(savingsDeposit.getAmount().doubleValue() * tenure.doubleValue())); + BigDecimal projectedInterestForReccuring = futureValueOnMaturity.getAmount().subtract(BigDecimal.valueOf(savingsDeposit.getAmount().doubleValue() * tenure.doubleValue() / payEvery)); //presently only for months + this.projectedInterestAccruedOnMaturity = savingProductType.isReccuring() && tenureTypeEnum.isFixedPeriod() ? projectedInterestForReccuring : BigDecimal.ZERO; } public boolean isDeleted() { @@ -456,6 +462,7 @@ public class SavingAccount extends AbstractAuditableCustom { this.maturesOnDate = null; this.withdrawnOnDate = withdrawnOn.toDateTimeAtCurrentTime().toDate(); this.closedOnDate = withdrawnOn.toDateTimeAtCurrentTime().toDate(); + this.savingScheduleInstallments.clear(); if (withdrawnOn.isBefore(projectedCommencementDate())) { @@ -480,7 +487,6 @@ public class SavingAccount extends AbstractAuditableCustom { this.closedOnDate = new Date(); } - @SuppressWarnings("null") public void approveSavingAccount(LocalDate approvalDate, BigDecimal savingsDepositAmountPerPeriod, BigDecimal recurringInterestRate, BigDecimal savingInterestRate, Integer interestType, Integer tenure, Integer tenureType, Integer frequency, Integer payEvery, DepositLifecycleStateMachine depositLifecycleStateMachine, ReccuringDepositInterestCalculator reccuringDepositInterestCalculator, @@ -496,12 +502,13 @@ public class SavingAccount extends AbstractAuditableCustom { SavingInterestCalculationMethod interestCalculationMethod = SavingInterestCalculationMethod.fromInt(this.interestCalculationMethod); Money futureValueOnMaturity = null; - if (SavingProductType.fromInt(product.getSavingProductRelatedDetail().getSavingProductType()).isReccuring()) { + if (SavingProductType.fromInt(this.savingProductType).isReccuring() && tenureTypeEnum.isFixedPeriod()) { futureValueOnMaturity = reccuringDepositInterestCalculator.calculateInterestOnMaturityFor(savingsAmountPerPeriod, tenure, recurringInterestRate, approvalDate, tenureTypeEnum, savingFrequencyType, interestCalculationMethod,payEvery); - } else if (SavingProductType.fromInt(product.getSavingProductRelatedDetail().getSavingProductType()).isRegular()) { - futureValueOnMaturity = reccuringDepositInterestCalculator.calculateInterestOnMaturityFor(savingsAmountPerPeriod, tenure, - savingInterestRate, approvalDate, tenureTypeEnum, savingFrequencyType, interestCalculationMethod,payEvery); + } else if (SavingProductType.fromInt(this.savingProductType).isReccuring() && tenureTypeEnum.isPerpetual()) { + futureValueOnMaturity = savingsAmountPerPeriod; + } else { + futureValueOnMaturity = savingsAmountPerPeriod; } this.actualCommencementDate = approvalDate.toDate(); @@ -515,7 +522,8 @@ public class SavingAccount extends AbstractAuditableCustom { this.payEvery = payEvery; this.savingScheduleInstallments.clear(); this.total=futureValueOnMaturity.getAmount(); - this.interestAccrued = futureValueOnMaturity.getAmount().subtract(BigDecimal.valueOf(savingsDepositAmountPerPeriod.doubleValue() * tenure/payEvery.doubleValue())); + BigDecimal interestForReccuring = futureValueOnMaturity.getAmount().subtract(BigDecimal.valueOf(savingsDepositAmountPerPeriod.doubleValue() * tenure.doubleValue()/payEvery.doubleValue())); //presently only for months + this.interestAccrued = SavingProductType.fromInt(this.savingProductType).isReccuring() && tenureTypeEnum.isFixedPeriod() ? interestForReccuring : BigDecimal.ZERO; this.interestPostEvery = interestPostEvery; this.interestPostFrequency = interestPostFrequency; @@ -537,25 +545,32 @@ public class SavingAccount extends AbstractAuditableCustom { this.outstandingAmount = this.outstandingAmount.add(command.getSavingsDepostiAmountPerPeriod()); this.totalSavingsAmount = this.totalSavingsAmount.add(command.getSavingsDepostiAmountPerPeriod()); - for(SavingScheduleInstallments savingScheduleInstallment : this.savingScheduleInstallments){ - if(!savingScheduleInstallment.isCompleted()){ - depositAmount = savingScheduleInstallment.getDeposit(); - remainAmountToBePaid = depositAmount.subtract(savingScheduleInstallment.getDepositPaid()); - if (remainAmountToBePaid.doubleValue() > 0) { - if (commandRemainDepositAmount.doubleValue() > 0) { - if (commandRemainDepositAmount.doubleValue() >= remainAmountToBePaid.doubleValue()) { - savingScheduleInstallment.setDepositPaid(remainAmountToBePaid.add(savingScheduleInstallment.getDepositPaid())); - savingScheduleInstallment.setPaymentDate(command.getDepositDate().toDate()); - savingScheduleInstallment.setCompleted(true); - commandRemainDepositAmount = commandRemainDepositAmount.subtract(remainAmountToBePaid); - } else if(commandRemainDepositAmount.doubleValue() < remainAmountToBePaid.doubleValue()){ - savingScheduleInstallment.setDepositPaid(commandRemainDepositAmount.add(savingScheduleInstallment.getDepositPaid())); - savingScheduleInstallment.setPaymentDate(command.getDepositDate().toDate()); - commandRemainDepositAmount = BigDecimal.ZERO; + if(SavingProductType.fromInt(this.savingProductType).isReccuring() && TenureTypeEnum.fromInt(tenureType).isFixedPeriod()) { + for(SavingScheduleInstallments savingScheduleInstallment : this.savingScheduleInstallments){ + if(!savingScheduleInstallment.isCompleted()){ + depositAmount = savingScheduleInstallment.getDeposit(); + remainAmountToBePaid = depositAmount.subtract(savingScheduleInstallment.getDepositPaid()); + if (remainAmountToBePaid.doubleValue() > 0) { + if (commandRemainDepositAmount.doubleValue() > 0) { + if (commandRemainDepositAmount.doubleValue() >= remainAmountToBePaid.doubleValue()) { + savingScheduleInstallment.setDepositPaid(remainAmountToBePaid.add(savingScheduleInstallment.getDepositPaid())); + savingScheduleInstallment.setPaymentDate(command.getDepositDate().toDate()); + savingScheduleInstallment.setCompleted(true); + commandRemainDepositAmount = commandRemainDepositAmount.subtract(remainAmountToBePaid); + } else if(commandRemainDepositAmount.doubleValue() < remainAmountToBePaid.doubleValue()){ + savingScheduleInstallment.setDepositPaid(commandRemainDepositAmount.add(savingScheduleInstallment.getDepositPaid())); + savingScheduleInstallment.setPaymentDate(command.getDepositDate().toDate()); + commandRemainDepositAmount = BigDecimal.ZERO; + } } } } } + } else { + for(SavingScheduleInstallments savingScheduleInstallment : this.savingScheduleInstallments){ + savingScheduleInstallment.setDepositPaid(remainAmountToBePaid.add(savingScheduleInstallment.getDepositPaid())); + savingScheduleInstallment.setPaymentDate(command.getDepositDate().toDate()); + } } } @@ -582,7 +597,7 @@ public class SavingAccount extends AbstractAuditableCustom { this.externalId = this.getId() + "_" + this.externalId; } - public void postInterest(ReccuringDepositInterestCalculator reccuringDepositInterestCalculator) { + public void postInterest() { LocalDate lastInterestPostedDate = getLastInterestPostedDate(); @SuppressWarnings("unused") @@ -643,8 +658,9 @@ public class SavingAccount extends AbstractAuditableCustom { termTotalAmount = termTotalAmount.add(totalOutstandingAmount); transactionStartDate = transactionEndDate; isOutstandingAmountCalculated = true; + } - // FIXME-MADHUKAR calculate interest on calculation method + // TODO- calculate interest on calculation method // if (savingInterestCalculationMethod.isAverageBalance()) { averageBalanceForTerm =BigDecimal.valueOf(termTotalAmount.doubleValue()/this.interestPostEvery); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/domain/SavingScheduleInstallments.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/domain/SavingScheduleInstallments.java index 7fe316c00..80270ee09 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/domain/SavingScheduleInstallments.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/domain/SavingScheduleInstallments.java @@ -45,6 +45,10 @@ public class SavingScheduleInstallments extends AbstractAuditableCustom periods = new ArrayList(); + CurrencyData currencyData = new CurrencyData(applicationCurrency.getCode(), applicationCurrency.getName(), + savingProduct.getCurrency().getDigitsAfterDecimal(), applicationCurrency.getDisplaySymbol(), applicationCurrency.getNameCode()); + SavingSchedulePeriodData installment = SavingSchedulePeriodData.addScheduleInformation(1, new LocalDate(command.getPaymentsStartingFromDate()).plusMonths(depositFrequency), command.getDeposit(), BigDecimal.ZERO); + periods.add(installment); + savingScheduleData = new SavingScheduleData(currencyData, command.getDeposit(), BigDecimal.ZERO, BigDecimal.ZERO, periods); + } + return savingScheduleData; } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/service/DefaultDepositScheduleDateGenerator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/service/DefaultDepositScheduleDateGenerator.java index c842c1efa..30c93e0e5 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/service/DefaultDepositScheduleDateGenerator.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/service/DefaultDepositScheduleDateGenerator.java @@ -4,14 +4,14 @@ import java.util.ArrayList; import java.util.List; import org.joda.time.LocalDate; -import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType; import org.mifosplatform.portfolio.savingsaccount.domain.DepositScheduleDateGenerator; +import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingFrequencyType; public class DefaultDepositScheduleDateGenerator implements DepositScheduleDateGenerator { @Override public List generate(LocalDate scheuleStartDate, Integer paymentPeriods, Integer depositFrequency, - PeriodFrequencyType depositFrequencyType) { + SavingFrequencyType savingFrequencyType) { List duePaymentPeriodDates = new ArrayList(depositFrequency); LocalDate startDate = scheuleStartDate; @@ -22,21 +22,24 @@ public class DefaultDepositScheduleDateGenerator implements DepositScheduleDateG if (period == 1) { duePaymentPeriodDate = startDate; } else { - switch (depositFrequencyType) { - case DAYS: + switch (savingFrequencyType) { + case DAILY: duePaymentPeriodDate = startDate.plusDays(depositFrequency); break; - case WEEKS: - duePaymentPeriodDate = startDate.plusWeeks(depositFrequency); - break; - case MONTHS: + case MONTHLY: duePaymentPeriodDate = startDate.plusMonths(depositFrequency); break; - case YEARS: - duePaymentPeriodDate = startDate.plusYears(depositFrequency); + case QUATERLY: + duePaymentPeriodDate = startDate.plusMonths(3*depositFrequency); break; - case INVALID: + case HALFYEARLY: + duePaymentPeriodDate = startDate.plusMonths(6*depositFrequency); break; + case YEARLY: + duePaymentPeriodDate = startDate.plusYears(depositFrequency); + break; + default: + break; } } duePaymentPeriodDates.add(duePaymentPeriodDate); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/service/SavingAccountAssembler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/service/SavingAccountAssembler.java index f38340bb1..3f0477616 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/service/SavingAccountAssembler.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/service/SavingAccountAssembler.java @@ -80,9 +80,6 @@ public class SavingAccountAssembler { } SavingProductType savingProductType = SavingProductType.fromInt(product.getSavingProductRelatedDetail().getSavingProductType()); - if (command.getSavingProductType() != null) { - savingProductType = SavingProductType.fromInt(command.getSavingProductType()); - } SavingFrequencyType savingFrequencyType = SavingFrequencyType.fromInt(product.getSavingProductRelatedDetail().getFrequency()); if (command.getFrequency() != null) { @@ -135,7 +132,7 @@ public class SavingAccountAssembler { for (SavingSchedulePeriodData savingSchedulePeriodData : savingScheduleData.getPeriods()) { final SavingScheduleInstallments installment = new SavingScheduleInstallments(account, savingSchedulePeriodData.getDueDate() - .toDate(), savingSchedulePeriodData.getPeriod(), savingSchedulePeriodData.getDepositDue()); + .toDate(), savingSchedulePeriodData.getPeriod(), savingSchedulePeriodData.getDepositDue(), savingSchedulePeriodData.getInterestAccured()); account.addSavingScheduleInstallment(installment); } @@ -177,9 +174,6 @@ public class SavingAccountAssembler { } SavingProductType savingProductType = SavingProductType.fromInt(account.getSavingProductType()); - if (command.isSavingProductTypeChanged()) { - savingProductType = SavingProductType.fromInt(command.getSavingProductType()); - } SavingFrequencyType savingFrequencyType = SavingFrequencyType.fromInt(account.getFrequency()); if (command.isSavingFrequencyTypeChanged()) { @@ -220,9 +214,28 @@ public class SavingAccountAssembler { if(command.isDepositEveryChanged()){ payEvery = command.getDepositEvery(); } + + SavingsInterestType interestType = SavingsInterestType.fromInt(product.getSavingProductRelatedDetail().getInterestType()); + if (command.getInterestType() != null) { + interestType = SavingsInterestType.fromInt(command.getInterestType()); + } + + Integer interestPostEvery = command.getInterestPostEvery(); + + Integer interestPostFrequency =command.getInterestPostFrequency(); + account.modifyAccount(product, externalId, savingsDeposit, reccuringInterestRate, savingInterestRate, tenure, commencementDate, tenureTypeEnum, savingProductType, savingFrequencyType, savingInterestCalculationMethod, isLockinPeriodAllowed, - lockinPeriod, lockinPeriodType, this.reccuringDepositInterestCalculator,payEvery); + lockinPeriod, lockinPeriodType, this.reccuringDepositInterestCalculator,payEvery, interestType, interestPostEvery, interestPostFrequency); + + SavingScheduleData savingScheduleData = this.calculateSavingSchedule.calculateSavingSchedule(command + .toCalculateSavingScheduleCommand()); + for (SavingSchedulePeriodData savingSchedulePeriodData : savingScheduleData.getPeriods()) { + + final SavingScheduleInstallments installment = new SavingScheduleInstallments(account, savingSchedulePeriodData.getDueDate() + .toDate(), savingSchedulePeriodData.getPeriod(), savingSchedulePeriodData.getDepositDue(), savingSchedulePeriodData.getInterestAccured()); + account.addSavingScheduleInstallment(installment); + } } @@ -292,13 +305,13 @@ public class SavingAccountAssembler { CalculateSavingScheduleCommand calculateSavingScheduleCommand = new CalculateSavingScheduleCommand(account.getProduct().getId(), savingsDepositAmountPerPeriod, payEvery, - frequency, recurringInterestRate, approvalDate, tenure,interestPostEvery,interestPostFrequency); + frequency, recurringInterestRate, approvalDate, tenure,tenureType,interestPostEvery,interestPostFrequency,account.getInterestCalculationMethod()); SavingScheduleData savingScheduleData = this.calculateSavingSchedule.calculateSavingSchedule(calculateSavingScheduleCommand); for (SavingSchedulePeriodData savingSchedulePeriodData : savingScheduleData.getPeriods()) { final SavingScheduleInstallments installment = new SavingScheduleInstallments(account, savingSchedulePeriodData.getDueDate() - .toDate(), savingSchedulePeriodData.getPeriod(), savingSchedulePeriodData.getDepositDue()); + .toDate(), savingSchedulePeriodData.getPeriod(), savingSchedulePeriodData.getDepositDue(),savingSchedulePeriodData.getInterestAccured()); account.addSavingScheduleInstallment(installment); } } @@ -315,7 +328,7 @@ public class SavingAccountAssembler { } public void postInterest(SavingAccount account) { - account.postInterest(this.reccuringDepositInterestCalculator); + account.postInterest(); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/service/SavingAccountReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/service/SavingAccountReadPlatformService.java index eb96c5a96..4eeb9662c 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/service/SavingAccountReadPlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/service/SavingAccountReadPlatformService.java @@ -6,6 +6,7 @@ import java.util.Collection; import org.mifosplatform.organisation.monetary.data.CurrencyData; import org.mifosplatform.portfolio.savingsaccount.data.SavingAccountData; import org.mifosplatform.portfolio.savingsaccount.data.SavingAccountForLookup; +import org.mifosplatform.portfolio.savingsaccount.data.SavingAccountTransactionsData; import org.mifosplatform.portfolio.savingsaccount.data.SavingPermissionData; import org.mifosplatform.portfolio.savingsaccount.data.SavingScheduleData; @@ -24,4 +25,6 @@ public interface SavingAccountReadPlatformService { SavingScheduleData retrieveSavingsAccountSchedule(Long accountId, CurrencyData currencyData); Collection retrieveSavingAccountsForLookUp(); + + Collection retrieveSavingsAccountTransactions(Long accountId); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/service/SavingAccountReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/service/SavingAccountReadPlatformServiceImpl.java index e63269cf0..f478f3db7 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/service/SavingAccountReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/service/SavingAccountReadPlatformServiceImpl.java @@ -17,6 +17,7 @@ import org.mifosplatform.portfolio.client.data.ClientData; import org.mifosplatform.portfolio.client.service.ClientReadPlatformService; import org.mifosplatform.portfolio.savingsaccount.data.SavingAccountData; import org.mifosplatform.portfolio.savingsaccount.data.SavingAccountForLookup; +import org.mifosplatform.portfolio.savingsaccount.data.SavingAccountTransactionsData; import org.mifosplatform.portfolio.savingsaccount.data.SavingPermissionData; import org.mifosplatform.portfolio.savingsaccount.data.SavingScheduleData; import org.mifosplatform.portfolio.savingsaccount.data.SavingSchedulePeriodData; @@ -25,6 +26,7 @@ import org.mifosplatform.portfolio.savingsaccountproduct.data.SavingProductLooku import org.mifosplatform.portfolio.savingsaccountproduct.service.SavingProductEnumerations; import org.mifosplatform.portfolio.savingsaccountproduct.service.SavingProductReadPlatformService; import org.mifosplatform.portfolio.savingsdepositaccount.service.DepositAccountEnumerations; +import org.mifosplatform.portfolio.savingsdepositaccount.service.DepositAccountTransactionEnumerations; import org.mifosplatform.portfolio.savingsdepositproduct.domain.TenureTypeEnum; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; @@ -85,6 +87,7 @@ public class SavingAccountReadPlatformServiceImpl implements SavingAccountReadPl + " sa.pre_closure_interest_rate AS preClosureInterestRate, sa.is_lock_in_period_allowed AS isLockinPeriodAllowed," + " sa.lock_in_period AS lockinPeriod, sa.lock_in_period_type AS lockinPeriodType, sa.withdrawnon_date AS withdrawnonDate," + " sa.rejectedon_date AS rejectedonDate, sa.closedon_date AS closedonDate, ps.name AS productName, sa.deposit_every as depositEvery, " + + " sa.interest_posting_every AS interestPostEvery, sa.interest_posting_frequency AS interestPostFrequency, " + " c.firstname AS firstname, c.lastname AS lastname, curr.name AS currencyName, " + " curr.internationalized_name_code AS currencyNameCode, curr.display_symbol AS currencyDisplaySymbol " + " FROM m_saving_account sa " + " JOIN m_client c ON c.id = sa.client_id" @@ -150,13 +153,17 @@ public class SavingAccountReadPlatformServiceImpl implements SavingAccountReadPl Integer lockinPeriodTypeValue = JdbcSupport.getInteger(rs, "lockinPeriodType"); EnumOptionData lockinPeriodType = SavingProductEnumerations.savingsLockinPeriod(lockinPeriodTypeValue); Integer depositEvery = JdbcSupport.getInteger(rs, "depositEvery"); + + Integer interestPostEvery = JdbcSupport.getInteger(rs, "interestPostEvery"); + EnumOptionData interestPostFrequency = SavingProductEnumerations.interestFrequencyType(JdbcSupport.getInteger(rs, "interestPostFrequency")); + return new SavingAccountData(id, status, externalId, clientId, clientName, productId, productName, productType, currencyData, savingsDepostiAmountPerPeriod, savingsFrequencyType, totalDepositAmount, reccuringInterestRate, savingInterestRate, interestType, interestCalculationMethod, tenure, tenureType, projectedCommencementDate, actualCommencementDate, maturesOnDate, projectedInterestAccuredOnMaturity, actualInterestAccured, projectedMaturityAmount, actualMaturityAmount, preClosureAllowed, preClosureInterestRate, withdrawnonDate, rejectedonDate, closedonDate, - isLockinPeriodAllowed, lockinPeriod, lockinPeriodType,depositEvery,outstandingAmount); + isLockinPeriodAllowed, lockinPeriod, lockinPeriodType,depositEvery,outstandingAmount, interestPostEvery, interestPostFrequency); } } @@ -229,10 +236,10 @@ public class SavingAccountReadPlatformServiceImpl implements SavingAccountReadPl Integer noOfMonths = Months.monthsBetween(date, new LocalDate()).getMonths(); Integer noOfPeriodsExistedTillDate = noOfMonths/depositEvery; BigDecimal totalAmountToBePaidTillDate = BigDecimal.valueOf(noOfPeriodsExistedTillDate.doubleValue()*amountPerPeriod.doubleValue()); - dueAmount = dueAmount.add(BigDecimal.valueOf(totalAmountToBePaidTillDate.doubleValue() - account.getTotalDepositAmount().doubleValue())); + dueAmount = dueAmount.add(BigDecimal.valueOf(totalAmountToBePaidTillDate.doubleValue() - account.getOutstandingAmount().doubleValue())); } - + dueAmount = dueAmount.doubleValue() < 0 ? BigDecimal.ZERO : dueAmount; return dueAmount; } @@ -243,10 +250,14 @@ public class SavingAccountReadPlatformServiceImpl implements SavingAccountReadPl String sql = "Select " + mapper.savingScheduleSchema() +" where ss.saving_account_id =? order by ss.installment"; List periods = this.jdbcTemplate.query(sql, mapper, new Object[]{accountId}); BigDecimal cumulativeDepositDue = BigDecimal.ZERO; + BigDecimal cumulativeDepositPaid = BigDecimal.ZERO; + BigDecimal cummulativeInterestAccured = BigDecimal.ZERO; for(SavingSchedulePeriodData data : periods){ - cumulativeDepositDue = cumulativeDepositDue.add(data.getDepositDue()).subtract(data.getDepositPaid()); + cumulativeDepositDue = cumulativeDepositDue.add(data.getDepositDue())/*.subtract(data.getDepositPaid())*/; + cumulativeDepositPaid = cumulativeDepositPaid.add(data.getDepositPaid()); + cummulativeInterestAccured = cummulativeInterestAccured.add(data.getInterestAccured()); } - SavingScheduleData scheduleData = new SavingScheduleData(currency, cumulativeDepositDue, periods); + SavingScheduleData scheduleData = new SavingScheduleData(currency, cumulativeDepositDue, cumulativeDepositPaid, cummulativeInterestAccured, periods); return scheduleData; } @@ -255,7 +266,7 @@ public class SavingAccountReadPlatformServiceImpl implements SavingAccountReadPl public String savingScheduleSchema(){ return "ss.id as id, ss.saving_account_id as savingAccountId, ss.duedate as dueDate, ss.installment as installment, " + " ss.deposit as deposit, ss.payment_date as paymentDate, ss.deposit_paid as depositPaid, " - + " ss.completed_derived as completedDerived FROM m_saving_schedule ss"; + + " ss.completed_derived as completedDerived, ss.interest_accured AS interestAccured FROM m_saving_schedule ss"; } @Override @@ -265,8 +276,9 @@ public class SavingAccountReadPlatformServiceImpl implements SavingAccountReadPl Integer installment = JdbcSupport.getInteger(rs, "installment"); BigDecimal depositDue = rs.getBigDecimal("deposit"); BigDecimal depositPaid = rs.getBigDecimal("depositPaid"); + BigDecimal interestAccured = rs.getBigDecimal("interestAccured"); - return new SavingSchedulePeriodData(installment, dueDate, depositDue, depositPaid); + return new SavingSchedulePeriodData(installment, dueDate, depositDue, depositPaid, interestAccured); } } @@ -292,4 +304,30 @@ public class SavingAccountReadPlatformServiceImpl implements SavingAccountReadPl } + @Override + public Collection retrieveSavingsAccountTransactions(Long accountId) { + this.context.authenticatedUser(); + SavingAccountTransactionMapper savingAccountTransactionMapper = new SavingAccountTransactionMapper(); + String sql = "select "+ savingAccountTransactionMapper.schema() + " where stxn.saving_account_id = ? "; + return jdbcTemplate.query(sql, savingAccountTransactionMapper, new Object[] {accountId}); + } + + private static final class SavingAccountTransactionMapper implements RowMapper { + + public String schema() { + return "stxn.id as id, stxn.transaction_type_enum as type, stxn.transaction_date as transactionDate, stxn.amount as amount FROM m_saving_account_transaction stxn"; + } + + @Override + public SavingAccountTransactionsData mapRow(ResultSet rs, @SuppressWarnings("unused") int rowNum) throws SQLException { + Long id = rs.getLong("id"); + LocalDate transactionDate = JdbcSupport.getLocalDate(rs, "transactionDate"); + Integer transactionTypeValue = JdbcSupport.getInteger(rs, "type"); + EnumOptionData transactionType = DepositAccountTransactionEnumerations.depositType(transactionTypeValue); + BigDecimal amount = rs.getBigDecimal("amount"); + return new SavingAccountTransactionsData(id, transactionDate, transactionType, amount); + } + + } + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/service/SavingScheduleGenerator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/service/SavingScheduleGenerator.java index bd9c1f061..ee7936a02 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/service/SavingScheduleGenerator.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsaccount/service/SavingScheduleGenerator.java @@ -1,6 +1,8 @@ package org.mifosplatform.portfolio.savingsaccount.service; import java.math.BigDecimal; +import java.math.MathContext; +import java.math.RoundingMode; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -10,19 +12,21 @@ import org.mifosplatform.organisation.monetary.data.CurrencyData; import org.mifosplatform.organisation.monetary.domain.ApplicationCurrency; import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; import org.mifosplatform.organisation.monetary.domain.Money; -import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType; import org.mifosplatform.portfolio.savingsaccount.data.SavingScheduleData; import org.mifosplatform.portfolio.savingsaccount.data.SavingSchedulePeriodData; import org.mifosplatform.portfolio.savingsaccount.domain.DepositScheduleDateGenerator; +import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingFrequencyType; +import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingInterestCalculationMethod; import org.mifosplatform.portfolio.savingsaccountproduct.domain.SavingProduct; public class SavingScheduleGenerator { private final DepositScheduleDateGenerator scheduledDateGenerator = new DefaultDepositScheduleDateGenerator(); + private final Integer monthsInYear = 12; public SavingScheduleData generate(final LocalDate scheduleStartDate, final BigDecimal depositAmountPerPeriod, - final Integer depositFrequency, final PeriodFrequencyType depositFrequencyType, final SavingProduct savingProduct, - final Integer tenure, final ApplicationCurrency applicationCurrency) { + final Integer depositFrequency, final SavingFrequencyType savingFrequencyType, final SavingProduct savingProduct, + final Integer tenure, final ApplicationCurrency applicationCurrency, final BigDecimal interestRate, final SavingInterestCalculationMethod interestCalculationMethod) { LocalDate startDate = scheduleStartDate; int periodNumber = 1; @@ -30,23 +34,92 @@ public class SavingScheduleGenerator { Integer paymentPeriods = tenure / depositFrequency; final Collection periods = new ArrayList(); final List scheduledDates = this.scheduledDateGenerator.generate(startDate, paymentPeriods, depositFrequency, - depositFrequencyType); + savingFrequencyType); final MonetaryCurrency currency = savingProduct.getCurrency(); final Money depositAmount = Money.of(currency, depositAmountPerPeriod); Money totalDeposit = Money.zero(currency); - + + + MathContext mc = new MathContext(8, RoundingMode.HALF_EVEN); + BigDecimal interestRateAsFraction = interestRate.divide(BigDecimal.valueOf(100), mc); + Integer noofTimesInterestCompoundPerYear = determineIntValue(savingFrequencyType); + BigDecimal interestRatePerPeriod = BigDecimal.valueOf(interestRateAsFraction.doubleValue()/ noofTimesInterestCompoundPerYear.doubleValue()); + BigDecimal onePlusInterestRatePerPeriod = BigDecimal.ONE.add(interestRatePerPeriod); + BigDecimal cummulativeDepositPaid = BigDecimal.ZERO; + BigDecimal cummulativeInterestAccured = BigDecimal.ZERO; + Integer tempTenure = tenure; + + BigDecimal termAmount = BigDecimal.ZERO; + BigDecimal totalInterest = BigDecimal.ZERO; + BigDecimal closingBalance = BigDecimal.ZERO; + for (LocalDate scheduleDate : scheduledDates) { - totalDeposit = totalDeposit.plus(depositAmount); - SavingSchedulePeriodData installment = SavingSchedulePeriodData.addScheduleInformation(periodNumber, scheduleDate, - depositAmount.getAmount()); - periods.add(installment); - periodNumber++; + + if (interestCalculationMethod.isMonthlyCollection()) { + BigDecimal monthsExpressedInYears = BigDecimal.valueOf(tempTenure.doubleValue() / monthsInYear.doubleValue()); + BigDecimal timeforOneCalculationPeriod = BigDecimal.valueOf(noofTimesInterestCompoundPerYear * monthsExpressedInYears.doubleValue()); + BigDecimal amountPerPeriod = depositAmountPerPeriod.multiply(BigDecimal.valueOf(Math.pow(onePlusInterestRatePerPeriod.doubleValue(), timeforOneCalculationPeriod.doubleValue()))); + BigDecimal interestAccured = amountPerPeriod.subtract(depositAmountPerPeriod); + + totalDeposit = totalDeposit.plus(depositAmount); + cummulativeInterestAccured = cummulativeInterestAccured.add(interestAccured); + SavingSchedulePeriodData installment = SavingSchedulePeriodData.addScheduleInformation(periodNumber, scheduleDate, + depositAmount.getAmount(), interestAccured); + periods.add(installment); + periodNumber++; + tempTenure = tempTenure - depositFrequency; + } else if (interestCalculationMethod.isAverageBalance()){ + + BigDecimal amountPerPeriod = depositAmount.getAmount(); + Integer depositEveryOriginalValue = depositFrequency; + BigDecimal amountPermonth = BigDecimal.valueOf(amountPerPeriod.doubleValue()/depositFrequency.doubleValue()); + + while (depositEveryOriginalValue > 0) { + closingBalance = closingBalance.add(amountPermonth); + termAmount = termAmount.add(closingBalance); + depositEveryOriginalValue--; + } + + BigDecimal averageAmount = BigDecimal.valueOf(termAmount.doubleValue()/depositFrequency.doubleValue()); + BigDecimal interestRatePerTerm = BigDecimal.valueOf(interestRateAsFraction.doubleValue()/monthsInYear.doubleValue()*depositFrequency.doubleValue()); + BigDecimal interestAccured = averageAmount.multiply(interestRatePerTerm); + totalInterest = totalInterest.add(interestAccured); + depositEveryOriginalValue = depositFrequency; + termAmount = BigDecimal.ZERO; + + totalDeposit = totalDeposit.plus(depositAmount); + cummulativeInterestAccured = totalInterest; + SavingSchedulePeriodData installment = SavingSchedulePeriodData.addScheduleInformation(periodNumber, scheduleDate, + depositAmount.getAmount(), interestAccured); + periods.add(installment); + periodNumber++; + } } CurrencyData currencyData = new CurrencyData(applicationCurrency.getCode(), applicationCurrency.getName(), currency.getDigitsAfterDecimal(), applicationCurrency.getDisplaySymbol(), applicationCurrency.getNameCode()); - return new SavingScheduleData(currencyData, totalDeposit.getAmount(), periods); + return new SavingScheduleData(currencyData, totalDeposit.getAmount(),cummulativeDepositPaid, cummulativeInterestAccured, periods); } + private Integer determineIntValue(SavingFrequencyType frequencyType){ + Integer noofTimesInterestCompoundPerYear = Integer.valueOf(0); + switch (frequencyType) { + case MONTHLY: + noofTimesInterestCompoundPerYear = monthsInYear; + break; + case QUATERLY: + noofTimesInterestCompoundPerYear = monthsInYear / 3; + break; + case HALFYEARLY: + noofTimesInterestCompoundPerYear = monthsInYear / 6; + break; + case YEARLY: + noofTimesInterestCompoundPerYear = monthsInYear / 12; + break; + default: + throw new RuntimeException("The specified frequency not supported"); + } + return noofTimesInterestCompoundPerYear; + } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsdepositproduct/domain/TenureTypeEnum.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsdepositproduct/domain/TenureTypeEnum.java index 5255a6d17..6134ccb6e 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsdepositproduct/domain/TenureTypeEnum.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savingsdepositproduct/domain/TenureTypeEnum.java @@ -38,4 +38,12 @@ public enum TenureTypeEnum { } return tenureTypeEnum; } + + public boolean isFixedPeriod() { + return this.value.equals(TenureTypeEnum.FIXED_PERIOD.value); + } + + public boolean isPerpetual() { + return this.value.equals(TenureTypeEnum.PERPETUAL.value); + } } \ No newline at end of file