From ec810d9485decac3d480f51bef6b6947a201b07e Mon Sep 17 00:00:00 2001 From: Keith Woodlock Date: Tue, 2 Apr 2013 17:12:03 +0100 Subject: [PATCH] MIFOSX-250: interest calculation change for compounding with api docs updates. --- api-docs/apiLive.htm | 387 +++++++++++++----- ...ate-savings-product-and-account-tables.sql | 11 + ...tfolioCommandsReadPlatformServiceImpl.java | 6 +- .../api/SavingsAccountsApiResource.java | 13 +- .../savings/api/SavingsApiConstants.java | 32 +- .../api/SavingsProductsApiResource.java | 33 +- .../savings/data/SavingsAccountData.java | 72 ++-- .../data/SavingsAccountDataValidator.java | 41 +- .../savings/data/SavingsProductData.java | 66 ++- .../data/SavingsProductDataValidator.java | 48 +-- .../InterestCompoundingPeriodSummary.java | 53 +++ .../savings/domain/InterestPeriodSummary.java | 61 --- ...odInterval.java => LocalDateInterval.java} | 8 +- .../savings/domain/SavingsAccount.java | 235 +++++------ .../domain/SavingsAccountAssembler.java | 43 +- .../domain/SavingsAccountDailyBalance.java | 30 +- .../savings/domain/SavingsAccountSummary.java | 16 +- .../domain/SavingsAccountTransaction.java | 18 +- ...=> SavingsCompoundInterestCalculator.java} | 2 +- ...dInterestCalculatorForAverageBalance.java} | 4 +- ...undInterestCalculatorForDailyBalance.java} | 6 +- .../SavingsCompoundingInterestPeriodType.java | 74 ++++ .../SavingsInterestCalculatorFactory.java | 8 +- .../domain/SavingsInterestPeriodType.java | 75 ---- .../savings/domain/SavingsProduct.java | 79 ++-- .../domain/SavingsProductAssembler.java | 28 +- ...SavingsAccountReadPlatformServiceImpl.java | 80 ++-- ...WritePlatformServiceJpaRepositoryImpl.java | 4 +- .../SavingsDropdownReadPlatformService.java | 4 +- ...avingsDropdownReadPlatformServiceImpl.java | 29 +- .../savings/service/SavingsEnumerations.java | 76 ++-- ...SavingsProductReadPlatformServiceImpl.java | 23 +- 32 files changed, 866 insertions(+), 799 deletions(-) create mode 100644 mifosng-db/migrations/V5__update-savings-product-and-account-tables.sql create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/InterestCompoundingPeriodSummary.java delete mode 100644 mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/InterestPeriodSummary.java rename mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/{InterestPeriodInterval.java => LocalDateInterval.java} (76%) rename mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/{SavingsInterestCalculator.java => SavingsCompoundInterestCalculator.java} (79%) rename mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/{SavingsInterestCalculatorForAverageBalance.java => SavingsCompoundInterestCalculatorForAverageBalance.java} (88%) rename mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/{SavingsInterestCalculatorForDailyBalance.java => SavingsCompoundInterestCalculatorForDailyBalance.java} (81%) create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsCompoundingInterestPeriodType.java delete mode 100644 mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsInterestPeriodType.java diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm index ca4b31fb5..7ddfb1777 100644 --- a/api-docs/apiLive.htm +++ b/api-docs/apiLive.htm @@ -7496,11 +7496,17 @@ Content-Type: application/json digitsAfterDecimal Override the currency default value for digitsAfterDecimal. - interestRate - The default interest rate set when creating savings accounts of this type of product. e.g. 5% Per year + nominalAnnualInterestRate + The default interest rate set when creating savings accounts of this type of product. e.g. 5% Per year - It number here is always expressed as the Nominal APR. - interestRatePeriodFrequencyType - The default interest rate period type. 2=Per month, 3=Per year e.g. 5% Per year + interestCompoundingPeriodType + The period at which interest rate is compounded. 1=Daily, 2=Weekly (at end of week, sunday), 3=Every two weeks (at end of two weeks, sunday), 4=Monthly (at end of month), 5=Quarterly (at end of quarter, 31st Mar, 30th Jun, 30th Sep, 31st Dec), 6=Bi-Annually (30th June, 31st Dec), 7=Annually (31st Dec), 8=No Compounding - Simple Interest + + interestCalculationType + The interest calculation method used: 1=Daily Balance or 2=Average Daily Balance + + interestCalculationDaysInYearType + The setting for number of days in year to use: 360=360 Days, 365=365 Days minRequiredOpeningBalance Optional: If provided, sets the minimum deposit amount required to open a savings account e.g. 2,000 @@ -7515,7 +7521,7 @@ Content-Type: application/json -   +  

Retrieve Savings Product Template

@@ -7533,17 +7539,27 @@ Content-Type: application/json { "currency": { - "code": "", - "name": "", - "decimalPlaces": 0, - "displaySymbol": "", - "nameCode": "", - "displayLabel": " []" + "code": "USD", + "name": "US Dollar", + "decimalPlaces": 2, + "displaySymbol": "$", + "nameCode": "currency.USD", + "displayLabel": "US Dollar ($)" }, - "interestRatePeriodFrequencyType": { - "id": 3, - "code": "savings.interest.rate.periodFrequencyType.years", - "value": "Per year" + "interestCompoundingPeriodType": { + "id": 1, + "code": "savings.interest.period.savingsCompoundingInterestPeriodType.daily", + "value": "Daily" + }, + "interestCalculationType": { + "id": 1, + "code": "savingsInterestCalculationType.dailybalance", + "value": "Daily Balance" + }, + "interestCalculationDaysInYearType": { + "id": 365, + "code": "savingsInterestCalculationDaysInYearType.days365", + "value": "365 Days" }, "currencyOptions": [ { @@ -7555,37 +7571,91 @@ Content-Type: application/json "displayLabel": "US Dollar ($)" } ], - "interestRatePeriodFrequencyTypeOptions": [ + "interestCompoundingPeriodTypeOptions": [ + { + "id": 1, + "code": "savings.interest.period.savingsCompoundingInterestPeriodType.daily", + "value": "Daily" + }, { "id": 2, - "code": "savings.interest.rate.periodFrequencyType.months", - "value": "Per month" + "code": "savings.interest.period.savingsCompoundingInterestPeriodType.weekly", + "value": "Weekly" }, { "id": 3, - "code": "savings.interest.rate.periodFrequencyType.years", - "value": "Per year" + "code": "savings.interest.period.savingsCompoundingInterestPeriodType.biweekly", + "value": "Bi-Weekly" + }, + { + "id": 4, + "code": "savings.interest.period.savingsCompoundingInterestPeriodType.monthly", + "value": "Monthly" + }, + { + "id": 5, + "code": "savings.interest.period.savingsCompoundingInterestPeriodType.quarterly", + "value": "Quarterly" + }, + { + "id": 6, + "code": "savings.interest.period.savingsCompoundingInterestPeriodType.biannual", + "value": "Semi-Annual" + }, + { + "id": 7, + "code": "savings.interest.period.savingsCompoundingInterestPeriodType.annual", + "value": "Annually" + }, + { + "id": 8, + "code": "savings.interest.period.savingsCompoundingInterestPeriodType.nocompounding", + "value": "No Compounding - Simple Interest" + } + ], + "interestCalculationTypeOptions": [ + { + "id": 1, + "code": "savingsInterestCalculationType.dailybalance", + "value": "Daily Balance" + }, + { + "id": 2, + "code": "savingsInterestCalculationType.averagedailybalance", + "value": "Average Daily Balance" + } + ], + "interestCalculationDaysInYearTypeOptions": [ + { + "id": 360, + "code": "savingsInterestCalculationDaysInYearType.days360", + "value": "360 Days" + }, + { + "id": 365, + "code": "savingsInterestCalculationDaysInYearType.days365", + "value": "365 Days" } ], "lockinPeriodFrequencyTypeOptions": [ { "id": 0, - "code": "savings.lockin.periodFrequencyType.days", + "code": "savings.lockin.savingsPeriodFrequencyType.days", "value": "Days" }, { "id": 1, - "code": "savings.lockin.periodFrequencyType.weeks", + "code": "savings.lockin.savingsPeriodFrequencyType.weeks", "value": "Weeks" }, { "id": 2, - "code": "savings.lockin.periodFrequencyType.months", + "code": "savings.lockin.savingsPeriodFrequencyType.months", "value": "Months" }, { "id": 3, - "code": "savings.lockin.periodFrequencyType.years", + "code": "savings.lockin.savingsPeriodFrequencyType.years", "value": "Years" } ] @@ -7600,7 +7670,10 @@ Content-Type: application/json

Create a Savings Product

- + + +
Mandatory Fields
name, description, currencyCode, digitsAfterDecimal, interestRate, interestRatePeriodFrequencyType
name, description, currencyCode, digitsAfterDecimal, nominalAnnualInterestRate, + interestCompoundingPeriodType, interestCalculationType, interestCalculationDaysInYearType

@@ -7614,13 +7687,15 @@ Content-Type: application/json Content-Type: application/json Request Body: { - "name": "individual savings", - "description": "An savings product offering for individuals.", + "name": "Passbook Savings", + "description": "Daily compounding using Daily Balance, 5% per year, 365 days in year", "currencyCode": "USD", "digitsAfterDecimal": 2, "locale": "en", - "interestRate": "5.65", - "interestRatePeriodFrequencyType": 2 + "nominalAnnualInterestRate": "5.0", + "interestCompoundingPeriodType": 1, + "interestCalculationType": 1, + "interestCalculationDaysInYearType": "365" } @@ -7647,8 +7722,8 @@ Request Body: { "id": 1, - "name": "individual savings", - "description": "An savings product offering for individuals. (updated)", + "name": "Passbook Savings", + "description": "Daily compounding using Daily Balance, 5% per year, 365 days in year", "currency": { "code": "USD", "name": "US Dollar", @@ -7657,13 +7732,23 @@ Request Body: "nameCode": "currency.USD", "displayLabel": "US Dollar ($)" }, - "interestRate": 5.73, - "interestRatePeriodFrequencyType": { - "id": 2, - "code": "savings.interest.rate.periodFrequencyType.months", - "value": "Per month" + "nominalAnnualInterestRate": 5, + "interestCompoundingPeriodType": { + "id": 1, + "code": "savings.interest.period.savingsCompoundingInterestPeriodType.daily", + "value": "Daily" + }, + "interestCalculationType": { + "id": 1, + "code": "savingsInterestCalculationType.dailybalance", + "value": "Daily Balance" + }, + "interestCalculationDaysInYearType": { + "id": 365, + "code": "savingsInterestCalculationDaysInYearType.days365", + "value": "365 Days" } -} +} @@ -7679,7 +7764,7 @@ Request Body: Content-Type: application/json Request Body: { - "description": "An savings product offering for individuals. (updated)", + "description": "Passbook Savings Lite.", "locale": "en", "interestRate": "5.73" } @@ -7688,7 +7773,7 @@ Request Body: { "resourceId": 1, "changes": { - "description": "An savings product offering for individuals. (updated)", + "description": "Passbook Savings Lite.", "interestRate": 5.73, "locale": "en" } @@ -7731,32 +7816,35 @@ Content-Type: application/json GET https://Domain Name/api/v1/savingsproducts [ - { + { + "id": 1, + "name": "Passbook Savings", + "description": "Daily compounding using Daily Balance, 5% per year, 365 days in year", + "currency": { + "code": "USD", + "name": "US Dollar", + "decimalPlaces": 2, + "displaySymbol": "$", + "nameCode": "currency.USD", + "displayLabel": "US Dollar ($)" + }, + "nominalAnnualInterestRate": 5, + "interestCompoundingPeriodType": { "id": 1, - "name": "individual savings", - "description": "An savings product offering for individuals. (updated)", - "currency": { - "code": "USD", - "name": "US Dollar", - "decimalPlaces": 2, - "displaySymbol": "$", - "nameCode": "currency.USD", - "displayLabel": "US Dollar ($)" - }, - "interestRate": 9.85, - "interestRatePeriodFrequencyType": { - "id": 3, - "code": "savings.interest.rate.periodFrequencyType.years", - "value": "Per year" - }, - "minRequiredOpeningBalance": 1000, - "lockinPeriodFrequency": 3, - "lockinPeriodFrequencyType": { - "id": 2, - "code": "savings.interest.rate.periodFrequencyType.months", - "value": "Per month" - } + "code": "savings.interest.period.savingsCompoundingInterestPeriodType.daily", + "value": "Daily" + }, + "interestCalculationType": { + "id": 1, + "code": "savingsInterestCalculationType.dailybalance", + "value": "Daily Balance" + }, + "interestCalculationDaysInYearType": { + "id": 365, + "code": "savingsInterestCalculationDaysInYearType.days365", + "value": "365 Days" } + } ] @@ -7793,11 +7881,17 @@ Content-Type: application/json - - + + - - + + + + + + + + @@ -7856,9 +7950,9 @@ Content-Type: application/json { "clientId": 1, - "clientName": "Client A AB", - "savingsProductId": 1, - "savingsProductName": "First", + "clientName": "John Doe", + "savingsProductId": 3, + "savingsProductName": "Passbook Savings", "currency": { "code": "USD", "name": "US Dollar", @@ -7867,56 +7961,121 @@ Content-Type: application/json "nameCode": "currency.USD", "displayLabel": "US Dollar ($)" }, - "interestRate": 12, - "interestRatePeriodFrequencyType": { - "id": 3, - "code": "savings.interest.rate.periodFrequencyType.years", - "value": "Per year" + "nominalAnnualInterestRate": 5, + "interestCompoundingPeriodType": { + "id": 1, + "code": "savings.interest.period.savingsCompoundingInterestPeriodType.daily", + "value": "Daily" }, - "minRequiredOpeningBalance": 1000, - "lockinPeriodFrequency": 3, - "lockinPeriodFrequencyType": { - "id": 2, - "code": "savings.interest.rate.periodFrequencyType.months", - "value": "Per month" + "interestCalculationType": { + "id": 1, + "code": "savingsInterestCalculationType.dailybalance", + "value": "Daily Balance" + }, + "interestCalculationDaysInYearType": { + "id": 365, + "code": "savingsInterestCalculationDaysInYearType.days365", + "value": "365 Days" }, "productOptions": [ { "id": 1, - "name": "First" - } - ], - "interestRatePeriodFrequencyTypeOptions": [ + "name": "01-Compounding Daily" + }, { "id": 2, - "code": "savings.interest.rate.periodFrequencyType.months", - "value": "Per month" + "name": "02-Compounding Monthly" }, { "id": 3, - "code": "savings.interest.rate.periodFrequencyType.years", - "value": "Per year" + "name": "Passbook Savings" + } + ], + "interestCompoundingPeriodTypeOptions": [ + { + "id": 1, + "code": "savings.interest.period.savingsCompoundingInterestPeriodType.daily", + "value": "Daily" + }, + { + "id": 2, + "code": "savings.interest.period.savingsCompoundingInterestPeriodType.weekly", + "value": "Weekly" + }, + { + "id": 3, + "code": "savings.interest.period.savingsCompoundingInterestPeriodType.biweekly", + "value": "Bi-Weekly" + }, + { + "id": 4, + "code": "savings.interest.period.savingsCompoundingInterestPeriodType.monthly", + "value": "Monthly" + }, + { + "id": 5, + "code": "savings.interest.period.savingsCompoundingInterestPeriodType.quarterly", + "value": "Quarterly" + }, + { + "id": 6, + "code": "savings.interest.period.savingsCompoundingInterestPeriodType.biannual", + "value": "Semi-Annual" + }, + { + "id": 7, + "code": "savings.interest.period.savingsCompoundingInterestPeriodType.annual", + "value": "Annually" + }, + { + "id": 8, + "code": "savings.interest.period.savingsCompoundingInterestPeriodType.nocompounding", + "value": "No Compounding - Simple Interest" + } + ], + "interestCalculationTypeOptions": [ + { + "id": 1, + "code": "savingsInterestCalculationType.dailybalance", + "value": "Daily Balance" + }, + { + "id": 2, + "code": "savingsInterestCalculationType.averagedailybalance", + "value": "Average Daily Balance" + } + ], + "interestCalculationDaysInYearTypeOptions": [ + { + "id": 360, + "code": "savingsInterestCalculationDaysInYearType.days360", + "value": "360 Days" + }, + { + "id": 365, + "code": "savingsInterestCalculationDaysInYearType.days365", + "value": "365 Days" } ], "lockinPeriodFrequencyTypeOptions": [ { "id": 0, - "code": "savings.lockin.periodFrequencyType.days", + "code": "savings.lockin.savingsPeriodFrequencyType.days", "value": "Days" }, { "id": 1, - "code": "savings.lockin.periodFrequencyType.weeks", + "code": "savings.lockin.savingsPeriodFrequencyType.weeks", "value": "Weeks" }, { "id": 2, - "code": "savings.lockin.periodFrequencyType.months", + "code": "savings.lockin.savingsPeriodFrequencyType.months", "value": "Months" }, { "id": 3, - "code": "savings.lockin.periodFrequencyType.years", + "code": "savings.lockin.savingsPeriodFrequencyType.years", "value": "Years" } ] @@ -7932,7 +8091,8 @@ Content-Type: application/json
activationDate
If active is true the activationDate must be provided. If the savings account has an entry for minRequiredOpeningBalance then a deposit for that amount with activationDate as the date is automatically entered.
interestRate
The default interest rate set when creating savings accounts of this type of product. e.g. 5% Per year
nominalAnnualInterestRate
The interest rate set for savings account e.g. 5% Per year - It is always expressed as the Nominal APR.
interestRatePeriodFrequencyType
The default interest rate period type. 2=Per month, 3=Per year e.g. 5% Per year
interestCompoundingPeriodType
The period at which interest rate is compounded. 1=Daily, 2=Weekly (at end of week, sunday), 3=Every two weeks (at end of two weeks, sunday), 4=Monthly (at end of month), 5=Quarterly (at end of quarter, 31st Mar, 30th Jun, 30th Sep, 31st Dec), 6=Bi-Annually (30th June, 31st Dec), 7=Annually (31st Dec), 8=No Compounding - Simple Interest
interestCalculationType
The interest calculation method used: 1=Daily Balance or 2=Average Daily Balance
interestCalculationDaysInYearType
The setting for number of days in year to use: 360=360 Days, 365=365 Days
minRequiredOpeningBalance
Optional: If provided, sets the minimum deposit amount required to open a savings account e.g. 2,000
- +
Mandatory Fields
clientId or groupId, productId, accountNo, externalId, active, (activationDate if active is true)
clientId or groupId, productId, accountNo, externalId, + active, (activationDate if active is true)

@@ -7942,7 +8102,7 @@ Content-Type: application/json
- +
Inherited from Product (if not provided)
interestRate, interestRatePeriodFrequencyType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType
nominalAnnualInterestRate, interestCompoundingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType
@@ -8028,6 +8188,33 @@ Request Body:
+   +
+
+

Calculate Interest on Savings Account

+

+ Calculates interest earned on a savings account based on todays date. It does not attempt to post or credit the interest on the account. That is responsibility of another API that will be called by overnight process. +

+
+
+ POST https://Domain Name/api/v1/savingsaccounts/{savingsId}?command=calculateInterest + POST savingsaccount/1?command=calculateInterest +Content-Type: application/json +Request Body: +{ +} + + +{ + "officeId": 1, + "clientId": 1, + "savingsId": 1, + "resourceId": 1 +} + +
+
+  
@@ -12290,6 +12477,14 @@ GET https://DomainName/api/v1/search?query=000000111 + + savingsaccounts/{accountId}?command=calculateInterest + Calculate Interest on a Savings Account + + + + + Savings Transactions savingsaccounts/{accountId}/transactions?command=deposit Make a Deposit @@ -12297,7 +12492,7 @@ GET https://DomainName/api/v1/search?query=000000111 - + savingsaccounts/{accountId}/transactions?command=withdrawal Make a Withdrawal diff --git a/mifosng-db/migrations/V5__update-savings-product-and-account-tables.sql b/mifosng-db/migrations/V5__update-savings-product-and-account-tables.sql new file mode 100644 index 000000000..b8c72d9c9 --- /dev/null +++ b/mifosng-db/migrations/V5__update-savings-product-and-account-tables.sql @@ -0,0 +1,11 @@ +ALTER TABLE `m_savings_product` +DROP COLUMN `nominal_interest_rate_period_frequency_enum`, +CHANGE COLUMN `nominal_interest_rate_per_period` `nominal_annual_interest_rate` DECIMAL(19,6) NOT NULL, +CHANGE COLUMN `interest_period_enum` `interest_compounding_period_enum` SMALLINT(5) NOT NULL; + + +ALTER TABLE `m_savings_account` +DROP COLUMN `annual_nominal_interest_rate`, +DROP COLUMN `nominal_interest_rate_period_frequency_enum`, +CHANGE COLUMN `nominal_interest_rate_per_period` `nominal_annual_interest_rate` DECIMAL(19,6) NOT NULL, +CHANGE COLUMN `interest_period_enum` `interest_compounding_period_enum` SMALLINT(5) NOT NULL; \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/PortfolioCommandsReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/PortfolioCommandsReadPlatformServiceImpl.java index 7c8b7625c..1a6279b54 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/PortfolioCommandsReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/PortfolioCommandsReadPlatformServiceImpl.java @@ -13,7 +13,6 @@ import org.joda.time.LocalDate; import org.mifosplatform.commands.data.CommandSourceData; import org.mifosplatform.infrastructure.core.domain.JdbcSupport; import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource; -import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; @@ -23,11 +22,9 @@ import org.springframework.stereotype.Service; public class PortfolioCommandsReadPlatformServiceImpl implements PortfolioCommandsReadPlatformService { private final JdbcTemplate jdbcTemplate; - private final PlatformSecurityContext context; @Autowired - public PortfolioCommandsReadPlatformServiceImpl(final PlatformSecurityContext context, final TenantAwareRoutingDataSource dataSource) { - this.context = context; + public PortfolioCommandsReadPlatformServiceImpl(final TenantAwareRoutingDataSource dataSource) { this.jdbcTemplate = new JdbcTemplate(dataSource); } @@ -53,7 +50,6 @@ public class PortfolioCommandsReadPlatformServiceImpl implements PortfolioComman } } - @Override public CommandSourceData retrieveById(final Long id) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/api/SavingsAccountsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/api/SavingsAccountsApiResource.java index 4d8474d16..6ed13ffdf 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/api/SavingsAccountsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/api/SavingsAccountsApiResource.java @@ -140,8 +140,7 @@ public class SavingsAccountsApiResource { Collection transactions = null; Collection productOptions = null; - Collection interestRatePeriodFrequencyTypeOptions = null; - Collection interestPeriodTypeOptions = null; + Collection interestCompoundingPeriodTypeOptions = null; Collection interestCalculationTypeOptions = null; Collection interestCalculationDaysInYearTypeOptions = null; Collection lockinPeriodFrequencyTypeOptions = null; @@ -166,15 +165,13 @@ public class SavingsAccountsApiResource { final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters()); if (settings.isTemplate()) { productOptions = this.savingsProductReadPlatformService.retrieveAllForLookup(); - interestRatePeriodFrequencyTypeOptions = this.dropdownReadPlatformService.retrieveInterestRatePeriodFrequencyTypeOptions(); - interestPeriodTypeOptions = this.dropdownReadPlatformService.retrieveInterestPeriodTypeOptions(); + interestCompoundingPeriodTypeOptions = this.dropdownReadPlatformService.retrieveCompoundingInterestPeriodTypeOptions(); interestCalculationTypeOptions = this.dropdownReadPlatformService.retrieveInterestCalculationTypeOptions(); lockinPeriodFrequencyTypeOptions = this.dropdownReadPlatformService.retrieveLockinPeriodFrequencyTypeOptions(); } - return SavingsAccountData.withTemplateOptions(savingsAccount, productOptions, interestRatePeriodFrequencyTypeOptions, - interestPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, - lockinPeriodFrequencyTypeOptions, transactions); + return SavingsAccountData.withTemplateOptions(savingsAccount, productOptions, interestCompoundingPeriodTypeOptions, + interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, transactions); } @PUT @@ -195,7 +192,7 @@ public class SavingsAccountsApiResource { @Path("{accountId}") @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) - public String activate(@PathParam("accountId") final Long accountId, @QueryParam("command") final String commandParam, + public String handleCommands(@PathParam("accountId") final Long accountId, @QueryParam("command") final String commandParam, final String apiRequestBodyAsJson) { final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(apiRequestBodyAsJson); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/api/SavingsApiConstants.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/api/SavingsApiConstants.java index 5eeae9afe..35ac6ef28 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/api/SavingsApiConstants.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/api/SavingsApiConstants.java @@ -31,9 +31,9 @@ public class SavingsApiConstants { public static final String descriptionParamName = "description"; public static final String currencyCodeParamName = "currencyCode"; public static final String digitsAfterDecimalParamName = "digitsAfterDecimal"; - public static final String interestRateParamName = "interestRate"; - public static final String interestRatePeriodFrequencyTypeParamName = "interestRatePeriodFrequencyType"; - public static final String interestPeriodTypeParamName = "interestPeriodType"; + public static final String nominalAnnualInterestRateParamName = "nominalAnnualInterestRate"; + + public static final String interestCompoundingPeriodTypeParamName = "interestCompoundingPeriodType"; public static final String interestCalculationTypeParamName = "interestCalculationType"; public static final String interestCalculationDaysInYearTypeParamName = "interestCalculationDaysInYearType"; public static final String minRequiredOpeningBalanceParamName = "minRequiredOpeningBalance"; @@ -45,10 +45,9 @@ public class SavingsApiConstants { public static final String transactionAmountParamName = "transactionAmount"; public static final Set SAVINGS_PRODUCT_REQUEST_DATA_PARAMETERS = new HashSet(Arrays.asList(localeParamName, - nameParamName, descriptionParamName, currencyCodeParamName, digitsAfterDecimalParamName, interestRateParamName, - interestRatePeriodFrequencyTypeParamName, interestPeriodTypeParamName, interestCalculationTypeParamName, - interestCalculationDaysInYearTypeParamName, minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName, - lockinPeriodFrequencyTypeParamName)); + nameParamName, descriptionParamName, currencyCodeParamName, digitsAfterDecimalParamName, nominalAnnualInterestRateParamName, + interestCompoundingPeriodTypeParamName, interestCalculationTypeParamName, interestCalculationDaysInYearTypeParamName, + minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName)); /** * These parameters will match the class level parameters of @@ -56,17 +55,16 @@ public class SavingsApiConstants { * parameters to match those of request parameters. */ public static final Set SAVINGS_PRODUCT_RESPONSE_DATA_PARAMETERS = new HashSet(Arrays.asList(idParamName, - nameParamName, descriptionParamName, "currency", digitsAfterDecimalParamName, interestRateParamName, - interestRatePeriodFrequencyTypeParamName, interestPeriodTypeParamName, interestCalculationTypeParamName, - interestCalculationDaysInYearTypeParamName, minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName, - lockinPeriodFrequencyTypeParamName, "currencyOptions", "interestRatePeriodFrequencyTypeOptions", - "lockinPeriodFrequencyTypeOptions")); + nameParamName, descriptionParamName, "currency", digitsAfterDecimalParamName, nominalAnnualInterestRateParamName, + interestCompoundingPeriodTypeParamName, interestCalculationTypeParamName, interestCalculationDaysInYearTypeParamName, + minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName, "currencyOptions", + "interestRatePeriodFrequencyTypeOptions", "lockinPeriodFrequencyTypeOptions")); public static final Set SAVINGS_ACCOUNT_REQUEST_DATA_PARAMETERS = new HashSet(Arrays.asList(localeParamName, dateFormatParamName, accountNoParamName, externalIdParamName, clientIdParamName, groupIdParamName, productIdParamName, - activeParamName, activationDateParamName, interestRateParamName, interestRatePeriodFrequencyTypeParamName, - interestPeriodTypeParamName, interestCalculationTypeParamName, interestCalculationDaysInYearTypeParamName, - minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName)); + activeParamName, activationDateParamName, nominalAnnualInterestRateParamName, interestCompoundingPeriodTypeParamName, + interestCalculationTypeParamName, interestCalculationDaysInYearTypeParamName, minRequiredOpeningBalanceParamName, + lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName)); /** * These parameters will match the class level parameters of @@ -75,8 +73,8 @@ public class SavingsApiConstants { */ public static final Set SAVINGS_ACCOUNT_RESPONSE_DATA_PARAMETERS = new HashSet(Arrays.asList(idParamName, accountNoParamName, externalIdParamName, statusParamName, activationDateParamName, clientIdParamName, "clientName", - groupIdParamName, "groupName", "savingsProductId", "savingsProductName", "currency", interestRateParamName, - interestRatePeriodFrequencyTypeParamName, "annualInterestRate", interestPeriodTypeParamName, interestCalculationTypeParamName, + groupIdParamName, "groupName", "savingsProductId", "savingsProductName", "currency", nominalAnnualInterestRateParamName, + interestCompoundingPeriodTypeParamName, interestCalculationTypeParamName, interestCalculationDaysInYearTypeParamName, minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName, "summary", "transactions", "productOptions", "interestRatePeriodFrequencyTypeOptions", "lockinPeriodFrequencyTypeOptions")); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/api/SavingsProductsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/api/SavingsProductsApiResource.java index 7ea8b326c..e0baa3f37 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/api/SavingsProductsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/api/SavingsProductsApiResource.java @@ -5,6 +5,7 @@ */ package org.mifosplatform.portfolio.savings.api; +import java.util.ArrayList; import java.util.Collection; import javax.ws.rs.Consumes; @@ -31,10 +32,9 @@ import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext import org.mifosplatform.organisation.monetary.data.CurrencyData; import org.mifosplatform.organisation.monetary.service.CurrencyReadPlatformService; import org.mifosplatform.portfolio.savings.data.SavingsProductData; +import org.mifosplatform.portfolio.savings.domain.SavingsCompoundingInterestPeriodType; import org.mifosplatform.portfolio.savings.domain.SavingsInterestCalculationDaysInYearType; import org.mifosplatform.portfolio.savings.domain.SavingsInterestCalculationType; -import org.mifosplatform.portfolio.savings.domain.SavingsInterestPeriodType; -import org.mifosplatform.portfolio.savings.domain.SavingsPeriodFrequencyType; import org.mifosplatform.portfolio.savings.service.SavingsDropdownReadPlatformService; import org.mifosplatform.portfolio.savings.service.SavingsEnumerations; import org.mifosplatform.portfolio.savings.service.SavingsProductReadPlatformService; @@ -146,22 +146,23 @@ public class SavingsProductsApiResource { private SavingsProductData handleTemplateRelatedData(final SavingsProductData savingsProduct) { - final EnumOptionData interestRatePeriodFrequencyType = SavingsEnumerations - .interestRatePeriodFrequencyType(SavingsPeriodFrequencyType.YEARS); - - final EnumOptionData interestPeriodType = SavingsEnumerations.interestPeriodType(SavingsInterestPeriodType.MONTHLY); + final EnumOptionData interestPeriodType = SavingsEnumerations + .compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.DAILY); final EnumOptionData interestCalculationType = SavingsEnumerations - .interestCalculationType(SavingsInterestCalculationType.AVERAGE_DAILY_BALANCE); + .interestCalculationType(SavingsInterestCalculationType.DAILY_BALANCE); final EnumOptionData interestCalculationDaysInYearType = SavingsEnumerations .interestCalculationDaysInYearType(SavingsInterestCalculationDaysInYearType.DAYS_365); + CurrencyData currency = CurrencyData.blank(); final Collection currencyOptions = this.currencyReadPlatformService.retrieveAllowedCurrencies(); - final Collection interestRatePeriodFrequencyTypeOptions = this.dropdownReadPlatformService - .retrieveInterestRatePeriodFrequencyTypeOptions(); + if (currencyOptions.size() == 1) { + currency = new ArrayList(currencyOptions).get(0); + } - final Collection interestPeriodTypeOptions = this.dropdownReadPlatformService.retrieveInterestPeriodTypeOptions(); + final Collection interestPeriodTypeOptions = this.dropdownReadPlatformService + .retrieveCompoundingInterestPeriodTypeOptions(); final Collection interestCalculationTypeOptions = this.dropdownReadPlatformService .retrieveInterestCalculationTypeOptions(); @@ -174,14 +175,12 @@ public class SavingsProductsApiResource { SavingsProductData savingsProductToReturn = null; if (savingsProduct != null) { - savingsProductToReturn = SavingsProductData.withTemplate(savingsProduct, currencyOptions, - interestRatePeriodFrequencyTypeOptions, interestPeriodTypeOptions, interestCalculationTypeOptions, - interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions); + savingsProductToReturn = SavingsProductData.withTemplate(savingsProduct, currencyOptions, interestPeriodTypeOptions, + interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions); } else { - savingsProductToReturn = SavingsProductData.template(CurrencyData.blank(), interestRatePeriodFrequencyType, interestPeriodType, - interestCalculationType, interestCalculationDaysInYearType, currencyOptions, interestRatePeriodFrequencyTypeOptions, - interestPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, - lockinPeriodFrequencyTypeOptions); + savingsProductToReturn = SavingsProductData.template(currency, interestPeriodType, interestCalculationType, + interestCalculationDaysInYearType, currencyOptions, interestPeriodTypeOptions, interestCalculationTypeOptions, + interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions); } return savingsProductToReturn; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountData.java index 7e641408b..725f1e9db 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountData.java @@ -30,10 +30,8 @@ public class SavingsAccountData { private final Long savingsProductId; private final String savingsProductName; private final CurrencyData currency; - private final BigDecimal interestRate; - private final EnumOptionData interestRatePeriodFrequencyType; - private final BigDecimal annualInterestRate; - private final EnumOptionData interestPeriodType; + private final BigDecimal nominalAnnualInterestRate; + private final EnumOptionData interestCompoundingPeriodType; private final EnumOptionData interestCalculationType; private final EnumOptionData interestCalculationDaysInYearType; private final BigDecimal minRequiredOpeningBalance; @@ -46,8 +44,7 @@ public class SavingsAccountData { // template private final Collection productOptions; - private final Collection interestRatePeriodFrequencyTypeOptions; - private final Collection interestPeriodTypeOptions; + private final Collection interestCompoundingPeriodTypeOptions; private final Collection interestCalculationTypeOptions; private final Collection interestCalculationDaysInYearTypeOptions; private final Collection lockinPeriodFrequencyTypeOptions; @@ -55,39 +52,37 @@ public class SavingsAccountData { public static SavingsAccountData instance(final Long id, final String accountNo, final String externalId, final SavingsAccountStatusEnumData status, final LocalDate activationDate, final Long groupId, final String groupName, final Long clientId, final String clientName, final Long productId, final String productName, final CurrencyData currency, - final BigDecimal interestRate, final EnumOptionData interestRatePeriodFrequencyType, final BigDecimal annualInterestRate, - final EnumOptionData interestPeriodType, final EnumOptionData interestCalculationType, - final EnumOptionData interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance, - final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType, final SavingsAccountSummaryData summary) { + final BigDecimal interestRate, final EnumOptionData interestCompoundingPeriodType, + final EnumOptionData interestCalculationType, final EnumOptionData interestCalculationDaysInYearType, + final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency, + final EnumOptionData lockinPeriodFrequencyType, final SavingsAccountSummaryData summary) { final Collection productOptions = null; - final Collection interestRatePeriodFrequencyTypeOptions = null; - final Collection interestPeriodTypeOptions = null; + final Collection interestCompoundingPeriodTypeOptions = null; final Collection interestCalculationTypeOptions = null; final Collection interestCalculationDaysInYearTypeOptions = null; final Collection lockinPeriodFrequencyTypeOptions = null; final Collection transactions = null; return new SavingsAccountData(id, accountNo, externalId, status, activationDate, groupId, groupName, clientId, clientName, - productId, productName, currency, interestRate, interestRatePeriodFrequencyType, annualInterestRate, interestPeriodType, - interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, - lockinPeriodFrequencyType, summary, productOptions, interestRatePeriodFrequencyTypeOptions, interestPeriodTypeOptions, - interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, transactions); + productId, productName, currency, interestRate, interestCompoundingPeriodType, interestCalculationType, + interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, summary, + productOptions, interestCompoundingPeriodTypeOptions, interestCalculationTypeOptions, + interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, transactions); } public static SavingsAccountData withTemplateOptions(final SavingsAccountData account, - final Collection productOptions, final Collection interestRatePeriodFrequencyTypeOptions, - final Collection interestPeriodTypeOptions, final Collection interestCalculationTypeOptions, + final Collection productOptions, final Collection interestCompoundingPeriodTypeOptions, + final Collection interestCalculationTypeOptions, final Collection interestCalculationDaysInYearTypeOptions, final Collection lockinPeriodFrequencyTypeOptions, final Collection transactions) { return new SavingsAccountData(account.id, account.accountNo, account.externalId, account.status, account.activationDate, account.groupId, account.groupName, account.clientId, account.clientName, account.savingsProductId, - account.savingsProductName, account.currency, account.interestRate, account.interestRatePeriodFrequencyType, - account.annualInterestRate, account.interestPeriodType, account.interestCalculationType, - account.interestCalculationDaysInYearType, account.minRequiredOpeningBalance, account.lockinPeriodFrequency, - account.lockinPeriodFrequencyType, account.summary, productOptions, interestRatePeriodFrequencyTypeOptions, - interestPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, + account.savingsProductName, account.currency, account.nominalAnnualInterestRate, account.interestCompoundingPeriodType, + account.interestCalculationType, account.interestCalculationDaysInYearType, account.minRequiredOpeningBalance, + account.lockinPeriodFrequency, account.lockinPeriodFrequencyType, account.summary, productOptions, + interestCompoundingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, transactions); } @@ -102,9 +97,7 @@ public class SavingsAccountData { final Long productId = null; final String productName = null; final CurrencyData currency = null; - final BigDecimal interestRate = null; - final EnumOptionData interestRatePeriodFrequencyType = null; - final BigDecimal annualInterestRate = null; + final BigDecimal nominalAnnualInterestRate = null; final EnumOptionData interestPeriodType = null; final EnumOptionData interestCalculationType = null; final EnumOptionData interestCalculationDaysInYearType = null; @@ -114,29 +107,27 @@ public class SavingsAccountData { final SavingsAccountSummaryData summary = null; final Collection productOptions = null; final Collection currencyOptions = null; - final Collection interestRatePeriodFrequencyTypeOptions = null; - final Collection interestPeriodTypeOptions = null; + final Collection interestCompoundingPeriodTypeOptions = null; final Collection interestCalculationTypeOptions = null; final Collection interestCalculationDaysInYearTypeOptions = null; final Collection lockinPeriodFrequencyTypeOptions = null; final Collection transactions = null; return new SavingsAccountData(id, accountNo, externalId, status, activationDate, groupId, groupName, clientId, clientName, - productId, productName, currency, interestRate, interestRatePeriodFrequencyType, annualInterestRate, interestPeriodType, - interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, - lockinPeriodFrequencyType, summary, productOptions, interestRatePeriodFrequencyTypeOptions, interestPeriodTypeOptions, - interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, transactions); + productId, productName, currency, nominalAnnualInterestRate, interestPeriodType, interestCalculationType, + interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, summary, + productOptions, interestCompoundingPeriodTypeOptions, interestCalculationTypeOptions, + interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, transactions); } private SavingsAccountData(final Long id, final String accountNo, final String externalId, final SavingsAccountStatusEnumData status, final LocalDate activationDate, final Long groupId, final String groupName, final Long clientId, final String clientName, - final Long productId, final String productName, final CurrencyData currency, final BigDecimal interestRate, - final EnumOptionData interestRatePeriodFrequencyType, final BigDecimal annualInterestRate, + final Long productId, final String productName, final CurrencyData currency, final BigDecimal nominalAnnualInterestRate, final EnumOptionData interestPeriodType, final EnumOptionData interestCalculationType, final EnumOptionData interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType, final SavingsAccountSummaryData summary, - final Collection productOptions, final Collection interestRatePeriodFrequencyTypeOptions, - final Collection interestPeriodTypeOptions, final Collection interestCalculationTypeOptions, + final Collection productOptions, final Collection interestCompoundingPeriodTypeOptions, + final Collection interestCalculationTypeOptions, final Collection interestCalculationDaysInYearTypeOptions, final Collection lockinPeriodFrequencyTypeOptions, final Collection transactions) { this.id = id; @@ -151,10 +142,8 @@ public class SavingsAccountData { this.savingsProductId = productId; this.savingsProductName = productName; this.currency = currency; - this.interestRate = interestRate; - this.interestRatePeriodFrequencyType = interestRatePeriodFrequencyType; - this.annualInterestRate = annualInterestRate; - this.interestPeriodType = interestPeriodType; + this.nominalAnnualInterestRate = nominalAnnualInterestRate; + this.interestCompoundingPeriodType = interestPeriodType; this.interestCalculationType = interestCalculationType; this.interestCalculationDaysInYearType = interestCalculationDaysInYearType; this.minRequiredOpeningBalance = minRequiredOpeningBalance; @@ -163,8 +152,7 @@ public class SavingsAccountData { this.summary = summary; this.productOptions = productOptions; - this.interestRatePeriodFrequencyTypeOptions = interestRatePeriodFrequencyTypeOptions; - this.interestPeriodTypeOptions = interestPeriodTypeOptions; + this.interestCompoundingPeriodTypeOptions = interestCompoundingPeriodTypeOptions; this.interestCalculationTypeOptions = interestCalculationTypeOptions; this.interestCalculationDaysInYearTypeOptions = interestCalculationDaysInYearTypeOptions; this.lockinPeriodFrequencyTypeOptions = lockinPeriodFrequencyTypeOptions; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountDataValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountDataValidator.java index 803b27dff..ee8d91363 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountDataValidator.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountDataValidator.java @@ -8,12 +8,11 @@ import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.extern import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.groupIdParamName; import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestCalculationDaysInYearTypeParamName; import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestCalculationTypeParamName; -import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestPeriodTypeParamName; -import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestRateParamName; -import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestRatePeriodFrequencyTypeParamName; +import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestCompoundingPeriodTypeParamName; import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockinPeriodFrequencyParamName; import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockinPeriodFrequencyTypeParamName; import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.minRequiredOpeningBalanceParamName; +import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.nominalAnnualInterestRateParamName; import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.productIdParamName; import java.lang.reflect.Type; @@ -94,20 +93,13 @@ public class SavingsAccountDataValidator { baseDataValidator.reset().parameter(externalIdParamName).value(externalId).notExceedingLengthOf(100); } - if (fromApiJsonHelper.parameterExists(interestRateParamName, element)) { - final BigDecimal interestRate = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(interestRateParamName, element); - baseDataValidator.reset().parameter(interestRateParamName).value(interestRate).notNull().zeroOrPositiveAmount(); + if (fromApiJsonHelper.parameterExists(nominalAnnualInterestRateParamName, element)) { + final BigDecimal interestRate = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(nominalAnnualInterestRateParamName, element); + baseDataValidator.reset().parameter(nominalAnnualInterestRateParamName).value(interestRate).notNull().zeroOrPositiveAmount(); } - if (fromApiJsonHelper.parameterExists(interestRatePeriodFrequencyTypeParamName, element)) { - final Integer interestRatePeriodFrequencyType = fromApiJsonHelper.extractIntegerSansLocaleNamed( - interestRatePeriodFrequencyTypeParamName, element); - baseDataValidator.reset().parameter(interestRatePeriodFrequencyTypeParamName).value(interestRatePeriodFrequencyType).notNull() - .inMinMaxRange(1, 3); - } - - final Integer interestPeriodType = fromApiJsonHelper.extractIntegerSansLocaleNamed(interestPeriodTypeParamName, element); - baseDataValidator.reset().parameter(interestPeriodTypeParamName).value(interestPeriodType).notNull().inMinMaxRange(1, 7); + final Integer interestPeriodType = fromApiJsonHelper.extractIntegerSansLocaleNamed(interestCompoundingPeriodTypeParamName, element); + baseDataValidator.reset().parameter(interestCompoundingPeriodTypeParamName).value(interestPeriodType).notNull().inMinMaxRange(1, 7); final Integer interestCalculationType = fromApiJsonHelper.extractIntegerSansLocaleNamed(interestCalculationTypeParamName, element); baseDataValidator.reset().parameter(interestCalculationTypeParamName).value(interestCalculationType).notNull().inMinMaxRange(1, 2); @@ -215,21 +207,14 @@ public class SavingsAccountDataValidator { baseDataValidator.reset().parameter(externalIdParamName).value(externalId).notExceedingLengthOf(100); } - if (fromApiJsonHelper.parameterExists(interestRateParamName, element)) { - final BigDecimal interestRate = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(interestRateParamName, element); - baseDataValidator.reset().parameter(interestRateParamName).value(interestRate).notNull().zeroOrPositiveAmount(); + if (fromApiJsonHelper.parameterExists(nominalAnnualInterestRateParamName, element)) { + final BigDecimal interestRate = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(nominalAnnualInterestRateParamName, element); + baseDataValidator.reset().parameter(nominalAnnualInterestRateParamName).value(interestRate).notNull().zeroOrPositiveAmount(); } - if (fromApiJsonHelper.parameterExists(interestRatePeriodFrequencyTypeParamName, element)) { - final Integer interestRatePeriodFrequencyType = fromApiJsonHelper.extractIntegerSansLocaleNamed( - interestRatePeriodFrequencyTypeParamName, element); - baseDataValidator.reset().parameter(interestRatePeriodFrequencyTypeParamName).value(interestRatePeriodFrequencyType).notNull() - .inMinMaxRange(1, 3); - } - - if (this.fromApiJsonHelper.parameterExists(interestPeriodTypeParamName, element)) { - final Integer interestPeriodType = fromApiJsonHelper.extractIntegerSansLocaleNamed(interestPeriodTypeParamName, element); - baseDataValidator.reset().parameter(interestPeriodTypeParamName).value(interestPeriodType).notNull().inMinMaxRange(1, 7); + if (this.fromApiJsonHelper.parameterExists(interestCompoundingPeriodTypeParamName, element)) { + final Integer interestPeriodType = fromApiJsonHelper.extractIntegerSansLocaleNamed(interestCompoundingPeriodTypeParamName, element); + baseDataValidator.reset().parameter(interestCompoundingPeriodTypeParamName).value(interestPeriodType).notNull().inMinMaxRange(1, 7); } if (this.fromApiJsonHelper.parameterExists(interestCalculationTypeParamName, element)) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsProductData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsProductData.java index a4e410d77..06f6342ae 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsProductData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsProductData.java @@ -20,9 +20,8 @@ public class SavingsProductData { private final String name; private final String description; private final CurrencyData currency; - private final BigDecimal interestRate; - private final EnumOptionData interestRatePeriodFrequencyType; - private final EnumOptionData interestPeriodType; + private final BigDecimal nominalAnnualInterestRate; + private final EnumOptionData interestCompoundingPeriodType; private final EnumOptionData interestCalculationType; private final EnumOptionData interestCalculationDaysInYearType; private final BigDecimal minRequiredOpeningBalance; @@ -33,9 +32,7 @@ public class SavingsProductData { @SuppressWarnings("unused") private final Collection currencyOptions; @SuppressWarnings("unused") - private final Collection interestRatePeriodFrequencyTypeOptions; - @SuppressWarnings("unused") - private final Collection interestPeriodTypeOptions; + private final Collection interestCompoundingPeriodTypeOptions; @SuppressWarnings("unused") private final Collection interestCalculationTypeOptions; @SuppressWarnings("unused") @@ -43,26 +40,25 @@ public class SavingsProductData { @SuppressWarnings("unused") private final Collection lockinPeriodFrequencyTypeOptions; - public static SavingsProductData template(final CurrencyData currency, final EnumOptionData interestRatePeriodFrequencyType, - final EnumOptionData interestPeriodType, final EnumOptionData interestCalculationType, - final EnumOptionData interestCalculationDaysInYearType, final Collection currencyOptions, - final Collection interestRatePeriodFrequencyTypeOptions, - final Collection interestPeriodTypeOptions, final Collection interestCalculationTypeOptions, + public static SavingsProductData template(final CurrencyData currency, final EnumOptionData interestCompoundingPeriodType, + final EnumOptionData interestCalculationType, final EnumOptionData interestCalculationDaysInYearType, + final Collection currencyOptions, final Collection interestPeriodTypeOptions, + final Collection interestCalculationTypeOptions, final Collection interestCalculationDaysInYearTypeOptions, final Collection lockinPeriodFrequencyTypeOptions) { final Long id = null; final String name = null; final String description = null; - final BigDecimal interestRate = null; + final BigDecimal nominalAnnualInterestRate = null; final BigDecimal minRequiredOpeningBalance = null; final Integer lockinPeriodFrequency = null; final EnumOptionData lockinPeriodFrequencyType = null; - return new SavingsProductData(id, name, description, currency, interestRate, interestRatePeriodFrequencyType, interestPeriodType, + return new SavingsProductData(id, name, description, currency, nominalAnnualInterestRate, interestCompoundingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, - lockinPeriodFrequencyType, currencyOptions, interestRatePeriodFrequencyTypeOptions, interestPeriodTypeOptions, - interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions); + lockinPeriodFrequencyType, currencyOptions, interestPeriodTypeOptions, interestCalculationTypeOptions, + interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions); } /** @@ -70,45 +66,41 @@ public class SavingsProductData { * {@link SavingsProductData} data with further template data for dropdowns. */ public static SavingsProductData withTemplate(final SavingsProductData existingProduct, final Collection currencyOptions, - final Collection interestRatePeriodFrequencyTypeOptions, final Collection interestPeriodTypeOptions, final Collection interestCalculationTypeOptions, final Collection interestCalculationDaysInYearTypeOptions, final Collection lockinPeriodFrequencyTypeOptions) { return new SavingsProductData(existingProduct.id, existingProduct.name, existingProduct.description, existingProduct.currency, - existingProduct.interestRate, existingProduct.interestRatePeriodFrequencyType, existingProduct.interestPeriodType, + existingProduct.nominalAnnualInterestRate, existingProduct.interestCompoundingPeriodType, existingProduct.interestCalculationType, existingProduct.interestCalculationDaysInYearType, existingProduct.minRequiredOpeningBalance, existingProduct.lockinPeriodFrequency, - existingProduct.lockinPeriodFrequencyType, currencyOptions, interestRatePeriodFrequencyTypeOptions, - interestPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, - lockinPeriodFrequencyTypeOptions); + existingProduct.lockinPeriodFrequencyType, currencyOptions, interestPeriodTypeOptions, interestCalculationTypeOptions, + interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions); } public static SavingsProductData instance(final Long id, final String name, final String description, final CurrencyData currency, - final BigDecimal interestRate, final EnumOptionData interestRatePeriodFrequencyType, final EnumOptionData interestPeriodType, + final BigDecimal nominalAnnualInterestRate, final EnumOptionData interestCompoundingPeriodType, final EnumOptionData interestCalculationType, final EnumOptionData interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType) { final Collection currencyOptions = null; - final Collection interestRatePeriodFrequencyTypeOptions = null; final Collection interestPeriodTypeOptions = null; final Collection interestCalculationTypeOptions = null; final Collection interestCalculationDaysInYearTypeOptions = null; final Collection lockinPeriodFrequencyTypeOptions = null; - return new SavingsProductData(id, name, description, currency, interestRate, interestRatePeriodFrequencyType, interestPeriodType, + return new SavingsProductData(id, name, description, currency, nominalAnnualInterestRate, interestCompoundingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, - lockinPeriodFrequencyType, currencyOptions, interestRatePeriodFrequencyTypeOptions, interestPeriodTypeOptions, - interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions); + lockinPeriodFrequencyType, currencyOptions, interestPeriodTypeOptions, interestCalculationTypeOptions, + interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions); } public static SavingsProductData lookup(final Long id, final String name) { final CurrencyData currency = null; final String description = null; - final BigDecimal interestRate = null; - final EnumOptionData interestRatePeriodFrequencyType = null; - final EnumOptionData interestPeriodType = null; + final BigDecimal nominalAnnualInterestRate = null; + final EnumOptionData interestCompoundingPeriodType = null; final EnumOptionData interestCalculationType = null; final EnumOptionData interestCalculationDaysInYearType = null; final BigDecimal minRequiredOpeningBalance = null; @@ -116,24 +108,22 @@ public class SavingsProductData { final EnumOptionData lockinPeriodFrequencyType = null; final Collection currencyOptions = null; - final Collection interestRatePeriodFrequencyTypeOptions = null; final Collection interestPeriodTypeOptions = null; final Collection interestCalculationTypeOptions = null; final Collection interestCalculationDaysInYearTypeOptions = null; final Collection lockinPeriodFrequencyTypeOptions = null; - return new SavingsProductData(id, name, description, currency, interestRate, interestRatePeriodFrequencyType, interestPeriodType, + return new SavingsProductData(id, name, description, currency, nominalAnnualInterestRate, interestCompoundingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, - lockinPeriodFrequencyType, currencyOptions, interestRatePeriodFrequencyTypeOptions, interestPeriodTypeOptions, - interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions); + lockinPeriodFrequencyType, currencyOptions, interestPeriodTypeOptions, interestCalculationTypeOptions, + interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions); } private SavingsProductData(final Long id, final String name, final String description, final CurrencyData currency, - final BigDecimal interestRate, final EnumOptionData interestRatePeriodFrequencyType, final EnumOptionData interestPeriodType, + final BigDecimal nominalAnnualInterestRate, final EnumOptionData interestCompoundingPeriodType, final EnumOptionData interestCalculationType, final EnumOptionData interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType, final Collection currencyOptions, - final Collection interestRatePeriodFrequencyTypeOptions, final Collection interestPeriodTypeOptions, final Collection interestCalculationTypeOptions, final Collection interestCalculationDaysInYearTypeOptions, final Collection lockinPeriodFrequencyTypeOptions) { @@ -141,9 +131,8 @@ public class SavingsProductData { this.name = name; this.description = description; this.currency = currency; - this.interestRate = interestRate; - this.interestRatePeriodFrequencyType = interestRatePeriodFrequencyType; - this.interestPeriodType = interestPeriodType; + this.nominalAnnualInterestRate = nominalAnnualInterestRate; + this.interestCompoundingPeriodType = interestCompoundingPeriodType; this.interestCalculationType = interestCalculationType; this.interestCalculationDaysInYearType = interestCalculationDaysInYearType; this.minRequiredOpeningBalance = minRequiredOpeningBalance; @@ -151,8 +140,7 @@ public class SavingsProductData { this.lockinPeriodFrequencyType = lockinPeriodFrequencyType; this.currencyOptions = currencyOptions; - this.interestRatePeriodFrequencyTypeOptions = interestRatePeriodFrequencyTypeOptions; - this.interestPeriodTypeOptions = interestPeriodTypeOptions; + this.interestCompoundingPeriodTypeOptions = interestPeriodTypeOptions; this.interestCalculationTypeOptions = interestCalculationTypeOptions; this.interestCalculationDaysInYearTypeOptions = interestCalculationDaysInYearTypeOptions; this.lockinPeriodFrequencyTypeOptions = lockinPeriodFrequencyTypeOptions; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsProductDataValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsProductDataValidator.java index c9876d1a2..3679293bb 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsProductDataValidator.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsProductDataValidator.java @@ -7,13 +7,12 @@ import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.descri import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.digitsAfterDecimalParamName; import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestCalculationDaysInYearTypeParamName; import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestCalculationTypeParamName; -import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestPeriodTypeParamName; -import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestRateParamName; -import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestRatePeriodFrequencyTypeParamName; +import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestCompoundingPeriodTypeParamName; import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockinPeriodFrequencyParamName; import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockinPeriodFrequencyTypeParamName; import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.minRequiredOpeningBalanceParamName; import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.nameParamName; +import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.nominalAnnualInterestRateParamName; import java.lang.reflect.Type; import java.math.BigDecimal; @@ -67,16 +66,13 @@ public class SavingsProductDataValidator { final Integer digitsAfterDecimal = fromApiJsonHelper.extractIntegerSansLocaleNamed(digitsAfterDecimalParamName, element); baseDataValidator.reset().parameter(digitsAfterDecimalParamName).value(digitsAfterDecimal).notNull().inMinMaxRange(0, 6); - final BigDecimal interestRate = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(interestRateParamName, element); - baseDataValidator.reset().parameter(interestRateParamName).value(interestRate).notNull().zeroOrPositiveAmount(); + final BigDecimal interestRate = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(nominalAnnualInterestRateParamName, element); + baseDataValidator.reset().parameter(nominalAnnualInterestRateParamName).value(interestRate).notNull().zeroOrPositiveAmount(); - final Integer interestRatePeriodFrequencyType = fromApiJsonHelper.extractIntegerSansLocaleNamed( - interestRatePeriodFrequencyTypeParamName, element); - baseDataValidator.reset().parameter(interestRatePeriodFrequencyTypeParamName).value(interestRatePeriodFrequencyType).notNull() - .inMinMaxRange(1, 3); - - final Integer interestPeriodType = fromApiJsonHelper.extractIntegerSansLocaleNamed(interestPeriodTypeParamName, element); - baseDataValidator.reset().parameter(interestPeriodTypeParamName).value(interestPeriodType).notNull().inMinMaxRange(1, 7); + final Integer interestCompoundingPeriodType = fromApiJsonHelper.extractIntegerSansLocaleNamed( + interestCompoundingPeriodTypeParamName, element); + baseDataValidator.reset().parameter(interestCompoundingPeriodTypeParamName).value(interestCompoundingPeriodType).notNull() + .inMinMaxRange(1, 8); final Integer interestCalculationType = fromApiJsonHelper.extractIntegerSansLocaleNamed(interestCalculationTypeParamName, element); baseDataValidator.reset().parameter(interestCalculationTypeParamName).value(interestCalculationType).notNull().inMinMaxRange(1, 2); @@ -153,21 +149,16 @@ public class SavingsProductDataValidator { baseDataValidator.reset().parameter(digitsAfterDecimalParamName).value(digitsAfterDecimal).notNull().inMinMaxRange(0, 6); } - if (this.fromApiJsonHelper.parameterExists(interestRateParamName, element)) { - final BigDecimal interestRate = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(interestRateParamName, element); - baseDataValidator.reset().parameter(interestRateParamName).value(interestRate).notNull().zeroOrPositiveAmount(); + if (this.fromApiJsonHelper.parameterExists(nominalAnnualInterestRateParamName, element)) { + final BigDecimal interestRate = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(nominalAnnualInterestRateParamName, element); + baseDataValidator.reset().parameter(nominalAnnualInterestRateParamName).value(interestRate).notNull().zeroOrPositiveAmount(); } - if (this.fromApiJsonHelper.parameterExists(interestRatePeriodFrequencyTypeParamName, element)) { - final Integer interestRatePeriodFrequencyType = fromApiJsonHelper.extractIntegerSansLocaleNamed( - interestRatePeriodFrequencyTypeParamName, element); - baseDataValidator.reset().parameter(interestRatePeriodFrequencyTypeParamName).value(interestRatePeriodFrequencyType).notNull() - .inMinMaxRange(1, 3); - } - - if (this.fromApiJsonHelper.parameterExists(interestPeriodTypeParamName, element)) { - final Integer interestPeriodType = fromApiJsonHelper.extractIntegerSansLocaleNamed(interestPeriodTypeParamName, element); - baseDataValidator.reset().parameter(interestPeriodTypeParamName).value(interestPeriodType).notNull().inMinMaxRange(1, 7); + if (this.fromApiJsonHelper.parameterExists(interestCompoundingPeriodTypeParamName, element)) { + final Integer interestCompoundingPeriodType = fromApiJsonHelper.extractIntegerSansLocaleNamed( + interestCompoundingPeriodTypeParamName, element); + baseDataValidator.reset().parameter(interestCompoundingPeriodTypeParamName).value(interestCompoundingPeriodType).notNull() + .inMinMaxRange(1, 8); } if (this.fromApiJsonHelper.parameterExists(interestCalculationTypeParamName, element)) { @@ -201,7 +192,10 @@ public class SavingsProductDataValidator { } private void throwExceptionIfValidationWarningsExist(final List dataValidationErrors) { - if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", - "Validation errors exist.", dataValidationErrors); } + if (!dataValidationErrors.isEmpty()) { + // + throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", + dataValidationErrors); + } } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/InterestCompoundingPeriodSummary.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/InterestCompoundingPeriodSummary.java new file mode 100644 index 000000000..1b17d0966 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/InterestCompoundingPeriodSummary.java @@ -0,0 +1,53 @@ +package org.mifosplatform.portfolio.savings.domain; + +import java.math.BigDecimal; +import java.math.MathContext; + +import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; +import org.mifosplatform.organisation.monetary.domain.Money; + +public class InterestCompoundingPeriodSummary { + + @SuppressWarnings("unused") + private final LocalDateInterval periodInterval; + @SuppressWarnings("unused") + private final BigDecimal openingBalance; + private final BigDecimal closingBalance; + private final BigDecimal interestEarnedUnrounded; + private final BigDecimal cumulativeCompoundedInterestToDate; + + public static InterestCompoundingPeriodSummary create(final LocalDateInterval periodInterval, final BigDecimal openingBalance, + final BigDecimal closingBalance, final BigDecimal interestEarnedUnrounded, final BigDecimal cumulativeCompoundedInterestToDate) { + return new InterestCompoundingPeriodSummary(periodInterval, openingBalance, closingBalance, interestEarnedUnrounded, + cumulativeCompoundedInterestToDate); + } + + public InterestCompoundingPeriodSummary(final LocalDateInterval periodInterval, final BigDecimal openingBalance, + final BigDecimal closingBalance, final BigDecimal interestEarnedUnrounded, final BigDecimal cumulativeCompoundedInterestToDate) { + this.periodInterval = periodInterval; + this.openingBalance = openingBalance; + this.closingBalance = closingBalance; + this.interestEarnedUnrounded = interestEarnedUnrounded; + this.cumulativeCompoundedInterestToDate = cumulativeCompoundedInterestToDate; + } + + public Money closingBalance(final MonetaryCurrency currency) { + return Money.of(currency, this.closingBalance); + } + + public BigDecimal closingBalance() { + return this.closingBalance; + } + + public BigDecimal closingBalanceWithUnroundedInterest(final MathContext mc) { + return this.closingBalance.add(interestEarnedUnrounded, mc); + } + + public BigDecimal compoundedInterest() { + return cumulativeCompoundedInterestToDate; + } + + public BigDecimal interestUnrounded() { + return this.interestEarnedUnrounded; + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/InterestPeriodSummary.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/InterestPeriodSummary.java deleted file mode 100644 index a53f5b8f6..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/InterestPeriodSummary.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.mifosplatform.portfolio.savings.domain; - -import java.math.BigDecimal; -import java.util.Date; -import java.util.List; - -import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; -import org.mifosplatform.organisation.monetary.domain.Money; - -public class InterestPeriodSummary { - - @SuppressWarnings("unused") - private final Date startDate; - @SuppressWarnings("unused") - private final Date endDate; - @SuppressWarnings("unused") - private final Integer numberOfDays; - @SuppressWarnings("unused") - private final BigDecimal startingBalance; - private final BigDecimal closingBalance; - private final BigDecimal interestEarnedUnrounded; - private final BigDecimal interestEarned; - @SuppressWarnings("unused") - private final List dailyBalances; - - public static InterestPeriodSummary from(final InterestPeriodInterval interestPeriodInterval, final Money startingBalance, - final List dailyBalances, final BigDecimal totalInterestEarnedUnrounded) { - - return new InterestPeriodSummary(interestPeriodInterval, startingBalance, dailyBalances, totalInterestEarnedUnrounded); - } - - private InterestPeriodSummary(final InterestPeriodInterval interestPeriodInterval, final Money startingBalance, - final List dailyBalances, final BigDecimal totalInterestEarnedUnrounded) { - this.startDate = interestPeriodInterval.startDate().toDate(); - this.endDate = interestPeriodInterval.endDate().toDate(); - this.numberOfDays = interestPeriodInterval.daysInPeriodInclusiveOfEndDate(); - this.startingBalance = startingBalance.getAmount(); - - final MonetaryCurrency currency = startingBalance.getCurrency(); - - this.interestEarnedUnrounded = totalInterestEarnedUnrounded; - this.interestEarned = Money.of(currency, this.interestEarnedUnrounded).getAmount(); - - Money closingBalanceForPeriod = startingBalance.copy(); - - for (SavingsAccountDailyBalance balance : dailyBalances) { - closingBalanceForPeriod = balance.dailyRunningBalance(currency); - } - - this.closingBalance = closingBalanceForPeriod.getAmount(); - this.dailyBalances = dailyBalances; - } - - public Money closingBalance(final MonetaryCurrency currency) { - return Money.of(currency, this.closingBalance); - } - - public BigDecimal interest() { - return this.interestEarned; - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/InterestPeriodInterval.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/LocalDateInterval.java similarity index 76% rename from mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/InterestPeriodInterval.java rename to mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/LocalDateInterval.java index e0a9d4012..03fd5c781 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/InterestPeriodInterval.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/LocalDateInterval.java @@ -3,16 +3,16 @@ package org.mifosplatform.portfolio.savings.domain; import org.joda.time.Days; import org.joda.time.LocalDate; -public class InterestPeriodInterval { +public class LocalDateInterval { private final LocalDate startDate; private final LocalDate endDate; - public static InterestPeriodInterval create(final LocalDate startDate, final LocalDate endDate) { - return new InterestPeriodInterval(startDate, endDate); + public static LocalDateInterval create(final LocalDate startDate, final LocalDate endDate) { + return new LocalDateInterval(startDate, endDate); } - public InterestPeriodInterval(final LocalDate startDate, final LocalDate endDate) { + public LocalDateInterval(final LocalDate startDate, final LocalDate endDate) { this.startDate = startDate; this.endDate = endDate; } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java index 2929ee3d7..06f5e9efc 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccount.java @@ -81,20 +81,18 @@ public class SavingsAccount extends AbstractPersistable { @Embedded private MonetaryCurrency currency; - @Column(name = "nominal_interest_rate_per_period", scale = 6, precision = 19, nullable = false) - private BigDecimal interestRate; - - @Column(name = "nominal_interest_rate_period_frequency_enum", nullable = false) - private Integer interestRatePeriodFrequencyType; + @Column(name = "nominal_annual_interest_rate", scale = 6, precision = 19, nullable = false) + private BigDecimal nominalAnnualInterestRate; /** * The interest period is the span of time at the end of which savings in a * client’s account earn interest. * - * A value from the {@link SavingsInterestPeriodType} enumeration. + * A value from the {@link SavingsCompoundingInterestPeriodType} + * enumeration. */ - @Column(name = "interest_period_enum", nullable = false) - private Integer interestPeriodType; + @Column(name = "interest_compounding_period_enum", nullable = false) + private Integer interestCompoundingPeriodType; /** * A value from the {@link SavingsInterestCalculationType} enumeration. @@ -109,9 +107,6 @@ public class SavingsAccount extends AbstractPersistable { @Column(name = "interest_calculation_days_in_year_type_enum", nullable = false) private Integer interestCalculationDaysInYearType; - @Column(name = "annual_nominal_interest_rate", scale = 6, precision = 19, nullable = false) - private BigDecimal annualInterestRate; - @Column(name = "min_required_opening_balance", scale = 6, precision = 19, nullable = false) private BigDecimal minRequiredOpeningBalance; @@ -149,24 +144,22 @@ public class SavingsAccount extends AbstractPersistable { public static SavingsAccount createNewAccount(final Client client, final Group group, final SavingsProduct product, final String accountNo, final String externalId, final BigDecimal interestRate, - final PeriodFrequencyType interestRatePeriodFrequencyType, final BigDecimal annualInterestRate, - final SavingsInterestPeriodType interestPeriodType, final SavingsInterestCalculationType interestCalculationType, + final SavingsCompoundingInterestPeriodType interestPeriodType, final SavingsInterestCalculationType interestCalculationType, final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance, - final Integer lockinPeriodFrequency, final PeriodFrequencyType lockinPeriodFrequencyType) { + final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType) { final SavingsAccountStatusType status = SavingsAccountStatusType.UNACTIVATED; final LocalDate activationDate = null; - return new SavingsAccount(client, group, product, accountNo, externalId, status, activationDate, interestRate, - interestRatePeriodFrequencyType, annualInterestRate, interestPeriodType, interestCalculationType, - interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType); + return new SavingsAccount(client, group, product, accountNo, externalId, status, activationDate, interestRate, interestPeriodType, + interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, + lockinPeriodFrequencyType); } private SavingsAccount(final Client client, final Group group, final SavingsProduct product, final String accountNo, final String externalId, final SavingsAccountStatusType status, final LocalDate activationDate, final BigDecimal interestRate, - final PeriodFrequencyType interestRatePeriodFrequencyType, final BigDecimal annualInterestRate, - final SavingsInterestPeriodType interestPeriodType, final SavingsInterestCalculationType interestCalculationType, + final SavingsCompoundingInterestPeriodType interestPeriodType, final SavingsInterestCalculationType interestCalculationType, final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance, - final Integer lockinPeriodFrequency, final PeriodFrequencyType lockinPeriodFrequencyType) { + final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType) { this.client = client; this.group = group; this.product = product; @@ -182,10 +175,8 @@ public class SavingsAccount extends AbstractPersistable { if (activationDate != null) { this.activationDate = activationDate.toDate(); } - this.interestRate = interestRate; - this.interestRatePeriodFrequencyType = interestRatePeriodFrequencyType.getValue(); - this.annualInterestRate = annualInterestRate; - this.interestPeriodType = interestPeriodType.getValue(); + this.nominalAnnualInterestRate = interestRate; + this.interestCompoundingPeriodType = interestPeriodType.getValue(); this.interestCalculationType = interestCalculationType.getValue(); this.interestCalculationDaysInYearType = interestCalculationDaysInYearType.getValue(); this.minRequiredOpeningBalance = minRequiredOpeningBalance; @@ -281,47 +272,112 @@ public class SavingsAccount extends AbstractPersistable { * Interest calculation is performed on-the-fly over all account * transactions. */ - /* - * The daily balance method is the application of a daily interest rate to - * the full amount of principal in the account each day. For the days the - * account is overdrawn, a zero balance is used to calculate the interest - * for those days. - */ - public void calculateInterest() { + public void calculateInterest(final LocalDate interestCalculationEndDate) { - // no openingBalance concept supported yet but probably will to all for - // migrations. + // no openingBalance concept supported yet but probably will to allow + // for migrations. final Money openingAccountBalance = Money.zero(this.currency); - // 1. update existing transactions so derived balance fields are + // update existing transactions so derived balance fields are // correct. recalculateDailyBalances(openingAccountBalance); - // 2. determine interest periods - final SavingsInterestPeriodType interestPeriodType = SavingsInterestPeriodType.fromInt(this.interestPeriodType); final SavingsInterestCalculationDaysInYearType daysInYearType = SavingsInterestCalculationDaysInYearType .fromInt(this.interestCalculationDaysInYearType); - final List interestPeriods = determineInterestPeriods(getActivationLocalDate(), interestPeriodType); + final SavingsCompoundingInterestPeriodType compoundingPeriodType = SavingsCompoundingInterestPeriodType + .fromInt(this.interestCompoundingPeriodType); + final List interestCompoundingPeriods = determineInterestCompoundingPeriods(getActivationLocalDate(), + interestCalculationEndDate, compoundingPeriodType); - final List interestPeriodSummaries = deriveInterestPeriodSummaries(openingAccountBalance, interestPeriods, - this.annualInterestRate, daysInYearType); + // determine opening balance, daily interest rate to apply, interest + // due, interest to compound for each period + final List compoundingPeriods = determineInterestCompoundingPeriodSummaries( + openingAccountBalance, this.nominalAnnualInterestRate, daysInYearType, interestCompoundingPeriods); - this.summary.updateFromInterestPeriodSummaries(currency, interestPeriodSummaries); + this.summary.updateFromInterestPeriodSummaries(currency, compoundingPeriods); } - private List determineInterestPeriods(final LocalDate activationLocalDate, - final SavingsInterestPeriodType interestPeriodType) { + private List determineInterestCompoundingPeriodSummaries(final Money openingAccountBalance, + final BigDecimal annualInterestRate, final SavingsInterestCalculationDaysInYearType daysInYearType, + final List interestCompoundingPeriods) { - LocalDate today = DateUtils.getLocalDateOfTenant(); + List summaries = new ArrayList(); + + final MathContext mc = new MathContext(10, RoundingMode.HALF_EVEN); + final BigDecimal percentageDivisor = BigDecimal.valueOf(100l); + final BigDecimal periodsInOneYear = determinePeriodsInOneYear(daysInYearType); + final BigDecimal periodsInOneYearAsFraction = BigDecimal.ONE.divide(periodsInOneYear, mc); + final BigDecimal annualInterestRateAsFraction = annualInterestRate.divide(percentageDivisor, mc); + + final SavingsInterestCalculationType interestCalculationType = SavingsInterestCalculationType.fromInt(this.interestCalculationType); + + final SavingsInterestCalculatorFactory interestCalculatorFactory = new SavingsInterestCalculatorFactory(); + final SavingsCompoundInterestCalculator interestCalculator = interestCalculatorFactory.createFrom(interestCalculationType, + periodsInOneYearAsFraction, annualInterestRateAsFraction); + + BigDecimal periodOpeningBalance = openingAccountBalance.copy().getAmount(); + BigDecimal compoundedInterestToDate = BigDecimal.ZERO; + for (LocalDateInterval periodInterval : interestCompoundingPeriods) { + + InterestCompoundingPeriodSummary compoundingSummary = calculateInterestCompoundingPeriodSummary(periodInterval, + periodOpeningBalance, compoundedInterestToDate, interestCalculator); + + periodOpeningBalance = compoundingSummary.closingBalance(); + compoundedInterestToDate = compoundingSummary.compoundedInterest(); + + summaries.add(compoundingSummary); + } + + return summaries; + } + + private InterestCompoundingPeriodSummary calculateInterestCompoundingPeriodSummary(final LocalDateInterval periodInterval, + final BigDecimal periodOpeningBalance, final BigDecimal compoundedInterestToDate, + final SavingsCompoundInterestCalculator interestCalculator) { + + BigDecimal periodClosingBalance = periodOpeningBalance; + List dailyBalances = new ArrayList(); + for (SavingsAccountTransaction transaction : this.transactions) { + + if (transaction.isAcceptableForDailyBalance(periodInterval)) { + SavingsAccountDailyBalance dailyBalance = transaction.toCompoundedDailyBalance(periodInterval.endDate(), + compoundedInterestToDate); + dailyBalances.add(dailyBalance); + + periodClosingBalance = dailyBalance.endOfDayBalance(); + } + } + + if (dailyBalances.isEmpty()) { + SavingsAccountDailyBalance dailyBalance = SavingsAccountDailyBalance.createFrom(periodInterval, periodOpeningBalance, + compoundedInterestToDate); + dailyBalances.add(dailyBalance); + } + + final BigDecimal totalInterestEarnedUnrounded = interestCalculator.calculate(dailyBalances, + periodInterval.daysInPeriodInclusiveOfEndDate()); + + final MathContext mc = new MathContext(10, RoundingMode.HALF_EVEN); + final BigDecimal cumulativeCompoundedInterestToDate = compoundedInterestToDate.add(totalInterestEarnedUnrounded, mc); + + return InterestCompoundingPeriodSummary.create(periodInterval, periodOpeningBalance, periodClosingBalance, + totalInterestEarnedUnrounded, cumulativeCompoundedInterestToDate); + } + + private List determineInterestCompoundingPeriods(final LocalDate activationLocalDate, + final LocalDate interestCalculationEndDate, final SavingsCompoundingInterestPeriodType interestPeriodType) { LocalDate periodStartDate = activationLocalDate; LocalDate periodEndDate = periodStartDate; - final List interestPeriods = new ArrayList(); + final List interestPeriods = new ArrayList(); - while (!periodStartDate.isAfter(today) && !periodEndDate.isAfter(today)) { + while (!periodStartDate.isAfter(interestCalculationEndDate) && !periodEndDate.isAfter(interestCalculationEndDate)) { periodEndDate = determineInterestPeriodEndDateFrom(periodStartDate, interestPeriodType); - interestPeriods.add(InterestPeriodInterval.create(periodStartDate, periodEndDate)); + if (periodEndDate.isAfter(interestCalculationEndDate)) { + periodEndDate = interestCalculationEndDate; + } + interestPeriods.add(LocalDateInterval.create(periodStartDate, periodEndDate)); // move periodStartDate forward to day after this period periodStartDate = periodEndDate.plusDays(1); @@ -330,7 +386,8 @@ public class SavingsAccount extends AbstractPersistable { return interestPeriods; } - private LocalDate determineInterestPeriodEndDateFrom(final LocalDate periodStartDate, final SavingsInterestPeriodType interestPeriodType) { + private LocalDate determineInterestPeriodEndDateFrom(final LocalDate periodStartDate, + final SavingsCompoundingInterestPeriodType interestPeriodType) { LocalDate periodEndDate = DateUtils.getLocalDateOfTenant(); @@ -366,7 +423,7 @@ public class SavingsAccount extends AbstractPersistable { periodEndDate = new DateTime().withDate(year, 12, 31).toLocalDate(); } break; - case SEMIANNUAL: + case BI_ANNUAL: // jan 1st to 30, jul 1st to dec 31 year = periodStartDate.getYearOfEra(); monthofYear = periodStartDate.getMonthOfYear(); @@ -380,6 +437,10 @@ public class SavingsAccount extends AbstractPersistable { periodEndDate = periodStartDate.monthOfYear().withMaximumValue(); periodEndDate = periodStartDate.dayOfMonth().withMaximumValue(); break; + case NO_COMPOUNDING_SIMPLE_INTEREST: + periodEndDate = periodStartDate.monthOfYear().withMaximumValue(); + periodEndDate = periodStartDate.dayOfMonth().withMaximumValue(); + break; } return periodEndDate; @@ -403,62 +464,6 @@ public class SavingsAccount extends AbstractPersistable { return periodsInOneYear; } - private List deriveInterestPeriodSummaries(final Money openingAccountBalance, - final List interestPeriods, final BigDecimal annualInterestRate, - final SavingsInterestCalculationDaysInYearType daysInYearType) { - - final List summaries = new ArrayList(); - - final MathContext mc = new MathContext(10, RoundingMode.HALF_EVEN); - final BigDecimal percentageDivisor = BigDecimal.valueOf(100l); - final BigDecimal periodsInOneYear = determinePeriodsInOneYear(daysInYearType); - final BigDecimal periodsInOneYearAsFraction = BigDecimal.ONE.divide(periodsInOneYear, mc); - final BigDecimal annualInterestRateAsFraction = annualInterestRate.divide(percentageDivisor, mc); - - final SavingsInterestCalculationType interestCalculationType = SavingsInterestCalculationType.fromInt(this.interestCalculationType); - - final SavingsInterestCalculatorFactory interestCalculatorFactory = new SavingsInterestCalculatorFactory(); - final SavingsInterestCalculator interestCalculator = interestCalculatorFactory.createFrom(interestCalculationType, - periodsInOneYearAsFraction, annualInterestRateAsFraction); - - Money periodOpeningBalance = openingAccountBalance.copy(); - for (InterestPeriodInterval interestPeriodInterval : interestPeriods) { - - InterestPeriodSummary interestPeriodSummary = calculateInterestPeriodSummaryFor(interestPeriodInterval, periodOpeningBalance, - interestCalculator); - - periodOpeningBalance = interestPeriodSummary.closingBalance(this.currency); - - summaries.add(interestPeriodSummary); - } - - return summaries; - } - - private InterestPeriodSummary calculateInterestPeriodSummaryFor(final InterestPeriodInterval interestPeriodInterval, - final Money startingBalanceForPeriod, final SavingsInterestCalculator interestCalculator) { - - List dailyBalances = new ArrayList(); - for (SavingsAccountTransaction transaction : this.transactions) { - - if (transaction.isAcceptableForDailyBalance(interestPeriodInterval)) { - SavingsAccountDailyBalance dailyBalance = transaction.toDailyBalance(interestPeriodInterval.endDate()); - dailyBalances.add(dailyBalance); - } - } - - if (dailyBalances.isEmpty()) { - SavingsAccountDailyBalance dailyBalance = SavingsAccountDailyBalance.createFrom(interestPeriodInterval, - startingBalanceForPeriod.getAmount()); - dailyBalances.add(dailyBalance); - } - - final BigDecimal totalInterestEarnedUnrounded = interestCalculator.calculate(dailyBalances, - interestPeriodInterval.daysInPeriodInclusiveOfEndDate()); - - return InterestPeriodSummary.from(interestPeriodInterval, startingBalanceForPeriod, dailyBalances, totalInterestEarnedUnrounded); - } - private void recalculateDailyBalances(final Money openingAccountBalance) { Money runningBalance = openingAccountBalance.copy(); @@ -537,7 +542,8 @@ public class SavingsAccount extends AbstractPersistable { this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions); - calculateInterest(); + final LocalDate today = DateUtils.getLocalDateOfTenant(); + calculateInterest(today); return transaction; } @@ -614,7 +620,8 @@ public class SavingsAccount extends AbstractPersistable { this.summary.updateSummary(this.currency, this.savingsAccountTransactionSummaryWrapper, this.transactions); - calculateInterest(); + final LocalDate today = DateUtils.getLocalDateOfTenant(); + calculateInterest(today); return transaction; } @@ -683,18 +690,12 @@ public class SavingsAccount extends AbstractPersistable { actualChanges.put(SavingsApiConstants.productIdParamName, newValue); } - if (command.isChangeInBigDecimalParameterNamed(SavingsApiConstants.interestRateParamName, this.interestRate)) { - final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(SavingsApiConstants.interestRateParamName); - actualChanges.put(SavingsApiConstants.interestRateParamName, newValue); + if (command.isChangeInBigDecimalParameterNamed(SavingsApiConstants.nominalAnnualInterestRateParamName, + this.nominalAnnualInterestRate)) { + final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(SavingsApiConstants.nominalAnnualInterestRateParamName); + actualChanges.put(SavingsApiConstants.nominalAnnualInterestRateParamName, newValue); actualChanges.put("locale", localeAsInput); - this.interestRate = newValue; - } - - if (command.isChangeInIntegerParameterNamed(SavingsApiConstants.interestRatePeriodFrequencyTypeParamName, - this.interestRatePeriodFrequencyType)) { - final Integer newValue = command.integerValueOfParameterNamed(SavingsApiConstants.interestRatePeriodFrequencyTypeParamName); - actualChanges.put(SavingsApiConstants.interestRatePeriodFrequencyTypeParamName, newValue); - this.interestRatePeriodFrequencyType = PeriodFrequencyType.fromInt(newValue).getValue(); + this.nominalAnnualInterestRate = newValue; } if (command.isChangeInBigDecimalParameterNamed(SavingsApiConstants.minRequiredOpeningBalanceParamName, diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountAssembler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountAssembler.java index 59afef0af..47ef538ff 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountAssembler.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountAssembler.java @@ -9,12 +9,11 @@ import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.activa import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.activeParamName; import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestCalculationDaysInYearTypeParamName; import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestCalculationTypeParamName; -import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestPeriodTypeParamName; -import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestRateParamName; -import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestRatePeriodFrequencyTypeParamName; +import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestCompoundingPeriodTypeParamName; import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockinPeriodFrequencyParamName; import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockinPeriodFrequencyTypeParamName; import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.minRequiredOpeningBalanceParamName; +import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.nominalAnnualInterestRateParamName; import java.math.BigDecimal; import java.util.Locale; @@ -30,8 +29,6 @@ import org.mifosplatform.portfolio.client.exception.ClientNotFoundException; import org.mifosplatform.portfolio.group.domain.Group; import org.mifosplatform.portfolio.group.domain.GroupRepository; import org.mifosplatform.portfolio.group.exception.GroupNotFoundException; -import org.mifosplatform.portfolio.loanaccount.loanschedule.domain.AprCalculator; -import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType; import org.mifosplatform.portfolio.savings.exception.SavingsProductNotFoundException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -46,18 +43,15 @@ public class SavingsAccountAssembler { private final GroupRepository groupRepository; private final SavingsProductRepository savingProductRepository; private final FromJsonHelper fromApiJsonHelper; - private final AprCalculator aprCalculator; @Autowired public SavingsAccountAssembler(final SavingsAccountTransactionSummaryWrapper savingsAccountTransactionSummaryWrapper, final ClientRepository clientRepository, final GroupRepository groupRepository, - final SavingsProductRepository savingProductRepository, final AprCalculator aprCalculator, - final FromJsonHelper fromApiJsonHelper) { + final SavingsProductRepository savingProductRepository, final FromJsonHelper fromApiJsonHelper) { this.savingsAccountTransactionSummaryWrapper = savingsAccountTransactionSummaryWrapper; this.clientRepository = clientRepository; this.groupRepository = groupRepository; this.savingProductRepository = savingProductRepository; - this.aprCalculator = aprCalculator; this.fromApiJsonHelper = fromApiJsonHelper; } @@ -93,8 +87,8 @@ public class SavingsAccountAssembler { } BigDecimal interestRate = null; - if (command.parameterExists(interestRateParamName)) { - interestRate = command.bigDecimalValueOfParameterNamed(interestRateParamName); + if (command.parameterExists(nominalAnnualInterestRateParamName)) { + interestRate = command.bigDecimalValueOfParameterNamed(nominalAnnualInterestRateParamName); } else { interestRate = product.interestRate(); } @@ -102,23 +96,10 @@ public class SavingsAccountAssembler { final boolean active = fromApiJsonHelper.extractBooleanNamed(activeParamName, element); final LocalDate activationDate = fromApiJsonHelper.extractLocalDateNamed(activationDateParamName, element); - PeriodFrequencyType interestRatePeriodFrequencyType = null; - Integer interestRatePeriodFrequencyTypeValue = null; - if (command.parameterExists(interestRatePeriodFrequencyTypeParamName)) { - interestRatePeriodFrequencyTypeValue = command.integerValueOfParameterNamed(interestRatePeriodFrequencyTypeParamName); - if (interestRatePeriodFrequencyTypeValue != null) { - interestRatePeriodFrequencyType = PeriodFrequencyType.fromInt(interestRatePeriodFrequencyTypeValue); - } - } else { - interestRatePeriodFrequencyType = product.interestRatePeriodFrequencyType(); - } - - final BigDecimal annualInterestRate = this.aprCalculator.calculateFrom(interestRatePeriodFrequencyType, interestRate); - - SavingsInterestPeriodType interestPeriodType = null; - final Integer interestPeriodTypeValue = command.integerValueOfParameterNamed(interestPeriodTypeParamName); + SavingsCompoundingInterestPeriodType interestPeriodType = null; + final Integer interestPeriodTypeValue = command.integerValueOfParameterNamed(interestCompoundingPeriodTypeParamName); if (interestPeriodTypeValue != null) { - interestPeriodType = SavingsInterestPeriodType.fromInt(interestPeriodTypeValue); + interestPeriodType = SavingsCompoundingInterestPeriodType.fromInt(interestPeriodTypeValue); } SavingsInterestCalculationType interestCalculationType = null; @@ -148,20 +129,20 @@ public class SavingsAccountAssembler { lockinPeriodFrequency = product.lockinPeriodFrequency(); } - PeriodFrequencyType lockinPeriodFrequencyType = null; + SavingsPeriodFrequencyType lockinPeriodFrequencyType = null; Integer lockinPeriodFrequencyTypeValue = null; if (command.parameterExists(lockinPeriodFrequencyTypeParamName)) { lockinPeriodFrequencyTypeValue = command.integerValueOfParameterNamed(lockinPeriodFrequencyTypeParamName); if (lockinPeriodFrequencyTypeValue != null) { - lockinPeriodFrequencyType = PeriodFrequencyType.fromInt(lockinPeriodFrequencyTypeValue); + lockinPeriodFrequencyType = SavingsPeriodFrequencyType.fromInt(lockinPeriodFrequencyTypeValue); } } else { lockinPeriodFrequencyType = product.lockinPeriodFrequencyType(); } final SavingsAccount account = SavingsAccount.createNewAccount(client, group, product, accountNo, externalId, interestRate, - interestRatePeriodFrequencyType, annualInterestRate, interestPeriodType, interestCalculationType, - interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType); + interestPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, + lockinPeriodFrequency, lockinPeriodFrequencyType); account.setHelpers(this.savingsAccountTransactionSummaryWrapper); if (active) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountDailyBalance.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountDailyBalance.java index 6f0e676f7..689e0439b 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountDailyBalance.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountDailyBalance.java @@ -9,24 +9,32 @@ import org.mifosplatform.organisation.monetary.domain.Money; public class SavingsAccountDailyBalance { - private final InterestPeriodInterval interestPeriodInterval; - private final BigDecimal runningBalance; + private final LocalDateInterval interestPeriodInterval; + private final BigDecimal endOfDayBalance; private final BigDecimal cumulativeBalance; + private final BigDecimal compoundedInterestToDate; - public static SavingsAccountDailyBalance createFrom(final InterestPeriodInterval interestPeriodInterval, final BigDecimal runningBalance) { - return new SavingsAccountDailyBalance(interestPeriodInterval, runningBalance); + public static SavingsAccountDailyBalance createFrom(final LocalDateInterval interestPeriodInterval, final BigDecimal endOfDayBalance, + final BigDecimal compoundedInterestToDate) { + return new SavingsAccountDailyBalance(interestPeriodInterval, endOfDayBalance, compoundedInterestToDate); } - private SavingsAccountDailyBalance(final InterestPeriodInterval interestPeriodInterval, final BigDecimal runningBalance) { + private SavingsAccountDailyBalance(final LocalDateInterval interestPeriodInterval, final BigDecimal endOfDayBalance, + final BigDecimal compoundedInterestToDate) { this.interestPeriodInterval = interestPeriodInterval; - this.runningBalance = runningBalance; + this.endOfDayBalance = endOfDayBalance; + this.compoundedInterestToDate = compoundedInterestToDate; final MathContext mc = new MathContext(10, RoundingMode.HALF_EVEN); final BigDecimal numberOfDaysBigDecimal = BigDecimal.valueOf(interestPeriodInterval.daysInPeriodInclusiveOfEndDate()); - this.cumulativeBalance = runningBalance.multiply(numberOfDaysBigDecimal, mc); + this.cumulativeBalance = endOfDayBalance.multiply(numberOfDaysBigDecimal, mc); } public Money dailyRunningBalance(final MonetaryCurrency currency) { - return Money.of(currency, runningBalance); + return Money.of(currency, endOfDayBalance); + } + + public BigDecimal endOfDayBalance() { + return this.endOfDayBalance; } public BigDecimal cumulativeBalance() { @@ -38,12 +46,14 @@ public class SavingsAccountDailyBalance { } public boolean isGreaterThanZero() { - return this.runningBalance.compareTo(BigDecimal.ZERO) > 0; + return this.endOfDayBalance.compareTo(BigDecimal.ZERO) > 0; } public BigDecimal interestUsingDailyBalanceMethod(final BigDecimal dailyInterestRate, final Integer numberOfDays) { final MathContext mc = new MathContext(10, RoundingMode.HALF_EVEN); final BigDecimal numberOfDaysBigDecimal = BigDecimal.valueOf(numberOfDays.longValue()); - return this.runningBalance.multiply(dailyInterestRate, mc).multiply(numberOfDaysBigDecimal, mc); + + final BigDecimal compoundedEndOfDayBalance = this.endOfDayBalance.add(this.compoundedInterestToDate, mc); + return compoundedEndOfDayBalance.multiply(dailyInterestRate, mc).multiply(numberOfDaysBigDecimal, mc); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountSummary.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountSummary.java index c745e6659..af83e5a0d 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountSummary.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountSummary.java @@ -47,13 +47,19 @@ public final class SavingsAccountSummary { .getAmount(); } - public void updateFromInterestPeriodSummaries(final MonetaryCurrency currency, final List interestPeriodSummaries) { - Money totalInterestEarned = Money.zero(currency); - for (InterestPeriodSummary interestPeriodSummary : interestPeriodSummaries) { - totalInterestEarned = totalInterestEarned.plus(interestPeriodSummary.interest()); + public void updateFromInterestPeriodSummaries(final MonetaryCurrency currency, + final List compoundingPeriods) { + + // get the max compounded interest + final BigDecimal compoundedInterestToDate = compoundingPeriods.get(compoundingPeriods.size() - 1).compoundedInterest(); + final Money maxIntrestCompoundedToDate = Money.of(currency, compoundedInterestToDate); + + BigDecimal totalInterestUnrounded = BigDecimal.ZERO; + for (InterestCompoundingPeriodSummary interestPeriodSummary : compoundingPeriods) { + totalInterestUnrounded = totalInterestUnrounded.add(interestPeriodSummary.interestUnrounded()); } - this.totalInterestEarned = totalInterestEarned.getAmountDefaultedToNullIfZero(); + this.totalInterestEarned = maxIntrestCompoundedToDate.getAmountDefaultedToNullIfZero(); } public boolean isLessThanOrEqualToAccountBalance(final Money amount) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountTransaction.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountTransaction.java index dae320886..2d2b0c45c 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountTransaction.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsAccountTransaction.java @@ -130,7 +130,7 @@ public final class SavingsAccountTransaction extends AbstractPersistable { public void updateCumulativeBalanceAndDates(final MonetaryCurrency currency, final LocalDate endOfBalanceDate) { this.balanceEndDate = endOfBalanceDate.toDate(); - this.balanceNumberOfDays = InterestPeriodInterval.create(getTransactionLocalDate(), endOfBalanceDate) + this.balanceNumberOfDays = LocalDateInterval.create(getTransactionLocalDate(), endOfBalanceDate) .daysInPeriodInclusiveOfEndDate(); this.cumulativeBalance = Money.of(currency, this.runningBalance).multipliedBy(this.balanceNumberOfDays).getAmount(); } @@ -147,7 +147,7 @@ public final class SavingsAccountTransaction extends AbstractPersistable { return endDate; } - public boolean isAcceptableForDailyBalance(final InterestPeriodInterval interestPeriodInterval) { + public boolean isAcceptableForDailyBalance(final LocalDateInterval interestPeriodInterval) { return isNotReversed() && interestPeriodInterval.contains(getTransactionLocalDate()) && isABalanceForAtLeastOneDay(); } @@ -162,7 +162,17 @@ public final class SavingsAccountTransaction extends AbstractPersistable { balanceValidTo = periodEnd; } - final InterestPeriodInterval interestPeriodInterval = InterestPeriodInterval.create(getTransactionLocalDate(), balanceValidTo); - return SavingsAccountDailyBalance.createFrom(interestPeriodInterval, this.runningBalance); + final LocalDateInterval interestPeriodInterval = LocalDateInterval.create(getTransactionLocalDate(), balanceValidTo); + return SavingsAccountDailyBalance.createFrom(interestPeriodInterval, this.runningBalance, BigDecimal.ZERO); + } + + public SavingsAccountDailyBalance toCompoundedDailyBalance(final LocalDate periodEnd, final BigDecimal compoundedInterestToDate) { + LocalDate balanceValidTo = getEndOfBalanceLocalDate(); + if (periodEnd.isBefore(getEndOfBalanceLocalDate())) { + balanceValidTo = periodEnd; + } + + final LocalDateInterval interestPeriodInterval = LocalDateInterval.create(getTransactionLocalDate(), balanceValidTo); + return SavingsAccountDailyBalance.createFrom(interestPeriodInterval, this.runningBalance, compoundedInterestToDate); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsInterestCalculator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsCompoundInterestCalculator.java similarity index 79% rename from mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsInterestCalculator.java rename to mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsCompoundInterestCalculator.java index 5d624315f..4f4bace10 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsInterestCalculator.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsCompoundInterestCalculator.java @@ -3,7 +3,7 @@ package org.mifosplatform.portfolio.savings.domain; import java.math.BigDecimal; import java.util.List; -public interface SavingsInterestCalculator { +public interface SavingsCompoundInterestCalculator { BigDecimal calculate(List dailyBalances, Integer numberOfDays); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsInterestCalculatorForAverageBalance.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsCompoundInterestCalculatorForAverageBalance.java similarity index 88% rename from mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsInterestCalculatorForAverageBalance.java rename to mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsCompoundInterestCalculatorForAverageBalance.java index 9d4fc6a88..2c9cbb867 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsInterestCalculatorForAverageBalance.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsCompoundInterestCalculatorForAverageBalance.java @@ -9,12 +9,12 @@ import java.util.List; * Calculates interest on a savings account using the Average Balance * method. */ -public class SavingsInterestCalculatorForAverageBalance implements SavingsInterestCalculator { +public class SavingsCompoundInterestCalculatorForAverageBalance implements SavingsCompoundInterestCalculator { private final BigDecimal periodsInOneYearAsFraction; private final BigDecimal annualInterestRateAsFraction; - public SavingsInterestCalculatorForAverageBalance(final BigDecimal periodsInOneYearAsFraction, + public SavingsCompoundInterestCalculatorForAverageBalance(final BigDecimal periodsInOneYearAsFraction, final BigDecimal annualInterestRateAsFraction) { this.periodsInOneYearAsFraction = periodsInOneYearAsFraction; this.annualInterestRateAsFraction = annualInterestRateAsFraction; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsInterestCalculatorForDailyBalance.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsCompoundInterestCalculatorForDailyBalance.java similarity index 81% rename from mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsInterestCalculatorForDailyBalance.java rename to mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsCompoundInterestCalculatorForDailyBalance.java index 287025d0d..98bd09b93 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsInterestCalculatorForDailyBalance.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsCompoundInterestCalculatorForDailyBalance.java @@ -9,12 +9,12 @@ import java.util.List; * Calculates interest on a savings account using the Daily Balance * method. */ -public class SavingsInterestCalculatorForDailyBalance implements SavingsInterestCalculator { +public class SavingsCompoundInterestCalculatorForDailyBalance implements SavingsCompoundInterestCalculator { private final BigDecimal periodsInOneYearAsFraction; private final BigDecimal annualInterestRateAsFraction; - public SavingsInterestCalculatorForDailyBalance(final BigDecimal periodsInOneYearAsFraction, + public SavingsCompoundInterestCalculatorForDailyBalance(final BigDecimal periodsInOneYearAsFraction, final BigDecimal annualInterestRateAsFraction) { this.periodsInOneYearAsFraction = periodsInOneYearAsFraction; this.annualInterestRateAsFraction = annualInterestRateAsFraction; @@ -29,7 +29,7 @@ public class SavingsInterestCalculatorForDailyBalance implements SavingsInterest for (SavingsAccountDailyBalance balance : dailyBalances) { if (balance.isGreaterThanZero()) { - final BigDecimal interestForBalance = balance.interestUsingDailyBalanceMethod(dailyInterestRate, numberOfDays); + final BigDecimal interestForBalance = balance.interestUsingDailyBalanceMethod(dailyInterestRate, balance.numberOfDays()); interestCalculated = interestCalculated.add(interestForBalance, mc); } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsCompoundingInterestPeriodType.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsCompoundingInterestPeriodType.java new file mode 100644 index 000000000..ae009a8c2 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsCompoundingInterestPeriodType.java @@ -0,0 +1,74 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.portfolio.savings.domain; + +/** + *

+ * The compounding interest period is the span of time at the end of which + * savings in a client’s account earn interest. + *

+ */ +public enum SavingsCompoundingInterestPeriodType { + + INVALID(0, "savingsCompoundingInterestPeriodType.invalid"), // + DAILY(1, "savingsCompoundingInterestPeriodType.daily"), // + WEEKLY(2, "savingsCompoundingInterestPeriodType.weekly"), // + BIWEEKLY(3, "savingsCompoundingInterestPeriodType.biweekly"), // + MONTHLY(4, "savingsCompoundingInterestPeriodType.monthly"), // + QUATERLY(5, "savingsCompoundingInterestPeriodType.quarterly"), // + BI_ANNUAL(6, "savingsCompoundingInterestPeriodType.biannual"), // + ANNUAL(7, "savingsCompoundingInterestPeriodType.annual"), // + NO_COMPOUNDING_SIMPLE_INTEREST(8, "savingsCompoundingInterestPeriodType.nocompounding"); + + private final Integer value; + private final String code; + + private SavingsCompoundingInterestPeriodType(final Integer value, final String code) { + this.value = value; + this.code = code; + } + + public Integer getValue() { + return this.value; + } + + public String getCode() { + return code; + } + + public static SavingsCompoundingInterestPeriodType fromInt(final Integer type) { + SavingsCompoundingInterestPeriodType repaymentFrequencyType = SavingsCompoundingInterestPeriodType.INVALID; + if (type != null) { + switch (type) { + case 1: + repaymentFrequencyType = SavingsCompoundingInterestPeriodType.DAILY; + break; + case 2: + repaymentFrequencyType = SavingsCompoundingInterestPeriodType.WEEKLY; + break; + case 3: + repaymentFrequencyType = SavingsCompoundingInterestPeriodType.BIWEEKLY; + break; + case 4: + repaymentFrequencyType = SavingsCompoundingInterestPeriodType.MONTHLY; + break; + case 5: + repaymentFrequencyType = SavingsCompoundingInterestPeriodType.QUATERLY; + break; + case 6: + repaymentFrequencyType = SavingsCompoundingInterestPeriodType.BI_ANNUAL; + break; + case 7: + repaymentFrequencyType = SavingsCompoundingInterestPeriodType.ANNUAL; + break; + case 8: + repaymentFrequencyType = SavingsCompoundingInterestPeriodType.NO_COMPOUNDING_SIMPLE_INTEREST; + break; + } + } + return repaymentFrequencyType; + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsInterestCalculatorFactory.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsInterestCalculatorFactory.java index 20c7e600b..508e4a582 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsInterestCalculatorFactory.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsInterestCalculatorFactory.java @@ -4,18 +4,18 @@ import java.math.BigDecimal; public class SavingsInterestCalculatorFactory { - public SavingsInterestCalculator createFrom(final SavingsInterestCalculationType interestCalculationType, + public SavingsCompoundInterestCalculator createFrom(final SavingsInterestCalculationType interestCalculationType, final BigDecimal periodsInOneYearAsFraction, final BigDecimal annualInterestRateAsFraction) { - SavingsInterestCalculator savingsInterestCalculator = new SavingsInterestCalculatorForDailyBalance(periodsInOneYearAsFraction, + SavingsCompoundInterestCalculator savingsInterestCalculator = new SavingsCompoundInterestCalculatorForDailyBalance(periodsInOneYearAsFraction, annualInterestRateAsFraction); switch (interestCalculationType) { case AVERAGE_DAILY_BALANCE: - savingsInterestCalculator = new SavingsInterestCalculatorForAverageBalance(periodsInOneYearAsFraction, + savingsInterestCalculator = new SavingsCompoundInterestCalculatorForAverageBalance(periodsInOneYearAsFraction, annualInterestRateAsFraction); break; case DAILY_BALANCE: - savingsInterestCalculator = new SavingsInterestCalculatorForDailyBalance(periodsInOneYearAsFraction, + savingsInterestCalculator = new SavingsCompoundInterestCalculatorForDailyBalance(periodsInOneYearAsFraction, annualInterestRateAsFraction); break; case INVALID: diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsInterestPeriodType.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsInterestPeriodType.java deleted file mode 100644 index 9ab136fef..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsInterestPeriodType.java +++ /dev/null @@ -1,75 +0,0 @@ -/** - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - */ -package org.mifosplatform.portfolio.savings.domain; - -/** - *

- * The interest period is the span of time at the end of which savings in a - * client’s account earn interest. - *

- * - *

- * Interest periods may differ for different types of savings products. In all - * cases, savings accounts must have established and published interest periods. - *

- */ -public enum SavingsInterestPeriodType { - - INVALID(0, "savingsCalculationPeriodType.invalid"), // - DAILY(1, "savingsCalculationPeriodType.daily"), // - WEEKLY(2, "savingsCalculationPeriodType.weekly"), // - BIWEEKLY(3, "savingsCalculationPeriodType.biweekly"), // - MONTHLY(4, "savingsCalculationPeriodType.monthly"), // - QUATERLY(5, "savingsCalculationPeriodType.quarterly"), // - SEMIANNUAL(6, "savingsCalculationPeriodType.semiannual"), // - ANNUAL(7, "savingsCalculationPeriodType.annual"); - - private final Integer value; - private final String code; - - private SavingsInterestPeriodType(final Integer value, final String code) { - this.value = value; - this.code = code; - } - - public Integer getValue() { - return this.value; - } - - public String getCode() { - return code; - } - - public static SavingsInterestPeriodType fromInt(final Integer type) { - SavingsInterestPeriodType repaymentFrequencyType = SavingsInterestPeriodType.INVALID; - if (type != null) { - switch (type) { - case 1: - repaymentFrequencyType = SavingsInterestPeriodType.DAILY; - break; - case 2: - repaymentFrequencyType = SavingsInterestPeriodType.WEEKLY; - break; - case 3: - repaymentFrequencyType = SavingsInterestPeriodType.BIWEEKLY; - break; - case 4: - repaymentFrequencyType = SavingsInterestPeriodType.MONTHLY; - break; - case 5: - repaymentFrequencyType = SavingsInterestPeriodType.QUATERLY; - break; - case 6: - repaymentFrequencyType = SavingsInterestPeriodType.SEMIANNUAL; - break; - case 7: - repaymentFrequencyType = SavingsInterestPeriodType.ANNUAL; - break; - } - } - return repaymentFrequencyType; - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsProduct.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsProduct.java index 3c18282ae..a062061c8 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsProduct.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsProduct.java @@ -10,14 +10,13 @@ import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.descri import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.digitsAfterDecimalParamName; import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestCalculationDaysInYearTypeParamName; import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestCalculationTypeParamName; -import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestPeriodTypeParamName; -import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestRateParamName; -import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestRatePeriodFrequencyTypeParamName; +import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestCompoundingPeriodTypeParamName; import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.localeParamName; import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockinPeriodFrequencyParamName; import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockinPeriodFrequencyTypeParamName; import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.minRequiredOpeningBalanceParamName; import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.nameParamName; +import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.nominalAnnualInterestRateParamName; import java.math.BigDecimal; import java.util.LinkedHashMap; @@ -31,7 +30,6 @@ import javax.persistence.Table; import org.mifosplatform.infrastructure.core.api.JsonCommand; 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.savings.exception.InvalidSavingsProductSettingsException; import org.springframework.data.jpa.domain.AbstractPersistable; @@ -48,20 +46,17 @@ public class SavingsProduct extends AbstractPersistable { @Embedded private MonetaryCurrency currency; - @Column(name = "nominal_interest_rate_per_period", scale = 6, precision = 19, nullable = false) - private BigDecimal interestRate; - - @Column(name = "nominal_interest_rate_period_frequency_enum", nullable = false) - private Integer interestRatePeriodFrequencyType; + @Column(name = "nominal_annual_interest_rate", scale = 6, precision = 19, nullable = false) + private BigDecimal nominalAnnualInterestRate; /** * The interest period is the span of time at the end of which savings in a * client’s account earn interest. * - * A value from the {@link SavingsInterestPeriodType} enumeration. + * A value from the {@link SavingsCompoundingInterestPeriodType} enumeration. */ - @Column(name = "interest_period_enum", nullable = false) - private Integer interestPeriodType; + @Column(name = "interest_compounding_period_enum", nullable = false) + private Integer interestCompoundingPeriodType; /** * A value from the {@link SavingsInterestCalculationType} enumeration. @@ -86,15 +81,13 @@ public class SavingsProduct extends AbstractPersistable { private Integer lockinPeriodFrequencyType; public static SavingsProduct createNew(final String name, final String description, final MonetaryCurrency currency, - final BigDecimal interestRate, final SavingsPeriodFrequencyType interestRatePeriodFrequencyType, - final SavingsInterestPeriodType interestPeriodType, final SavingsInterestCalculationType interestCalculationType, + final BigDecimal interestRate, final SavingsCompoundingInterestPeriodType interestPeriodType, + final SavingsInterestCalculationType interestCalculationType, final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance, - final Integer lockinPeriodFrequency, - final PeriodFrequencyType lockinPeriodFrequencyType) { + final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType) { - return new SavingsProduct(name, description, currency, interestRate, interestRatePeriodFrequencyType, interestPeriodType, - interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, - lockinPeriodFrequencyType); + return new SavingsProduct(name, description, currency, interestRate, interestPeriodType, interestCalculationType, + interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType); } protected SavingsProduct() { @@ -103,18 +96,16 @@ public class SavingsProduct extends AbstractPersistable { } private SavingsProduct(final String name, final String description, final MonetaryCurrency currency, final BigDecimal interestRate, - final SavingsPeriodFrequencyType interestRatePeriodFrequencyType, final SavingsInterestPeriodType interestPeriodType, - final SavingsInterestCalculationType interestCalculationType, + final SavingsCompoundingInterestPeriodType interestPeriodType, final SavingsInterestCalculationType interestCalculationType, final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance, - final Integer lockinPeriodFrequency, final PeriodFrequencyType lockinPeriodFrequencyType) { + final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType) { this.name = name; this.description = description; this.currency = currency; - this.interestRate = interestRate; - this.interestRatePeriodFrequencyType = interestRatePeriodFrequencyType.getValue(); - this.interestPeriodType = interestPeriodType.getValue(); + this.nominalAnnualInterestRate = interestRate; + this.interestCompoundingPeriodType = interestPeriodType.getValue(); this.interestCalculationType = interestCalculationType.getValue(); this.interestCalculationDaysInYearType = interestCalculationDaysInYearType.getValue(); @@ -135,15 +126,7 @@ public class SavingsProduct extends AbstractPersistable { } public BigDecimal interestRate() { - return Money.of(this.currency, this.interestRate).getAmount(); - } - - public PeriodFrequencyType interestRatePeriodFrequencyType() { - PeriodFrequencyType type = null; - if (this.interestRatePeriodFrequencyType != null) { - type = PeriodFrequencyType.fromInt(this.interestRatePeriodFrequencyType); - } - return type; + return Money.of(this.currency, this.nominalAnnualInterestRate).getAmount(); } public BigDecimal minRequiredOpeningBalance() { @@ -154,10 +137,10 @@ public class SavingsProduct extends AbstractPersistable { return this.lockinPeriodFrequency; } - public PeriodFrequencyType lockinPeriodFrequencyType() { - PeriodFrequencyType type = null; + public SavingsPeriodFrequencyType lockinPeriodFrequencyType() { + SavingsPeriodFrequencyType type = null; if (this.lockinPeriodFrequencyType != null) { - type = PeriodFrequencyType.fromInt(this.lockinPeriodFrequencyType); + type = SavingsPeriodFrequencyType.fromInt(this.lockinPeriodFrequencyType); } return type; } @@ -197,23 +180,17 @@ public class SavingsProduct extends AbstractPersistable { this.currency = new MonetaryCurrency(currencyCode, this.currency.getDigitsAfterDecimal()); } - if (command.isChangeInBigDecimalParameterNamed(interestRateParamName, this.interestRate)) { - final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(interestRateParamName); - actualChanges.put(interestRateParamName, newValue); + if (command.isChangeInBigDecimalParameterNamed(nominalAnnualInterestRateParamName, this.nominalAnnualInterestRate)) { + final BigDecimal newValue = command.bigDecimalValueOfParameterNamed(nominalAnnualInterestRateParamName); + actualChanges.put(nominalAnnualInterestRateParamName, newValue); actualChanges.put(localeParamName, localeAsInput); - this.interestRate = newValue; + this.nominalAnnualInterestRate = newValue; } - if (command.isChangeInIntegerParameterNamed(interestRatePeriodFrequencyTypeParamName, this.interestRatePeriodFrequencyType)) { - final Integer newValue = command.integerValueOfParameterNamed(interestRatePeriodFrequencyTypeParamName); - actualChanges.put(interestRatePeriodFrequencyTypeParamName, newValue); - this.interestRatePeriodFrequencyType = SavingsPeriodFrequencyType.fromInt(newValue).getValue(); - } - - if (command.isChangeInIntegerParameterNamed(interestPeriodTypeParamName, this.interestPeriodType)) { - final Integer newValue = command.integerValueOfParameterNamed(interestPeriodTypeParamName); - actualChanges.put(interestPeriodTypeParamName, newValue); - this.interestPeriodType = SavingsInterestPeriodType.fromInt(newValue).getValue(); + if (command.isChangeInIntegerParameterNamed(interestCompoundingPeriodTypeParamName, this.interestCompoundingPeriodType)) { + final Integer newValue = command.integerValueOfParameterNamed(interestCompoundingPeriodTypeParamName); + actualChanges.put(interestCompoundingPeriodTypeParamName, newValue); + this.interestCompoundingPeriodType = SavingsCompoundingInterestPeriodType.fromInt(newValue).getValue(); } if (command.isChangeInIntegerParameterNamed(interestCalculationTypeParamName, this.interestCalculationType)) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsProductAssembler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsProductAssembler.java index 378f67aab..8b81189ad 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsProductAssembler.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsProductAssembler.java @@ -5,19 +5,17 @@ import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.descri import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.digitsAfterDecimalParamName; import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestCalculationDaysInYearTypeParamName; import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestCalculationTypeParamName; -import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestPeriodTypeParamName; -import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestRateParamName; -import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestRatePeriodFrequencyTypeParamName; +import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestCompoundingPeriodTypeParamName; import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockinPeriodFrequencyParamName; import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.lockinPeriodFrequencyTypeParamName; import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.minRequiredOpeningBalanceParamName; import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.nameParamName; +import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.nominalAnnualInterestRateParamName; import java.math.BigDecimal; import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.organisation.monetary.domain.MonetaryCurrency; -import org.mifosplatform.portfolio.loanproduct.domain.PeriodFrequencyType; import org.springframework.stereotype.Component; @Component @@ -32,17 +30,12 @@ public class SavingsProductAssembler { final Integer digitsAfterDecimal = command.integerValueOfParameterNamed(digitsAfterDecimalParamName); MonetaryCurrency currency = new MonetaryCurrency(currencyCode, digitsAfterDecimal); - final BigDecimal interestRate = command.bigDecimalValueOfParameterNamed(interestRateParamName); - SavingsPeriodFrequencyType interestRatePeriodFrequencyType = null; - final Integer interestRatePeriodFrequencyTypeValue = command.integerValueOfParameterNamed(interestRatePeriodFrequencyTypeParamName); - if (interestRatePeriodFrequencyTypeValue != null) { - interestRatePeriodFrequencyType = SavingsPeriodFrequencyType.fromInt(interestRatePeriodFrequencyTypeValue); - } + final BigDecimal interestRate = command.bigDecimalValueOfParameterNamed(nominalAnnualInterestRateParamName); - SavingsInterestPeriodType interestPeriodType = null; - final Integer interestPeriodTypeValue = command.integerValueOfParameterNamed(interestPeriodTypeParamName); + SavingsCompoundingInterestPeriodType interestPeriodType = null; + final Integer interestPeriodTypeValue = command.integerValueOfParameterNamed(interestCompoundingPeriodTypeParamName); if (interestPeriodTypeValue != null) { - interestPeriodType = SavingsInterestPeriodType.fromInt(interestPeriodTypeValue); + interestPeriodType = SavingsCompoundingInterestPeriodType.fromInt(interestPeriodTypeValue); } SavingsInterestCalculationType interestCalculationType = null; @@ -61,14 +54,13 @@ public class SavingsProductAssembler { final BigDecimal minRequiredOpeningBalance = command.bigDecimalValueOfParameterNamed(minRequiredOpeningBalanceParamName); final Integer lockinPeriodFrequency = command.integerValueOfParameterNamed(lockinPeriodFrequencyParamName); - PeriodFrequencyType lockinPeriodFrequencyType = null; + SavingsPeriodFrequencyType lockinPeriodFrequencyType = null; final Integer lockinPeriodFrequencyTypeValue = command.integerValueOfParameterNamed(lockinPeriodFrequencyTypeParamName); if (lockinPeriodFrequencyTypeValue != null) { - lockinPeriodFrequencyType = PeriodFrequencyType.fromInt(lockinPeriodFrequencyTypeValue); + lockinPeriodFrequencyType = SavingsPeriodFrequencyType.fromInt(lockinPeriodFrequencyTypeValue); } - return SavingsProduct.createNew(name, description, currency, interestRate, interestRatePeriodFrequencyType, interestPeriodType, - interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, - lockinPeriodFrequencyType); + return SavingsProduct.createNew(name, description, currency, interestRate, interestPeriodType, interestCalculationType, + interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java index 2e1588505..75e7754a2 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java @@ -27,9 +27,9 @@ import org.mifosplatform.portfolio.savings.data.SavingsAccountSummaryData; import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionData; import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionEnumData; import org.mifosplatform.portfolio.savings.data.SavingsProductData; +import org.mifosplatform.portfolio.savings.domain.SavingsCompoundingInterestPeriodType; import org.mifosplatform.portfolio.savings.domain.SavingsInterestCalculationDaysInYearType; import org.mifosplatform.portfolio.savings.domain.SavingsInterestCalculationType; -import org.mifosplatform.portfolio.savings.domain.SavingsInterestPeriodType; import org.mifosplatform.portfolio.savings.domain.SavingsPeriodFrequencyType; import org.mifosplatform.portfolio.savings.exception.SavingsAccountNotFoundException; import org.springframework.beans.factory.annotation.Autowired; @@ -103,10 +103,8 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead sqlBuilder.append("sa.currency_code as currencyCode, sa.currency_digits as currencyDigits, "); sqlBuilder.append("curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, "); sqlBuilder.append("curr.display_symbol as currencyDisplaySymbol, "); - sqlBuilder.append("sa.nominal_interest_rate_per_period as interestRate, "); - sqlBuilder.append("sa.nominal_interest_rate_period_frequency_enum as interestRatePeriodFrequencyType, "); - sqlBuilder.append("sa.annual_nominal_interest_rate as annualInterestRate, "); - sqlBuilder.append("sa.interest_period_enum as interestPeriodType, "); + sqlBuilder.append("sa.nominal_annual_interest_rate as nominalAnnualInterestRate, "); + sqlBuilder.append("sa.interest_compounding_period_enum as interestCompoundingPeriodType, "); sqlBuilder.append("sa.interest_calculation_type_enum as interestCalculationType, "); sqlBuilder.append("sa.interest_calculation_days_in_year_type_enum as interestCalculationDaysInYearType, "); sqlBuilder.append("sa.min_required_opening_balance as minRequiredOpeningBalance, "); @@ -158,20 +156,16 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead final CurrencyData currency = new CurrencyData(currencyCode, currencyName, currencyDigits, currencyDisplaySymbol, currencyNameCode); - final BigDecimal interestRate = rs.getBigDecimal("interestRate"); - final SavingsPeriodFrequencyType interestRatePeriodType = SavingsPeriodFrequencyType.fromInt(JdbcSupport.getInteger(rs, - "interestRatePeriodFrequencyType")); - final EnumOptionData interestRatePeriodFrequencyType = SavingsEnumerations - .interestRatePeriodFrequencyType(interestRatePeriodType); - final BigDecimal annualInterestRate = rs.getBigDecimal("annualInterestRate"); + final BigDecimal nominalAnnualInterestRate = rs.getBigDecimal("nominalAnnualInterestRate"); - EnumOptionData interestPeriodType = SavingsEnumerations.interestPeriodType(SavingsInterestPeriodType.fromInt(JdbcSupport - .getInteger(rs, "interestPeriodType"))); + final EnumOptionData interestCompoundingPeriodType = SavingsEnumerations + .compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.fromInt(JdbcSupport.getInteger(rs, + "interestCompoundingPeriodType"))); - EnumOptionData interestCalculationType = SavingsEnumerations.interestCalculationType(SavingsInterestCalculationType + final EnumOptionData interestCalculationType = SavingsEnumerations.interestCalculationType(SavingsInterestCalculationType .fromInt(JdbcSupport.getInteger(rs, "interestCalculationType"))); - EnumOptionData interestCalculationDaysInYearType = SavingsEnumerations + final EnumOptionData interestCalculationDaysInYearType = SavingsEnumerations .interestCalculationDaysInYearType(SavingsInterestCalculationDaysInYearType.fromInt(JdbcSupport.getInteger(rs, "interestCalculationDaysInYearType"))); @@ -194,10 +188,11 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead final SavingsAccountSummaryData summary = new SavingsAccountSummaryData(currency, totalDeposits, totalWithdrawals, totalInterestEarned, totalInterestPosted, accountBalance); - return SavingsAccountData.instance(id, accountNo, externalId, status, activationDate, groupId, groupName, clientId, clientName, - productId, productName, currency, interestRate, interestRatePeriodFrequencyType, annualInterestRate, - interestPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, - lockinPeriodFrequency, lockinPeriodFrequencyType, summary); + return SavingsAccountData + .instance(id, accountNo, externalId, status, activationDate, groupId, groupName, clientId, clientName, productId, + productName, currency, nominalAnnualInterestRate, interestCompoundingPeriodType, interestCalculationType, + interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, + summary); } } @@ -225,11 +220,8 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead final String sql = "select " + mapper.schema() + " where sp.id = ?"; template = this.jdbcTemplate.queryForObject(sql, mapper, new Object[] { productId }); - final Collection interestRatePeriodFrequencyTypeOptions = this.dropdownReadPlatformService - .retrieveInterestRatePeriodFrequencyTypeOptions(); - - final Collection interestPeriodTypeOptions = this.dropdownReadPlatformService - .retrieveInterestPeriodTypeOptions(); + final Collection interestCompoundingPeriodTypeOptions = this.dropdownReadPlatformService + .retrieveCompoundingInterestPeriodTypeOptions(); final Collection interestCalculationTypeOptions = this.dropdownReadPlatformService .retrieveInterestCalculationTypeOptions(); @@ -241,9 +233,9 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead .retrieveLockinPeriodFrequencyTypeOptions(); final Collection transactions = null; - template = SavingsAccountData.withTemplateOptions(template, productOptions, interestRatePeriodFrequencyTypeOptions, - interestPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, - lockinPeriodFrequencyTypeOptions, transactions); + template = SavingsAccountData.withTemplateOptions(template, productOptions, interestCompoundingPeriodTypeOptions, + interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, + transactions); } else { String clientName = null; @@ -258,16 +250,15 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead template = SavingsAccountData.withClientTemplate(clientId, clientName, groupId, groupName); - final Collection interestRatePeriodFrequencyTypeOptions = null; - final Collection interestPeriodTypeOptions = null; + final Collection interestCompoundingPeriodTypeOptions = null; final Collection interestCalculationTypeOptions = null; final Collection interestCalculationDaysInYearTypeOptions = null; final Collection lockinPeriodFrequencyTypeOptions = null; final Collection transactions = null; - template = SavingsAccountData.withTemplateOptions(template, productOptions, interestRatePeriodFrequencyTypeOptions, - interestPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, - lockinPeriodFrequencyTypeOptions, transactions); + template = SavingsAccountData.withTemplateOptions(template, productOptions, interestCompoundingPeriodTypeOptions, + interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, + transactions); } return template; @@ -398,9 +389,8 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead sqlBuilder.append("sp.currency_code as currencyCode, sp.currency_digits as currencyDigits, "); sqlBuilder.append("curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, "); sqlBuilder.append("curr.display_symbol as currencyDisplaySymbol, "); - sqlBuilder.append("sp.nominal_interest_rate_per_period as interestRate, "); - sqlBuilder.append("sp.nominal_interest_rate_period_frequency_enum as interestRatePeriodFrequencyType, "); - sqlBuilder.append("sp.interest_period_enum as interestPeriodType, "); + sqlBuilder.append("sp.nominal_annual_interest_rate as nominalAnnualIterestRate, "); + sqlBuilder.append("sp.interest_compounding_period_enum as interestCompoundingPeriodType, "); sqlBuilder.append("sp.interest_calculation_type_enum as interestCalculationType, "); sqlBuilder.append("sp.interest_calculation_days_in_year_type_enum as interestCalculationDaysInYearType, "); sqlBuilder.append("sp.min_required_opening_balance as minRequiredOpeningBalance, "); @@ -430,15 +420,10 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead final CurrencyData currency = new CurrencyData(currencyCode, currencyName, currencyDigits, currencyDisplaySymbol, currencyNameCode); - final BigDecimal interestRate = rs.getBigDecimal("interestRate"); - final SavingsPeriodFrequencyType interestRatePeriodType = SavingsPeriodFrequencyType.fromInt(JdbcSupport.getInteger(rs, - "interestRatePeriodFrequencyType")); - final EnumOptionData interestRatePeriodFrequencyType = SavingsEnumerations - .interestRatePeriodFrequencyType(interestRatePeriodType); - final BigDecimal annualInterestRate = null; + final BigDecimal nominalAnnualIterestRate = rs.getBigDecimal("nominalAnnualIterestRate"); - EnumOptionData interestPeriodType = SavingsEnumerations.interestPeriodType(SavingsInterestPeriodType.fromInt(JdbcSupport - .getInteger(rs, "interestPeriodType"))); + EnumOptionData interestPeriodType = SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType + .fromInt(JdbcSupport.getInteger(rs, "interestCompoundingPeriodType"))); EnumOptionData interestCalculationType = SavingsEnumerations.interestCalculationType(SavingsInterestCalculationType .fromInt(JdbcSupport.getInteger(rs, "interestCalculationType"))); @@ -474,10 +459,11 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead final SavingsAccountStatusEnumData status = null; final LocalDate activationDate = null; final SavingsAccountSummaryData summary = null; - return SavingsAccountData.instance(null, null, null, status, activationDate, groupId, groupName, clientId, clientName, - productId, productName, currency, interestRate, interestRatePeriodFrequencyType, annualInterestRate, - interestPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, - lockinPeriodFrequency, lockinPeriodFrequencyType, summary); + return SavingsAccountData + .instance(null, null, null, status, activationDate, groupId, groupName, clientId, clientName, productId, productName, + currency, nominalAnnualIterestRate, interestPeriodType, interestCalculationType, + interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, + summary); } } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java index 09402160f..5e3683ee6 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountWritePlatformServiceJpaRepositoryImpl.java @@ -17,6 +17,7 @@ import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder; import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException; +import org.mifosplatform.infrastructure.core.service.DateUtils; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.portfolio.client.domain.AccountNumberGenerator; import org.mifosplatform.portfolio.client.domain.AccountNumberGeneratorFactory; @@ -321,7 +322,8 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi final SavingsAccount account = this.savingAccountRepository.findOneWithNotFoundDetection(savingsId); - account.calculateInterest(); + final LocalDate today = DateUtils.getLocalDateOfTenant(); + account.calculateInterest(today); this.savingAccountRepository.save(account); return new CommandProcessingResultBuilder() // diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsDropdownReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsDropdownReadPlatformService.java index 08afbf43b..51ee36e00 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsDropdownReadPlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsDropdownReadPlatformService.java @@ -6,11 +6,9 @@ import org.mifosplatform.infrastructure.core.data.EnumOptionData; public interface SavingsDropdownReadPlatformService { - Collection retrieveInterestRatePeriodFrequencyTypeOptions(); - Collection retrieveLockinPeriodFrequencyTypeOptions(); - Collection retrieveInterestPeriodTypeOptions(); + Collection retrieveCompoundingInterestPeriodTypeOptions(); Collection retrieveInterestCalculationTypeOptions(); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsDropdownReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsDropdownReadPlatformServiceImpl.java index abc9e19c3..d21eb83cb 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsDropdownReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsDropdownReadPlatformServiceImpl.java @@ -5,25 +5,15 @@ import java.util.Collection; import java.util.List; import org.mifosplatform.infrastructure.core.data.EnumOptionData; +import org.mifosplatform.portfolio.savings.domain.SavingsCompoundingInterestPeriodType; import org.mifosplatform.portfolio.savings.domain.SavingsInterestCalculationDaysInYearType; import org.mifosplatform.portfolio.savings.domain.SavingsInterestCalculationType; -import org.mifosplatform.portfolio.savings.domain.SavingsInterestPeriodType; import org.mifosplatform.portfolio.savings.domain.SavingsPeriodFrequencyType; import org.springframework.stereotype.Service; @Service public class SavingsDropdownReadPlatformServiceImpl implements SavingsDropdownReadPlatformService { - @Override - public List retrieveInterestRatePeriodFrequencyTypeOptions() { - List allowedInterestRatePeriodFrequencyTypeOptions = Arrays.asList( // - SavingsEnumerations.interestRatePeriodFrequencyType(SavingsPeriodFrequencyType.MONTHS), // - SavingsEnumerations.interestRatePeriodFrequencyType(SavingsPeriodFrequencyType.YEARS) // - ); - - return allowedInterestRatePeriodFrequencyTypeOptions; - } - @Override public List retrieveLockinPeriodFrequencyTypeOptions() { List allowedLockinPeriodFrequencyTypeOptions = Arrays.asList( // @@ -37,15 +27,16 @@ public class SavingsDropdownReadPlatformServiceImpl implements SavingsDropdownRe } @Override - public Collection retrieveInterestPeriodTypeOptions() { + public Collection retrieveCompoundingInterestPeriodTypeOptions() { List allowedOptions = Arrays.asList( // - SavingsEnumerations.interestPeriodType(SavingsInterestPeriodType.DAILY), // - SavingsEnumerations.interestPeriodType(SavingsInterestPeriodType.WEEKLY), // - SavingsEnumerations.interestPeriodType(SavingsInterestPeriodType.BIWEEKLY), // - SavingsEnumerations.interestPeriodType(SavingsInterestPeriodType.MONTHLY), // - SavingsEnumerations.interestPeriodType(SavingsInterestPeriodType.QUATERLY), // - SavingsEnumerations.interestPeriodType(SavingsInterestPeriodType.SEMIANNUAL), // - SavingsEnumerations.interestPeriodType(SavingsInterestPeriodType.ANNUAL) // + SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.DAILY), // + SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.WEEKLY), // + SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.BIWEEKLY), // + SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.MONTHLY), // + SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.QUATERLY), // + SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.BI_ANNUAL), // + SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.ANNUAL), // + SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.NO_COMPOUNDING_SIMPLE_INTEREST) // ); return allowedOptions; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsEnumerations.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsEnumerations.java index 545107e23..10055fae0 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsEnumerations.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsEnumerations.java @@ -10,44 +10,13 @@ import org.mifosplatform.portfolio.savings.data.SavingsAccountStatusEnumData; import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionEnumData; import org.mifosplatform.portfolio.savings.domain.SavingsAccountStatusType; import org.mifosplatform.portfolio.savings.domain.SavingsAccountTransactionType; +import org.mifosplatform.portfolio.savings.domain.SavingsCompoundingInterestPeriodType; import org.mifosplatform.portfolio.savings.domain.SavingsInterestCalculationDaysInYearType; import org.mifosplatform.portfolio.savings.domain.SavingsInterestCalculationType; -import org.mifosplatform.portfolio.savings.domain.SavingsInterestPeriodType; import org.mifosplatform.portfolio.savings.domain.SavingsPeriodFrequencyType; public class SavingsEnumerations { - public static EnumOptionData interestRatePeriodFrequencyType(final int id) { - return interestRatePeriodFrequencyType(SavingsPeriodFrequencyType.fromInt(id)); - } - - public static EnumOptionData interestRatePeriodFrequencyType(final SavingsPeriodFrequencyType type) { - final String codePrefix = "savings.interest.rate."; - EnumOptionData optionData = new EnumOptionData(SavingsPeriodFrequencyType.INVALID.getValue().longValue(), - SavingsPeriodFrequencyType.INVALID.getCode(), "Invalid"); - switch (type) { - case INVALID: - break; - case DAYS: - optionData = new EnumOptionData(SavingsPeriodFrequencyType.DAYS.getValue().longValue(), codePrefix - + SavingsPeriodFrequencyType.DAYS.getCode(), "Per day"); - break; - case WEEKS: - optionData = new EnumOptionData(SavingsPeriodFrequencyType.WEEKS.getValue().longValue(), codePrefix - + SavingsPeriodFrequencyType.WEEKS.getCode(), "Per week"); - break; - case MONTHS: - optionData = new EnumOptionData(SavingsPeriodFrequencyType.MONTHS.getValue().longValue(), codePrefix - + SavingsPeriodFrequencyType.MONTHS.getCode(), "Per month"); - break; - case YEARS: - optionData = new EnumOptionData(SavingsPeriodFrequencyType.YEARS.getValue().longValue(), codePrefix - + SavingsPeriodFrequencyType.YEARS.getCode(), "Per year"); - break; - } - return optionData; - } - public static EnumOptionData lockinPeriodFrequencyType(final int id) { return lockinPeriodFrequencyType(SavingsPeriodFrequencyType.fromInt(id)); } @@ -141,45 +110,50 @@ public class SavingsEnumerations { } public static EnumOptionData interestPeriodType(final Integer type) { - return interestPeriodType(SavingsInterestPeriodType.fromInt(type)); + return compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.fromInt(type)); } - public static EnumOptionData interestPeriodType(final SavingsInterestPeriodType type) { + public static EnumOptionData compoundingInterestPeriodType(final SavingsCompoundingInterestPeriodType type) { final String codePrefix = "savings.interest.period."; - EnumOptionData optionData = new EnumOptionData(SavingsInterestPeriodType.INVALID.getValue().longValue(), - SavingsInterestPeriodType.INVALID.getCode(), "Invalid"); + EnumOptionData optionData = new EnumOptionData(SavingsCompoundingInterestPeriodType.INVALID.getValue().longValue(), + SavingsCompoundingInterestPeriodType.INVALID.getCode(), "Invalid"); switch (type) { case INVALID: break; case DAILY: - optionData = new EnumOptionData(SavingsInterestPeriodType.DAILY.getValue().longValue(), codePrefix - + SavingsInterestPeriodType.DAILY.getCode(), "Daily"); + optionData = new EnumOptionData(SavingsCompoundingInterestPeriodType.DAILY.getValue().longValue(), codePrefix + + SavingsCompoundingInterestPeriodType.DAILY.getCode(), "Daily"); break; case WEEKLY: - optionData = new EnumOptionData(SavingsInterestPeriodType.WEEKLY.getValue().longValue(), codePrefix - + SavingsInterestPeriodType.WEEKLY.getCode(), "Weekly"); + optionData = new EnumOptionData(SavingsCompoundingInterestPeriodType.WEEKLY.getValue().longValue(), codePrefix + + SavingsCompoundingInterestPeriodType.WEEKLY.getCode(), "Weekly"); break; case BIWEEKLY: - optionData = new EnumOptionData(SavingsInterestPeriodType.BIWEEKLY.getValue().longValue(), codePrefix - + SavingsInterestPeriodType.BIWEEKLY.getCode(), "Bi-Weekly"); + optionData = new EnumOptionData(SavingsCompoundingInterestPeriodType.BIWEEKLY.getValue().longValue(), codePrefix + + SavingsCompoundingInterestPeriodType.BIWEEKLY.getCode(), "Bi-Weekly"); break; case MONTHLY: - optionData = new EnumOptionData(SavingsInterestPeriodType.MONTHLY.getValue().longValue(), codePrefix - + SavingsInterestPeriodType.MONTHLY.getCode(), "Monthly"); + optionData = new EnumOptionData(SavingsCompoundingInterestPeriodType.MONTHLY.getValue().longValue(), codePrefix + + SavingsCompoundingInterestPeriodType.MONTHLY.getCode(), "Monthly"); break; case QUATERLY: - optionData = new EnumOptionData(SavingsInterestPeriodType.QUATERLY.getValue().longValue(), codePrefix - + SavingsInterestPeriodType.QUATERLY.getCode(), "Quarterly"); + optionData = new EnumOptionData(SavingsCompoundingInterestPeriodType.QUATERLY.getValue().longValue(), codePrefix + + SavingsCompoundingInterestPeriodType.QUATERLY.getCode(), "Quarterly"); break; - case SEMIANNUAL: - optionData = new EnumOptionData(SavingsInterestPeriodType.SEMIANNUAL.getValue().longValue(), codePrefix - + SavingsInterestPeriodType.SEMIANNUAL.getCode(), "Semi-Annual"); + case BI_ANNUAL: + optionData = new EnumOptionData(SavingsCompoundingInterestPeriodType.BI_ANNUAL.getValue().longValue(), codePrefix + + SavingsCompoundingInterestPeriodType.BI_ANNUAL.getCode(), "Semi-Annual"); break; case ANNUAL: - optionData = new EnumOptionData(SavingsInterestPeriodType.ANNUAL.getValue().longValue(), codePrefix - + SavingsInterestPeriodType.ANNUAL.getCode(), "Annually"); + optionData = new EnumOptionData(SavingsCompoundingInterestPeriodType.ANNUAL.getValue().longValue(), codePrefix + + SavingsCompoundingInterestPeriodType.ANNUAL.getCode(), "Annually"); + break; + case NO_COMPOUNDING_SIMPLE_INTEREST: + optionData = new EnumOptionData(SavingsCompoundingInterestPeriodType.NO_COMPOUNDING_SIMPLE_INTEREST.getValue().longValue(), + codePrefix + SavingsCompoundingInterestPeriodType.NO_COMPOUNDING_SIMPLE_INTEREST.getCode(), + "No Compounding - Simple Interest"); break; } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsProductReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsProductReadPlatformServiceImpl.java index e9861bfb7..ee965cff3 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsProductReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsProductReadPlatformServiceImpl.java @@ -16,9 +16,9 @@ import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSourc import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.organisation.monetary.data.CurrencyData; import org.mifosplatform.portfolio.savings.data.SavingsProductData; +import org.mifosplatform.portfolio.savings.domain.SavingsCompoundingInterestPeriodType; import org.mifosplatform.portfolio.savings.domain.SavingsInterestCalculationDaysInYearType; import org.mifosplatform.portfolio.savings.domain.SavingsInterestCalculationType; -import org.mifosplatform.portfolio.savings.domain.SavingsInterestPeriodType; import org.mifosplatform.portfolio.savings.domain.SavingsPeriodFrequencyType; import org.mifosplatform.portfolio.savings.exception.SavingsProductNotFoundException; import org.springframework.beans.factory.annotation.Autowired; @@ -80,9 +80,8 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead sqlBuilder.append("sp.currency_code as currencyCode, sp.currency_digits as currencyDigits, "); sqlBuilder.append("curr.name as currencyName, curr.internationalized_name_code as currencyNameCode, "); sqlBuilder.append("curr.display_symbol as currencyDisplaySymbol, "); - sqlBuilder.append("sp.nominal_interest_rate_per_period as interestRate, "); - sqlBuilder.append("sp.nominal_interest_rate_period_frequency_enum as interestRatePeriodFrequencyType, "); - sqlBuilder.append("sp.interest_period_enum as interestPeriodType, "); + sqlBuilder.append("sp.nominal_annual_interest_rate as nominalAnnualInterestRate, "); + sqlBuilder.append("sp.interest_compounding_period_enum as compoundingInterestPeriodType, "); sqlBuilder.append("sp.interest_calculation_type_enum as interestCalculationType, "); sqlBuilder.append("sp.interest_calculation_days_in_year_type_enum as interestCalculationDaysInYearType, "); sqlBuilder.append("sp.min_required_opening_balance as minRequiredOpeningBalance, "); @@ -113,13 +112,11 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead final CurrencyData currency = new CurrencyData(currencyCode, currencyName, currencyDigits, currencyDisplaySymbol, currencyNameCode); - BigDecimal interestRate = rs.getBigDecimal("interestRate"); + final BigDecimal nominalAnnualInterestRate = rs.getBigDecimal("nominalAnnualInterestRate"); - EnumOptionData interestRatePeriodFrequencyType = SavingsEnumerations.interestRatePeriodFrequencyType(SavingsPeriodFrequencyType - .fromInt(JdbcSupport.getInteger(rs, "interestRatePeriodFrequencyType"))); - - EnumOptionData interestPeriodType = SavingsEnumerations.interestPeriodType(SavingsInterestPeriodType.fromInt(JdbcSupport - .getInteger(rs, "interestPeriodType"))); + EnumOptionData compoundingInterestPeriodType = SavingsEnumerations + .compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.fromInt(JdbcSupport.getInteger(rs, + "compoundingInterestPeriodType"))); EnumOptionData interestCalculationType = SavingsEnumerations.interestCalculationType(SavingsInterestCalculationType .fromInt(JdbcSupport.getInteger(rs, "interestCalculationType"))); @@ -142,9 +139,9 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead .fromInt(lockinPeriodFrequencyTypeValue)); } - return SavingsProductData.instance(id, name, description, currency, interestRate, interestRatePeriodFrequencyType, - interestPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, - lockinPeriodFrequency, lockinPeriodFrequencyType); + return SavingsProductData.instance(id, name, description, currency, nominalAnnualInterestRate, compoundingInterestPeriodType, + interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, + lockinPeriodFrequencyType); } }