MIFOSX-1511 custom formats for client, loan and savings account numbers

This commit is contained in:
Vishwas Babu A J
2014-12-02 08:34:08 -08:00
parent 06dfb9d732
commit 637f062ce3
33 changed files with 1832 additions and 231 deletions
+347
View File
@@ -2014,6 +2014,22 @@
<td><a href="#configs_hook_update">Update a Hook</a></td>
<td><a href="#configs_hook_delete">Delete a Hook</a></td>
</tr>
<tr>
<td><a href="#accountnumberformats">Account number format</a></td>
<td>accountnumberformats</td>
<td><a href="#accountnumberformats_create">Create an Account number format</a></td>
<td><a href="#accountnumberformats_list">List Account number formats</a></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>accountnumberformats/{accountnumberformatId}</td>
<td></td>
<td><a href="#accountnumberformats_retrieve">Retrieve an Account number format</a></td>
<td><a href="#accountnumberformats_update">Update an Account number format</a></td>
<td><a href="#accountnumberformats_delete">Delete an Account number format</a></td>
</tr>
<tr>
<td><a href="#configs_codes">Codes</a></td>
<td>codes</td>
@@ -14452,6 +14468,337 @@ GET https://DomainName/api/v1/audits
</div>
</div>
<!--Start of Account Number Format functionality-->
<a id="accountnumberformats" name="accountnumberformats" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h3>Account number format</h3>
<p>Account number preferences are used to describe custom formats for account numbers associated with Customer, Loan and Savings accounts.
</p>
<table class=matrixHeading>
<tr class="matrixHeadingBG">
<td><div class="mifosXHeading2">Field Descriptions</div></td>
</tr>
<tr class=alt>
<td>accountType</td>
</tr>
<tr>
<td class=fielddesc>Identifies the type of the Account for which the Account number format applies <br/>
Refer <a href="#accountnumberformats_template">Retrieve
Account number formats Template</a> for complete
details
</td>
</tr>
<tr class=alt>
<td>prefixType</td>
</tr>
<tr>
<td class=fielddesc>Identifies a custom prefix for the account number
<br/>
Refer <a href="#accountnumberformats_template">Retrieve
Account number formats Template</a> for complete
details
</td>
</tr>
</table>
</div>
</div>
<a id="accountnumberformats_list" name="accountnumberformats_list"
class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>List Account number formats</h4>
<p>Example Requests:</p>
<div class=apiClick>accountnumberformats</div>
<br>
<br>
<div class=apiClick>accountnumberformats?fields=accountType,prefixType</div>
</div>
<div class="method-example">
<code class="method-declaration">
GET https://DomainName/api/v1/accountnumberformats
</code>
<code class="method-response">
[
{
"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"
}
}
]
</code>
</div>
</div>
<a id="accountnumberformats_template" name="accountnumberformats_template"
class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Retrieve Account number format Template</h4>
<p>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:
<ul>
<li class=normalli>Field Defaults</li>
<li class=normalli>Allowed Value Lists</li>
</ul>
</p>
<p>Example Request:</p>
<div class=apiClick>accountnumberformats/template</div>
</div>
<div class="method-example">
<code class="method-declaration">
GET https://DomainName/api/v1/accountnumberformats/template
</code>
<code class="method-response">
{
"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"
}
]
}
}
</code>
</div>
</div>
<a id="accountnumberformats_retrieve" name="accountnumberformats_retrieve"
class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Retrieve an Account number format</h4>
<p>Example Requests:</p>
<div class=apiClick>accountnumberformats/1</div>
<br>
<br>
<div class=apiClick>accountnumberformats/1?template=true</div>
<br>
<br>
<div class=apiClick>accountnumberformats/1?fields=accountType,prefixType</div>
</div>
<div class="method-example">
<code class="method-declaration">
GET https://DomainName/api/v1/accountnumberformats/{accountnumberformatId}
</code>
<code class="method-response">
{
"id": 2,
"accountType":
{
"id": 1,
"code": "accountType.client",
"value": "CLIENT"
},
"prefixType":
{
"id": 101,
"code": "accountNumberPrefixType.clientType",
"value": "CLIENT_TYPE"
}
}
</code>
</div>
</div>
<a id="accountnumberformats_create" name="accountnumberformats_create" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Create an Account number format</h4>
<p>
<b>Note:</b> You may associate a single Account number format for a given account type<br>
</p>
<table class=matrixHeading>
<tr class="matrixHeadingBG">
<td><div class="mifosXHeading2">Mandatory Fields
for Account number formats</div></td>
</tr>
<tr class=alt>
<td>accountType</td>
</tr>
</table>
</div>
<div class="method-example">
<code class="method-declaration">
POST https://DomainName/api/v1/accountnumberformats
</code>
<code class="method-request">
POST /accountnumberformats
Content-Type: application/json
Request Body:
{
accountType :1,
prefixType: 101
}
</code>
<code class="method-response">
{
"resourceId": 4
}
</code>
<code class="method-request">
POST /accountnumberformats
Content-Type: application/json
Request Body:
{
accountType :2,
prefixType: 201
}
</code>
<code class="method-response">
{
"resourceId": 5
}
</code>
</div>
</div>
<a id="accountnumberformats_update" name="accountnumberformats_update"
class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Update an Account number format</h4>
</div>
<div class="method-example">
<code class="method-declaration">
PUT https://DomainName/api/v1/accountnumberformats/{accountnumberformatId}
</code>
<code class="method-request">
PUT accountnumberformats/2
Content-Type: application/json
Request Body:
{
prefixType:1
}
</code>
<code class="method-response">
{
"resourceId": 2,
"changes":
{
"prefixType": "OFFICE_NAME"
}
}
</code>
</div>
</div>
<a id="accountnumberformats_delete" name="accountnumberformats_delete" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Delete an Account number format</h4>
<p>
<b>Note:</b> Account numbers created while this format was active would remain unchanged.
</p>
</div>
<div class="method-example">
<code class="method-declaration">
DELETE https://DomainName/api/v1/accountnumberformats/{accountnumberformatId}
</code>
<code class="method-request">
DELETE accountnumberformats/2
Content-Type: application/json
No Request Body:
</code>
<code class="method-response">
{
"resourceId": 2
}
</code>
</div>
</div>
<!-- Maker Checker starts here -->
<a id="makercheckers" name="makercheckers" class="old-syle-anchor">&nbsp;</a>
@@ -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");
}
@@ -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;
}
}
@@ -43,8 +43,7 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
public SynchronousCommandProcessingService(final PlatformSecurityContext context, final ApplicationContext applicationContext,
final ToApiJsonSerializer<Map<String, Object>> toApiJsonSerializer,
final ToApiJsonSerializer<CommandProcessingResult> 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);
}
}
@@ -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<AccountNumberFormatData> toApiJsonSerializer;
private final ApiRequestParameterHelper apiRequestParameterHelper;
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
@Autowired
public AccountNumberFormatsApiResource(final PlatformSecurityContext context,
final ToApiJsonSerializer<AccountNumberFormatData> 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> 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);
}
}
@@ -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<EnumOptionData> accountTypeOptions;
private Map<String, List<EnumOptionData>> prefixTypeOptions;
public AccountNumberFormatData(final Long id, final EnumOptionData accountType, final EnumOptionData prefixType) {
this(id, accountType, prefixType, null, null);
}
public AccountNumberFormatData(final List<EnumOptionData> accountTypeOptions, Map<String, List<EnumOptionData>> prefixTypeOptions) {
this(null, null, null, accountTypeOptions, prefixTypeOptions);
}
public void templateOnTop(List<EnumOptionData> accountTypeOptions, Map<String, List<EnumOptionData>> prefixTypeOptions) {
this.accountTypeOptions = accountTypeOptions;
this.prefixTypeOptions = prefixTypeOptions;
}
private AccountNumberFormatData(final Long id, final EnumOptionData accountType, final EnumOptionData prefixType,
final List<EnumOptionData> accountTypeOptions, Map<String, List<EnumOptionData>> 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<EnumOptionData> getAccountTypeOptions() {
return this.accountTypeOptions;
}
public Map<String, List<EnumOptionData>> getPrefixTypeOptions() {
return this.prefixTypeOptions;
}
}
@@ -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<Map<String, Object>>() {}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json,
AccountNumberFormatConstants.ACCOUNT_NUMBER_FORMAT_CREATE_REQUEST_DATA_PARAMETERS);
final JsonElement element = this.fromApiJsonHelper.parse(json);
final List<ApiParameterError> 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<Integer> validAccountNumberPrefixes = determineValidAccountNumberPrefixes(entityAccountType);
dataValidatorForValidatingPrefixType.isOneOfTheseValues(validAccountNumberPrefixes.toArray());
}
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
public Set<Integer> determineValidAccountNumberPrefixes(EntityAccountType entityAccountType) {
Set<AccountNumberPrefixType> validAccountNumberPrefixes = new HashSet<>();
switch (entityAccountType) {
case CLIENT:
validAccountNumberPrefixes = AccountNumberFormatEnumerations.accountNumberPrefixesForClientAccounts;
break;
case LOAN:
validAccountNumberPrefixes = AccountNumberFormatEnumerations.accountNumberPrefixesForLoanAccounts;
break;
case SAVINGS:
validAccountNumberPrefixes = AccountNumberFormatEnumerations.accountNumberPrefixesForSavingsAccounts;
break;
}
Set<Integer> 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<Map<String, Object>>() {}.getType();
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json,
AccountNumberFormatConstants.ACCOUNT_NUMBER_FORMAT_UPDATE_REQUEST_DATA_PARAMETERS);
final JsonElement element = this.fromApiJsonHelper.parse(json);
final List<ApiParameterError> 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<Integer> 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<ApiParameterError> dataValidationErrors) {
if (!dataValidationErrors.isEmpty()) {
//
throw new PlatformApiDataValidationException(dataValidationErrors);
}
}
}
@@ -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<Long> {
@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());
}
}
@@ -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<AccountNumberPrefixType> accountNumberPrefixesForClientAccounts = new HashSet<>(Arrays.asList(
AccountNumberPrefixType.OFFICE_NAME, AccountNumberPrefixType.CLIENT_TYPE));
public final static Set<AccountNumberPrefixType> accountNumberPrefixesForLoanAccounts = new HashSet<>(Arrays.asList(
AccountNumberPrefixType.OFFICE_NAME, AccountNumberPrefixType.LOAN_PRODUCT_SHORT_NAME));
public final static Set<AccountNumberPrefixType> 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<Integer, AccountNumberPrefixType> 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<EnumOptionData> entityAccountType(final EntityAccountType[] entityAccountTypes) {
final List<EnumOptionData> 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<EnumOptionData> accountNumberPrefixType(final AccountNumberPrefixType[] accountNumberPrefixTypes) {
final List<EnumOptionData> 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<EnumOptionData> accountNumberPrefixType(Object[] array) {
AccountNumberPrefixType[] accountNumberPrefixTypes = Arrays.copyOf(array, array.length, AccountNumberPrefixType[].class);
return accountNumberPrefixType(accountNumberPrefixTypes);
}
}
@@ -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<AccountNumberFormat, Long>,
JpaSpecificationExecutor<AccountNumberFormat> {
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);
}
@@ -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());
}
}
@@ -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<Integer, EntityAccountType> 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());
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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());
}
}
@@ -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);
}
}
@@ -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<String> ACCOUNT_NUMBER_FORMAT_CREATE_REQUEST_DATA_PARAMETERS = new HashSet<>(Arrays.asList(
accountTypeParamName, prefixTypeParamName));
public static final Set<String> 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<String> 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";
}
@@ -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<AccountNumberFormatData> getAllAccountNumberFormats();
AccountNumberFormatData getAccountNumberFormat(Long id);
AccountNumberFormatData retrieveTemplate(EntityAccountType entityAccountTypeForTemplate);
}
@@ -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<AccountNumberFormatData> {
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<AccountNumberFormatData> 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<EnumOptionData> entityAccountTypeOptions = AccountNumberFormatEnumerations.entityAccountType(EntityAccountType.values());
Map<String, List<EnumOptionData>> 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<String, List<EnumOptionData>> accountNumberPrefixTypeOptions,
EntityAccountType entityAccountType) {
Set<AccountNumberPrefixType> 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));
}
}
@@ -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);
}
@@ -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<String, Object> 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.");
}
}
@@ -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 <code>maxLength</code>.
*/
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<String, String> 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<String, String> 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<String, String> 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<String, String> 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;
}
}
@@ -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);
}
}
@@ -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 <code>maxLength</code>.
*/
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);
}
}
@@ -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);
}
@@ -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);
}
@@ -981,8 +981,12 @@ public class LoanProduct extends AbstractPersistable<Long> {
return this.holdGuaranteeFunds;
}
public LoanProductGuaranteeDetails getLoanProductGuaranteeDetails() {
return this.loanProductGuaranteeDetails;
}
public String getShortName() {
return this.shortName;
}
}
@@ -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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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<Long> 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);
@@ -826,14 +826,12 @@ public class SavingsAccount extends AbstractPersistable<Long> {
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<Long> {
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<Long> {
}
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<Long> {
}
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<Long> {
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);
@@ -553,4 +553,8 @@ public class SavingsProduct extends AbstractPersistable<Long> {
return this.minBalanceForInterestCalculation;
}
public String getShortName() {
return this.shortName;
}
}
@@ -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();
@@ -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);
}
@@ -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);