From 637f062ce3d6ce9b4e920c023fd985778b430144 Mon Sep 17 00:00:00 2001 From: Vishwas Babu A J Date: Tue, 2 Dec 2014 08:31:50 -0800 Subject: [PATCH 1/4] MIFOSX-1511 custom formats for client, loan and savings account numbers --- api-docs/apiLive.htm | 347 ++++++++++++++++++ .../commands/domain/CommandWrapper.java | 36 +- .../service/CommandWrapperBuilder.java | 56 ++- .../SynchronousCommandProcessingService.java | 77 ++-- .../api/AccountNumberFormatsApiResource.java | 156 ++++++++ .../data/AccountNumberFormatData.java | 62 ++++ .../AccountNumberFormatDataValidator.java | 148 ++++++++ .../domain/AccountNumberFormat.java | 65 ++++ .../AccountNumberFormatEnumerations.java | 124 +++++++ .../domain/AccountNumberFormatRepository.java | 20 + .../AccountNumberFormatRepositoryWrapper.java | 38 ++ .../domain/EntityAccountType.java | 80 ++++ .../AccountNumberFormatNotFoundException.java | 21 ++ ...eateAccountNumberFormatCommandHandler.java | 28 ++ ...leteAccountNumberFormatCommandHandler.java | 28 ++ ...dateAccountNumberFormatCommandHandler.java | 28 ++ .../service/AccountNumberFormatConstants.java | 56 +++ ...ccountNumberFormatReadPlatformService.java | 16 + ...ntNumberFormatReadPlatformServiceImpl.java | 133 +++++++ ...countNumberFormatWritePlatformService.java | 14 + ...WritePlatformServiceJpaRepositoryImpl.java | 131 +++++++ .../client/domain/AccountNumberGenerator.java | 89 ++++- .../domain/AccountNumberGeneratorFactory.java | 24 -- .../ZeroPaddedAccountNumberGenerator.java | 27 -- ...WritePlatformServiceJpaRepositoryImpl.java | 20 +- ...WritePlatformServiceJpaRepositoryImpl.java | 21 +- .../loanproduct/domain/LoanProduct.java | 6 +- .../DepositAccountDomainServiceJpa.java | 111 +++--- .../savings/domain/SavingsAccount.java | 17 +- .../savings/domain/SavingsProduct.java | 4 + ...WritePlatformServiceJpaRepositoryImpl.java | 32 +- ...WritePlatformServiceJpaRepositoryImpl.java | 26 +- .../V220__account_number_preferences.sql | 22 ++ 33 files changed, 1832 insertions(+), 231 deletions(-) create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/api/AccountNumberFormatsApiResource.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/data/AccountNumberFormatData.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/data/AccountNumberFormatDataValidator.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/domain/AccountNumberFormat.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/domain/AccountNumberFormatEnumerations.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/domain/AccountNumberFormatRepository.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/domain/AccountNumberFormatRepositoryWrapper.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/domain/EntityAccountType.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/exception/AccountNumberFormatNotFoundException.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/handler/CreateAccountNumberFormatCommandHandler.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/handler/DeleteAccountNumberFormatCommandHandler.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/handler/UpdateAccountNumberFormatCommandHandler.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatConstants.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatReadPlatformService.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatReadPlatformServiceImpl.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatWritePlatformService.java create mode 100644 mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatWritePlatformServiceJpaRepositoryImpl.java delete mode 100644 mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/AccountNumberGeneratorFactory.java delete mode 100644 mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ZeroPaddedAccountNumberGenerator.java create mode 100644 mifosng-provider/src/main/resources/sql/migrations/core_db/V220__account_number_preferences.sql diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm index 16e6ab529..7ba0ba757 100644 --- a/api-docs/apiLive.htm +++ b/api-docs/apiLive.htm @@ -2014,6 +2014,22 @@ Update a Hook Delete a Hook + + Account number format + accountnumberformats + Create an Account number format + List Account number formats + + + + + + accountnumberformats/{accountnumberformatId} + + Retrieve an Account number format + Update an Account number format + Delete an Account number format + Codes codes @@ -14452,6 +14468,337 @@ GET https://DomainName/api/v1/audits + + +   +
+
+

Account number format

+

Account number preferences are used to describe custom formats for account numbers associated with Customer, Loan and Savings accounts. +

+ + + + + + + + + + + + + + + + + +
Field Descriptions
accountType
Identifies the type of the Account for which the Account number format applies
+ Refer Retrieve + Account number formats Template for complete + details +
prefixType
Identifies a custom prefix for the account number +
+ Refer Retrieve + Account number formats Template for complete + details +
+
+
+ +   +
+
+

List Account number formats

+

Example Requests:

+
accountnumberformats
+
+
+
accountnumberformats?fields=accountType,prefixType
+
+
+ +GET https://DomainName/api/v1/accountnumberformats + + +[ + { + "id": 2, + "accountType": + { + "id": 1, + "code": "accountType.client", + "value": "CLIENT" + }, + "prefixType": + { + "id": 101, + "code": "accountNumberPrefixType.clientType", + "value": "CLIENT_TYPE" + } + }, + { + "id": 3, + "accountType": + { + "id": 2, + "code": "accountType.loan", + "value": "LOAN" + }, + "prefixType": + { + "id": 201, + "code": "accountNumberPrefixType.loanProductShortName", + "value": "LOAN_PRODUCT_SHORT_NAME" + } + } +] + +
+
+ +   +
+
+

Retrieve Account number format Template

+

This is a convenience resource. It can be useful when + building maintenance user interface screens for client + applications. The template data returned consists of any or all + of: +

    +
  • Field Defaults
  • +
  • Allowed Value Lists
  • +
+

+

Example Request:

+
accountnumberformats/template
+
+
+ +GET https://DomainName/api/v1/accountnumberformats/template + + + + + { + "accountTypeOptions": + [ + { + "id": 1, + "code": "accountType.client", + "value": "CLIENT" + }, + { + "id": 2, + "code": "accountType.loan", + "value": "LOAN" + }, + { + "id": 3, + "code": "accountType.savings", + "value": "SAVINGS" + } + ], + "prefixTypeOptions": + { + "accountType.loan": + [ + { + "id": 201, + "code": "accountNumberPrefixType.loanProductShortName", + "value": "LOAN_PRODUCT_SHORT_NAME" + }, + { + "id": 1, + "code": "accountNumberPrefixType.officeName", + "value": "OFFICE_NAME" + } + ], + "accountType.client": + [ + { + "id": 1, + "code": "accountNumberPrefixType.officeName", + "value": "OFFICE_NAME" + }, + { + "id": 101, + "code": "accountNumberPrefixType.clientType", + "value": "CLIENT_TYPE" + } + ], + "accountType.savings": + [ + { + "id": 301, + "code": "accountNumberPrefixType.savingsProductShortName", + "value": "SAVINGS_PRODUCT_SHORT_NAME" + }, + { + "id": 1, + "code": "accountNumberPrefixType.officeName", + "value": "OFFICE_NAME" + } + ] + } + } + + + +
+
+ +   +
+
+

Retrieve an Account number format

+

Example Requests:

+
accountnumberformats/1
+
+
+
accountnumberformats/1?template=true
+
+
+
accountnumberformats/1?fields=accountType,prefixType
+
+
+ +GET https://DomainName/api/v1/accountnumberformats/{accountnumberformatId} + + + +{ + "id": 2, + "accountType": + { + "id": 1, + "code": "accountType.client", + "value": "CLIENT" + }, + "prefixType": + { + "id": 101, + "code": "accountNumberPrefixType.clientType", + "value": "CLIENT_TYPE" + } +} + + +
+
+ +   +
+
+

Create an Account number format

+

+ Note: You may associate a single Account number format for a given account type
+

+ + + + + + + +
Mandatory Fields + for Account number formats
accountType
+
+
+ +POST https://DomainName/api/v1/accountnumberformats + + +POST /accountnumberformats +Content-Type: application/json +Request Body: +{ + accountType :1, + prefixType: 101 +} + + +{ + "resourceId": 4 +} + + + +POST /accountnumberformats +Content-Type: application/json +Request Body: +{ + accountType :2, + prefixType: 201 +} + + +{ + "resourceId": 5 +} + +
+
+ +   +
+
+

Update an Account number format

+
+
+ +PUT https://DomainName/api/v1/accountnumberformats/{accountnumberformatId} + + +PUT accountnumberformats/2 +Content-Type: application/json +Request Body: +{ + prefixType:1 +} + + +{ + "resourceId": 2, + "changes": + { + "prefixType": "OFFICE_NAME" + } +} + + +
+
+ +   +
+
+

Delete an Account number format

+

+ Note: Account numbers created while this format was active would remain unchanged. +

+
+
+ +DELETE https://DomainName/api/v1/accountnumberformats/{accountnumberformatId} + + +DELETE accountnumberformats/2 +Content-Type: application/json +No Request Body: + + +{ + "resourceId": 2 +} + + +
+
  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 6c2f3aa4b..39a47bf19 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java @@ -5,6 +5,7 @@ */ package org.mifosplatform.commands.domain; +import org.mifosplatform.infrastructure.accountnumberformat.service.AccountNumberFormatConstants; import org.mifosplatform.portfolio.loanaccount.rescheduleloan.RescheduleLoansApiConstants; public class CommandWrapper { @@ -245,25 +246,30 @@ public class CommandWrapper { return this.entityName.equalsIgnoreCase("SMS"); } - public boolean isSmsCampaignResource(){ + public boolean isSmsCampaignResource() { return this.entityName.equals("SMS_CAMPAIGN"); } - + public boolean isLoanRescheduleResource() { - return this.entityName.equals(RescheduleLoansApiConstants.ENTITY_NAME); + return this.entityName.equals(RescheduleLoansApiConstants.ENTITY_NAME); } - + + public boolean isAccountNumberFormatResource() { + return this.entityName.equals(AccountNumberFormatConstants.ENTITY_NAME.toUpperCase()); + } + public boolean isApprove() { - return this.actionName.equalsIgnoreCase("APPROVE"); + return this.actionName.equalsIgnoreCase("APPROVE"); } - + public boolean isReject() { - return this.actionName.equalsIgnoreCase("REJECT"); + return this.actionName.equalsIgnoreCase("REJECT"); } public boolean isSmsCampaignActivation() { return this.actionName.equalsIgnoreCase("ACTIVATE") && this.entityName.equalsIgnoreCase("SMS_CAMPAIGN"); } + public boolean isSmsCampaignClosure() { return this.actionName.equalsIgnoreCase("CLOSE") && this.entityName.equalsIgnoreCase("SMS_CAMPAIGN"); } @@ -295,11 +301,11 @@ public class CommandWrapper { public boolean isJournalEntryResource() { return this.entityName.equalsIgnoreCase("JOURNALENTRY"); } - + public boolean isPeriodicAccrualResource() { return this.entityName.equalsIgnoreCase("PERIODICACCRUALACCOUNTING"); } - + public boolean isExecute() { return this.actionName.equalsIgnoreCase("EXECUTE"); } @@ -588,15 +594,15 @@ public class CommandWrapper { public boolean isAdjustSavingsAccountTransaction() { return this.actionName.equalsIgnoreCase("ADJUSTTRANSACTION") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT"); } - - public boolean isUpdateSavingsOfficer(){ - return this.actionName.equalsIgnoreCase("UPDATESAVINGSOFFICER") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT"); + + public boolean isUpdateSavingsOfficer() { + return this.actionName.equalsIgnoreCase("UPDATESAVINGSOFFICER") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT"); } - public boolean isRemoveSavingsOfficer(){ - return this.actionName.equalsIgnoreCase("REMOVESAVINGSOFFICER") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT"); + public boolean isRemoveSavingsOfficer() { + return this.actionName.equalsIgnoreCase("REMOVESAVINGSOFFICER") && this.entityName.equalsIgnoreCase("SAVINGSACCOUNT"); } - + public boolean isSavingsAccountChargeResource() { return this.entityName.equalsIgnoreCase("SAVINGSACCOUNTCHARGE"); } 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 a9c83213b..f12c2c948 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java @@ -6,6 +6,7 @@ package org.mifosplatform.commands.service; import org.mifosplatform.commands.domain.CommandWrapper; +import org.mifosplatform.infrastructure.accountnumberformat.service.AccountNumberFormatConstants; public class CommandWrapperBuilder { @@ -833,7 +834,7 @@ public class CommandWrapperBuilder { this.href = "/glclosures/" + glClosureId; return this; } - + public CommandWrapperBuilder excuteAccrualAccounting() { this.actionName = "EXECUTE"; this.entityName = "PERIODICACCRUALACCOUNTING"; @@ -1504,7 +1505,7 @@ public class CommandWrapperBuilder { this.href = "/centers/" + centerId + "?command=close"; return this; } - + public CommandWrapperBuilder associateGroupsToCenter(final Long centerId) { this.actionName = "ASSOCIATEGROUPS"; this.entityName = "CENTER"; @@ -2074,8 +2075,9 @@ public class CommandWrapperBuilder { this.entityId = entityId; return this; } + public CommandWrapperBuilder assignSavingsOfficer(final Long accountId) { - this.actionName = "UPDATESAVINGSOFFICER"; + this.actionName = "UPDATESAVINGSOFFICER"; this.entityName = "SAVINGSACCOUNT"; this.entityId = accountId; this.href = "/savingsaccounts/" + accountId + "?command=assignSavingsOfficer"; @@ -2097,20 +2099,44 @@ public class CommandWrapperBuilder { this.href = "/rescheduleloans"; return this; } - + public CommandWrapperBuilder approveLoanRescheduleRequest(final String entityName, final Long requestId) { - this.actionName = "APPROVE"; - this.entityName = entityName; - this.entityId = requestId; - this.href = "/rescheduleloans/" + requestId + "?command=approve"; - return this; + this.actionName = "APPROVE"; + this.entityName = entityName; + this.entityId = requestId; + this.href = "/rescheduleloans/" + requestId + "?command=approve"; + return this; } - + public CommandWrapperBuilder rejectLoanRescheduleRequest(final String entityName, final Long requestId) { - this.actionName = "REJECT"; - this.entityName = entityName; - this.entityId = requestId; - this.href = "/rescheduleloans/" + requestId + "?command=reject"; - return this; + this.actionName = "REJECT"; + this.entityName = entityName; + this.entityId = requestId; + this.href = "/rescheduleloans/" + requestId + "?command=reject"; + return this; + } + + public CommandWrapperBuilder createAccountNumberFormat() { + this.actionName = "CREATE"; + this.entityName = AccountNumberFormatConstants.ENTITY_NAME.toUpperCase(); + this.href = AccountNumberFormatConstants.resourceRelativeURL; + return this; + } + + public CommandWrapperBuilder updateAccountNumberFormat(final Long accountNumberFormatId) { + this.actionName = "UPDATE"; + this.entityName = AccountNumberFormatConstants.ENTITY_NAME.toUpperCase(); + this.entityId = accountNumberFormatId; + this.href = AccountNumberFormatConstants.resourceRelativeURL + "/" + accountNumberFormatId; + return this; + } + + public CommandWrapperBuilder deleteAccountNumberFormat(final Long accountNumberFormatId) { + this.actionName = "DELETE"; + this.entityName = AccountNumberFormatConstants.ENTITY_NAME.toUpperCase(); + this.entityId = accountNumberFormatId; + this.href = "AccountNumberFormatConstants.resourceRelativeURL" + "/" + accountNumberFormatId; + this.json = "{}"; + return this; } } \ No newline at end of file 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 bb146845e..ec44c6471 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java @@ -43,8 +43,7 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer public SynchronousCommandProcessingService(final PlatformSecurityContext context, final ApplicationContext applicationContext, final ToApiJsonSerializer> toApiJsonSerializer, final ToApiJsonSerializer toApiResultJsonSerializer, - final CommandSourceRepository commandSourceRepository, - final ConfigurationDomainService configurationDomainService) { + final CommandSourceRepository commandSourceRepository, final ConfigurationDomainService configurationDomainService) { this.context = context; this.context = context; this.applicationContext = applicationContext; @@ -59,7 +58,7 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer @Override public CommandProcessingResult processAndLogCommand(final CommandWrapper wrapper, final JsonCommand command, final boolean isApprovedByChecker) { - + final boolean rollbackTransaction = this.configurationDomainService.isMakerCheckerEnabledForTask(wrapper.taskPermissionName()); final NewCommandSourceHandler handler = findCommandHandler(wrapper); @@ -108,9 +107,9 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer throw new RollbackTransactionAsCommandIsNotApprovedByCheckerException(commandSourceResult); } result.setRollbackTransaction(null); - + publishEvent(wrapper.entityName(), wrapper.actionName(), result); - + return result; } @@ -512,12 +511,11 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer handler = this.applicationContext.getBean("savingsTransactionAdjustmentCommandHandler", NewCommandSourceHandler.class); } else if (wrapper.isSavingsAccountClose()) { handler = this.applicationContext.getBean("closeSavingsAccountCommandHandler", NewCommandSourceHandler.class); - }else if(wrapper.isUpdateSavingsOfficer()) { - handler = this.applicationContext.getBean("updateSavingsOfficerCommandHandler", NewCommandSourceHandler.class); - }else if(wrapper.isRemoveSavingsOfficer()) { - handler = this.applicationContext.getBean("removeSavingsOfficerCommandHandler", NewCommandSourceHandler.class); - } - else { + } else if (wrapper.isUpdateSavingsOfficer()) { + handler = this.applicationContext.getBean("updateSavingsOfficerCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isRemoveSavingsOfficer()) { + handler = this.applicationContext.getBean("removeSavingsOfficerCommandHandler", NewCommandSourceHandler.class); + } else { throw new UnsupportedCommandException(wrapper.commandName()); } } else if (wrapper.isSavingsAccountChargeResource()) { @@ -847,16 +845,26 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer } else { throw new UnsupportedCommandException(wrapper.commandName()); } - } else if (wrapper.isLoanRescheduleResource()) { - if (wrapper.isCreate()) { - handler = this.applicationContext.getBean("createLoanRescheduleRequestCommandHandler", NewCommandSourceHandler.class); - } else if(wrapper.isApprove()) { - handler = this.applicationContext.getBean("approveLoanRescheduleRequestCommandHandler", NewCommandSourceHandler.class); - } else if(wrapper.isReject()) { - handler = this.applicationContext.getBean("rejectLoanRescheduleRequestCommandHandler", NewCommandSourceHandler.class); - } else { - throw new UnsupportedCommandException(wrapper.commandName()); - } + } else if (wrapper.isLoanRescheduleResource()) { + if (wrapper.isCreate()) { + handler = this.applicationContext.getBean("createLoanRescheduleRequestCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isApprove()) { + handler = this.applicationContext.getBean("approveLoanRescheduleRequestCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isReject()) { + handler = this.applicationContext.getBean("rejectLoanRescheduleRequestCommandHandler", NewCommandSourceHandler.class); + } else { + throw new UnsupportedCommandException(wrapper.commandName()); + } + } else if (wrapper.isAccountNumberFormatResource()) { + if (wrapper.isCreate()) { + handler = this.applicationContext.getBean("createAccountNumberFormatCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isUpdate()) { + handler = this.applicationContext.getBean("updateAccountNumberFormatCommandHandler", NewCommandSourceHandler.class); + } else if (wrapper.isDelete()) { + handler = this.applicationContext.getBean("deleteAccountNumberFormatCommandHandler", NewCommandSourceHandler.class); + } else { + throw new UnsupportedCommandException(wrapper.commandName()); + } } else { throw new UnsupportedCommandException(wrapper.commandName()); @@ -871,20 +879,19 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer user.validateHasPermissionTo(commandWrapper.getTaskPermissionName()); return rollbackTransaction; } - + private void publishEvent(final String entityName, final String actionName, final CommandProcessingResult result) { - - final String authToken = ThreadLocalContextUtil.getAuthToken(); - final String tenantIdentifier = ThreadLocalContextUtil.getTenant().getTenantIdentifier(); - final AppUser appUser = this.context.authenticatedUser(); - - final HookEventSource hookEventSource = new HookEventSource(entityName, actionName); - - final String serializedResult = this.toApiResultJsonSerializer.serialize(result); - - final HookEvent applicationEvent = - new HookEvent(hookEventSource, serializedResult, tenantIdentifier, appUser, authToken); - - applicationContext.publishEvent(applicationEvent); + + final String authToken = ThreadLocalContextUtil.getAuthToken(); + final String tenantIdentifier = ThreadLocalContextUtil.getTenant().getTenantIdentifier(); + final AppUser appUser = this.context.authenticatedUser(); + + final HookEventSource hookEventSource = new HookEventSource(entityName, actionName); + + final String serializedResult = this.toApiResultJsonSerializer.serialize(result); + + final HookEvent applicationEvent = new HookEvent(hookEventSource, serializedResult, tenantIdentifier, appUser, authToken); + + applicationContext.publishEvent(applicationEvent); } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/api/AccountNumberFormatsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/api/AccountNumberFormatsApiResource.java new file mode 100644 index 000000000..5a0500ccc --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/api/AccountNumberFormatsApiResource.java @@ -0,0 +1,156 @@ +package org.mifosplatform.infrastructure.accountnumberformat.api; + +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.UriInfo; + +import org.mifosplatform.commands.domain.CommandWrapper; +import org.mifosplatform.commands.service.CommandWrapperBuilder; +import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService; +import org.mifosplatform.infrastructure.accountnumberformat.data.AccountNumberFormatData; +import org.mifosplatform.infrastructure.accountnumberformat.domain.EntityAccountType; +import org.mifosplatform.infrastructure.accountnumberformat.service.AccountNumberFormatConstants; +import org.mifosplatform.infrastructure.accountnumberformat.service.AccountNumberFormatReadPlatformService; +import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; +import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; +import org.mifosplatform.infrastructure.core.serialization.ToApiJsonSerializer; +import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +@Path(AccountNumberFormatConstants.resourceRelativeURL) +@Component +@Scope("singleton") +public class AccountNumberFormatsApiResource { + + private final PlatformSecurityContext context; + private final AccountNumberFormatReadPlatformService accountNumberFormatReadPlatformService; + private final ToApiJsonSerializer toApiJsonSerializer; + private final ApiRequestParameterHelper apiRequestParameterHelper; + private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; + + @Autowired + public AccountNumberFormatsApiResource(final PlatformSecurityContext context, + final ToApiJsonSerializer toApiJsonSerializer, + final AccountNumberFormatReadPlatformService accountNumberFormatReadPlatformService, + final ApiRequestParameterHelper apiRequestParameterHelper, + final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) { + this.context = context; + this.accountNumberFormatReadPlatformService = accountNumberFormatReadPlatformService; + this.apiRequestParameterHelper = apiRequestParameterHelper; + this.commandsSourceWritePlatformService = commandsSourceWritePlatformService; + this.toApiJsonSerializer = toApiJsonSerializer; + } + + @GET + @Path("template") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveTemplate(@Context final UriInfo uriInfo) { + + this.context.authenticatedUser().validateHasReadPermission(AccountNumberFormatConstants.ENTITY_NAME); + + EntityAccountType accountType = null; + AccountNumberFormatData accountNumberFormatData = this.accountNumberFormatReadPlatformService.retrieveTemplate(accountType); + + final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); + return this.toApiJsonSerializer.serialize(settings, accountNumberFormatData, + AccountNumberFormatConstants.ACCOUNT_NUMBER_FORMAT_RESPONSE_DATA_PARAMETERS); + } + + @GET + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveAll(@Context final UriInfo uriInfo) { + + this.context.authenticatedUser().validateHasReadPermission(AccountNumberFormatConstants.ENTITY_NAME); + + final List accountNumberFormatData = this.accountNumberFormatReadPlatformService + .getAllAccountNumberFormats(); + + final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); + return this.toApiJsonSerializer.serialize(settings, accountNumberFormatData, + AccountNumberFormatConstants.ACCOUNT_NUMBER_FORMAT_RESPONSE_DATA_PARAMETERS); + } + + @GET + @Path("{accountNumberFormatId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retrieveOne(@Context final UriInfo uriInfo, @PathParam("accountNumberFormatId") final Long accountNumberFormatId) { + + this.context.authenticatedUser().validateHasReadPermission(AccountNumberFormatConstants.ENTITY_NAME); + + final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); + + AccountNumberFormatData accountNumberFormatData = this.accountNumberFormatReadPlatformService + .getAccountNumberFormat(accountNumberFormatId); + if (settings.isTemplate()) { + final AccountNumberFormatData templateData = this.accountNumberFormatReadPlatformService.retrieveTemplate(EntityAccountType + .fromInt(accountNumberFormatData.getAccountType().getId().intValue())); + accountNumberFormatData.templateOnTop(templateData.getAccountTypeOptions(), templateData.getPrefixTypeOptions()); + } + + return this.toApiJsonSerializer.serialize(settings, accountNumberFormatData, + AccountNumberFormatConstants.ACCOUNT_NUMBER_FORMAT_RESPONSE_DATA_PARAMETERS); + } + + @POST + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String create(final String apiRequestBodyAsJson) { + + final CommandWrapper commandRequest = new CommandWrapperBuilder() // + .createAccountNumberFormat() // + .withJson(apiRequestBodyAsJson) // + .build(); // + + final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); + + return this.toApiJsonSerializer.serialize(result); + } + + @PUT + @Path("{accountNumberFormatId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String update(@PathParam("accountNumberFormatId") final Long accountNumberFormatId, final String apiRequestBodyAsJson) { + + final CommandWrapper commandRequest = new CommandWrapperBuilder() // + .updateAccountNumberFormat(accountNumberFormatId) // + .withJson(apiRequestBodyAsJson) // + .build(); // + + final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); + + return this.toApiJsonSerializer.serialize(result); + } + + @DELETE + @Path("{accountNumberFormatId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String delete(@PathParam("accountNumberFormatId") final Long accountNumberFormatId) { + + final CommandWrapper commandRequest = new CommandWrapperBuilder() // + .deleteAccountNumberFormat(accountNumberFormatId) // + .build(); // + + final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); + + return this.toApiJsonSerializer.serialize(result); + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/data/AccountNumberFormatData.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/data/AccountNumberFormatData.java new file mode 100644 index 000000000..2fdad3dd9 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/data/AccountNumberFormatData.java @@ -0,0 +1,62 @@ +package org.mifosplatform.infrastructure.accountnumberformat.data; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +import org.mifosplatform.infrastructure.core.data.EnumOptionData; + +public class AccountNumberFormatData implements Serializable { + + private final Long id; + + private final EnumOptionData accountType; + private final EnumOptionData prefixType; + + // template options + private List accountTypeOptions; + private Map> prefixTypeOptions; + + public AccountNumberFormatData(final Long id, final EnumOptionData accountType, final EnumOptionData prefixType) { + this(id, accountType, prefixType, null, null); + } + + public AccountNumberFormatData(final List accountTypeOptions, Map> prefixTypeOptions) { + this(null, null, null, accountTypeOptions, prefixTypeOptions); + } + + public void templateOnTop(List accountTypeOptions, Map> prefixTypeOptions) { + this.accountTypeOptions = accountTypeOptions; + this.prefixTypeOptions = prefixTypeOptions; + } + + private AccountNumberFormatData(final Long id, final EnumOptionData accountType, final EnumOptionData prefixType, + final List accountTypeOptions, Map> prefixTypeOptions) { + this.id = id; + this.accountType = accountType; + this.prefixType = prefixType; + this.accountTypeOptions = accountTypeOptions; + this.prefixTypeOptions = prefixTypeOptions; + } + + public Long getId() { + return this.id; + } + + public EnumOptionData getAccountType() { + return this.accountType; + } + + public EnumOptionData getPrefixType() { + return this.prefixType; + } + + public List getAccountTypeOptions() { + return this.accountTypeOptions; + } + + public Map> getPrefixTypeOptions() { + return this.prefixTypeOptions; + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/data/AccountNumberFormatDataValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/data/AccountNumberFormatDataValidator.java new file mode 100644 index 000000000..5eb7871a8 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/data/AccountNumberFormatDataValidator.java @@ -0,0 +1,148 @@ +package org.mifosplatform.infrastructure.accountnumberformat.data; + +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang.StringUtils; +import org.mifosplatform.infrastructure.accountnumberformat.domain.AccountNumberFormatEnumerations; +import org.mifosplatform.infrastructure.accountnumberformat.domain.AccountNumberFormatEnumerations.AccountNumberPrefixType; +import org.mifosplatform.infrastructure.accountnumberformat.domain.EntityAccountType; +import org.mifosplatform.infrastructure.accountnumberformat.service.AccountNumberFormatConstants; +import org.mifosplatform.infrastructure.core.data.ApiParameterError; +import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; +import org.mifosplatform.infrastructure.core.exception.InvalidJsonException; +import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; +import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import com.google.gson.JsonElement; +import com.google.gson.reflect.TypeToken; + +@Component +public class AccountNumberFormatDataValidator { + + private final FromJsonHelper fromApiJsonHelper; + + @Autowired + public AccountNumberFormatDataValidator(final FromJsonHelper fromApiJsonHelper) { + this.fromApiJsonHelper = fromApiJsonHelper; + } + + public void validateForCreate(final String json) { + + if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } + final Type typeOfMap = new TypeToken>() {}.getType(); + this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, + AccountNumberFormatConstants.ACCOUNT_NUMBER_FORMAT_CREATE_REQUEST_DATA_PARAMETERS); + final JsonElement element = this.fromApiJsonHelper.parse(json); + final List dataValidationErrors = new ArrayList<>(); + + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) + .resource(AccountNumberFormatConstants.ENTITY_NAME); + + final Integer accountType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed(AccountNumberFormatConstants.accountTypeParamName, + element); + baseDataValidator.reset().parameter(AccountNumberFormatConstants.accountTypeParamName).value(accountType).notNull() + .integerGreaterThanZero().inMinMaxRange(EntityAccountType.getMinValue(), EntityAccountType.getMaxValue()); + + if (this.fromApiJsonHelper.parameterExists(AccountNumberFormatConstants.prefixTypeParamName, element)) { + final Integer prefixType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed( + AccountNumberFormatConstants.prefixTypeParamName, element); + DataValidatorBuilder dataValidatorForValidatingPrefixType = baseDataValidator.reset() + .parameter(AccountNumberFormatConstants.prefixTypeParamName).value(prefixType).notNull().integerGreaterThanZero(); + + /** + * Permitted values for prefix type vary based on the actual + * selected accountType, carry out this validation only if data + * validation errors do not exist for both entity type and prefix + * type + **/ + boolean areAccountTypeAndPrefixTypeValid = true; + for (ApiParameterError apiParameterError : dataValidationErrors) { + if (apiParameterError.getParameterName().equalsIgnoreCase(AccountNumberFormatConstants.accountTypeParamName) + || apiParameterError.getParameterName().equalsIgnoreCase(AccountNumberFormatConstants.prefixTypeParamName)) { + areAccountTypeAndPrefixTypeValid = false; + } + } + + if (areAccountTypeAndPrefixTypeValid) { + EntityAccountType entityAccountType = EntityAccountType.fromInt(accountType); + Set validAccountNumberPrefixes = determineValidAccountNumberPrefixes(entityAccountType); + dataValidatorForValidatingPrefixType.isOneOfTheseValues(validAccountNumberPrefixes.toArray()); + } + } + + throwExceptionIfValidationWarningsExist(dataValidationErrors); + + } + + public Set determineValidAccountNumberPrefixes(EntityAccountType entityAccountType) { + Set validAccountNumberPrefixes = new HashSet<>(); + + switch (entityAccountType) { + case CLIENT: + validAccountNumberPrefixes = AccountNumberFormatEnumerations.accountNumberPrefixesForClientAccounts; + break; + + case LOAN: + validAccountNumberPrefixes = AccountNumberFormatEnumerations.accountNumberPrefixesForLoanAccounts; + break; + + case SAVINGS: + validAccountNumberPrefixes = AccountNumberFormatEnumerations.accountNumberPrefixesForSavingsAccounts; + break; + + } + + Set validAccountNumberPrefixValues = new HashSet<>(); + for (AccountNumberPrefixType validAccountNumberPrefix : validAccountNumberPrefixes) { + validAccountNumberPrefixValues.add(validAccountNumberPrefix.getValue()); + } + return validAccountNumberPrefixValues; + } + + public void validateForUpdate(final String json, EntityAccountType entityAccountType) { + + if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); } + + final Type typeOfMap = new TypeToken>() {}.getType(); + this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, + AccountNumberFormatConstants.ACCOUNT_NUMBER_FORMAT_UPDATE_REQUEST_DATA_PARAMETERS); + final JsonElement element = this.fromApiJsonHelper.parse(json); + + final List dataValidationErrors = new ArrayList<>(); + + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) + .resource(AccountNumberFormatConstants.ENTITY_NAME); + + boolean atLeastOneParameterPassedForUpdate = false; + if (this.fromApiJsonHelper.parameterExists(AccountNumberFormatConstants.prefixTypeParamName, element)) { + atLeastOneParameterPassedForUpdate = true; + Set validAccountNumberPrefixes = determineValidAccountNumberPrefixes(entityAccountType); + final Integer prefixType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed( + AccountNumberFormatConstants.prefixTypeParamName, element); + baseDataValidator.reset().parameter(AccountNumberFormatConstants.prefixTypeParamName).value(prefixType).notNull() + .integerGreaterThanZero().isOneOfTheseValues(validAccountNumberPrefixes.toArray()); + } + + if (!atLeastOneParameterPassedForUpdate) { + final Object forceError = null; + baseDataValidator.reset().anyOfNotNull(forceError); + } + + throwExceptionIfValidationWarningsExist(dataValidationErrors); + + } + + private void throwExceptionIfValidationWarningsExist(final List dataValidationErrors) { + if (!dataValidationErrors.isEmpty()) { + // + throw new PlatformApiDataValidationException(dataValidationErrors); + } + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/domain/AccountNumberFormat.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/domain/AccountNumberFormat.java new file mode 100644 index 000000000..65fda13c6 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/domain/AccountNumberFormat.java @@ -0,0 +1,65 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.infrastructure.accountnumberformat.domain; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; +import javax.persistence.UniqueConstraint; + +import org.mifosplatform.infrastructure.accountnumberformat.domain.AccountNumberFormatEnumerations.AccountNumberPrefixType; +import org.mifosplatform.infrastructure.accountnumberformat.service.AccountNumberFormatConstants; +import org.springframework.data.jpa.domain.AbstractPersistable; + +@Entity +@Table(name = AccountNumberFormatConstants.ACCOUNT_NUMBER_FORMAT_TABLE_NAME, uniqueConstraints = { @UniqueConstraint(columnNames = { AccountNumberFormatConstants.ACCOUNT_TYPE_ENUM_COLUMN_NAME }, name = AccountNumberFormatConstants.ACCOUNT_TYPE_UNIQUE_CONSTRAINT_NAME) }) +public class AccountNumberFormat extends AbstractPersistable { + + @Column(name = AccountNumberFormatConstants.ACCOUNT_TYPE_ENUM_COLUMN_NAME, nullable = false) + private Integer accountTypeEnum; + + @Column(name = AccountNumberFormatConstants.PREFIX_TYPE_ENUM_COLUMN_NAME, nullable = false) + private Integer prefixEnum; + + protected AccountNumberFormat() { + // + } + + public AccountNumberFormat(EntityAccountType entityAccountType, AccountNumberPrefixType prefixType) { + this.accountTypeEnum = entityAccountType.getValue(); + if (prefixType != null) { + this.prefixEnum = prefixType.getValue(); + } + } + + public Integer getAccountTypeEnum() { + return this.accountTypeEnum; + } + + public EntityAccountType getAccountType() { + return EntityAccountType.fromInt(this.accountTypeEnum); + } + + private void setAccountTypeEnum(Integer accountTypeEnum) { + this.accountTypeEnum = accountTypeEnum; + } + + public void setAccountType(EntityAccountType entityAccountType) { + setAccountTypeEnum(entityAccountType.getValue()); + } + + public Integer getPrefixEnum() { + return this.prefixEnum; + } + + private void setPrefixEnum(Integer prefixEnum) { + this.prefixEnum = prefixEnum; + } + + public void setPrefix(AccountNumberPrefixType accountNumberPrefixType) { + setPrefixEnum(accountNumberPrefixType.getValue()); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/domain/AccountNumberFormatEnumerations.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/domain/AccountNumberFormatEnumerations.java new file mode 100644 index 000000000..0e51a3752 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/domain/AccountNumberFormatEnumerations.java @@ -0,0 +1,124 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.infrastructure.accountnumberformat.domain; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.mifosplatform.infrastructure.core.data.EnumOptionData; + +public class AccountNumberFormatEnumerations { + + public final static Set accountNumberPrefixesForClientAccounts = new HashSet<>(Arrays.asList( + AccountNumberPrefixType.OFFICE_NAME, AccountNumberPrefixType.CLIENT_TYPE)); + public final static Set accountNumberPrefixesForLoanAccounts = new HashSet<>(Arrays.asList( + AccountNumberPrefixType.OFFICE_NAME, AccountNumberPrefixType.LOAN_PRODUCT_SHORT_NAME)); + public final static Set accountNumberPrefixesForSavingsAccounts = new HashSet<>(Arrays.asList( + AccountNumberPrefixType.OFFICE_NAME, AccountNumberPrefixType.SAVINGS_PRODUCT_SHORT_NAME)); + + public enum AccountNumberPrefixType { + OFFICE_NAME(1, "accountNumberPrefixType.officeName"), CLIENT_TYPE(101, "accountNumberPrefixType.clientType"), LOAN_PRODUCT_SHORT_NAME( + 201, "accountNumberPrefixType.loanProductShortName"), SAVINGS_PRODUCT_SHORT_NAME(301, + "accountNumberPrefixType.savingsProductShortName"); + + private final Integer value; + private final String code; + + private AccountNumberPrefixType(final Integer value, final String code) { + this.value = value; + this.code = code; + } + + public Integer getValue() { + return this.value; + } + + public String getCode() { + return this.code; + } + + private static final Map intToEnumMap = new HashMap<>(); + private static int minValue; + private static int maxValue; + static { + int i = 0; + for (final AccountNumberPrefixType type : AccountNumberPrefixType.values()) { + if (i == 0) { + minValue = type.value; + } + intToEnumMap.put(type.value, type); + if (minValue >= type.value) { + minValue = type.value; + } + if (maxValue < type.value) { + maxValue = type.value; + } + i = i + 1; + } + } + + public static AccountNumberPrefixType fromInt(final int i) { + final AccountNumberPrefixType type = intToEnumMap.get(Integer.valueOf(i)); + return type; + } + + public static int getMinValue() { + return minValue; + } + + public static int getMaxValue() { + return maxValue; + } + + } + + public static EnumOptionData entityAccountType(final Integer accountTypeId) { + return AccountNumberFormatEnumerations.entityAccountType(EntityAccountType.fromInt(accountTypeId)); + } + + public static List entityAccountType(final EntityAccountType[] entityAccountTypes) { + final List optionDatas = new ArrayList<>(); + for (final EntityAccountType accountType : entityAccountTypes) { + optionDatas.add(entityAccountType(accountType)); + } + return optionDatas; + } + + public static EnumOptionData entityAccountType(final EntityAccountType accountType) { + final EnumOptionData optionData = new EnumOptionData(accountType.getValue().longValue(), accountType.getCode(), + accountType.toString()); + return optionData; + } + + public static EnumOptionData accountNumberPrefixType(final Integer accountNumberPrefixTypeId) { + return AccountNumberFormatEnumerations.entityAccountType(AccountNumberPrefixType.fromInt(accountNumberPrefixTypeId)); + } + + public static List accountNumberPrefixType(final AccountNumberPrefixType[] accountNumberPrefixTypes) { + final List optionDatas = new ArrayList<>(); + for (final AccountNumberPrefixType accountNumberPrefixType : accountNumberPrefixTypes) { + optionDatas.add(entityAccountType(accountNumberPrefixType)); + } + return optionDatas; + } + + public static EnumOptionData entityAccountType(final AccountNumberPrefixType accountNumberPrefixType) { + final EnumOptionData optionData = new EnumOptionData(accountNumberPrefixType.getValue().longValue(), + accountNumberPrefixType.getCode(), accountNumberPrefixType.toString()); + return optionData; + } + + public static List accountNumberPrefixType(Object[] array) { + AccountNumberPrefixType[] accountNumberPrefixTypes = Arrays.copyOf(array, array.length, AccountNumberPrefixType[].class); + return accountNumberPrefixType(accountNumberPrefixTypes); + } + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/domain/AccountNumberFormatRepository.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/domain/AccountNumberFormatRepository.java new file mode 100644 index 000000000..c91421893 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/domain/AccountNumberFormatRepository.java @@ -0,0 +1,20 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.infrastructure.accountnumberformat.domain; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +public interface AccountNumberFormatRepository extends JpaRepository, + JpaSpecificationExecutor { + + public static final String FIND_ACCOUNT_NUMBER_FORMAT_FOR_ENTITY = "from AccountNumberFormat anf where anf.accountTypeEnum = :accountTypeEnum"; + + @Query(FIND_ACCOUNT_NUMBER_FORMAT_FOR_ENTITY) + AccountNumberFormat findOneByAccountTypeEnum(@Param("accountTypeEnum") Integer accountTypeEnum); +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/domain/AccountNumberFormatRepositoryWrapper.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/domain/AccountNumberFormatRepositoryWrapper.java new file mode 100644 index 000000000..2ba63e7fa --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/domain/AccountNumberFormatRepositoryWrapper.java @@ -0,0 +1,38 @@ +package org.mifosplatform.infrastructure.accountnumberformat.domain; + +import org.mifosplatform.infrastructure.accountnumberformat.exception.AccountNumberFormatNotFoundException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +@Repository +public class AccountNumberFormatRepositoryWrapper { + + private final AccountNumberFormatRepository repository; + + @Autowired + public AccountNumberFormatRepositoryWrapper(final AccountNumberFormatRepository repository) { + this.repository = repository; + } + + public AccountNumberFormat findOneWithNotFoundDetection(final Long id) { + final AccountNumberFormat accountNumberFormat = this.repository.findOne(id); + if (accountNumberFormat == null) { throw new AccountNumberFormatNotFoundException(id); } + return accountNumberFormat; + } + + public void save(final AccountNumberFormat accountNumberFormat) { + this.repository.save(accountNumberFormat); + } + + public void saveAndFlush(final AccountNumberFormat accountNumberFormat) { + this.repository.saveAndFlush(accountNumberFormat); + } + + public void delete(final AccountNumberFormat accountNumberFormat) { + this.repository.delete(accountNumberFormat); + } + + public AccountNumberFormat findByAccountType(final EntityAccountType entityAccountType) { + return this.repository.findOneByAccountTypeEnum(entityAccountType.getValue()); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/domain/EntityAccountType.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/domain/EntityAccountType.java new file mode 100644 index 000000000..d1744da9e --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/domain/EntityAccountType.java @@ -0,0 +1,80 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.infrastructure.accountnumberformat.domain; + +import java.util.HashMap; +import java.util.Map; + +public enum EntityAccountType { + CLIENT(1, "accountType.client"), LOAN(2, "accountType.loan"), SAVINGS(3, "accountType.savings"); + + private final Integer value; + private final String code; + + private EntityAccountType(final Integer value, final String code) { + this.value = value; + this.code = code; + } + + public Integer getValue() { + return this.value; + } + + public String getCode() { + return this.code; + } + + private static final Map intToEnumMap = new HashMap<>(); + private static int minValue; + private static int maxValue; + static { + int i = 0; + for (final EntityAccountType type : EntityAccountType.values()) { + if (i == 0) { + minValue = type.value; + } + intToEnumMap.put(type.value, type); + if (minValue >= type.value) { + minValue = type.value; + } + if (maxValue < type.value) { + maxValue = type.value; + } + i = i + 1; + } + } + + public static EntityAccountType fromInt(final int i) { + final EntityAccountType type = intToEnumMap.get(Integer.valueOf(i)); + return type; + } + + public static int getMinValue() { + return minValue; + } + + public static int getMaxValue() { + return maxValue; + } + + @Override + public String toString() { + return name().toString(); + } + + public boolean isClientAccount() { + return this.value.equals(EntityAccountType.CLIENT.getValue()); + } + + public boolean isLoanAccount() { + return this.value.equals(EntityAccountType.LOAN.getValue()); + } + + public boolean isSavingsAccount() { + return this.value.equals(EntityAccountType.SAVINGS.getValue()); + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/exception/AccountNumberFormatNotFoundException.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/exception/AccountNumberFormatNotFoundException.java new file mode 100644 index 000000000..d1db7e3e7 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/exception/AccountNumberFormatNotFoundException.java @@ -0,0 +1,21 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ +package org.mifosplatform.infrastructure.accountnumberformat.exception; + +import org.mifosplatform.infrastructure.accountnumberformat.service.AccountNumberFormatConstants; +import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceNotFoundException; + +/** + * A {@link RuntimeException} thrown when client resources are not found. + */ +public class AccountNumberFormatNotFoundException extends AbstractPlatformResourceNotFoundException { + + public AccountNumberFormatNotFoundException(final Long id) { + super(AccountNumberFormatConstants.EXCEPTION_ACCOUNT_NUMBER_FORMAT_NOT_FOUND, "AccountNumber format with identifier " + id + + " does not exist", id); + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/handler/CreateAccountNumberFormatCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/handler/CreateAccountNumberFormatCommandHandler.java new file mode 100644 index 000000000..88f79eac2 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/handler/CreateAccountNumberFormatCommandHandler.java @@ -0,0 +1,28 @@ +package org.mifosplatform.infrastructure.accountnumberformat.handler; + +import javax.transaction.Transactional; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.accountnumberformat.service.AccountNumberFormatWritePlatformService; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class CreateAccountNumberFormatCommandHandler implements NewCommandSourceHandler { + + private final AccountNumberFormatWritePlatformService accountNumberFormatWritePlatformService; + + @Autowired + public CreateAccountNumberFormatCommandHandler(final AccountNumberFormatWritePlatformService accountNumberFormatWritePlatformService) { + this.accountNumberFormatWritePlatformService = accountNumberFormatWritePlatformService; + } + + @Override + @Transactional + public CommandProcessingResult processCommand(JsonCommand command) { + return this.accountNumberFormatWritePlatformService.createAccountNumberFormat(command); + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/handler/DeleteAccountNumberFormatCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/handler/DeleteAccountNumberFormatCommandHandler.java new file mode 100644 index 000000000..696953e82 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/handler/DeleteAccountNumberFormatCommandHandler.java @@ -0,0 +1,28 @@ +package org.mifosplatform.infrastructure.accountnumberformat.handler; + +import javax.transaction.Transactional; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.accountnumberformat.service.AccountNumberFormatWritePlatformService; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class DeleteAccountNumberFormatCommandHandler implements NewCommandSourceHandler { + + private final AccountNumberFormatWritePlatformService accountNumberFormatWritePlatformService; + + @Autowired + public DeleteAccountNumberFormatCommandHandler(final AccountNumberFormatWritePlatformService accountNumberFormatWritePlatformService) { + this.accountNumberFormatWritePlatformService = accountNumberFormatWritePlatformService; + } + + @Override + @Transactional + public CommandProcessingResult processCommand(JsonCommand command) { + return this.accountNumberFormatWritePlatformService.deleteAccountNumberFormat(command.entityId()); + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/handler/UpdateAccountNumberFormatCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/handler/UpdateAccountNumberFormatCommandHandler.java new file mode 100644 index 000000000..5699d8c83 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/handler/UpdateAccountNumberFormatCommandHandler.java @@ -0,0 +1,28 @@ +package org.mifosplatform.infrastructure.accountnumberformat.handler; + +import javax.transaction.Transactional; + +import org.mifosplatform.commands.handler.NewCommandSourceHandler; +import org.mifosplatform.infrastructure.accountnumberformat.service.AccountNumberFormatWritePlatformService; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class UpdateAccountNumberFormatCommandHandler implements NewCommandSourceHandler { + + private final AccountNumberFormatWritePlatformService accountNumberFormatWritePlatformService; + + @Autowired + public UpdateAccountNumberFormatCommandHandler(final AccountNumberFormatWritePlatformService accountNumberFormatWritePlatformService) { + this.accountNumberFormatWritePlatformService = accountNumberFormatWritePlatformService; + } + + @Override + @Transactional + public CommandProcessingResult processCommand(JsonCommand command) { + return this.accountNumberFormatWritePlatformService.updateAccountNumberFormat(command.entityId(), command); + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatConstants.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatConstants.java new file mode 100644 index 000000000..4181bbaa4 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatConstants.java @@ -0,0 +1,56 @@ +package org.mifosplatform.infrastructure.accountnumberformat.service; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import org.mifosplatform.infrastructure.accountnumberformat.data.AccountNumberFormatData; + +public class AccountNumberFormatConstants { + + // resource name for validation + public static final String ENTITY_NAME = "accountNumberFormat"; + + // general + public static final String localeParamName = "locale"; + public static final String dateFormatParamName = "dateFormat"; + + // REST end point + public static final String resourceRelativeURL = "/accountnumberformats"; + + // request parameters + public static final String idParamName = "id"; + public static final String accountTypeParamName = "accountType"; + public static final String prefixTypeParamName = "prefixType"; + + // response parameters + + // associations related part of response + + // template related part of response + public static final String accountTypeOptionsParamName = "accountTypeOptions"; + public static final String prefixTypeOptionsParamName = "prefixTypeOptions"; + + public static final Set ACCOUNT_NUMBER_FORMAT_CREATE_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList( + accountTypeParamName, prefixTypeParamName)); + + public static final Set ACCOUNT_NUMBER_FORMAT_UPDATE_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(prefixTypeParamName)); + + /** + * These parameters will match the class level parameters of + * {@link AccountNumberFormatData}. Where possible, we try to get response + * parameters to match those of request parameters. + */ + public static final Set ACCOUNT_NUMBER_FORMAT_RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(idParamName, + accountTypeParamName, prefixTypeParamName, accountTypeOptionsParamName, prefixTypeOptionsParamName)); + + // Error messages codes + public static final String EXCEPTION_DUPLICATE_ACCOUNT_TYPE = "error.msg.account.number.format.duplicate.account.type"; + public static final String EXCEPTION_ACCOUNT_NUMBER_FORMAT_NOT_FOUND = "error.msg.account.number.format.id.invalid"; + // JPA related constants + public static final String ACCOUNT_NUMBER_FORMAT_TABLE_NAME = "c_account_number_format"; + public static final String ACCOUNT_TYPE_ENUM_COLUMN_NAME = "account_type_enum"; + public static final String PREFIX_TYPE_ENUM_COLUMN_NAME = "prefix_type_enum"; + public static final String ACCOUNT_TYPE_UNIQUE_CONSTRAINT_NAME = "account_type_enum"; + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatReadPlatformService.java new file mode 100644 index 000000000..51ce8378b --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatReadPlatformService.java @@ -0,0 +1,16 @@ +package org.mifosplatform.infrastructure.accountnumberformat.service; + +import java.util.List; + +import org.mifosplatform.infrastructure.accountnumberformat.data.AccountNumberFormatData; +import org.mifosplatform.infrastructure.accountnumberformat.domain.EntityAccountType; + +public interface AccountNumberFormatReadPlatformService { + + List getAllAccountNumberFormats(); + + AccountNumberFormatData getAccountNumberFormat(Long id); + + AccountNumberFormatData retrieveTemplate(EntityAccountType entityAccountTypeForTemplate); + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatReadPlatformServiceImpl.java new file mode 100644 index 000000000..f4cc66dda --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatReadPlatformServiceImpl.java @@ -0,0 +1,133 @@ +package org.mifosplatform.infrastructure.accountnumberformat.service; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.mifosplatform.infrastructure.accountnumberformat.data.AccountNumberFormatData; +import org.mifosplatform.infrastructure.accountnumberformat.domain.AccountNumberFormatEnumerations; +import org.mifosplatform.infrastructure.accountnumberformat.domain.AccountNumberFormatEnumerations.AccountNumberPrefixType; +import org.mifosplatform.infrastructure.accountnumberformat.domain.EntityAccountType; +import org.mifosplatform.infrastructure.accountnumberformat.exception.AccountNumberFormatNotFoundException; +import org.mifosplatform.infrastructure.core.data.EnumOptionData; +import org.mifosplatform.infrastructure.core.domain.JdbcSupport; +import org.mifosplatform.infrastructure.core.service.RoutingDataSource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Service; + +@Service +public class AccountNumberFormatReadPlatformServiceImpl implements AccountNumberFormatReadPlatformService { + + private final JdbcTemplate jdbcTemplate; + + // data mapper + private final AccountNumberFormatMapper accountNumberFormatMapper = new AccountNumberFormatMapper(); + + @Autowired + public AccountNumberFormatReadPlatformServiceImpl(final RoutingDataSource dataSource) { + this.jdbcTemplate = new JdbcTemplate(dataSource); + } + + private static final class AccountNumberFormatMapper implements RowMapper { + + private final String schema; + + public AccountNumberFormatMapper() { + final StringBuilder builder = new StringBuilder(400); + + builder.append(" anf.id as id, anf.account_type_enum as accountTypeEnum, anf.prefix_type_enum as prefixTypeEnum"); + builder.append(" from c_account_number_format anf "); + + this.schema = builder.toString(); + } + + public String schema() { + return this.schema; + } + + @Override + public AccountNumberFormatData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + + final Long id = rs.getLong("id"); + final Integer accountTypeEnum = rs.getInt("accountTypeEnum"); + final Integer prefixTypeEnum = JdbcSupport.getInteger(rs, "prefixTypeEnum"); + + final EnumOptionData accountNumberType = AccountNumberFormatEnumerations.entityAccountType(accountTypeEnum); + EnumOptionData prefixType = null; + if (prefixTypeEnum != null) { + prefixType = AccountNumberFormatEnumerations.accountNumberPrefixType(prefixTypeEnum); + } + return new AccountNumberFormatData(id, accountNumberType, prefixType); + } + } + + @Override + public List getAllAccountNumberFormats() { + String sql = "select " + this.accountNumberFormatMapper.schema(); + return this.jdbcTemplate.query(sql, this.accountNumberFormatMapper, new Object[] {}); + } + + @Override + public AccountNumberFormatData getAccountNumberFormat(Long id) { + try { + final String sql = "select " + this.accountNumberFormatMapper.schema() + " where anf.id = ?"; + + final AccountNumberFormatData accountNumberFormatData = this.jdbcTemplate.queryForObject(sql, this.accountNumberFormatMapper, + new Object[] { id }); + return accountNumberFormatData; + } catch (final EmptyResultDataAccessException e) { + throw new AccountNumberFormatNotFoundException(id); + } + } + + @Override + public AccountNumberFormatData retrieveTemplate(EntityAccountType entityAccountTypeForTemplate) { + final List entityAccountTypeOptions = AccountNumberFormatEnumerations.entityAccountType(EntityAccountType.values()); + + Map> accountNumberPrefixTypeOptions = new HashMap<>(); + /*** + * If an Account type is passed in, return prefixes only for the passed + * in account type, else return all allowed prefixes keyed by all + * possible entity type + **/ + if (entityAccountTypeForTemplate != null) { + determinePrefixTypesForAccounts(accountNumberPrefixTypeOptions, entityAccountTypeForTemplate); + } else { + for (EntityAccountType entityAccountType : EntityAccountType.values()) { + determinePrefixTypesForAccounts(accountNumberPrefixTypeOptions, entityAccountType); + + } + } + return new AccountNumberFormatData(entityAccountTypeOptions, accountNumberPrefixTypeOptions); + } + + public void determinePrefixTypesForAccounts(Map> accountNumberPrefixTypeOptions, + EntityAccountType entityAccountType) { + Set accountNumberPrefixTypesSet = new HashSet<>(); + switch (entityAccountType) { + case CLIENT: + accountNumberPrefixTypesSet = AccountNumberFormatEnumerations.accountNumberPrefixesForClientAccounts; + break; + case LOAN: + accountNumberPrefixTypesSet = AccountNumberFormatEnumerations.accountNumberPrefixesForLoanAccounts; + break; + case SAVINGS: + accountNumberPrefixTypesSet = AccountNumberFormatEnumerations.accountNumberPrefixesForSavingsAccounts; + break; + } + + Object[] array = accountNumberPrefixTypesSet.toArray(); + AccountNumberPrefixType[] accountNumberPrefixTypes = Arrays.copyOf(array, array.length, AccountNumberPrefixType[].class); + + accountNumberPrefixTypeOptions.put(entityAccountType.getCode(), + AccountNumberFormatEnumerations.accountNumberPrefixType(accountNumberPrefixTypes)); + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatWritePlatformService.java new file mode 100644 index 000000000..814ca2040 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatWritePlatformService.java @@ -0,0 +1,14 @@ +package org.mifosplatform.infrastructure.accountnumberformat.service; + +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; + +public interface AccountNumberFormatWritePlatformService { + + CommandProcessingResult createAccountNumberFormat(JsonCommand command); + + CommandProcessingResult updateAccountNumberFormat(Long accountNumberFormatId, JsonCommand command); + + CommandProcessingResult deleteAccountNumberFormat(Long accountNumberFormatId); + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatWritePlatformServiceJpaRepositoryImpl.java new file mode 100644 index 000000000..3631b8590 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatWritePlatformServiceJpaRepositoryImpl.java @@ -0,0 +1,131 @@ +package org.mifosplatform.infrastructure.accountnumberformat.service; + +import java.util.LinkedHashMap; +import java.util.Map; + +import javax.transaction.Transactional; + +import org.mifosplatform.infrastructure.accountnumberformat.data.AccountNumberFormatDataValidator; +import org.mifosplatform.infrastructure.accountnumberformat.domain.AccountNumberFormat; +import org.mifosplatform.infrastructure.accountnumberformat.domain.AccountNumberFormatEnumerations.AccountNumberPrefixType; +import org.mifosplatform.infrastructure.accountnumberformat.domain.AccountNumberFormatRepositoryWrapper; +import org.mifosplatform.infrastructure.accountnumberformat.domain.EntityAccountType; +import org.mifosplatform.infrastructure.core.api.JsonCommand; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; +import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder; +import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.stereotype.Service; + +@Service +public class AccountNumberFormatWritePlatformServiceJpaRepositoryImpl implements AccountNumberFormatWritePlatformService { + + private final static Logger logger = LoggerFactory.getLogger(AccountNumberFormatWritePlatformServiceJpaRepositoryImpl.class); + private final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository; + private final AccountNumberFormatDataValidator accountNumberFormatDataValidator; + + @Autowired + AccountNumberFormatWritePlatformServiceJpaRepositoryImpl(final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository, + final AccountNumberFormatDataValidator accountNumberFormatDataValidator) { + this.accountNumberFormatRepository = accountNumberFormatRepository; + this.accountNumberFormatDataValidator = accountNumberFormatDataValidator; + } + + @Override + @Transactional + public CommandProcessingResult createAccountNumberFormat(JsonCommand command) { + try { + this.accountNumberFormatDataValidator.validateForCreate(command.json()); + + final Integer accountTypeId = command.integerValueSansLocaleOfParameterNamed(AccountNumberFormatConstants.accountTypeParamName); + final EntityAccountType entityAccountType = EntityAccountType.fromInt(accountTypeId); + + final Integer prefixTypeId = command.integerValueSansLocaleOfParameterNamed(AccountNumberFormatConstants.prefixTypeParamName); + AccountNumberPrefixType accountNumberPrefixType = null; + if (prefixTypeId != null) { + accountNumberPrefixType = AccountNumberPrefixType.fromInt(prefixTypeId); + } + + AccountNumberFormat accountNumberFormat = new AccountNumberFormat(entityAccountType, accountNumberPrefixType); + + this.accountNumberFormatRepository.save(accountNumberFormat); + + return new CommandProcessingResultBuilder() // + .withEntityId(accountNumberFormat.getId()) // + .build(); + } catch (final DataIntegrityViolationException dve) { + handleDataIntegrityIssues(command, dve); + return CommandProcessingResult.empty(); + } + } + + @Override + @Transactional + public CommandProcessingResult updateAccountNumberFormat(Long accountNumberFormatId, JsonCommand command) { + try { + + final AccountNumberFormat accountNumberFormatForUpdate = this.accountNumberFormatRepository + .findOneWithNotFoundDetection(accountNumberFormatId); + EntityAccountType accountType = accountNumberFormatForUpdate.getAccountType(); + + this.accountNumberFormatDataValidator.validateForUpdate(command.json(), accountType); + + final Map actualChanges = new LinkedHashMap<>(9); + + if (command.isChangeInIntegerSansLocaleParameterNamed(AccountNumberFormatConstants.prefixTypeParamName, + accountNumberFormatForUpdate.getPrefixEnum())) { + final Integer newValue = command.integerValueSansLocaleOfParameterNamed(AccountNumberFormatConstants.prefixTypeParamName); + final AccountNumberPrefixType accountNumberPrefixType = AccountNumberPrefixType.fromInt(newValue); + actualChanges.put(AccountNumberFormatConstants.prefixTypeParamName, accountNumberPrefixType); + accountNumberFormatForUpdate.setPrefix(accountNumberPrefixType); + } + + if (!actualChanges.isEmpty()) { + this.accountNumberFormatRepository.saveAndFlush(accountNumberFormatForUpdate); + } + + return new CommandProcessingResultBuilder() // + .withCommandId(command.commandId()) // + .withEntityId(accountNumberFormatId) // + .with(actualChanges) // + .build(); + } catch (final DataIntegrityViolationException dve) { + handleDataIntegrityIssues(command, dve); + return CommandProcessingResult.empty(); + } + } + + @Override + @Transactional + public CommandProcessingResult deleteAccountNumberFormat(Long accountNumberFormatId) { + AccountNumberFormat accountNumberFormat = this.accountNumberFormatRepository.findOneWithNotFoundDetection(accountNumberFormatId); + this.accountNumberFormatRepository.delete(accountNumberFormat); + + return new CommandProcessingResultBuilder() // + .withEntityId(accountNumberFormatId) // + .build(); + } + + /* + * Guaranteed to throw an exception no matter what the data integrity issue + * is. + */ + private void handleDataIntegrityIssues(final JsonCommand command, final DataIntegrityViolationException dve) { + + final Throwable realCause = dve.getMostSpecificCause(); + if (realCause.getMessage().contains(AccountNumberFormatConstants.ACCOUNT_TYPE_UNIQUE_CONSTRAINT_NAME)) { + + final Integer accountTypeId = command.integerValueSansLocaleOfParameterNamed(AccountNumberFormatConstants.accountTypeParamName); + final EntityAccountType entityAccountType = EntityAccountType.fromInt(accountTypeId); + throw new PlatformDataIntegrityException(AccountNumberFormatConstants.EXCEPTION_DUPLICATE_ACCOUNT_TYPE, + "Account Format preferences for Account type `" + entityAccountType.getCode() + "` already exists", "externalId", + entityAccountType.getValue(), entityAccountType.getCode()); + } + logger.error(dve.getMessage(), dve); + throw new PlatformDataIntegrityException("error.msg.account.number.format.unknown.data.integrity.issue", + "Unknown data integrity issue with resource."); + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/AccountNumberGenerator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/AccountNumberGenerator.java index 2b46bd833..91b34cb81 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/AccountNumberGenerator.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/AccountNumberGenerator.java @@ -5,14 +5,89 @@ */ package org.mifosplatform.portfolio.client.domain; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.mifosplatform.infrastructure.accountnumberformat.domain.AccountNumberFormat; +import org.mifosplatform.infrastructure.accountnumberformat.domain.AccountNumberFormatEnumerations.AccountNumberPrefixType; +import org.mifosplatform.infrastructure.codes.domain.CodeValue; +import org.mifosplatform.portfolio.loanaccount.domain.Loan; +import org.mifosplatform.portfolio.savings.domain.SavingsAccount; +import org.springframework.stereotype.Component; + /** - * Responsible for generating unique account number based on some rules or - * patterns. - * - * @see ZeroPaddedAccountNumberGenerator + * Example {@link AccountNumberGenerator} for clients that takes an entities + * auto generated database id and zero fills it ensuring the identifier is + * always of a given maxLength. */ -public interface AccountNumberGenerator { +@Component +public class AccountNumberGenerator { - String generate(); + private final static int maxLength = 9; -} + private final static String ID = "id"; + private final static String CLIENT_TYPE = "clientType"; + private final static String OFFICE_NAME = "officeName"; + private final static String LOAN_PRODUCT_SHORT_NAME = "loanProductShortName"; + private final static String SAVINGS_PRODUCT_SHORT_NAME = "savingsProductShortName"; + + public String generate(Client client, AccountNumberFormat accountNumberFormat) { + Map propertyMap = new HashMap<>(); + propertyMap.put(ID, client.getId().toString()); + propertyMap.put(OFFICE_NAME, client.getOffice().getName()); + CodeValue clientType = client.clientType(); + if (clientType != null) { + propertyMap.put(CLIENT_TYPE, clientType.label()); + } + return generateAccountNumber(propertyMap, accountNumberFormat); + } + + public String generate(Loan loan, AccountNumberFormat accountNumberFormat) { + Map propertyMap = new HashMap<>(); + propertyMap.put(ID, loan.getId().toString()); + propertyMap.put(OFFICE_NAME, loan.getOffice().getName()); + propertyMap.put(LOAN_PRODUCT_SHORT_NAME, loan.loanProduct().getShortName()); + return generateAccountNumber(propertyMap, accountNumberFormat); + } + + public String generate(SavingsAccount savingsAccount, AccountNumberFormat accountNumberFormat) { + Map propertyMap = new HashMap<>(); + propertyMap.put(ID, savingsAccount.getId().toString()); + propertyMap.put(OFFICE_NAME, savingsAccount.office().getName()); + propertyMap.put(SAVINGS_PRODUCT_SHORT_NAME, savingsAccount.savingsProduct().getShortName()); + return generateAccountNumber(propertyMap, accountNumberFormat); + } + + private String generateAccountNumber(Map propertyMap, AccountNumberFormat accountNumberFormat) { + String accountNumber = StringUtils.leftPad(propertyMap.get(ID), this.maxLength, '0'); + if (accountNumberFormat != null && accountNumberFormat.getPrefixEnum() != null) { + AccountNumberPrefixType accountNumberPrefixType = AccountNumberPrefixType.fromInt(accountNumberFormat.getPrefixEnum()); + String prefix = null; + switch (accountNumberPrefixType) { + case CLIENT_TYPE: + prefix = propertyMap.get(CLIENT_TYPE); + break; + + case OFFICE_NAME: + prefix = propertyMap.get(OFFICE_NAME); + break; + + case LOAN_PRODUCT_SHORT_NAME: + prefix = propertyMap.get(LOAN_PRODUCT_SHORT_NAME); + break; + + case SAVINGS_PRODUCT_SHORT_NAME: + prefix = propertyMap.get(SAVINGS_PRODUCT_SHORT_NAME); + break; + + default: + break; + + } + accountNumber = StringUtils.overlay(accountNumber, prefix, 0, 0); + } + return accountNumber; + } + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/AccountNumberGeneratorFactory.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/AccountNumberGeneratorFactory.java deleted file mode 100644 index d73ca7923..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/AccountNumberGeneratorFactory.java +++ /dev/null @@ -1,24 +0,0 @@ -/** - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - */ -package org.mifosplatform.portfolio.client.domain; - -import org.springframework.stereotype.Component; - -@Component -public class AccountNumberGeneratorFactory { - - public AccountNumberGenerator determineClientAccountNoGenerator(final Long clientId) { - return new ZeroPaddedAccountNumberGenerator(clientId, 9); - } - - public AccountNumberGenerator determineLoanAccountNoGenerator(final Long loanId) { - return new ZeroPaddedAccountNumberGenerator(loanId, 9); - } - - public AccountNumberGenerator determineSavingsAccountNoGenerator(final Long savingsAccountId) { - return new ZeroPaddedAccountNumberGenerator(savingsAccountId, 9); - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ZeroPaddedAccountNumberGenerator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ZeroPaddedAccountNumberGenerator.java deleted file mode 100644 index 9e18e0dd5..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ZeroPaddedAccountNumberGenerator.java +++ /dev/null @@ -1,27 +0,0 @@ -/** - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. - */ -package org.mifosplatform.portfolio.client.domain; - -/** - * Example {@link AccountNumberGenerator} for clients that takes an entities - * auto generated database id and zero fills it ensuring the identifier is - * always of a given maxLength. - */ -public class ZeroPaddedAccountNumberGenerator implements AccountNumberGenerator { - - private final Long id; - private final int maxLength; - - public ZeroPaddedAccountNumberGenerator(final Long id, final int maxLength) { - this.id = id; - this.maxLength = maxLength; - } - - @Override - public String generate() { - return String.format("%0" + this.maxLength + "d", this.id); - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java index cfe532718..176bc93b4 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java @@ -16,6 +16,9 @@ import org.joda.time.format.DateTimeFormatter; import org.mifosplatform.commands.domain.CommandWrapper; import org.mifosplatform.commands.service.CommandProcessingService; import org.mifosplatform.commands.service.CommandWrapperBuilder; +import org.mifosplatform.infrastructure.accountnumberformat.domain.AccountNumberFormat; +import org.mifosplatform.infrastructure.accountnumberformat.domain.AccountNumberFormatRepositoryWrapper; +import org.mifosplatform.infrastructure.accountnumberformat.domain.EntityAccountType; import org.mifosplatform.infrastructure.codes.domain.CodeValue; import org.mifosplatform.infrastructure.codes.domain.CodeValueRepositoryWrapper; import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService; @@ -32,7 +35,6 @@ import org.mifosplatform.organisation.staff.domain.StaffRepositoryWrapper; import org.mifosplatform.portfolio.client.api.ClientApiConstants; import org.mifosplatform.portfolio.client.data.ClientDataValidator; import org.mifosplatform.portfolio.client.domain.AccountNumberGenerator; -import org.mifosplatform.portfolio.client.domain.AccountNumberGeneratorFactory; import org.mifosplatform.portfolio.client.domain.Client; import org.mifosplatform.portfolio.client.domain.ClientRepositoryWrapper; import org.mifosplatform.portfolio.client.domain.ClientStatus; @@ -76,7 +78,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP private final NoteRepository noteRepository; private final GroupRepository groupRepository; private final ClientDataValidator fromApiJsonDeserializer; - private final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory; + private final AccountNumberGenerator accountNumberGenerator; private final StaffRepositoryWrapper staffRepository; private final CodeValueRepositoryWrapper codeValueRepository; private final LoanRepository loanRepository; @@ -85,22 +87,24 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP private final SavingsApplicationProcessWritePlatformService savingsApplicationProcessWritePlatformService; private final CommandProcessingService commandProcessingService; private final ConfigurationDomainService configurationDomainService; + private final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository; @Autowired public ClientWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final ClientRepositoryWrapper clientRepository, final OfficeRepository officeRepository, final NoteRepository noteRepository, - final ClientDataValidator fromApiJsonDeserializer, final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory, + final ClientDataValidator fromApiJsonDeserializer, final AccountNumberGenerator accountNumberGenerator, final GroupRepository groupRepository, final StaffRepositoryWrapper staffRepository, final CodeValueRepositoryWrapper codeValueRepository, final LoanRepository loanRepository, final SavingsAccountRepository savingsRepository, final SavingsProductRepository savingsProductRepository, final SavingsApplicationProcessWritePlatformService savingsApplicationProcessWritePlatformService, - final CommandProcessingService commandProcessingService, final ConfigurationDomainService configurationDomainService) { + final CommandProcessingService commandProcessingService, final ConfigurationDomainService configurationDomainService, + final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository) { this.context = context; this.clientRepository = clientRepository; this.officeRepository = officeRepository; this.noteRepository = noteRepository; this.fromApiJsonDeserializer = fromApiJsonDeserializer; - this.accountIdentifierGeneratorFactory = accountIdentifierGeneratorFactory; + this.accountNumberGenerator = accountNumberGenerator; this.groupRepository = groupRepository; this.staffRepository = staffRepository; this.codeValueRepository = codeValueRepository; @@ -110,6 +114,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP this.savingsApplicationProcessWritePlatformService = savingsApplicationProcessWritePlatformService; this.commandProcessingService = commandProcessingService; this.configurationDomainService = configurationDomainService; + this.accountNumberFormatRepository = accountNumberFormatRepository; } @Transactional @@ -227,9 +232,8 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP this.clientRepository.save(newClient); if (newClient.isAccountNumberRequiresAutoGeneration()) { - final AccountNumberGenerator accountNoGenerator = this.accountIdentifierGeneratorFactory - .determineClientAccountNoGenerator(newClient.getId()); - newClient.updateAccountNo(accountNoGenerator.generate()); + AccountNumberFormat accountNumberFormat = this.accountNumberFormatRepository.findByAccountType(EntityAccountType.CLIENT); + newClient.updateAccountNo(accountNumberGenerator.generate(newClient, accountNumberFormat)); this.clientRepository.save(newClient); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java index 9ab87a564..554a13f37 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanApplicationWritePlatformServiceJpaRepositoryImpl.java @@ -14,6 +14,9 @@ import java.util.Set; import org.apache.commons.lang.StringUtils; import org.joda.time.LocalDate; +import org.mifosplatform.infrastructure.accountnumberformat.domain.AccountNumberFormat; +import org.mifosplatform.infrastructure.accountnumberformat.domain.AccountNumberFormatRepositoryWrapper; +import org.mifosplatform.infrastructure.accountnumberformat.domain.EntityAccountType; import org.mifosplatform.infrastructure.codes.domain.CodeValue; import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.api.JsonQuery; @@ -39,7 +42,6 @@ import org.mifosplatform.portfolio.calendar.domain.CalendarRepository; import org.mifosplatform.portfolio.calendar.domain.CalendarType; import org.mifosplatform.portfolio.calendar.exception.CalendarNotFoundException; import org.mifosplatform.portfolio.client.domain.AccountNumberGenerator; -import org.mifosplatform.portfolio.client.domain.AccountNumberGeneratorFactory; import org.mifosplatform.portfolio.client.domain.Client; import org.mifosplatform.portfolio.client.domain.ClientRepositoryWrapper; import org.mifosplatform.portfolio.client.exception.ClientNotActiveException; @@ -114,7 +116,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa private final LoanChargeAssembler loanChargeAssembler; private final CollateralAssembler loanCollateralAssembler; private final AprCalculator aprCalculator; - private final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory; + private final AccountNumberGenerator accountNumberGenerator; private final LoanSummaryWrapper loanSummaryWrapper; private final GroupRepositoryWrapper groupRepository; private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory; @@ -125,6 +127,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa private final LoanReadPlatformService loanReadPlatformService; private final LoanRepaymentScheduleInstallmentRepository repaymentScheduleInstallmentRepository; private final LoanAccountDomainService loanAccountDomainService; + private final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository; @Autowired public LoanApplicationWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final FromJsonHelper fromJsonHelper, @@ -134,13 +137,14 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa final LoanAssembler loanAssembler, final LoanChargeAssembler loanChargeAssembler, final CollateralAssembler loanCollateralAssembler, final LoanRepository loanRepository, final NoteRepository noteRepository, final LoanScheduleCalculationPlatformService calculationPlatformService, final ClientRepositoryWrapper clientRepository, - final LoanProductRepository loanProductRepository, final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory, + final LoanProductRepository loanProductRepository, final AccountNumberGenerator accountNumberGenerator, final LoanSummaryWrapper loanSummaryWrapper, final GroupRepositoryWrapper groupRepository, final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory, final CalendarRepository calendarRepository, final CalendarInstanceRepository calendarInstanceRepository, final SavingsAccountAssembler savingsAccountAssembler, final AccountAssociationsRepository accountAssociationsRepository, final LoanRepaymentScheduleInstallmentRepository repaymentScheduleInstallmentRepository, - final LoanReadPlatformService loanReadPlatformService, final LoanAccountDomainService loanAccountDomainService) { + final LoanReadPlatformService loanReadPlatformService, final LoanAccountDomainService loanAccountDomainService, + final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository) { this.context = context; this.fromJsonHelper = fromJsonHelper; this.loanApplicationTransitionApiJsonValidator = loanApplicationTransitionApiJsonValidator; @@ -155,7 +159,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa this.calculationPlatformService = calculationPlatformService; this.clientRepository = clientRepository; this.loanProductRepository = loanProductRepository; - this.accountIdentifierGeneratorFactory = accountIdentifierGeneratorFactory; + this.accountNumberGenerator = accountNumberGenerator; this.loanSummaryWrapper = loanSummaryWrapper; this.groupRepository = groupRepository; this.loanRepaymentScheduleTransactionProcessorFactory = loanRepaymentScheduleTransactionProcessorFactory; @@ -166,6 +170,7 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa this.repaymentScheduleInstallmentRepository = repaymentScheduleInstallmentRepository; this.loanReadPlatformService = loanReadPlatformService; this.loanAccountDomainService = loanAccountDomainService; + this.accountNumberFormatRepository = accountNumberFormatRepository; } @@ -230,9 +235,9 @@ public class LoanApplicationWritePlatformServiceJpaRepositoryImpl implements Loa } if (newLoanApplication.isAccountNumberRequiresAutoGeneration()) { - final AccountNumberGenerator accountNoGenerator = this.accountIdentifierGeneratorFactory - .determineLoanAccountNoGenerator(newLoanApplication.getId()); - newLoanApplication.updateAccountNo(accountNoGenerator.generate()); + final AccountNumberFormat accountNumberFormat = this.accountNumberFormatRepository + .findByAccountType(EntityAccountType.LOAN); + newLoanApplication.updateAccountNo(this.accountNumberGenerator.generate(newLoanApplication, accountNumberFormat)); this.loanRepository.save(newLoanApplication); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProduct.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProduct.java index f996def8a..2e49759cc 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProduct.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/domain/LoanProduct.java @@ -981,8 +981,12 @@ public class LoanProduct extends AbstractPersistable { return this.holdGuaranteeFunds; } - public LoanProductGuaranteeDetails getLoanProductGuaranteeDetails() { return this.loanProductGuaranteeDetails; } + + public String getShortName() { + return this.shortName; + } + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/DepositAccountDomainServiceJpa.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/DepositAccountDomainServiceJpa.java index 1a261a271..9a5ad8543 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/DepositAccountDomainServiceJpa.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/domain/DepositAccountDomainServiceJpa.java @@ -20,6 +20,9 @@ import org.joda.time.LocalDate; import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; import org.mifosplatform.accounting.journalentry.service.JournalEntryWritePlatformService; +import org.mifosplatform.infrastructure.accountnumberformat.domain.AccountNumberFormat; +import org.mifosplatform.infrastructure.accountnumberformat.domain.AccountNumberFormatRepositoryWrapper; +import org.mifosplatform.infrastructure.accountnumberformat.domain.EntityAccountType; import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService; import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.service.DateUtils; @@ -32,7 +35,6 @@ import org.mifosplatform.portfolio.account.data.AccountTransferDTO; import org.mifosplatform.portfolio.account.domain.AccountTransferType; import org.mifosplatform.portfolio.account.service.AccountTransfersWritePlatformService; import org.mifosplatform.portfolio.client.domain.AccountNumberGenerator; -import org.mifosplatform.portfolio.client.domain.AccountNumberGeneratorFactory; import org.mifosplatform.portfolio.paymentdetail.domain.PaymentDetail; import org.mifosplatform.portfolio.savings.DepositAccountOnClosureType; import org.mifosplatform.portfolio.savings.DepositAccountType; @@ -50,28 +52,30 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi private final SavingsAccountRepositoryWrapper savingsAccountRepository; private final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepositoryWrapper; private final JournalEntryWritePlatformService journalEntryWritePlatformService; - private final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory; + private final AccountNumberGenerator accountNumberGenerator; private final DepositAccountAssembler depositAccountAssembler; private final SavingsAccountDomainService savingsAccountDomainService; private final AccountTransfersWritePlatformService accountTransfersWritePlatformService; private final ConfigurationDomainService configurationDomainService; + private final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository; @Autowired public DepositAccountDomainServiceJpa(final SavingsAccountRepositoryWrapper savingsAccountRepository, final ApplicationCurrencyRepositoryWrapper applicationCurrencyRepositoryWrapper, - final JournalEntryWritePlatformService journalEntryWritePlatformService, - final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory, final DepositAccountAssembler depositAccountAssembler, - final SavingsAccountDomainService savingsAccountDomainService, + final JournalEntryWritePlatformService journalEntryWritePlatformService, final AccountNumberGenerator accountNumberGenerator, + final DepositAccountAssembler depositAccountAssembler, final SavingsAccountDomainService savingsAccountDomainService, final AccountTransfersWritePlatformService accountTransfersWritePlatformService, - final ConfigurationDomainService configurationDomainService) { + final ConfigurationDomainService configurationDomainService, + final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository) { this.savingsAccountRepository = savingsAccountRepository; this.applicationCurrencyRepositoryWrapper = applicationCurrencyRepositoryWrapper; this.journalEntryWritePlatformService = journalEntryWritePlatformService; - this.accountIdentifierGeneratorFactory = accountIdentifierGeneratorFactory; + this.accountNumberGenerator = accountNumberGenerator; this.depositAccountAssembler = depositAccountAssembler; this.savingsAccountDomainService = savingsAccountDomainService; this.accountTransfersWritePlatformService = accountTransfersWritePlatformService; this.configurationDomainService = configurationDomainService; + this.accountNumberFormatRepository = accountNumberFormatRepository; } @Transactional @@ -104,12 +108,11 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi public SavingsAccountTransaction handleRDDeposit(final RecurringDepositAccount account, final DateTimeFormatter fmt, final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail, final boolean isRegularTransaction) { - - final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService - .isSavingsInterestPostingAtCurrentPeriodEnd(); - final Integer financialYearBeginningMonth = this.configurationDomainService - .retrieveFinancialYearBeginningMonth(); - + + final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService + .isSavingsInterestPostingAtCurrentPeriodEnd(); + final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth(); + boolean isAccountTransfer = false; final boolean isPreMatureClosure = false; final MathContext mc = MathContext.DECIMAL64; @@ -117,8 +120,7 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi transactionAmount, paymentDetail, isAccountTransfer, isRegularTransaction); account.handleScheduleInstallments(deposit); - account.updateMaturityDateAndAmount(mc, isPreMatureClosure, - isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth); + account.updateMaturityDateAndAmount(mc, isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth); account.updateOverduePayments(DateUtils.getLocalDateOfTenant()); return deposit; } @@ -127,12 +129,11 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi @Override public Long handleFDAccountClosure(final FixedDepositAccount account, final PaymentDetail paymentDetail, final AppUser user, final JsonCommand command, final LocalDate tenantsTodayDate, final Map changes) { - - final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService - .isSavingsInterestPostingAtCurrentPeriodEnd(); - final Integer financialYearBeginningMonth = this.configurationDomainService - .retrieveFinancialYearBeginningMonth(); - + + final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService + .isSavingsInterestPostingAtCurrentPeriodEnd(); + final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth(); + boolean isRegularTransaction = false; boolean isAccountTransfer = false; final boolean isPreMatureClosure = false; @@ -157,15 +158,14 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale); final LocalDate closedDate = command.localDateValueOfParameterNamed(SavingsApiConstants.closedOnDateParamName); Long savingsTransactionId = null; - account.postMaturityInterest(isSavingsInterestPostingAtCurrentPeriodEnd, - financialYearBeginningMonth); + account.postMaturityInterest(isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth); final Integer onAccountClosureId = command.integerValueOfParameterNamed(onAccountClosureIdParamName); final DepositAccountOnClosureType onClosureType = DepositAccountOnClosureType.fromInt(onAccountClosureId); if (onClosureType.isReinvest()) { FixedDepositAccount reinvestedDeposit = account.reInvest(account.getAccountBalance()); this.depositAccountAssembler.assignSavingAccountHelpers(reinvestedDeposit); reinvestedDeposit.updateMaturityDateAndAmountBeforeAccountActivation(mc, isPreMatureClosure, - isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth); + isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth); this.savingsAccountRepository.save(reinvestedDeposit); autoGenerateAccountNumber(reinvestedDeposit); final SavingsAccountTransaction withdrawal = this.handleWithdrawal(account, fmt, closedDate, account.getAccountBalance(), @@ -204,12 +204,11 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi @Override public Long handleRDAccountClosure(final RecurringDepositAccount account, final PaymentDetail paymentDetail, final AppUser user, final JsonCommand command, final LocalDate tenantsTodayDate, final Map changes) { - - final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService - .isSavingsInterestPostingAtCurrentPeriodEnd(); - final Integer financialYearBeginningMonth = this.configurationDomainService - .retrieveFinancialYearBeginningMonth(); - + + final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService + .isSavingsInterestPostingAtCurrentPeriodEnd(); + final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth(); + boolean isRegularTransaction = false; boolean isAccountTransfer = false; final boolean isPreMatureClosure = false; @@ -222,19 +221,18 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale); final LocalDate closedDate = command.localDateValueOfParameterNamed(SavingsApiConstants.closedOnDateParamName); Long savingsTransactionId = null; - account.postMaturityInterest(isSavingsInterestPostingAtCurrentPeriodEnd, - financialYearBeginningMonth); + account.postMaturityInterest(isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth); final BigDecimal transactionAmount = account.getAccountBalance(); final Integer onAccountClosureId = command.integerValueOfParameterNamed(onAccountClosureIdParamName); final DepositAccountOnClosureType onClosureType = DepositAccountOnClosureType.fromInt(onAccountClosureId); if (onClosureType.isReinvest()) { RecurringDepositAccount reinvestedDeposit = account.reInvest(transactionAmount); depositAccountAssembler.assignSavingAccountHelpers(reinvestedDeposit); - reinvestedDeposit.updateMaturityDateAndAmount(mc, isPreMatureClosure, - isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth); + reinvestedDeposit.updateMaturityDateAndAmount(mc, isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd, + financialYearBeginningMonth); reinvestedDeposit.processAccountUponActivation(fmt, user); - reinvestedDeposit.updateMaturityDateAndAmount(mc, isPreMatureClosure, - isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth); + reinvestedDeposit.updateMaturityDateAndAmount(mc, isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd, + financialYearBeginningMonth); this.savingsAccountRepository.save(reinvestedDeposit); Money amountForDeposit = reinvestedDeposit.activateWithBalance(); @@ -242,8 +240,8 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi handleRDDeposit(reinvestedDeposit, fmt, reinvestedDeposit.getActivationLocalDate(), amountForDeposit.getAmount(), paymentDetail, isRegularTransaction); } - reinvestedDeposit.updateMaturityDateAndAmount(mc, isPreMatureClosure, - isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth); + reinvestedDeposit.updateMaturityDateAndAmount(mc, isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd, + financialYearBeginningMonth); this.savingsAccountRepository.save(reinvestedDeposit); autoGenerateAccountNumber(reinvestedDeposit); @@ -283,9 +281,8 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi private void autoGenerateAccountNumber(final SavingsAccount account) { if (account.isAccountNumberRequiresAutoGeneration()) { - final AccountNumberGenerator accountNoGenerator = this.accountIdentifierGeneratorFactory - .determineSavingsAccountNoGenerator(account.getId()); - account.updateAccountNo(accountNoGenerator.generate()); + final AccountNumberFormat accountNumberFormat = this.accountNumberFormatRepository.findByAccountType(EntityAccountType.SAVINGS); + account.updateAccountNo(this.accountNumberGenerator.generate(account, accountNumberFormat)); this.savingsAccountRepository.save(account); } } @@ -294,12 +291,11 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi @Override public Long handleFDAccountPreMatureClosure(final FixedDepositAccount account, final PaymentDetail paymentDetail, final AppUser user, final JsonCommand command, final LocalDate tenantsTodayDate, final Map changes) { - - final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService - .isSavingsInterestPostingAtCurrentPeriodEnd(); - final Integer financialYearBeginningMonth = this.configurationDomainService - .retrieveFinancialYearBeginningMonth(); - + + final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService + .isSavingsInterestPostingAtCurrentPeriodEnd(); + final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth(); + boolean isAccountTransfer = false; boolean isRegularTransaction = false; final boolean isPreMatureClosure = true; @@ -312,8 +308,8 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale); Long savingsTransactionId = null; // post interest - account.postPreMaturityInterest(closedDate, isPreMatureClosure, - isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth); + account.postPreMaturityInterest(closedDate, isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd, + financialYearBeginningMonth); final Integer closureTypeValue = command.integerValueOfParameterNamed(DepositsApiConstants.onAccountClosureIdParamName); DepositAccountOnClosureType closureType = DepositAccountOnClosureType.fromInt(closureTypeValue); @@ -351,13 +347,12 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi @Override public Long handleRDAccountPreMatureClosure(final RecurringDepositAccount account, final PaymentDetail paymentDetail, final AppUser user, final JsonCommand command, final LocalDate tenantsTodayDate, final Map changes) { - - final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService - .isSavingsInterestPostingAtCurrentPeriodEnd(); - final Integer financialYearBeginningMonth = this.configurationDomainService - .retrieveFinancialYearBeginningMonth(); - - boolean isAccountTransfer = false; + + final boolean isSavingsInterestPostingAtCurrentPeriodEnd = this.configurationDomainService + .isSavingsInterestPostingAtCurrentPeriodEnd(); + final Integer financialYearBeginningMonth = this.configurationDomainService.retrieveFinancialYearBeginningMonth(); + + boolean isAccountTransfer = false; final boolean isPreMatureClosure = true; boolean isRegularTransaction = false; final Set existingTransactionIds = new HashSet<>(); @@ -369,8 +364,8 @@ public class DepositAccountDomainServiceJpa implements DepositAccountDomainServi final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale); Long savingsTransactionId = null; // post interest - account.postPreMaturityInterest(closedDate, isPreMatureClosure, - isSavingsInterestPostingAtCurrentPeriodEnd, financialYearBeginningMonth); + account.postPreMaturityInterest(closedDate, isPreMatureClosure, isSavingsInterestPostingAtCurrentPeriodEnd, + financialYearBeginningMonth); final Integer closureTypeValue = command.integerValueOfParameterNamed(DepositsApiConstants.onAccountClosureIdParamName); DepositAccountOnClosureType closureType = DepositAccountOnClosureType.fromInt(closureTypeValue); 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 2412be611..0f26e3835 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 @@ -826,14 +826,12 @@ public class SavingsAccount extends AbstractPersistable { if (applyWithdrawFee) { // auto pay withdrawal fee - payWithdrawalFee(transactionDTO.getTransactionAmount(), transactionDTO.getTransactionDate(), - transactionDTO.getAppUser()); + payWithdrawalFee(transactionDTO.getTransactionAmount(), transactionDTO.getTransactionDate(), transactionDTO.getAppUser()); } return transaction; } - private void payWithdrawalFee(final BigDecimal transactionAmoount, final LocalDate transactionDate, - final AppUser user) { + private void payWithdrawalFee(final BigDecimal transactionAmoount, final LocalDate transactionDate, final AppUser user) { for (SavingsAccountCharge charge : this.charges()) { if (charge.isWithdrawalFee() && charge.isActive()) { charge.updateWithdralFeeAmount(transactionAmoount); @@ -1214,6 +1212,10 @@ public class SavingsAccount extends AbstractPersistable { return this.product.getId(); } + public SavingsProduct savingsProduct() { + return this.product; + } + private Boolean isCashBasedAccountingEnabledOnSavingsProduct() { return this.product.isCashBasedAccountingEnabled(); } @@ -1851,7 +1853,7 @@ public class SavingsAccount extends AbstractPersistable { } private void payActivationCharges(final boolean isSavingsInterestPostingAtCurrentPeriodEnd, final Integer financialYearBeginningMonth, - final AppUser user) { + final AppUser user) { boolean isSavingsChargeApplied = false; for (SavingsAccountCharge savingsAccountCharge : this.charges()) { if (savingsAccountCharge.isSavingsActivation()) { @@ -2249,7 +2251,7 @@ public class SavingsAccount extends AbstractPersistable { } public void payCharge(final SavingsAccountCharge savingsAccountCharge, final Money amountPaid, final LocalDate transactionDate, - final AppUser user) { + final AppUser user) { savingsAccountCharge.pay(getCurrency(), amountPaid); handlePayChargeTransactions(savingsAccountCharge, amountPaid, transactionDate, user); } @@ -2269,8 +2271,7 @@ public class SavingsAccount extends AbstractPersistable { handleChargeTransactions(savingsAccountCharge, chargeTransaction); } - private void handleWaiverChargeTransactions(SavingsAccountCharge savingsAccountCharge, Money transactionAmount, - AppUser user) { + private void handleWaiverChargeTransactions(SavingsAccountCharge savingsAccountCharge, Money transactionAmount, AppUser user) { final SavingsAccountTransaction chargeTransaction = SavingsAccountTransaction.waiver(this, office(), DateUtils.getLocalDateOfTenant(), transactionAmount, user); handleChargeTransactions(savingsAccountCharge, chargeTransaction); 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 a86803b32..1bd57c058 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 @@ -553,4 +553,8 @@ public class SavingsProduct extends AbstractPersistable { return this.minBalanceForInterestCalculation; } + public String getShortName() { + return this.shortName; + } + } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl.java index f2f06ac0c..7f10c9fd5 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl.java @@ -19,6 +19,9 @@ import java.util.Set; import org.apache.commons.lang.StringUtils; import org.joda.time.LocalDate; +import org.mifosplatform.infrastructure.accountnumberformat.domain.AccountNumberFormat; +import org.mifosplatform.infrastructure.accountnumberformat.domain.AccountNumberFormatRepositoryWrapper; +import org.mifosplatform.infrastructure.accountnumberformat.domain.EntityAccountType; import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService; import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.data.ApiParameterError; @@ -44,7 +47,6 @@ import org.mifosplatform.portfolio.calendar.domain.CalendarInstanceRepository; import org.mifosplatform.portfolio.calendar.domain.CalendarType; import org.mifosplatform.portfolio.calendar.service.CalendarUtils; import org.mifosplatform.portfolio.client.domain.AccountNumberGenerator; -import org.mifosplatform.portfolio.client.domain.AccountNumberGeneratorFactory; import org.mifosplatform.portfolio.client.domain.Client; import org.mifosplatform.portfolio.client.domain.ClientRepositoryWrapper; import org.mifosplatform.portfolio.client.exception.ClientNotActiveException; @@ -91,7 +93,7 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl private final RecurringDepositAccountRepository recurringDepositAccountRepository; private final DepositAccountAssembler depositAccountAssembler; private final DepositAccountDataValidator depositAccountDataValidator; - private final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory; + private final AccountNumberGenerator accountNumberGenerator; private final ClientRepositoryWrapper clientRepository; private final GroupRepository groupRepository; private final SavingsProductRepository savingsProductRepository; @@ -103,24 +105,26 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl private final FromJsonHelper fromJsonHelper; private final CalendarInstanceRepository calendarInstanceRepository; private final ConfigurationDomainService configurationDomainService; + private final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository; @Autowired public DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final SavingsAccountRepositoryWrapper savingAccountRepository, final DepositAccountAssembler depositAccountAssembler, - final DepositAccountDataValidator depositAccountDataValidator, - final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory, final ClientRepositoryWrapper clientRepository, - final GroupRepository groupRepository, final SavingsProductRepository savingsProductRepository, - final NoteRepository noteRepository, final StaffRepositoryWrapper staffRepository, + final DepositAccountDataValidator depositAccountDataValidator, final AccountNumberGenerator accountNumberGenerator, + final ClientRepositoryWrapper clientRepository, final GroupRepository groupRepository, + final SavingsProductRepository savingsProductRepository, final NoteRepository noteRepository, + final StaffRepositoryWrapper staffRepository, final SavingsAccountApplicationTransitionApiJsonValidator savingsAccountApplicationTransitionApiJsonValidator, final SavingsAccountChargeAssembler savingsAccountChargeAssembler, final FixedDepositAccountRepository fixedDepositAccountRepository, final RecurringDepositAccountRepository recurringDepositAccountRepository, final AccountAssociationsRepository accountAssociationsRepository, final FromJsonHelper fromJsonHelper, - final CalendarInstanceRepository calendarInstanceRepository, final ConfigurationDomainService configurationDomainService) { + final CalendarInstanceRepository calendarInstanceRepository, final ConfigurationDomainService configurationDomainService, + final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository) { this.context = context; this.savingAccountRepository = savingAccountRepository; this.depositAccountAssembler = depositAccountAssembler; - this.accountIdentifierGeneratorFactory = accountIdentifierGeneratorFactory; + this.accountNumberGenerator = accountNumberGenerator; this.depositAccountDataValidator = depositAccountDataValidator; this.clientRepository = clientRepository; this.groupRepository = groupRepository; @@ -135,6 +139,7 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl this.fromJsonHelper = fromJsonHelper; this.calendarInstanceRepository = calendarInstanceRepository; this.configurationDomainService = configurationDomainService; + this.accountNumberFormatRepository = accountNumberFormatRepository; } /* @@ -187,9 +192,8 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl this.fixedDepositAccountRepository.save(account); if (account.isAccountNumberRequiresAutoGeneration()) { - final AccountNumberGenerator accountNoGenerator = this.accountIdentifierGeneratorFactory - .determineSavingsAccountNoGenerator(account.getId()); - account.updateAccountNo(accountNoGenerator.generate()); + AccountNumberFormat accountNumberFormat = this.accountNumberFormatRepository.findByAccountType(EntityAccountType.CLIENT); + account.updateAccountNo(this.accountNumberGenerator.generate(account, accountNumberFormat)); this.savingAccountRepository.save(account); } @@ -239,9 +243,9 @@ public class DepositApplicationProcessWritePlatformServiceJpaRepositoryImpl impl this.recurringDepositAccountRepository.save(account); if (account.isAccountNumberRequiresAutoGeneration()) { - final AccountNumberGenerator accountNoGenerator = this.accountIdentifierGeneratorFactory - .determineSavingsAccountNoGenerator(account.getId()); - account.updateAccountNo(accountNoGenerator.generate()); + final AccountNumberFormat accountNumberFormat = this.accountNumberFormatRepository + .findByAccountType(EntityAccountType.SAVINGS); + account.updateAccountNo(this.accountNumberGenerator.generate(account, accountNumberFormat)); } final Long savingsId = account.getId(); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl.java index 8b365d1f7..5bd7e0627 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl.java @@ -18,6 +18,9 @@ import org.apache.commons.lang.StringUtils; import org.mifosplatform.commands.domain.CommandWrapper; import org.mifosplatform.commands.service.CommandProcessingService; import org.mifosplatform.commands.service.CommandWrapperBuilder; +import org.mifosplatform.infrastructure.accountnumberformat.domain.AccountNumberFormat; +import org.mifosplatform.infrastructure.accountnumberformat.domain.AccountNumberFormatRepositoryWrapper; +import org.mifosplatform.infrastructure.accountnumberformat.domain.EntityAccountType; import org.mifosplatform.infrastructure.core.api.JsonCommand; import org.mifosplatform.infrastructure.core.data.ApiParameterError; import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; @@ -31,7 +34,6 @@ import org.mifosplatform.organisation.monetary.domain.Money; import org.mifosplatform.organisation.staff.domain.Staff; import org.mifosplatform.organisation.staff.domain.StaffRepositoryWrapper; import org.mifosplatform.portfolio.client.domain.AccountNumberGenerator; -import org.mifosplatform.portfolio.client.domain.AccountNumberGeneratorFactory; import org.mifosplatform.portfolio.client.domain.Client; import org.mifosplatform.portfolio.client.domain.ClientRepositoryWrapper; import org.mifosplatform.portfolio.client.exception.ClientNotActiveException; @@ -71,7 +73,7 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl private final SavingsAccountRepositoryWrapper savingAccountRepository; private final SavingsAccountAssembler savingAccountAssembler; private final SavingsAccountDataValidator savingsAccountDataValidator; - private final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory; + private final AccountNumberGenerator accountNumberGenerator; private final ClientRepositoryWrapper clientRepository; private final GroupRepository groupRepository; private final SavingsProductRepository savingsProductRepository; @@ -82,22 +84,24 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl private final CommandProcessingService commandProcessingService; private final SavingsAccountDomainService savingsAccountDomainService; private final SavingsAccountWritePlatformService savingsAccountWritePlatformService; + private final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository; @Autowired public SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final SavingsAccountRepositoryWrapper savingAccountRepository, final SavingsAccountAssembler savingAccountAssembler, - final SavingsAccountDataValidator savingsAccountDataValidator, - final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory, final ClientRepositoryWrapper clientRepository, - final GroupRepository groupRepository, final SavingsProductRepository savingsProductRepository, - final NoteRepository noteRepository, final StaffRepositoryWrapper staffRepository, + final SavingsAccountDataValidator savingsAccountDataValidator, final AccountNumberGenerator accountNumberGenerator, + final ClientRepositoryWrapper clientRepository, final GroupRepository groupRepository, + final SavingsProductRepository savingsProductRepository, final NoteRepository noteRepository, + final StaffRepositoryWrapper staffRepository, final SavingsAccountApplicationTransitionApiJsonValidator savingsAccountApplicationTransitionApiJsonValidator, final SavingsAccountChargeAssembler savingsAccountChargeAssembler, final CommandProcessingService commandProcessingService, final SavingsAccountDomainService savingsAccountDomainService, - final SavingsAccountWritePlatformService savingsAccountWritePlatformService) { + final SavingsAccountWritePlatformService savingsAccountWritePlatformService, + final AccountNumberFormatRepositoryWrapper accountNumberFormatRepository) { this.context = context; this.savingAccountRepository = savingAccountRepository; this.savingAccountAssembler = savingAccountAssembler; - this.accountIdentifierGeneratorFactory = accountIdentifierGeneratorFactory; + this.accountNumberGenerator = accountNumberGenerator; this.savingsAccountDataValidator = savingsAccountDataValidator; this.clientRepository = clientRepository; this.groupRepository = groupRepository; @@ -108,6 +112,7 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl this.savingsAccountChargeAssembler = savingsAccountChargeAssembler; this.commandProcessingService = commandProcessingService; this.savingsAccountDomainService = savingsAccountDomainService; + this.accountNumberFormatRepository = accountNumberFormatRepository; this.savingsAccountWritePlatformService = savingsAccountWritePlatformService; } @@ -168,9 +173,8 @@ public class SavingsApplicationProcessWritePlatformServiceJpaRepositoryImpl impl private void generateAccountNumber(final SavingsAccount account) { if (account.isAccountNumberRequiresAutoGeneration()) { - final AccountNumberGenerator accountNoGenerator = this.accountIdentifierGeneratorFactory - .determineSavingsAccountNoGenerator(account.getId()); - account.updateAccountNo(accountNoGenerator.generate()); + final AccountNumberFormat accountNumberFormat = this.accountNumberFormatRepository.findByAccountType(EntityAccountType.SAVINGS); + account.updateAccountNo(this.accountNumberGenerator.generate(account, accountNumberFormat)); this.savingAccountRepository.save(account); } diff --git a/mifosng-provider/src/main/resources/sql/migrations/core_db/V220__account_number_preferences.sql b/mifosng-provider/src/main/resources/sql/migrations/core_db/V220__account_number_preferences.sql new file mode 100644 index 000000000..e874bfb68 --- /dev/null +++ b/mifosng-provider/src/main/resources/sql/migrations/core_db/V220__account_number_preferences.sql @@ -0,0 +1,22 @@ +CREATE TABLE `c_account_number_format` ( + `id` BIGINT(20) NOT NULL AUTO_INCREMENT, + `account_type_enum` SMALLINT(1) NOT NULL, + `prefix_type_enum` SMALLINT(2) NULL DEFAULT NULL, + PRIMARY KEY (`id`), + UNIQUE INDEX `account_type_enum` (`account_type_enum`) +) +COLLATE='utf8_general_ci' +ENGINE=InnoDB +; + + +/*permissions*/ + +insert into `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) +VALUES ('configuration', 'CREATE_ACCOUNTNUMBERFORMAT', 'ACCOUNTNUMBERFORMAT', 'CREATE', 0); +insert into `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) +VALUES ('configuration', 'READ_ACCOUNTNUMBERFORMAT', 'ACCOUNTNUMBERFORMAT', 'READ', 0); +insert into `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) +VALUES ('configuration', 'UPDATE_ACCOUNTNUMBERFORMAT', 'ACCOUNTNUMBERFORMAT', 'UPDATE', 0); +insert into `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) +VALUES ('configuration', 'DELETE_ACCOUNTNUMBERFORMAT', 'HOOK', 'DELETE', 0); \ No newline at end of file From 78b6f2a3e658caf4b44b6ce288ad73dd9b933148 Mon Sep 17 00:00:00 2001 From: Vishwas Babu A J Date: Tue, 2 Dec 2014 08:35:59 -0800 Subject: [PATCH 2/4] updating licences --- .../api/AccountNumberFormatsApiResource.java | 5 +++++ .../accountnumberformat/data/AccountNumberFormatData.java | 5 +++++ .../data/AccountNumberFormatDataValidator.java | 5 +++++ .../domain/AccountNumberFormatRepositoryWrapper.java | 5 +++++ .../handler/CreateAccountNumberFormatCommandHandler.java | 5 +++++ .../handler/DeleteAccountNumberFormatCommandHandler.java | 5 +++++ .../handler/UpdateAccountNumberFormatCommandHandler.java | 5 +++++ .../service/AccountNumberFormatConstants.java | 5 +++++ .../service/AccountNumberFormatReadPlatformService.java | 5 +++++ .../service/AccountNumberFormatReadPlatformServiceImpl.java | 5 +++++ .../service/AccountNumberFormatWritePlatformService.java | 5 +++++ ...untNumberFormatWritePlatformServiceJpaRepositoryImpl.java | 5 +++++ 12 files changed, 60 insertions(+) diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/api/AccountNumberFormatsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/api/AccountNumberFormatsApiResource.java index 5a0500ccc..ca2afccd0 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/api/AccountNumberFormatsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/api/AccountNumberFormatsApiResource.java @@ -1,3 +1,8 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ package org.mifosplatform.infrastructure.accountnumberformat.api; import java.util.List; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/data/AccountNumberFormatData.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/data/AccountNumberFormatData.java index 2fdad3dd9..2ebb56b6a 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/data/AccountNumberFormatData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/data/AccountNumberFormatData.java @@ -1,3 +1,8 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ package org.mifosplatform.infrastructure.accountnumberformat.data; import java.io.Serializable; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/data/AccountNumberFormatDataValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/data/AccountNumberFormatDataValidator.java index 5eb7871a8..f6340dc98 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/data/AccountNumberFormatDataValidator.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/data/AccountNumberFormatDataValidator.java @@ -1,3 +1,8 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ package org.mifosplatform.infrastructure.accountnumberformat.data; import java.lang.reflect.Type; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/domain/AccountNumberFormatRepositoryWrapper.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/domain/AccountNumberFormatRepositoryWrapper.java index 2ba63e7fa..df822c122 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/domain/AccountNumberFormatRepositoryWrapper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/domain/AccountNumberFormatRepositoryWrapper.java @@ -1,3 +1,8 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ package org.mifosplatform.infrastructure.accountnumberformat.domain; import org.mifosplatform.infrastructure.accountnumberformat.exception.AccountNumberFormatNotFoundException; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/handler/CreateAccountNumberFormatCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/handler/CreateAccountNumberFormatCommandHandler.java index 88f79eac2..25a1ec7ae 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/handler/CreateAccountNumberFormatCommandHandler.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/handler/CreateAccountNumberFormatCommandHandler.java @@ -1,3 +1,8 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ package org.mifosplatform.infrastructure.accountnumberformat.handler; import javax.transaction.Transactional; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/handler/DeleteAccountNumberFormatCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/handler/DeleteAccountNumberFormatCommandHandler.java index 696953e82..6704cd303 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/handler/DeleteAccountNumberFormatCommandHandler.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/handler/DeleteAccountNumberFormatCommandHandler.java @@ -1,3 +1,8 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ package org.mifosplatform.infrastructure.accountnumberformat.handler; import javax.transaction.Transactional; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/handler/UpdateAccountNumberFormatCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/handler/UpdateAccountNumberFormatCommandHandler.java index 5699d8c83..ea93c6106 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/handler/UpdateAccountNumberFormatCommandHandler.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/handler/UpdateAccountNumberFormatCommandHandler.java @@ -1,3 +1,8 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ package org.mifosplatform.infrastructure.accountnumberformat.handler; import javax.transaction.Transactional; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatConstants.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatConstants.java index 4181bbaa4..e1857afa0 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatConstants.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatConstants.java @@ -1,3 +1,8 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ package org.mifosplatform.infrastructure.accountnumberformat.service; import java.util.Arrays; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatReadPlatformService.java index 51ce8378b..c77bc849f 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatReadPlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatReadPlatformService.java @@ -1,3 +1,8 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ package org.mifosplatform.infrastructure.accountnumberformat.service; import java.util.List; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatReadPlatformServiceImpl.java index f4cc66dda..737f8c719 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatReadPlatformServiceImpl.java @@ -1,3 +1,8 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ package org.mifosplatform.infrastructure.accountnumberformat.service; import java.sql.ResultSet; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatWritePlatformService.java index 814ca2040..8575b7f20 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatWritePlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatWritePlatformService.java @@ -1,3 +1,8 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ package org.mifosplatform.infrastructure.accountnumberformat.service; import org.mifosplatform.infrastructure.core.api.JsonCommand; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatWritePlatformServiceJpaRepositoryImpl.java index 3631b8590..f86129462 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/accountnumberformat/service/AccountNumberFormatWritePlatformServiceJpaRepositoryImpl.java @@ -1,3 +1,8 @@ +/** + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. + */ package org.mifosplatform.infrastructure.accountnumberformat.service; import java.util.LinkedHashMap; From f58fc1c1162d51a166ada5af355ed51e8e2be7f9 Mon Sep 17 00:00:00 2001 From: Vishwas Babu A J Date: Tue, 2 Dec 2014 13:24:55 -0800 Subject: [PATCH 3/4] add optimistic locking for savings account --- .../portfolio/savings/domain/SavingsAccount.java | 4 ++++ .../core_db/V221__add_version_for_m_savings_account.sql | 2 ++ 2 files changed, 6 insertions(+) create mode 100644 mifosng-provider/src/main/resources/sql/migrations/core_db/V221__add_version_for_m_savings_account.sql 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 0f26e3835..25b4105d7 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 @@ -49,6 +49,7 @@ import javax.persistence.Temporal; import javax.persistence.TemporalType; import javax.persistence.Transient; import javax.persistence.UniqueConstraint; +import javax.persistence.Version; import org.apache.commons.lang.ObjectUtils; import org.apache.commons.lang.StringUtils; @@ -105,6 +106,9 @@ import com.google.gson.JsonArray; @DiscriminatorValue("100") public class SavingsAccount extends AbstractPersistable { + @Version + int version; + @Column(name = "account_no", length = 20, unique = true, nullable = false) protected String accountNumber; diff --git a/mifosng-provider/src/main/resources/sql/migrations/core_db/V221__add_version_for_m_savings_account.sql b/mifosng-provider/src/main/resources/sql/migrations/core_db/V221__add_version_for_m_savings_account.sql new file mode 100644 index 000000000..9079cda38 --- /dev/null +++ b/mifosng-provider/src/main/resources/sql/migrations/core_db/V221__add_version_for_m_savings_account.sql @@ -0,0 +1,2 @@ +ALTER TABLE `m_savings_account` + ADD COLUMN `version` INT(15) NOT NULL DEFAULT '1' AFTER `on_hold_funds_derived`; From 07052f983ed02501f61a8e93c003836589234a1e Mon Sep 17 00:00:00 2001 From: Vishwas Babu A J Date: Tue, 2 Dec 2014 17:33:19 -0800 Subject: [PATCH 4/4] cath database errors related to savings withdrawals --- ...SavingsAccountTransactionsApiResource.java | 40 ++++++++++++------- .../savings/domain/SavingsAccount.java | 8 ++-- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/api/SavingsAccountTransactionsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/api/SavingsAccountTransactionsApiResource.java index d88b6988f..f2cfae597 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/api/SavingsAccountTransactionsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/api/SavingsAccountTransactionsApiResource.java @@ -26,6 +26,7 @@ import org.mifosplatform.infrastructure.codes.data.CodeValueData; import org.mifosplatform.infrastructure.codes.service.CodeValueReadPlatformService; import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper; import org.mifosplatform.infrastructure.core.data.CommandProcessingResult; +import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException; import org.mifosplatform.infrastructure.core.exception.UnrecognizedQueryParamException; import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings; import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer; @@ -37,6 +38,8 @@ import org.mifosplatform.portfolio.savings.data.SavingsAccountTransactionData; import org.mifosplatform.portfolio.savings.service.SavingsAccountReadPlatformService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; +import org.springframework.dao.CannotAcquireLockException; +import org.springframework.orm.ObjectOptimisticLockingFailureException; import org.springframework.stereotype.Component; @Path("/savingsaccounts/{savingsId}/transactions") @@ -119,24 +122,31 @@ public class SavingsAccountTransactionsApiResource { @Produces({ MediaType.APPLICATION_JSON }) public String transaction(@PathParam("savingsId") final Long savingsId, @QueryParam("command") final String commandParam, final String apiRequestBodyAsJson) { + try { + final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(apiRequestBodyAsJson); - final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(apiRequestBodyAsJson); + CommandProcessingResult result = null; + if (is(commandParam, "deposit")) { + final CommandWrapper commandRequest = builder.savingsAccountDeposit(savingsId).build(); + result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); + } else if (is(commandParam, "withdrawal")) { + final CommandWrapper commandRequest = builder.savingsAccountWithdrawal(savingsId).build(); + result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); + } - CommandProcessingResult result = null; - if (is(commandParam, "deposit")) { - final CommandWrapper commandRequest = builder.savingsAccountDeposit(savingsId).build(); - result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); - } else if (is(commandParam, "withdrawal")) { - final CommandWrapper commandRequest = builder.savingsAccountWithdrawal(savingsId).build(); - result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest); + if (result == null) { + // + throw new UnrecognizedQueryParamException("command", commandParam, new Object[] { "deposit", "withdrawal" }); + } + + return this.toApiJsonSerializer.serialize(result); + } catch (ObjectOptimisticLockingFailureException lockingFailureException) { + throw new PlatformDataIntegrityException("error.msg.savings.concurrent.operations", + "Concurrent Transactions being made on this savings account: " + lockingFailureException.getMessage()); + } catch (CannotAcquireLockException cannotAcquireLockException) { + throw new PlatformDataIntegrityException("error.msg.savings.concurrent.operations.unable.to.acquire.lock", + "Unable to acquir lock for this transaction: " + cannotAcquireLockException.getMessage()); } - - if (result == null) { - // - throw new UnrecognizedQueryParamException("command", commandParam, new Object[] { "deposit", "withdrawal" }); - } - - return this.toApiJsonSerializer.serialize(result); } @POST 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 25b4105d7..c82a1aa66 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 @@ -1149,16 +1149,16 @@ public class SavingsAccount extends AbstractPersistable { accountingBridgeData.put("accrualBasedAccountingEnabled", isAccrualBasedAccountingEnabledOnSavingsProduct()); accountingBridgeData.put("isAccountTransfer", isAccountTransfer); - final List> newLoanTransactions = new ArrayList<>(); + final List> newSavingsTransactions = new ArrayList<>(); for (final SavingsAccountTransaction transaction : this.transactions) { if (transaction.isReversed() && !existingReversedTransactionIds.contains(transaction.getId())) { - newLoanTransactions.add(transaction.toMapData(currencyData)); + newSavingsTransactions.add(transaction.toMapData(currencyData)); } else if (!existingTransactionIds.contains(transaction.getId())) { - newLoanTransactions.add(transaction.toMapData(currencyData)); + newSavingsTransactions.add(transaction.toMapData(currencyData)); } } - accountingBridgeData.put("newSavingsTransactions", newLoanTransactions); + accountingBridgeData.put("newSavingsTransactions", newSavingsTransactions); return accountingBridgeData; }