From 14aa62073e4b1a69fb6255c713ce1396da7e7e58 Mon Sep 17 00:00:00 2001 From: Keith Woodlock Date: Sat, 6 Apr 2013 11:41:14 +0100 Subject: [PATCH] MIFOSX-250: wip on interest compounding and posting --- ...0__interest-posting-fields-for-savings.sql | 12 ++ .../commands/domain/CommandWrapper.java | 4 + .../service/CommandWrapperBuilder.java | 11 +- .../SynchronousCommandProcessingService.java | 2 + .../core/data/DataValidatorBuilder.java | 2 +- .../UnrecognizedQueryParamException.java | 8 +- ...UnrecognizedQueryParamExceptionMapper.java | 25 ++-- .../api/SavingsAccountsApiResource.java | 13 +- .../savings/api/SavingsApiConstants.java | 27 ++-- .../api/SavingsProductsApiResource.java | 23 +++- .../savings/data/SavingsAccountData.java | 55 +++++--- .../data/SavingsAccountDataValidator.java | 51 ++++++-- .../savings/data/SavingsProductData.java | 67 ++++++---- .../data/SavingsProductDataValidator.java | 19 ++- .../savings/domain/SavingsAccount.java | 120 ++++++++++++++++-- .../domain/SavingsAccountAssembler.java | 25 +++- .../SavingsInterestPostingPeriodType.java | 56 ++++++++ .../savings/domain/SavingsProduct.java | 55 ++++++-- .../domain/SavingsProductAssembler.java | 14 +- ...tInterestSavingsAccountCommandHandler.java | 26 ++++ ...SavingsAccountReadPlatformServiceImpl.java | 41 +++--- .../SavingsAccountWritePlatformService.java | 2 + ...WritePlatformServiceJpaRepositoryImpl.java | 19 +++ .../SavingsDropdownReadPlatformService.java | 2 + ...avingsDropdownReadPlatformServiceImpl.java | 13 ++ .../savings/service/SavingsEnumerations.java | 35 +++++ ...SavingsProductReadPlatformServiceImpl.java | 10 +- 27 files changed, 590 insertions(+), 147 deletions(-) create mode 100644 mifosng-db/migrations/core_db/V10__interest-posting-fields-for-savings.sql create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsInterestPostingPeriodType.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/handler/PostInterestSavingsAccountCommandHandler.java diff --git a/mifosng-db/migrations/core_db/V10__interest-posting-fields-for-savings.sql b/mifosng-db/migrations/core_db/V10__interest-posting-fields-for-savings.sql new file mode 100644 index 000000000..b1a04c6bf --- /dev/null +++ b/mifosng-db/migrations/core_db/V10__interest-posting-fields-for-savings.sql @@ -0,0 +1,12 @@ +INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) +VALUES +('transaction_savings', 'POSTINTEREST_SAVINGSACCOUNT', 'SAVINGSACCOUNT', 'POSTINTEREST', '1'), +('transaction_savings', 'POSTINTEREST_SAVINGSACCOUNT_CHECKER', 'SAVINGSACCOUNT', 'POSTINTEREST', '0'); + + +ALTER TABLE `m_savings_product` +ADD COLUMN `interest_posting_period_enum` SMALLINT(5) NOT NULL DEFAULT 4 AFTER `interest_compounding_period_enum`; + + +ALTER TABLE `m_savings_account` +ADD COLUMN `interest_posting_period_enum` SMALLINT(5) NOT NULL DEFAULT 4 AFTER `interest_compounding_period_enum`; \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java index b03c6451b..0b2e4bdd6 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java @@ -450,6 +450,10 @@ public class CommandWrapper { return this.actionName.equalsIgnoreCase("CALCULATEINTEREST") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT"); } + public boolean isSavingsAccountInterestPosting() { + return this.actionName.equalsIgnoreCase("POSTINTEREST") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT"); + } + public boolean isCalendarResource() { return this.entityName.equalsIgnoreCase("CALENDAR"); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java index cf2b81ad2..3aaeeee4e 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java @@ -717,11 +717,20 @@ public class CommandWrapperBuilder { this.actionName = "CALCULATEINTEREST"; this.entityName = "SAVINGSACCOUNT"; this.savingsId = accountId; - this.entityId = null; + this.entityId = accountId; this.href = "/savingsaccounts/" + accountId + "?command=calculateInterest"; return this; } + public CommandWrapperBuilder savingsAccountInterestPosting(final Long accountId) { + this.actionName = "POSTINTEREST"; + this.entityName = "SAVINGSACCOUNT"; + this.savingsId = accountId; + this.entityId = accountId; + this.href = "/savingsaccounts/" + accountId + "?command=postInterest"; + return this; + } + public CommandWrapperBuilder createCalendar(final String supportedEntityType, final Long supportedEntityId) { this.actionName = "CREATE"; this.entityName = "CALENDAR"; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java index d0b4236e6..0898782aa 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java @@ -370,6 +370,8 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer handler = applicationContext.getBean("activateSavingsAccountCommandHandler", NewCommandSourceHandler.class); } else if (wrapper.isSavingsAccountInterestCalculation()) { handler = applicationContext.getBean("calculateInterestSavingsAccountCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isSavingsAccountInterestPosting()) { + handler = applicationContext.getBean("postInterestSavingsAccountCommandHandler", NewCommandSourceHandler.class); } else { throw new UnsupportedCommandException(wrapper.commandName()); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/data/DataValidatorBuilder.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/data/DataValidatorBuilder.java index a0e3cec0f..04db8a832 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/data/DataValidatorBuilder.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/data/DataValidatorBuilder.java @@ -192,7 +192,7 @@ public class DataValidatorBuilder { return this; } - public DataValidatorBuilder inOfTheseValues(final Object... values) { + public DataValidatorBuilder isOneOfTheseValues(final Object... values) { if (value == null && ignoreNullValue) { return this; } if (value != null) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/exception/UnrecognizedQueryParamException.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/exception/UnrecognizedQueryParamException.java index c2e05b549..56122c3c2 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/exception/UnrecognizedQueryParamException.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/exception/UnrecognizedQueryParamException.java @@ -9,10 +9,12 @@ public class UnrecognizedQueryParamException extends RuntimeException { private final String queryParamKey; private final String queryParamValue; + private final Object[] supportedParams; - public UnrecognizedQueryParamException(final String queryParamKey, final String queryParamValue) { + public UnrecognizedQueryParamException(final String queryParamKey, final String queryParamValue, final Object... supportedParams) { this.queryParamKey = queryParamKey; this.queryParamValue = queryParamValue; + this.supportedParams = supportedParams; } public String getQueryParamKey() { @@ -22,4 +24,8 @@ public class UnrecognizedQueryParamException extends RuntimeException { public String getQueryParamValue() { return queryParamValue; } + + public Object[] getSupportedParams() { + return this.supportedParams; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/exceptionmapper/UnrecognizedQueryParamExceptionMapper.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/exceptionmapper/UnrecognizedQueryParamExceptionMapper.java index ef99c7228..b94c7824a 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/exceptionmapper/UnrecognizedQueryParamExceptionMapper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/exceptionmapper/UnrecognizedQueryParamExceptionMapper.java @@ -33,22 +33,25 @@ import org.springframework.stereotype.Component; public class UnrecognizedQueryParamExceptionMapper implements ExceptionMapper { @Override - public Response toResponse(UnrecognizedQueryParamException exception) { + public Response toResponse(final UnrecognizedQueryParamException exception) { - String parameterName = exception.getQueryParamKey(); - String parameterValue = exception.getQueryParamValue(); + final String parameterName = exception.getQueryParamKey(); + final String parameterValue = exception.getQueryParamValue(); - StringBuilder validationErrorCode = new StringBuilder("error.msg.query.parameter.value.unsupported"); - StringBuilder defaultEnglishMessage = new StringBuilder("The query parameter ").append(parameterName) - .append(" has an unsupported value of: ").append(parameterValue); - ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(), defaultEnglishMessage.toString(), - parameterName, parameterName, parameterValue); + final StringBuilder validationErrorCode = new StringBuilder("error.msg.query.parameter.value.unsupported"); + final StringBuilder defaultEnglishMessage = new StringBuilder("The query parameter ") // + .append(parameterName) // + .append(" has an unsupported value of: ") // + .append(parameterValue); - List errors = new ArrayList(); + final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(), defaultEnglishMessage.toString(), + parameterName, parameterName, parameterValue, exception.getSupportedParams()); + + final List errors = new ArrayList(); errors.add(error); - ApiGlobalErrorResponse invalidParameterError = ApiGlobalErrorResponse.badClientRequest("validation.msg.validation.errors.exist", - "Validation errors exist.", errors); + final ApiGlobalErrorResponse invalidParameterError = ApiGlobalErrorResponse.badClientRequest( + "validation.msg.validation.errors.exist", "Validation errors exist.", errors); return Response.status(Status.BAD_REQUEST).entity(invalidParameterError).type(MediaType.APPLICATION_JSON).build(); } 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 6ed13ffdf..b532b9940 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 @@ -141,6 +141,7 @@ public class SavingsAccountsApiResource { Collection transactions = null; Collection productOptions = null; Collection interestCompoundingPeriodTypeOptions = null; + Collection interestCompoundingPostingTypeOptions = null; Collection interestCalculationTypeOptions = null; Collection interestCalculationDaysInYearTypeOptions = null; Collection lockinPeriodFrequencyTypeOptions = null; @@ -166,12 +167,14 @@ public class SavingsAccountsApiResource { if (settings.isTemplate()) { productOptions = this.savingsProductReadPlatformService.retrieveAllForLookup(); interestCompoundingPeriodTypeOptions = this.dropdownReadPlatformService.retrieveCompoundingInterestPeriodTypeOptions(); + interestCompoundingPostingTypeOptions = this.dropdownReadPlatformService.retrieveInterestPostingPeriodTypeOptions(); interestCalculationTypeOptions = this.dropdownReadPlatformService.retrieveInterestCalculationTypeOptions(); lockinPeriodFrequencyTypeOptions = this.dropdownReadPlatformService.retrieveLockinPeriodFrequencyTypeOptions(); } return SavingsAccountData.withTemplateOptions(savingsAccount, productOptions, interestCompoundingPeriodTypeOptions, - interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, transactions); + interestCompoundingPostingTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, + lockinPeriodFrequencyTypeOptions, transactions); } @PUT @@ -204,11 +207,15 @@ public class SavingsAccountsApiResource { } else if (is(commandParam, "calculateInterest")) { final CommandWrapper commandRequest = builder.savingsAccountInterestCalculation(accountId).build(); result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); + } else if (is(commandParam, "postInterest")) { + final CommandWrapper commandRequest = builder.savingsAccountInterestPosting(accountId).build(); + result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); } if (result == null) { - // FIXME - KW - handle blank command param use case - throw new UnrecognizedQueryParamException("command", commandParam); + // + throw new UnrecognizedQueryParamException("command", commandParam, new Object[] { "activate", "calculateInterest", + "postInterest" }); } return this.toApiJsonSerializer.serialize(result); 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 35ac6ef28..8ab1b5c15 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 @@ -32,8 +32,8 @@ public class SavingsApiConstants { public static final String currencyCodeParamName = "currencyCode"; public static final String digitsAfterDecimalParamName = "digitsAfterDecimal"; public static final String nominalAnnualInterestRateParamName = "nominalAnnualInterestRate"; - public static final String interestCompoundingPeriodTypeParamName = "interestCompoundingPeriodType"; + public static final String interestPostingPeriodTypeParamName = "interestPostingPeriodType"; public static final String interestCalculationTypeParamName = "interestCalculationType"; public static final String interestCalculationDaysInYearTypeParamName = "interestCalculationDaysInYearType"; public static final String minRequiredOpeningBalanceParamName = "minRequiredOpeningBalance"; @@ -46,8 +46,9 @@ public class SavingsApiConstants { public static final Set SAVINGS_PRODUCT_REQUEST_DATA_PARAMETERS = new HashSet(Arrays.asList(localeParamName, nameParamName, descriptionParamName, currencyCodeParamName, digitsAfterDecimalParamName, nominalAnnualInterestRateParamName, - interestCompoundingPeriodTypeParamName, interestCalculationTypeParamName, interestCalculationDaysInYearTypeParamName, - minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName)); + interestCompoundingPeriodTypeParamName, interestPostingPeriodTypeParamName, interestCalculationTypeParamName, + interestCalculationDaysInYearTypeParamName, minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName, + lockinPeriodFrequencyTypeParamName)); /** * These parameters will match the class level parameters of @@ -56,15 +57,17 @@ public class SavingsApiConstants { */ public static final Set SAVINGS_PRODUCT_RESPONSE_DATA_PARAMETERS = new HashSet(Arrays.asList(idParamName, nameParamName, descriptionParamName, "currency", digitsAfterDecimalParamName, nominalAnnualInterestRateParamName, - interestCompoundingPeriodTypeParamName, interestCalculationTypeParamName, interestCalculationDaysInYearTypeParamName, - minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName, "currencyOptions", - "interestRatePeriodFrequencyTypeOptions", "lockinPeriodFrequencyTypeOptions")); + interestCompoundingPeriodTypeParamName, interestPostingPeriodTypeParamName, interestCalculationTypeParamName, + interestCalculationDaysInYearTypeParamName, minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName, + lockinPeriodFrequencyTypeParamName, "currencyOptions", "interestCompoundingPeriodTypeOptions", + "interestPostingPeriodTypeOptions", "interestCalculationTypeOptions", "interestCalculationDaysInYearTypeOptions", + "lockinPeriodFrequencyTypeOptions")); public static final Set SAVINGS_ACCOUNT_REQUEST_DATA_PARAMETERS = new HashSet(Arrays.asList(localeParamName, dateFormatParamName, accountNoParamName, externalIdParamName, clientIdParamName, groupIdParamName, productIdParamName, activeParamName, activationDateParamName, nominalAnnualInterestRateParamName, interestCompoundingPeriodTypeParamName, - interestCalculationTypeParamName, interestCalculationDaysInYearTypeParamName, minRequiredOpeningBalanceParamName, - lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName)); + interestPostingPeriodTypeParamName, interestCalculationTypeParamName, interestCalculationDaysInYearTypeParamName, + minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName)); /** * These parameters will match the class level parameters of @@ -74,10 +77,10 @@ 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", nominalAnnualInterestRateParamName, - interestCompoundingPeriodTypeParamName, interestCalculationTypeParamName, - interestCalculationDaysInYearTypeParamName, minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName, - lockinPeriodFrequencyTypeParamName, "summary", "transactions", "productOptions", "interestRatePeriodFrequencyTypeOptions", - "lockinPeriodFrequencyTypeOptions")); + interestCompoundingPeriodTypeParamName, interestCalculationTypeParamName, interestCalculationDaysInYearTypeParamName, + minRequiredOpeningBalanceParamName, lockinPeriodFrequencyParamName, lockinPeriodFrequencyTypeParamName, "summary", + "transactions", "productOptions", "interestCompoundingPeriodTypeOptions", "interestPostingPeriodTypeOptions", + "interestCalculationTypeOptions", "interestCalculationDaysInYearTypeOptions", "lockinPeriodFrequencyTypeOptions")); public static final Set SAVINGS_ACCOUNT_TRANSACTION_REQUEST_DATA_PARAMETERS = new HashSet(Arrays.asList( localeParamName, dateFormatParamName, transactionDateParamName, transactionAmountParamName)); 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 e0baa3f37..8febadbb0 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 @@ -35,6 +35,7 @@ import org.mifosplatform.portfolio.savings.data.SavingsProductData; import org.mifosplatform.portfolio.savings.domain.SavingsCompoundingInterestPeriodType; import org.mifosplatform.portfolio.savings.domain.SavingsInterestCalculationDaysInYearType; import org.mifosplatform.portfolio.savings.domain.SavingsInterestCalculationType; +import org.mifosplatform.portfolio.savings.domain.SavingsInterestPostingPeriodType; import org.mifosplatform.portfolio.savings.service.SavingsDropdownReadPlatformService; import org.mifosplatform.portfolio.savings.service.SavingsEnumerations; import org.mifosplatform.portfolio.savings.service.SavingsProductReadPlatformService; @@ -146,9 +147,12 @@ public class SavingsProductsApiResource { private SavingsProductData handleTemplateRelatedData(final SavingsProductData savingsProduct) { - final EnumOptionData interestPeriodType = SavingsEnumerations + final EnumOptionData interestCompoundingPeriodType = SavingsEnumerations .compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.DAILY); + final EnumOptionData interestPostingPeriodType = SavingsEnumerations + .interestPostingPeriodType(SavingsInterestPostingPeriodType.MONTHLY); + final EnumOptionData interestCalculationType = SavingsEnumerations .interestCalculationType(SavingsInterestCalculationType.DAILY_BALANCE); @@ -161,9 +165,12 @@ public class SavingsProductsApiResource { currency = new ArrayList(currencyOptions).get(0); } - final Collection interestPeriodTypeOptions = this.dropdownReadPlatformService + final Collection interestCompoundingPeriodTypeOptions = this.dropdownReadPlatformService .retrieveCompoundingInterestPeriodTypeOptions(); + final Collection interestPostingPeriodTypeOptions = this.dropdownReadPlatformService + .retrieveInterestPostingPeriodTypeOptions(); + final Collection interestCalculationTypeOptions = this.dropdownReadPlatformService .retrieveInterestCalculationTypeOptions(); @@ -175,12 +182,14 @@ public class SavingsProductsApiResource { SavingsProductData savingsProductToReturn = null; if (savingsProduct != null) { - savingsProductToReturn = SavingsProductData.withTemplate(savingsProduct, currencyOptions, interestPeriodTypeOptions, - interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions); + savingsProductToReturn = SavingsProductData.withTemplate(savingsProduct, currencyOptions, interestCompoundingPeriodTypeOptions, + interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, + lockinPeriodFrequencyTypeOptions); } else { - savingsProductToReturn = SavingsProductData.template(currency, interestPeriodType, interestCalculationType, - interestCalculationDaysInYearType, currencyOptions, interestPeriodTypeOptions, interestCalculationTypeOptions, - interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions); + savingsProductToReturn = SavingsProductData.template(currency, interestCompoundingPeriodType, interestPostingPeriodType, + interestCalculationType, interestCalculationDaysInYearType, currencyOptions, interestCompoundingPeriodTypeOptions, + interestPostingPeriodTypeOptions, 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 725f1e9db..050b7d8b7 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 @@ -15,7 +15,6 @@ import org.mifosplatform.organisation.monetary.data.CurrencyData; /** * Immutable data object representing a savings account. */ -@SuppressWarnings("unused") public class SavingsAccountData { private final Long id; @@ -32,6 +31,7 @@ public class SavingsAccountData { private final CurrencyData currency; private final BigDecimal nominalAnnualInterestRate; private final EnumOptionData interestCompoundingPeriodType; + private final EnumOptionData interestPostingPeriodType; private final EnumOptionData interestCalculationType; private final EnumOptionData interestCalculationDaysInYearType; private final BigDecimal minRequiredOpeningBalance; @@ -40,39 +40,49 @@ public class SavingsAccountData { // associations private final SavingsAccountSummaryData summary; + @SuppressWarnings("unused") private final Collection transactions; // template + @SuppressWarnings("unused") private final Collection productOptions; + @SuppressWarnings("unused") private final Collection interestCompoundingPeriodTypeOptions; + @SuppressWarnings("unused") + private final Collection interestPostingPeriodTypeOptions; + @SuppressWarnings("unused") private final Collection interestCalculationTypeOptions; + @SuppressWarnings("unused") private final Collection interestCalculationDaysInYearTypeOptions; + @SuppressWarnings("unused") private final Collection lockinPeriodFrequencyTypeOptions; 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 interestCompoundingPeriodType, - final EnumOptionData interestCalculationType, final EnumOptionData interestCalculationDaysInYearType, - final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency, - final EnumOptionData lockinPeriodFrequencyType, final SavingsAccountSummaryData summary) { + final EnumOptionData interestPostingPeriodType, final EnumOptionData interestCalculationType, + final EnumOptionData interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance, + final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType, final SavingsAccountSummaryData summary) { final Collection productOptions = null; final Collection interestCompoundingPeriodTypeOptions = null; + final Collection interestPostingPeriodTypeOptions = 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, interestCompoundingPeriodType, interestCalculationType, - interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, summary, - productOptions, interestCompoundingPeriodTypeOptions, interestCalculationTypeOptions, - interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, transactions); + productId, productName, currency, interestRate, interestCompoundingPeriodType, interestPostingPeriodType, + interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, + lockinPeriodFrequencyType, summary, productOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, + interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, transactions); } public static SavingsAccountData withTemplateOptions(final SavingsAccountData account, final Collection productOptions, final Collection interestCompoundingPeriodTypeOptions, + final Collection interestPostingPeriodTypeOptions, final Collection interestCalculationTypeOptions, final Collection interestCalculationDaysInYearTypeOptions, final Collection lockinPeriodFrequencyTypeOptions, final Collection transactions) { @@ -80,10 +90,10 @@ public class SavingsAccountData { return new SavingsAccountData(account.id, account.accountNo, account.externalId, account.status, account.activationDate, account.groupId, account.groupName, account.clientId, account.clientName, account.savingsProductId, account.savingsProductName, account.currency, account.nominalAnnualInterestRate, account.interestCompoundingPeriodType, - account.interestCalculationType, account.interestCalculationDaysInYearType, account.minRequiredOpeningBalance, - account.lockinPeriodFrequency, account.lockinPeriodFrequencyType, account.summary, productOptions, - interestCompoundingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, - lockinPeriodFrequencyTypeOptions, transactions); + account.interestPostingPeriodType, account.interestCalculationType, account.interestCalculationDaysInYearType, + account.minRequiredOpeningBalance, account.lockinPeriodFrequency, account.lockinPeriodFrequencyType, account.summary, + productOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions, + interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, transactions); } public static SavingsAccountData withClientTemplate(final Long clientId, final String clientName, final Long groupId, @@ -99,6 +109,7 @@ public class SavingsAccountData { final CurrencyData currency = null; final BigDecimal nominalAnnualInterestRate = null; final EnumOptionData interestPeriodType = null; + final EnumOptionData interestPostingPeriodType = null; final EnumOptionData interestCalculationType = null; final EnumOptionData interestCalculationDaysInYearType = null; final BigDecimal minRequiredOpeningBalance = null; @@ -106,27 +117,29 @@ public class SavingsAccountData { final EnumOptionData lockinPeriodFrequencyType = null; final SavingsAccountSummaryData summary = null; final Collection productOptions = null; - final Collection currencyOptions = null; final Collection interestCompoundingPeriodTypeOptions = null; + final Collection interestPostingPeriodTypeOptions = 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, nominalAnnualInterestRate, interestPeriodType, interestCalculationType, - interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, summary, - productOptions, interestCompoundingPeriodTypeOptions, interestCalculationTypeOptions, - interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, transactions); + productId, productName, currency, nominalAnnualInterestRate, interestPeriodType, interestPostingPeriodType, + interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, + lockinPeriodFrequencyType, summary, productOptions, interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, + 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 nominalAnnualInterestRate, - final EnumOptionData interestPeriodType, final EnumOptionData interestCalculationType, - final EnumOptionData interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance, - final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType, final SavingsAccountSummaryData summary, + final EnumOptionData interestPeriodType, final EnumOptionData interestPostingPeriodType, + final EnumOptionData interestCalculationType, final EnumOptionData interestCalculationDaysInYearType, + final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency, + final EnumOptionData lockinPeriodFrequencyType, final SavingsAccountSummaryData summary, final Collection productOptions, final Collection interestCompoundingPeriodTypeOptions, + final Collection interestPostingPeriodTypeOptions, final Collection interestCalculationTypeOptions, final Collection interestCalculationDaysInYearTypeOptions, final Collection lockinPeriodFrequencyTypeOptions, final Collection transactions) { @@ -144,6 +157,7 @@ public class SavingsAccountData { this.currency = currency; this.nominalAnnualInterestRate = nominalAnnualInterestRate; this.interestCompoundingPeriodType = interestPeriodType; + this.interestPostingPeriodType = interestPostingPeriodType; this.interestCalculationType = interestCalculationType; this.interestCalculationDaysInYearType = interestCalculationDaysInYearType; this.minRequiredOpeningBalance = minRequiredOpeningBalance; @@ -153,6 +167,7 @@ public class SavingsAccountData { this.productOptions = productOptions; this.interestCompoundingPeriodTypeOptions = interestCompoundingPeriodTypeOptions; + this.interestPostingPeriodTypeOptions = interestPostingPeriodTypeOptions; 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 ee8d91363..16eaa012b 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 @@ -9,6 +9,7 @@ import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.groupI 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.interestCompoundingPeriodTypeParamName; +import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestPostingPeriodTypeParamName; 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; @@ -98,16 +99,33 @@ public class SavingsAccountDataValidator { baseDataValidator.reset().parameter(nominalAnnualInterestRateParamName).value(interestRate).notNull().zeroOrPositiveAmount(); } - final Integer interestPeriodType = fromApiJsonHelper.extractIntegerSansLocaleNamed(interestCompoundingPeriodTypeParamName, element); - baseDataValidator.reset().parameter(interestCompoundingPeriodTypeParamName).value(interestPeriodType).notNull().inMinMaxRange(1, 7); + if (fromApiJsonHelper.parameterExists(interestCompoundingPeriodTypeParamName, element)) { + final Integer interestCompoundingPeriodType = fromApiJsonHelper.extractIntegerSansLocaleNamed( + interestCompoundingPeriodTypeParamName, element); + baseDataValidator.reset().parameter(interestCompoundingPeriodTypeParamName).value(interestCompoundingPeriodType).notNull() + .isOneOfTheseValues(new Object[] { 1, 2, 3, 4, 5, 6, 7, 8 }); + } - final Integer interestCalculationType = fromApiJsonHelper.extractIntegerSansLocaleNamed(interestCalculationTypeParamName, element); - baseDataValidator.reset().parameter(interestCalculationTypeParamName).value(interestCalculationType).notNull().inMinMaxRange(1, 2); + if (fromApiJsonHelper.parameterExists(interestPostingPeriodTypeParamName, element)) { + final Integer interestPostingPeriodType = fromApiJsonHelper.extractIntegerSansLocaleNamed(interestPostingPeriodTypeParamName, + element); + baseDataValidator.reset().parameter(interestPostingPeriodTypeParamName).value(interestPostingPeriodType).notNull() + .isOneOfTheseValues(new Object[] { 4, 5, 6, 7 }); + } - final Integer interestCalculationDaysInYearType = fromApiJsonHelper.extractIntegerSansLocaleNamed( - interestCalculationDaysInYearTypeParamName, element); - baseDataValidator.reset().parameter(interestCalculationDaysInYearTypeParamName).value(interestCalculationDaysInYearType).notNull() - .inOfTheseValues(360, 365); + if (fromApiJsonHelper.parameterExists(interestCalculationTypeParamName, element)) { + final Integer interestCalculationType = fromApiJsonHelper.extractIntegerSansLocaleNamed(interestCalculationTypeParamName, + element); + baseDataValidator.reset().parameter(interestCalculationTypeParamName).value(interestCalculationType).notNull() + .isOneOfTheseValues(new Object[] { 1, 2 }); + } + + if (fromApiJsonHelper.parameterExists(interestCalculationDaysInYearTypeParamName, element)) { + final Integer interestCalculationDaysInYearType = fromApiJsonHelper.extractIntegerSansLocaleNamed( + interestCalculationDaysInYearTypeParamName, element); + baseDataValidator.reset().parameter(interestCalculationDaysInYearTypeParamName).value(interestCalculationDaysInYearType) + .notNull().isOneOfTheseValues(360, 365); + } if (this.fromApiJsonHelper.parameterExists(minRequiredOpeningBalanceParamName, element)) { final BigDecimal minOpeningBalance = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minRequiredOpeningBalanceParamName, @@ -213,22 +231,31 @@ public class SavingsAccountDataValidator { } if (this.fromApiJsonHelper.parameterExists(interestCompoundingPeriodTypeParamName, element)) { - final Integer interestPeriodType = fromApiJsonHelper.extractIntegerSansLocaleNamed(interestCompoundingPeriodTypeParamName, element); - baseDataValidator.reset().parameter(interestCompoundingPeriodTypeParamName).value(interestPeriodType).notNull().inMinMaxRange(1, 7); + final Integer interestCompoundingPeriodType = fromApiJsonHelper.extractIntegerSansLocaleNamed( + interestCompoundingPeriodTypeParamName, element); + baseDataValidator.reset().parameter(interestCompoundingPeriodTypeParamName).value(interestCompoundingPeriodType).notNull() + .isOneOfTheseValues(new Object[] { 1, 2, 3, 4, 5, 6, 7, 8 }); + } + + if (this.fromApiJsonHelper.parameterExists(interestPostingPeriodTypeParamName, element)) { + final Integer interestPostingPeriodType = fromApiJsonHelper.extractIntegerSansLocaleNamed(interestPostingPeriodTypeParamName, + element); + baseDataValidator.reset().parameter(interestPostingPeriodTypeParamName).value(interestPostingPeriodType).notNull() + .isOneOfTheseValues(new Object[] { 4, 5, 6, 7 }); } if (this.fromApiJsonHelper.parameterExists(interestCalculationTypeParamName, element)) { final Integer interestCalculationType = fromApiJsonHelper.extractIntegerSansLocaleNamed(interestCalculationTypeParamName, element); baseDataValidator.reset().parameter(interestCalculationTypeParamName).value(interestCalculationType).notNull() - .inMinMaxRange(1, 2); + .isOneOfTheseValues(new Object[] { 1, 2 }); } if (this.fromApiJsonHelper.parameterExists(interestCalculationDaysInYearTypeParamName, element)) { final Integer interestCalculationDaysInYearType = fromApiJsonHelper.extractIntegerSansLocaleNamed( interestCalculationDaysInYearTypeParamName, element); baseDataValidator.reset().parameter(interestCalculationDaysInYearTypeParamName).value(interestCalculationDaysInYearType) - .notNull().inOfTheseValues(360, 365); + .notNull().isOneOfTheseValues(360, 365); } if (this.fromApiJsonHelper.parameterExists(minRequiredOpeningBalanceParamName, 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 06f6342ae..294df78ce 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 @@ -22,6 +22,7 @@ public class SavingsProductData { private final CurrencyData currency; private final BigDecimal nominalAnnualInterestRate; private final EnumOptionData interestCompoundingPeriodType; + private final EnumOptionData interestPostingPeriodType; private final EnumOptionData interestCalculationType; private final EnumOptionData interestCalculationDaysInYearType; private final BigDecimal minRequiredOpeningBalance; @@ -34,6 +35,8 @@ public class SavingsProductData { @SuppressWarnings("unused") private final Collection interestCompoundingPeriodTypeOptions; @SuppressWarnings("unused") + private final Collection interestPostingPeriodTypeOptions; + @SuppressWarnings("unused") private final Collection interestCalculationTypeOptions; @SuppressWarnings("unused") private final Collection interestCalculationDaysInYearTypeOptions; @@ -41,8 +44,10 @@ public class SavingsProductData { private final Collection lockinPeriodFrequencyTypeOptions; public static SavingsProductData template(final CurrencyData currency, final EnumOptionData interestCompoundingPeriodType, - final EnumOptionData interestCalculationType, final EnumOptionData interestCalculationDaysInYearType, - final Collection currencyOptions, final Collection interestPeriodTypeOptions, + final EnumOptionData interestPostingPeriodType, final EnumOptionData interestCalculationType, + final EnumOptionData interestCalculationDaysInYearType, final Collection currencyOptions, + final Collection interestCompoundingPeriodTypeOptions, + final Collection interestPostingPeriodTypeOptions, final Collection interestCalculationTypeOptions, final Collection interestCalculationDaysInYearTypeOptions, final Collection lockinPeriodFrequencyTypeOptions) { @@ -56,9 +61,10 @@ public class SavingsProductData { final EnumOptionData lockinPeriodFrequencyType = null; return new SavingsProductData(id, name, description, currency, nominalAnnualInterestRate, interestCompoundingPeriodType, - interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, - lockinPeriodFrequencyType, currencyOptions, interestPeriodTypeOptions, interestCalculationTypeOptions, - interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions); + interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, + lockinPeriodFrequency, lockinPeriodFrequencyType, currencyOptions, interestCompoundingPeriodTypeOptions, + interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, + lockinPeriodFrequencyTypeOptions); } /** @@ -66,33 +72,39 @@ public class SavingsProductData { * {@link SavingsProductData} data with further template data for dropdowns. */ public static SavingsProductData withTemplate(final SavingsProductData existingProduct, final Collection currencyOptions, - final Collection interestPeriodTypeOptions, final Collection interestCalculationTypeOptions, + final Collection interestCompoundingPeriodTypeOptions, + final Collection interestPostingPeriodTypeOptions, + final Collection interestCalculationTypeOptions, final Collection interestCalculationDaysInYearTypeOptions, final Collection lockinPeriodFrequencyTypeOptions) { return new SavingsProductData(existingProduct.id, existingProduct.name, existingProduct.description, existingProduct.currency, existingProduct.nominalAnnualInterestRate, existingProduct.interestCompoundingPeriodType, - existingProduct.interestCalculationType, existingProduct.interestCalculationDaysInYearType, - existingProduct.minRequiredOpeningBalance, existingProduct.lockinPeriodFrequency, - existingProduct.lockinPeriodFrequencyType, currencyOptions, interestPeriodTypeOptions, interestCalculationTypeOptions, + existingProduct.interestPostingPeriodType, existingProduct.interestCalculationType, + existingProduct.interestCalculationDaysInYearType, existingProduct.minRequiredOpeningBalance, + existingProduct.lockinPeriodFrequency, existingProduct.lockinPeriodFrequencyType, currencyOptions, + interestCompoundingPeriodTypeOptions, interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions); } public static SavingsProductData instance(final Long id, final String name, final String description, final CurrencyData currency, final BigDecimal nominalAnnualInterestRate, final EnumOptionData interestCompoundingPeriodType, - final EnumOptionData interestCalculationType, final EnumOptionData interestCalculationDaysInYearType, - final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType) { + final EnumOptionData interestPostingPeriodType, final EnumOptionData interestCalculationType, + final EnumOptionData interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance, + final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType) { final Collection currencyOptions = null; - final Collection interestPeriodTypeOptions = null; + final Collection interestCompoundingPeriodTypeOptions = null; + final Collection interestPostingPeriodTypeOptions = null; final Collection interestCalculationTypeOptions = null; final Collection interestCalculationDaysInYearTypeOptions = null; final Collection lockinPeriodFrequencyTypeOptions = null; return new SavingsProductData(id, name, description, currency, nominalAnnualInterestRate, interestCompoundingPeriodType, - interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, - lockinPeriodFrequencyType, currencyOptions, interestPeriodTypeOptions, interestCalculationTypeOptions, - interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions); + interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, + lockinPeriodFrequency, lockinPeriodFrequencyType, currencyOptions, interestCompoundingPeriodTypeOptions, + interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, + lockinPeriodFrequencyTypeOptions); } public static SavingsProductData lookup(final Long id, final String name) { @@ -101,6 +113,7 @@ public class SavingsProductData { final String description = null; final BigDecimal nominalAnnualInterestRate = null; final EnumOptionData interestCompoundingPeriodType = null; + final EnumOptionData interestPostingPeriodType = null; final EnumOptionData interestCalculationType = null; final EnumOptionData interestCalculationDaysInYearType = null; final BigDecimal minRequiredOpeningBalance = null; @@ -108,23 +121,27 @@ public class SavingsProductData { final EnumOptionData lockinPeriodFrequencyType = null; final Collection currencyOptions = null; - final Collection interestPeriodTypeOptions = null; + final Collection interestCompoundingPeriodTypeOptions = null; + final Collection interestPostingPeriodTypeOptions = null; final Collection interestCalculationTypeOptions = null; final Collection interestCalculationDaysInYearTypeOptions = null; final Collection lockinPeriodFrequencyTypeOptions = null; return new SavingsProductData(id, name, description, currency, nominalAnnualInterestRate, interestCompoundingPeriodType, - interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, - lockinPeriodFrequencyType, currencyOptions, interestPeriodTypeOptions, interestCalculationTypeOptions, - interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions); + interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, + lockinPeriodFrequency, lockinPeriodFrequencyType, currencyOptions, interestCompoundingPeriodTypeOptions, + interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, + lockinPeriodFrequencyTypeOptions); } private SavingsProductData(final Long id, final String name, final String description, final CurrencyData currency, 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 interestPeriodTypeOptions, final Collection interestCalculationTypeOptions, + final EnumOptionData interestPostingPeriodType, final EnumOptionData interestCalculationType, + final EnumOptionData interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance, + final Integer lockinPeriodFrequency, final EnumOptionData lockinPeriodFrequencyType, + final Collection currencyOptions, final Collection interestCompoundingPeriodTypeOptions, + final Collection interestPostingPeriodTypeOptions, + final Collection interestCalculationTypeOptions, final Collection interestCalculationDaysInYearTypeOptions, final Collection lockinPeriodFrequencyTypeOptions) { this.id = id; @@ -133,6 +150,7 @@ public class SavingsProductData { this.currency = currency; this.nominalAnnualInterestRate = nominalAnnualInterestRate; this.interestCompoundingPeriodType = interestCompoundingPeriodType; + this.interestPostingPeriodType = interestPostingPeriodType; this.interestCalculationType = interestCalculationType; this.interestCalculationDaysInYearType = interestCalculationDaysInYearType; this.minRequiredOpeningBalance = minRequiredOpeningBalance; @@ -140,7 +158,8 @@ public class SavingsProductData { this.lockinPeriodFrequencyType = lockinPeriodFrequencyType; this.currencyOptions = currencyOptions; - this.interestCompoundingPeriodTypeOptions = interestPeriodTypeOptions; + this.interestCompoundingPeriodTypeOptions = interestCompoundingPeriodTypeOptions; + this.interestPostingPeriodTypeOptions = interestPostingPeriodTypeOptions; 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 3679293bb..c95541b2a 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 @@ -8,6 +8,7 @@ import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.digits 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.interestCompoundingPeriodTypeParamName; +import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestPostingPeriodTypeParamName; 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; @@ -66,21 +67,27 @@ 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(nominalAnnualInterestRateParamName, element); - baseDataValidator.reset().parameter(nominalAnnualInterestRateParamName).value(interestRate).notNull().zeroOrPositiveAmount(); + final BigDecimal nominalAnnualInterestRate = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(nominalAnnualInterestRateParamName, element); + baseDataValidator.reset().parameter(nominalAnnualInterestRateParamName).value(nominalAnnualInterestRate).notNull().zeroOrPositiveAmount(); final Integer interestCompoundingPeriodType = fromApiJsonHelper.extractIntegerSansLocaleNamed( interestCompoundingPeriodTypeParamName, element); baseDataValidator.reset().parameter(interestCompoundingPeriodTypeParamName).value(interestCompoundingPeriodType).notNull() - .inMinMaxRange(1, 8); + .isOneOfTheseValues(new Object[] { 1, 2, 3, 4, 5, 6, 7, 8 }); + + final Integer interestPostingPeriodType = fromApiJsonHelper.extractIntegerSansLocaleNamed(interestPostingPeriodTypeParamName, + element); + baseDataValidator.reset().parameter(interestPostingPeriodTypeParamName).value(interestPostingPeriodType).notNull() + .isOneOfTheseValues(new Object[] { 4, 5, 6, 7 }); final Integer interestCalculationType = fromApiJsonHelper.extractIntegerSansLocaleNamed(interestCalculationTypeParamName, element); - baseDataValidator.reset().parameter(interestCalculationTypeParamName).value(interestCalculationType).notNull().inMinMaxRange(1, 2); + baseDataValidator.reset().parameter(interestCalculationTypeParamName).value(interestCalculationType).notNull() + .isOneOfTheseValues(new Object[] { 1, 2 }); final Integer interestCalculationDaysInYearType = fromApiJsonHelper.extractIntegerSansLocaleNamed( interestCalculationDaysInYearTypeParamName, element); baseDataValidator.reset().parameter(interestCalculationDaysInYearTypeParamName).value(interestCalculationDaysInYearType).notNull() - .inOfTheseValues(360, 365); + .isOneOfTheseValues(360, 365); if (this.fromApiJsonHelper.parameterExists(minRequiredOpeningBalanceParamName, element)) { final BigDecimal minOpeningBalance = fromApiJsonHelper.extractBigDecimalWithLocaleNamed(minRequiredOpeningBalanceParamName, @@ -172,7 +179,7 @@ public class SavingsProductDataValidator { final Integer interestCalculationDaysInYearType = fromApiJsonHelper.extractIntegerSansLocaleNamed( interestCalculationDaysInYearTypeParamName, element); baseDataValidator.reset().parameter(interestCalculationDaysInYearTypeParamName).value(interestCalculationDaysInYearType) - .notNull().inOfTheseValues(360, 365); + .notNull().isOneOfTheseValues(360, 365); } if (this.fromApiJsonHelper.parameterExists(lockinPeriodFrequencyParamName, element)) { 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 06f5e9efc..131f47ec2 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 @@ -94,6 +94,12 @@ public class SavingsAccount extends AbstractPersistable { @Column(name = "interest_compounding_period_enum", nullable = false) private Integer interestCompoundingPeriodType; + /** + * A value from the {@link SavingsInterestPostingPeriodType} enumeration. + */ + @Column(name = "interest_posting_period_enum", nullable = false) + private Integer interestPostingPeriodType; + /** * A value from the {@link SavingsInterestCalculationType} enumeration. */ @@ -107,13 +113,13 @@ public class SavingsAccount extends AbstractPersistable { @Column(name = "interest_calculation_days_in_year_type_enum", nullable = false) private Integer interestCalculationDaysInYearType; - @Column(name = "min_required_opening_balance", scale = 6, precision = 19, nullable = false) + @Column(name = "min_required_opening_balance", scale = 6, precision = 19, nullable = true) private BigDecimal minRequiredOpeningBalance; - @Column(name = "lockin_period_frequency", nullable = false) + @Column(name = "lockin_period_frequency", nullable = true) private Integer lockinPeriodFrequency; - @Column(name = "lockin_period_frequency_enum", nullable = false) + @Column(name = "lockin_period_frequency_enum", nullable = true) private Integer lockinPeriodFrequencyType; /** @@ -144,20 +150,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 SavingsCompoundingInterestPeriodType interestPeriodType, final SavingsInterestCalculationType interestCalculationType, + final SavingsCompoundingInterestPeriodType interestCompoundingPeriodType, + final SavingsInterestPostingPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType, final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance, 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, interestPeriodType, - interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, - lockinPeriodFrequencyType); + return new SavingsAccount(client, group, product, accountNo, externalId, status, activationDate, interestRate, + interestCompoundingPeriodType, interestPostingPeriodType, 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 SavingsCompoundingInterestPeriodType interestPeriodType, final SavingsInterestCalculationType interestCalculationType, + final String externalId, final SavingsAccountStatusType status, final LocalDate activationDate, final BigDecimal nominalAnnualInterestRate, + final SavingsCompoundingInterestPeriodType interestCompoundingPeriodType, + final SavingsInterestPostingPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType, final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType) { this.client = client; @@ -175,8 +183,9 @@ public class SavingsAccount extends AbstractPersistable { if (activationDate != null) { this.activationDate = activationDate.toDate(); } - this.nominalAnnualInterestRate = interestRate; - this.interestCompoundingPeriodType = interestPeriodType.getValue(); + this.nominalAnnualInterestRate = nominalAnnualInterestRate; + this.interestCompoundingPeriodType = interestCompoundingPeriodType.getValue(); + this.interestPostingPeriodType = interestPostingPeriodType.getValue(); this.interestCalculationType = interestCalculationType.getValue(); this.interestCalculationDaysInYearType = interestCalculationDaysInYearType.getValue(); this.minRequiredOpeningBalance = minRequiredOpeningBalance; @@ -266,13 +275,47 @@ public class SavingsAccount extends AbstractPersistable { return lockedInUntilLocalDate; } + public void postInterest(final LocalDate interestPostingUpToDate) { + + final SavingsInterestPostingPeriodType postingPeriodType = SavingsInterestPostingPeriodType.fromInt(this.interestPostingPeriodType); + List postingLocalDates = determineInterestPostingDates(getActivationLocalDate(), interestPostingUpToDate, + postingPeriodType); + + List compoundingPeriods = calculateInterest(interestPostingUpToDate); + + // + for (InterestCompoundingPeriodSummary interestCompoundingPeriodSummary : compoundingPeriods) { + + } + } + + private List determineInterestPostingDates(final LocalDate activationLocalDate, final LocalDate interestPostingUpToDate, + final SavingsInterestPostingPeriodType postingPeriodType) { + + List postingDates = new ArrayList(); + + LocalDate periodStartDate = activationLocalDate; + LocalDate periodEndDate = periodStartDate; + + while (!periodStartDate.isAfter(interestPostingUpToDate) && !periodEndDate.isAfter(interestPostingUpToDate)) { + + final LocalDate interestPostingLocalDate = determineInterestPostingPeriodEndDateFrom(periodStartDate, postingPeriodType); + postingDates.add(interestPostingLocalDate); + + periodEndDate = interestPostingLocalDate; + periodStartDate = interestPostingLocalDate; + } + + return postingDates; + } + /** * All interest calculation based on END-OF-DAY-BALANCE. * * Interest calculation is performed on-the-fly over all account * transactions. */ - public void calculateInterest(final LocalDate interestCalculationEndDate) { + public List calculateInterest(final LocalDate interestCalculationUpToDate) { // no openingBalance concept supported yet but probably will to allow // for migrations. @@ -287,7 +330,7 @@ public class SavingsAccount extends AbstractPersistable { final SavingsCompoundingInterestPeriodType compoundingPeriodType = SavingsCompoundingInterestPeriodType .fromInt(this.interestCompoundingPeriodType); final List interestCompoundingPeriods = determineInterestCompoundingPeriods(getActivationLocalDate(), - interestCalculationEndDate, compoundingPeriodType); + interestCalculationUpToDate, compoundingPeriodType); // determine opening balance, daily interest rate to apply, interest // due, interest to compound for each period @@ -295,6 +338,8 @@ public class SavingsAccount extends AbstractPersistable { openingAccountBalance, this.nominalAnnualInterestRate, daysInYearType, interestCompoundingPeriods); this.summary.updateFromInterestPeriodSummaries(currency, compoundingPeriods); + + return compoundingPeriods; } private List determineInterestCompoundingPeriodSummaries(final Money openingAccountBalance, @@ -386,6 +431,55 @@ public class SavingsAccount extends AbstractPersistable { return interestPeriods; } + private LocalDate determineInterestPostingPeriodEndDateFrom(final LocalDate periodStartDate, + final SavingsInterestPostingPeriodType interestPostingPeriodType) { + + LocalDate periodEndDate = DateUtils.getLocalDateOfTenant(); + + switch (interestPostingPeriodType) { + case INVALID: + break; + case MONTHLY: + // produce period end date on last day of current month + periodEndDate = periodStartDate.dayOfMonth().withMaximumValue(); + break; + case QUATERLY: + // jan 1st to mar 31st, 1st apr to jun 30, jul 1st to sept 30, + // oct 1st to dec 31 + int year = periodStartDate.getYearOfEra(); + int monthofYear = periodStartDate.getMonthOfYear(); + if (monthofYear <= 3) { + periodEndDate = new DateTime().withDate(year, 3, 31).toLocalDate(); + } else if (monthofYear <= 6) { + periodEndDate = new DateTime().withDate(year, 6, 30).toLocalDate(); + } else if (monthofYear <= 9) { + periodEndDate = new DateTime().withDate(year, 9, 30).toLocalDate(); + } else if (monthofYear <= 12) { + periodEndDate = new DateTime().withDate(year, 12, 31).toLocalDate(); + } + break; + case BI_ANNUAL: + // jan 1st to 30, jul 1st to dec 31 + year = periodStartDate.getYearOfEra(); + monthofYear = periodStartDate.getMonthOfYear(); + if (monthofYear <= 6) { + periodEndDate = new DateTime().withDate(year, 6, 30).toLocalDate(); + } else if (monthofYear <= 12) { + periodEndDate = new DateTime().withDate(year, 12, 31).toLocalDate(); + } + break; + case ANNUAL: + periodEndDate = periodStartDate.monthOfYear().withMaximumValue(); + periodEndDate = periodStartDate.dayOfMonth().withMaximumValue(); + break; + } + + // interest posting always occurs on next day after the period end date. + periodEndDate = periodEndDate.plusDays(1); + + return periodEndDate; + } + private LocalDate determineInterestPeriodEndDateFrom(final LocalDate periodStartDate, final SavingsCompoundingInterestPeriodType interestPeriodType) { 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 47ef538ff..c90069cd2 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 @@ -10,6 +10,7 @@ import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.active 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.interestCompoundingPeriodTypeParamName; +import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestPostingPeriodTypeParamName; 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; @@ -90,22 +91,34 @@ public class SavingsAccountAssembler { if (command.parameterExists(nominalAnnualInterestRateParamName)) { interestRate = command.bigDecimalValueOfParameterNamed(nominalAnnualInterestRateParamName); } else { - interestRate = product.interestRate(); + interestRate = product.nominalAnnualInterestRate(); } final boolean active = fromApiJsonHelper.extractBooleanNamed(activeParamName, element); final LocalDate activationDate = fromApiJsonHelper.extractLocalDateNamed(activationDateParamName, element); - SavingsCompoundingInterestPeriodType interestPeriodType = null; + SavingsCompoundingInterestPeriodType interestCompoundingPeriodType = null; final Integer interestPeriodTypeValue = command.integerValueOfParameterNamed(interestCompoundingPeriodTypeParamName); if (interestPeriodTypeValue != null) { - interestPeriodType = SavingsCompoundingInterestPeriodType.fromInt(interestPeriodTypeValue); + interestCompoundingPeriodType = SavingsCompoundingInterestPeriodType.fromInt(interestPeriodTypeValue); + } else { + interestCompoundingPeriodType = product.interestCompoundingPeriodType(); + } + + SavingsInterestPostingPeriodType interestPostingPeriodType = null; + final Integer interestPostingPeriodTypeValue = command.integerValueOfParameterNamed(interestPostingPeriodTypeParamName); + if (interestPostingPeriodTypeValue != null) { + interestPostingPeriodType = SavingsInterestPostingPeriodType.fromInt(interestPostingPeriodTypeValue); + } else { + interestPostingPeriodType = product.interestPostingPeriodType(); } SavingsInterestCalculationType interestCalculationType = null; final Integer interestCalculationTypeValue = command.integerValueOfParameterNamed(interestCalculationTypeParamName); if (interestCalculationTypeValue != null) { interestCalculationType = SavingsInterestCalculationType.fromInt(interestCalculationTypeValue); + } else { + interestCalculationType = product.interestCalculationType(); } SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType = null; @@ -113,6 +126,8 @@ public class SavingsAccountAssembler { .integerValueOfParameterNamed(interestCalculationDaysInYearTypeParamName); if (interestCalculationDaysInYearTypeValue != null) { interestCalculationDaysInYearType = SavingsInterestCalculationDaysInYearType.fromInt(interestCalculationDaysInYearTypeValue); + } else { + interestCalculationDaysInYearType = product.interestCalculationDaysInYearType(); } BigDecimal minRequiredOpeningBalance = null; @@ -141,8 +156,8 @@ public class SavingsAccountAssembler { } final SavingsAccount account = SavingsAccount.createNewAccount(client, group, product, accountNo, externalId, interestRate, - interestPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, - lockinPeriodFrequency, lockinPeriodFrequencyType); + interestCompoundingPeriodType, interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, + minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType); account.setHelpers(this.savingsAccountTransactionSummaryWrapper); if (active) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsInterestPostingPeriodType.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsInterestPostingPeriodType.java new file mode 100644 index 000000000..24a5a4678 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/SavingsInterestPostingPeriodType.java @@ -0,0 +1,56 @@ +/** + * 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 posting period is the span of time at the end of which savings + * earned but not yet credited/posted in a client’s account is credited/posted. + */ +public enum SavingsInterestPostingPeriodType { + + INVALID(0, "savingsInterestPostingPeriodType.invalid"), // + MONTHLY(4, "savingsInterestPostingPeriodType.monthly"), // + QUATERLY(5, "savingsInterestPostingPeriodType.quarterly"), // + BI_ANNUAL(6, "savingsInterestPostingPeriodType.biannual"), // + ANNUAL(7, "savingsInterestPostingPeriodType.annual"); + + private final Integer value; + private final String code; + + private SavingsInterestPostingPeriodType(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 SavingsInterestPostingPeriodType fromInt(final Integer type) { + SavingsInterestPostingPeriodType repaymentFrequencyType = SavingsInterestPostingPeriodType.INVALID; + if (type != null) { + switch (type) { + case 4: + repaymentFrequencyType = SavingsInterestPostingPeriodType.MONTHLY; + break; + case 5: + repaymentFrequencyType = SavingsInterestPostingPeriodType.QUATERLY; + break; + case 6: + repaymentFrequencyType = SavingsInterestPostingPeriodType.BI_ANNUAL; + break; + case 7: + repaymentFrequencyType = SavingsInterestPostingPeriodType.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 a062061c8..8df85e0b6 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 @@ -11,6 +11,7 @@ import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.digits 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.interestCompoundingPeriodTypeParamName; +import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestPostingPeriodTypeParamName; 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; @@ -53,11 +54,18 @@ public class SavingsProduct extends AbstractPersistable { * 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 SavingsCompoundingInterestPeriodType} enumeration. + * A value from the {@link SavingsCompoundingInterestPeriodType} + * enumeration. */ @Column(name = "interest_compounding_period_enum", nullable = false) private Integer interestCompoundingPeriodType; + /** + * A value from the {@link SavingsInterestPostingPeriodType} enumeration. + */ + @Column(name = "interest_posting_period_enum", nullable = false) + private Integer interestPostingPeriodType; + /** * A value from the {@link SavingsInterestCalculationType} enumeration. */ @@ -71,23 +79,24 @@ public class SavingsProduct extends AbstractPersistable { @Column(name = "interest_calculation_days_in_year_type_enum", nullable = false) private Integer interestCalculationDaysInYearType; - @Column(name = "min_required_opening_balance", scale = 6, precision = 19, nullable = false) + @Column(name = "min_required_opening_balance", scale = 6, precision = 19, nullable = true) private BigDecimal minRequiredOpeningBalance; - @Column(name = "lockin_period_frequency", nullable = false) + @Column(name = "lockin_period_frequency", nullable = true) private Integer lockinPeriodFrequency; - @Column(name = "lockin_period_frequency_enum", nullable = false) + @Column(name = "lockin_period_frequency_enum", nullable = true) private Integer lockinPeriodFrequencyType; public static SavingsProduct createNew(final String name, final String description, final MonetaryCurrency currency, - final BigDecimal interestRate, final SavingsCompoundingInterestPeriodType interestPeriodType, - final SavingsInterestCalculationType interestCalculationType, + final BigDecimal interestRate, final SavingsCompoundingInterestPeriodType interestCompoundingPeriodType, + final SavingsInterestPostingPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType, final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType) { - return new SavingsProduct(name, description, currency, interestRate, interestPeriodType, interestCalculationType, - interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType); + return new SavingsProduct(name, description, currency, interestRate, interestCompoundingPeriodType, interestPostingPeriodType, + interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, + lockinPeriodFrequencyType); } protected SavingsProduct() { @@ -96,7 +105,8 @@ public class SavingsProduct extends AbstractPersistable { } private SavingsProduct(final String name, final String description, final MonetaryCurrency currency, final BigDecimal interestRate, - final SavingsCompoundingInterestPeriodType interestPeriodType, final SavingsInterestCalculationType interestCalculationType, + final SavingsCompoundingInterestPeriodType interestCompoundingPeriodType, + final SavingsInterestPostingPeriodType interestPostingPeriodType, final SavingsInterestCalculationType interestCalculationType, final SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType, final BigDecimal minRequiredOpeningBalance, final Integer lockinPeriodFrequency, final SavingsPeriodFrequencyType lockinPeriodFrequencyType) { @@ -105,7 +115,8 @@ public class SavingsProduct extends AbstractPersistable { this.currency = currency; this.nominalAnnualInterestRate = interestRate; - this.interestCompoundingPeriodType = interestPeriodType.getValue(); + this.interestCompoundingPeriodType = interestCompoundingPeriodType.getValue(); + this.interestPostingPeriodType = interestPostingPeriodType.getValue(); this.interestCalculationType = interestCalculationType.getValue(); this.interestCalculationDaysInYearType = interestCalculationDaysInYearType.getValue(); @@ -125,10 +136,26 @@ public class SavingsProduct extends AbstractPersistable { return this.currency.copy(); } - public BigDecimal interestRate() { + public BigDecimal nominalAnnualInterestRate() { return Money.of(this.currency, this.nominalAnnualInterestRate).getAmount(); } + public SavingsCompoundingInterestPeriodType interestCompoundingPeriodType() { + return SavingsCompoundingInterestPeriodType.fromInt(this.interestCompoundingPeriodType); + } + + public SavingsInterestPostingPeriodType interestPostingPeriodType() { + return SavingsInterestPostingPeriodType.fromInt(this.interestPostingPeriodType); + } + + public SavingsInterestCalculationType interestCalculationType() { + return SavingsInterestCalculationType.fromInt(this.interestCalculationType); + } + + public SavingsInterestCalculationDaysInYearType interestCalculationDaysInYearType() { + return SavingsInterestCalculationDaysInYearType.fromInt(this.interestCalculationDaysInYearType); + } + public BigDecimal minRequiredOpeningBalance() { return this.minRequiredOpeningBalance; } @@ -193,6 +220,12 @@ public class SavingsProduct extends AbstractPersistable { this.interestCompoundingPeriodType = SavingsCompoundingInterestPeriodType.fromInt(newValue).getValue(); } + if (command.isChangeInIntegerParameterNamed(interestPostingPeriodTypeParamName, this.interestPostingPeriodType)) { + final Integer newValue = command.integerValueOfParameterNamed(interestPostingPeriodTypeParamName); + actualChanges.put(interestPostingPeriodTypeParamName, newValue); + this.interestPostingPeriodType = SavingsInterestPostingPeriodType.fromInt(newValue).getValue(); + } + if (command.isChangeInIntegerParameterNamed(interestCalculationTypeParamName, this.interestCalculationType)) { final Integer newValue = command.integerValueOfParameterNamed(interestCalculationTypeParamName); actualChanges.put(interestCalculationTypeParamName, newValue); 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 8b81189ad..742072c5e 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 @@ -6,6 +6,7 @@ import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.digits 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.interestCompoundingPeriodTypeParamName; +import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.interestPostingPeriodTypeParamName; 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; @@ -32,10 +33,16 @@ public class SavingsProductAssembler { final BigDecimal interestRate = command.bigDecimalValueOfParameterNamed(nominalAnnualInterestRateParamName); - SavingsCompoundingInterestPeriodType interestPeriodType = null; + SavingsCompoundingInterestPeriodType interestCompoundingPeriodType = null; final Integer interestPeriodTypeValue = command.integerValueOfParameterNamed(interestCompoundingPeriodTypeParamName); if (interestPeriodTypeValue != null) { - interestPeriodType = SavingsCompoundingInterestPeriodType.fromInt(interestPeriodTypeValue); + interestCompoundingPeriodType = SavingsCompoundingInterestPeriodType.fromInt(interestPeriodTypeValue); + } + + SavingsInterestPostingPeriodType interestPostingPeriodType = null; + final Integer interestPostingPeriodTypeValue = command.integerValueOfParameterNamed(interestPostingPeriodTypeParamName); + if (interestPostingPeriodTypeValue != null) { + interestPostingPeriodType = SavingsInterestPostingPeriodType.fromInt(interestPostingPeriodTypeValue); } SavingsInterestCalculationType interestCalculationType = null; @@ -60,7 +67,8 @@ public class SavingsProductAssembler { lockinPeriodFrequencyType = SavingsPeriodFrequencyType.fromInt(lockinPeriodFrequencyTypeValue); } - return SavingsProduct.createNew(name, description, currency, interestRate, interestPeriodType, interestCalculationType, + return SavingsProduct.createNew(name, description, currency, interestRate, interestCompoundingPeriodType, + interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/handler/PostInterestSavingsAccountCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/handler/PostInterestSavingsAccountCommandHandler.java new file mode 100644 index 000000000..2629d43d7 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/handler/PostInterestSavingsAccountCommandHandler.java @@ -0,0 +1,26 @@ +package org.mifosplatform.portfolio.savings.handler; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; +import org.mifosplatform.portfolio.savings.service.SavingsAccountWritePlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class PostInterestSavingsAccountCommandHandler implements NewCommandSourceHandler { + + private final SavingsAccountWritePlatformService savingAccountWritePlatformService; + + @Autowired + public PostInterestSavingsAccountCommandHandler(final SavingsAccountWritePlatformService savingAccountWritePlatformService) { + this.savingAccountWritePlatformService = savingAccountWritePlatformService; + } + + @Transactional + @Override + public CommandProcessingResult processCommand(final JsonCommand command) { + return this.savingAccountWritePlatformService.postInterest(command.getSavingsId(), command); + } +} \ 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 75e7754a2..329960b25 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 @@ -30,6 +30,7 @@ import org.mifosplatform.portfolio.savings.data.SavingsProductData; import org.mifosplatform.portfolio.savings.domain.SavingsCompoundingInterestPeriodType; import org.mifosplatform.portfolio.savings.domain.SavingsInterestCalculationDaysInYearType; import org.mifosplatform.portfolio.savings.domain.SavingsInterestCalculationType; +import org.mifosplatform.portfolio.savings.domain.SavingsInterestPostingPeriodType; import org.mifosplatform.portfolio.savings.domain.SavingsPeriodFrequencyType; import org.mifosplatform.portfolio.savings.exception.SavingsAccountNotFoundException; import org.springframework.beans.factory.annotation.Autowired; @@ -105,6 +106,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead sqlBuilder.append("curr.display_symbol as currencyDisplaySymbol, "); sqlBuilder.append("sa.nominal_annual_interest_rate as nominalAnnualInterestRate, "); sqlBuilder.append("sa.interest_compounding_period_enum as interestCompoundingPeriodType, "); + sqlBuilder.append("sa.interest_posting_period_enum as interestPostingPeriodType, "); 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, "); @@ -162,6 +164,9 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead .compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.fromInt(JdbcSupport.getInteger(rs, "interestCompoundingPeriodType"))); + final EnumOptionData interestPostingPeriodType = SavingsEnumerations.interestPostingPeriodType(SavingsInterestPostingPeriodType + .fromInt(JdbcSupport.getInteger(rs, "interestPostingPeriodType"))); + final EnumOptionData interestCalculationType = SavingsEnumerations.interestCalculationType(SavingsInterestCalculationType .fromInt(JdbcSupport.getInteger(rs, "interestCalculationType"))); @@ -188,11 +193,10 @@ 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, nominalAnnualInterestRate, interestCompoundingPeriodType, interestCalculationType, - interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, - summary); + return SavingsAccountData.instance(id, accountNo, externalId, status, activationDate, groupId, groupName, clientId, clientName, + productId, productName, currency, nominalAnnualInterestRate, interestCompoundingPeriodType, interestPostingPeriodType, + interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, + lockinPeriodFrequencyType, summary); } } @@ -223,6 +227,9 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead final Collection interestCompoundingPeriodTypeOptions = this.dropdownReadPlatformService .retrieveCompoundingInterestPeriodTypeOptions(); + final Collection interestPostingPeriodTypeOptions = this.dropdownReadPlatformService + .retrieveInterestPostingPeriodTypeOptions(); + final Collection interestCalculationTypeOptions = this.dropdownReadPlatformService .retrieveInterestCalculationTypeOptions(); @@ -234,8 +241,8 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead final Collection transactions = null; template = SavingsAccountData.withTemplateOptions(template, productOptions, interestCompoundingPeriodTypeOptions, - interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, - transactions); + interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, + lockinPeriodFrequencyTypeOptions, transactions); } else { String clientName = null; @@ -251,14 +258,15 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead template = SavingsAccountData.withClientTemplate(clientId, clientName, groupId, groupName); final Collection interestCompoundingPeriodTypeOptions = null; + final Collection interestPostingPeriodTypeOptions = null; final Collection interestCalculationTypeOptions = null; final Collection interestCalculationDaysInYearTypeOptions = null; final Collection lockinPeriodFrequencyTypeOptions = null; final Collection transactions = null; template = SavingsAccountData.withTemplateOptions(template, productOptions, interestCompoundingPeriodTypeOptions, - interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, lockinPeriodFrequencyTypeOptions, - transactions); + interestPostingPeriodTypeOptions, interestCalculationTypeOptions, interestCalculationDaysInYearTypeOptions, + lockinPeriodFrequencyTypeOptions, transactions); } return template; @@ -391,6 +399,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead sqlBuilder.append("curr.display_symbol as currencyDisplaySymbol, "); sqlBuilder.append("sp.nominal_annual_interest_rate as nominalAnnualIterestRate, "); sqlBuilder.append("sp.interest_compounding_period_enum as interestCompoundingPeriodType, "); + sqlBuilder.append("sp.interest_posting_period_enum as interestPostingPeriodType, "); 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, "); @@ -422,9 +431,12 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead final BigDecimal nominalAnnualIterestRate = rs.getBigDecimal("nominalAnnualIterestRate"); - EnumOptionData interestPeriodType = SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType + EnumOptionData interestCompoundingPeriodType = SavingsEnumerations.compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType .fromInt(JdbcSupport.getInteger(rs, "interestCompoundingPeriodType"))); + final EnumOptionData interestPostingPeriodType = SavingsEnumerations.interestPostingPeriodType(SavingsInterestPostingPeriodType + .fromInt(JdbcSupport.getInteger(rs, "interestPostingPeriodType"))); + EnumOptionData interestCalculationType = SavingsEnumerations.interestCalculationType(SavingsInterestCalculationType .fromInt(JdbcSupport.getInteger(rs, "interestCalculationType"))); @@ -459,11 +471,10 @@ 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, nominalAnnualIterestRate, interestPeriodType, interestCalculationType, - interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, lockinPeriodFrequencyType, - summary); + return SavingsAccountData.instance(null, null, null, status, activationDate, groupId, groupName, clientId, clientName, + productId, productName, currency, nominalAnnualIterestRate, interestCompoundingPeriodType, interestPostingPeriodType, + 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/SavingsAccountWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountWritePlatformService.java index 912f47e41..51a760d2f 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountWritePlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountWritePlatformService.java @@ -23,4 +23,6 @@ public interface SavingsAccountWritePlatformService { CommandProcessingResult withdrawal(Long savingsId, JsonCommand command); CommandProcessingResult calculateInterest(Long savingsId, JsonCommand command); + + CommandProcessingResult postInterest(Long savingsId, JsonCommand command); } \ 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 5e3683ee6..6bf9e2e00 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 @@ -334,4 +334,23 @@ public class SavingsAccountWritePlatformServiceJpaRepositoryImpl implements Savi .withSavingsId(savingsId) // .build(); } + + @Override + public CommandProcessingResult postInterest(final Long savingsId, final JsonCommand command) { + this.context.authenticatedUser(); + + final SavingsAccount account = this.savingAccountRepository.findOneWithNotFoundDetection(savingsId); + + final LocalDate today = DateUtils.getLocalDateOfTenant(); + account.postInterest(today); + this.savingAccountRepository.save(account); + + return new CommandProcessingResultBuilder() // + .withEntityId(savingsId) // + .withOfficeId(account.officeId()) // + .withClientId(account.clientId()) // + .withGroupId(account.groupId()) // + .withSavingsId(savingsId) // + .build(); + } } \ No newline at end of file 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 51ee36e00..181f7971f 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 @@ -10,6 +10,8 @@ public interface SavingsDropdownReadPlatformService { Collection retrieveCompoundingInterestPeriodTypeOptions(); + Collection retrieveInterestPostingPeriodTypeOptions(); + Collection retrieveInterestCalculationTypeOptions(); Collection retrieveInterestCalculationDaysInYearTypeOptions(); 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 d21eb83cb..cedf7ea6d 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 @@ -8,6 +8,7 @@ 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.SavingsInterestPostingPeriodType; import org.mifosplatform.portfolio.savings.domain.SavingsPeriodFrequencyType; import org.springframework.stereotype.Service; @@ -42,6 +43,18 @@ public class SavingsDropdownReadPlatformServiceImpl implements SavingsDropdownRe return allowedOptions; } + @Override + public Collection retrieveInterestPostingPeriodTypeOptions() { + List allowedOptions = Arrays.asList( // + SavingsEnumerations.interestPostingPeriodType(SavingsInterestPostingPeriodType.MONTHLY), // + SavingsEnumerations.interestPostingPeriodType(SavingsInterestPostingPeriodType.QUATERLY), // + SavingsEnumerations.interestPostingPeriodType(SavingsInterestPostingPeriodType.BI_ANNUAL), // + SavingsEnumerations.interestPostingPeriodType(SavingsInterestPostingPeriodType.ANNUAL) // + ); + + return allowedOptions; + } + @Override public Collection retrieveInterestCalculationTypeOptions() { List allowedOptions = Arrays.asList( // 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 10055fae0..c945bb30d 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 @@ -13,6 +13,7 @@ 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.SavingsInterestPostingPeriodType; import org.mifosplatform.portfolio.savings.domain.SavingsPeriodFrequencyType; public class SavingsEnumerations { @@ -109,6 +110,40 @@ public class SavingsEnumerations { return optionData; } + public static EnumOptionData interestPostingPeriodType(final Integer type) { + return interestPostingPeriodType(SavingsInterestPostingPeriodType.fromInt(type)); + } + + public static EnumOptionData interestPostingPeriodType(final SavingsInterestPostingPeriodType type) { + + final String codePrefix = "savings.interest.posting.period."; + EnumOptionData optionData = new EnumOptionData(SavingsInterestPostingPeriodType.INVALID.getValue().longValue(), + SavingsInterestPostingPeriodType.INVALID.getCode(), "Invalid"); + + switch (type) { + case INVALID: + break; + case MONTHLY: + optionData = new EnumOptionData(SavingsInterestPostingPeriodType.MONTHLY.getValue().longValue(), codePrefix + + SavingsInterestPostingPeriodType.MONTHLY.getCode(), "Monthly"); + break; + case QUATERLY: + optionData = new EnumOptionData(SavingsInterestPostingPeriodType.QUATERLY.getValue().longValue(), codePrefix + + SavingsInterestPostingPeriodType.QUATERLY.getCode(), "Quarterly"); + break; + case BI_ANNUAL: + optionData = new EnumOptionData(SavingsInterestPostingPeriodType.BI_ANNUAL.getValue().longValue(), codePrefix + + SavingsInterestPostingPeriodType.BI_ANNUAL.getCode(), "Semi-Annual"); + break; + case ANNUAL: + optionData = new EnumOptionData(SavingsInterestPostingPeriodType.ANNUAL.getValue().longValue(), codePrefix + + SavingsInterestPostingPeriodType.ANNUAL.getCode(), "Annually"); + break; + } + + return optionData; + } + public static EnumOptionData interestPeriodType(final Integer type) { return compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.fromInt(type)); } 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 ee965cff3..a0077aaf5 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 @@ -19,6 +19,7 @@ import org.mifosplatform.portfolio.savings.data.SavingsProductData; import org.mifosplatform.portfolio.savings.domain.SavingsCompoundingInterestPeriodType; import org.mifosplatform.portfolio.savings.domain.SavingsInterestCalculationDaysInYearType; import org.mifosplatform.portfolio.savings.domain.SavingsInterestCalculationType; +import org.mifosplatform.portfolio.savings.domain.SavingsInterestPostingPeriodType; import org.mifosplatform.portfolio.savings.domain.SavingsPeriodFrequencyType; import org.mifosplatform.portfolio.savings.exception.SavingsProductNotFoundException; import org.springframework.beans.factory.annotation.Autowired; @@ -82,6 +83,7 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead sqlBuilder.append("curr.display_symbol as currencyDisplaySymbol, "); sqlBuilder.append("sp.nominal_annual_interest_rate as nominalAnnualInterestRate, "); sqlBuilder.append("sp.interest_compounding_period_enum as compoundingInterestPeriodType, "); + sqlBuilder.append("sp.interest_posting_period_enum as interestPostingPeriodType, "); 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, "); @@ -118,6 +120,10 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead .compoundingInterestPeriodType(SavingsCompoundingInterestPeriodType.fromInt(JdbcSupport.getInteger(rs, "compoundingInterestPeriodType"))); + SavingsInterestPostingPeriodType interestPostingPeriod = SavingsInterestPostingPeriodType.fromInt(JdbcSupport.getInteger(rs, + "interestPostingPeriodType")); + EnumOptionData interestPostingPeriodType = SavingsEnumerations.interestPostingPeriodType(interestPostingPeriod); + EnumOptionData interestCalculationType = SavingsEnumerations.interestCalculationType(SavingsInterestCalculationType .fromInt(JdbcSupport.getInteger(rs, "interestCalculationType"))); @@ -140,8 +146,8 @@ public class SavingsProductReadPlatformServiceImpl implements SavingsProductRead } return SavingsProductData.instance(id, name, description, currency, nominalAnnualInterestRate, compoundingInterestPeriodType, - interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, lockinPeriodFrequency, - lockinPeriodFrequencyType); + interestPostingPeriodType, interestCalculationType, interestCalculationDaysInYearType, minRequiredOpeningBalance, + lockinPeriodFrequency, lockinPeriodFrequencyType); } }