Skip to content

Commit

Permalink
Merge pull request apache#507 from ShruthiRajaram/Fineract-646
Browse files Browse the repository at this point in the history
FINERACT-646 Pockets API
  • Loading branch information
vishwasbabu authored Feb 26, 2019
2 parents 26d5459 + 3a67d01 commit 0a24570
Show file tree
Hide file tree
Showing 32 changed files with 1,613 additions and 2 deletions.
123 changes: 122 additions & 1 deletion api-docs/apiLive.htm
Original file line number Diff line number Diff line change
Expand Up @@ -3864,7 +3864,7 @@ <h2 class="flybar-button">Self Service</h2>
<td>self/loans/{loanId}/guarantors</td>
<td></td>
<td><a href="#self_guarantors_list">Guarantors list</a></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
Expand All @@ -3875,6 +3875,7 @@ <h2 class="flybar-button">Self Service</h2>
</td>
</td>
</tr>

<tr>
<td><a href="#self_service_user_reports">Run Report</a></td>
<td>self/runreports/{reportName}</td>
Expand Down Expand Up @@ -3904,6 +3905,30 @@ <h2 class="flybar-button">Self Service</h2>
<td>self/surveys/scorecards/clients/{clientId}</td>
<td></td>
<td><a href="#survey_score">Survey Scorecards</a></td>
<td></td>
<td></td>
</tr>
<tr>
<td><a href="#linkaccountstopocket">Link/Delink accounts to pocket</a></td>
<td>self/pockets?command=linkAccounts</td>
<td><a href="#linkaccountstopocket">Link accounts to pocket</a></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>self/pockets?command=delinkAccounts</td>
<td><a href="#delinkaccountstopocket">Delink accounts from pocket</a></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>self/pockets</td>
<td></td>
<td><a href="#retrievepocketaccounts">Retrieve accounts linked to pocket</a></td>
<td></td>
<td></td>
</tr>
Expand Down Expand Up @@ -50691,6 +50716,102 @@ <h5>Arguments</h5>
</code>
</div>
</div>

<a id="linkaccountstopocket" name="linkaccountstopocket" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h2>Link/delink accounts to/from pocket</h2>
<p>Pockets behave as favourites. An user can link his/her Loan, Savings and Share accounts to pocket for faster access. In a similar way linked accounts can be delinked from the pocket.</p>
<h2>Link accounts to pocket</h2>
<p>Example Requests:</p>
<div class=apiClick>self/pockets?command=linkAccounts</div>
</div>
<div class="method-example">
<code class="method-declaration">POST https://DomainName/api/v1/self/pockets?command=linkAccounts</code>
<code class="method-request">POST self/pockets?command=linkAccounts
Content-Type: application/json
Request Body:

{
"accountsDetail":[
{
"accountId":"11",
"accountType":"LOAN"
},
{
"accountId":"2",
"accountType":"SAVINGS"
}
]
}
</code>
<code class="method-response">
{
"resourceId": 6
}
</code>
</div>
</div>

<a id="delinkaccountstopocket" name="delinkaccountstopocket" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h2>Delink accounts from pocket</h2>
<p>Example Requests:</p>
<div class=apiClick>self/pockets?command=delinkAccounts</div>
</div>
<div class="method-example">
<code class="method-declaration">POST https://DomainName/api/v1/self/pockets?command=delinkAccounts</code>
<code class="method-request">POST self/pockets?command=delinkAccounts
Content-Type: application/json
Request Body:

{ "pocketAccountMappingIds" :[8,9]
}
</code>
<code class="method-response">
{
"resourceId":10
}
</code>
</div>
</div>

<a id="retrievepocketaccounts" name="retrievepocketaccounts" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h2>Retrieve accounts linked to pocket</h2>
<p>All linked loan </p>
<p>Example Requests:</p>
<div class=apiClick>self/pockets</div>
</div>
<div class="method-example">
<code class="method-declaration">POST https://DomainName/api/v1/self/pockets</code>
<code class="method-response">
{
"loanAccounts": [
{
"pocketId": 6,
"accountId": 11,
"accountType": 2,
"accountNumber": "000000011",
"id": 10
}
],
"savingsAccounts": [
{
"pocketId": 6,
"accountId": 2,
"accountType": 3,
"accountNumber": "000000002",
"id": 11
}
],
"shareAccounts": []
}
</code>
</div>
</div>
<!-- end of Customer Self Service APIs-->
</div>
<!-- main-content-wrapper -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.apache.fineract.portfolio.client.api.ClientApiConstants;
import org.apache.fineract.portfolio.paymenttype.api.PaymentTypeApiResourceConstants;
import org.apache.fineract.portfolio.savings.DepositsApiConstants;
import org.apache.fineract.portfolio.self.pockets.api.PocketApiConstants;
import org.apache.fineract.useradministration.api.PasswordPreferencesApiConstants;

public class CommandWrapperBuilder {
Expand Down Expand Up @@ -3132,4 +3133,18 @@ public CommandWrapperBuilder updateTwoFactorConfiguration() {
this.href = "/twofactor/configure";
return this;
}

public CommandWrapperBuilder linkAccountsToPocket() {
this.actionName = PocketApiConstants.linkAccountsActionName;
this.entityName = PocketApiConstants.pocketEntityName;
this.href = "/self/pocket?command="+PocketApiConstants.linkAccountsToPocketCommandParam;
return this;
}

public CommandWrapperBuilder delinkAccountsFromPocket() {
this.actionName = PocketApiConstants.delinkAccountsActionName;
this.entityName = PocketApiConstants.pocketEntityName;
this.href = "/self/pocket?command="+PocketApiConstants.delinkAccountsFromPocketCommandParam;
return this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -134,4 +134,7 @@ LoanScheduleData retrieveRepaymentSchedule(Long loanId, RepaymentScheduleRelated
LoanAccountData retrieveLoanByLoanAccount(String loanAccountNumber);

Long retrieveLoanIdByAccountNumber(String loanAccountNumber);

String retrieveAccountNumberByAccountId(Long accountId);

}
Original file line number Diff line number Diff line change
Expand Up @@ -2209,4 +2209,12 @@ public Long retrieveLoanIdByAccountNumber(String loanAccountNumber) {
}
}

public String retrieveAccountNumberByAccountId(Long accountId) {
try {
final String sql = "select loan.account_no from m_loan loan where loan.id = ?";
return this.jdbcTemplate.queryForObject(sql, new Object[] { accountId }, String.class);
} catch (final EmptyResultDataAccessException e) {
throw new LoanNotFoundException(accountId);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,6 @@ public interface SavingsAccountReadPlatformService {
List<Long> retrieveSavingsIdsPendingEscheat(LocalDate tenantLocalDate);
boolean isAccountBelongsToClient(final Long clientId, final Long accountId, final DepositAccountType depositAccountType, final String currencyCode) ;

String retrieveAccountNumberByAccountId(Long accountId);

}
Original file line number Diff line number Diff line change
Expand Up @@ -1248,4 +1248,14 @@ public boolean isAccountBelongsToClient(final Long clientId, final Long accountI
* return SavingsAccountAnnualFeeData.instance(id, accountNo,
* annualFeeNextDueDate); } }
*/

@Override
public String retrieveAccountNumberByAccountId(Long accountId) {
try {
final String sql = "select s.account_no from m_savings_account s where s.id = ?";
return this.jdbcTemplate.queryForObject(sql, new Object[] { accountId }, String.class);
} catch (final EmptyResultDataAccessException e) {
throw new SavingsAccountNotFoundException(accountId);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.fineract.portfolio.self.pockets.api;

public interface PocketApiConstants {

String pocketsResourceName = "pockets";
String linkAccountsToPocketCommandParam = "linkAccounts";
String delinkAccountsFromPocketCommandParam = "delinkAccounts";

String linkAccountsActionName = "LINK_ACCOUNT_TO";
String pocketEntityName = "POCKET";
String delinkAccountsActionName = "DELINK_ACCOUNT_FROM";

String accountIdParamName = "accountId";
String accountTypeParamName = "accountType";
String accountsDetail = "accountsDetail";
String pocketAccountMappingList = "pocketAccountMappingIds";
String pocketAccountMappingId = "pocketAccountMappingId";

String dataValidationMessage = "validation.msg.validation.errors.exist";
String validationErrorMessage = "Validation errors exist.";
String pocketNotFoundException = "error.msg.pocket.not.found";
String pocketNotFoundErrorMessage = "Pocket not found.";
String mappingIdNotLinkedToPocketException = "mapping.id.not.linked.to.pocket.exception";
String mappingIdNotLinkedToPocketErrorMessage = "Mapping Id is not linked to Pocket.";
String uniqueConstraintName = "m_pocket_account_unique_mapping";
String duplicateMappingException = "error.msg.one.or.more.accounts.are.already.mapped.to.pocket.";
String duplicateMappingExceptionMessage = "One or more accounts are already mapped to pocket.";
String unknownDataIntegrityException = "error.msg.unknown.data.integrity.issue";
String unknownDataIntegrityExceptionMessage = "Unknown data integrity issue with resource.";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.fineract.portfolio.self.pockets.api;

import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo;

import org.apache.commons.lang.StringUtils;
import org.apache.fineract.commands.domain.CommandWrapper;
import org.apache.fineract.commands.service.CommandWrapperBuilder;
import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.exception.UnrecognizedQueryParamException;
import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
import org.apache.fineract.portfolio.self.pockets.service.PocketAccountMappingReadPlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

@Path("/self/pockets")
@Component
@Scope("singleton")
public class PocketApiResource {
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
@SuppressWarnings("rawtypes")
private final DefaultToApiJsonSerializer toApiJsonSerializer;
private final PocketAccountMappingReadPlatformService pocketAccountMappingReadPlatformService;

@SuppressWarnings("rawtypes")
@Autowired
public PocketApiResource(PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
final DefaultToApiJsonSerializer toApiJsonSerializer,
final PocketAccountMappingReadPlatformService pocketAccountMappingReadPlatformService) {
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
this.toApiJsonSerializer = toApiJsonSerializer;
this.pocketAccountMappingReadPlatformService = pocketAccountMappingReadPlatformService;
}

@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String handleCommands(@QueryParam("command") final String commandParam, @Context final UriInfo uriInfo,
final String apiRequestBodyAsJson) {

final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(apiRequestBodyAsJson);

CommandProcessingResult result = null;

if (is(commandParam, PocketApiConstants.linkAccountsToPocketCommandParam)) {
final CommandWrapper commandRequest = builder.linkAccountsToPocket().build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
} else if (is(commandParam, PocketApiConstants.delinkAccountsFromPocketCommandParam)) {
final CommandWrapper commandRequest = builder.delinkAccountsFromPocket().build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
}

if (result == null) {
throw new UnrecognizedQueryParamException("command", commandParam);
}

return this.toApiJsonSerializer.serialize(result);
}

@GET
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveAll() {
return this.toApiJsonSerializer.serialize(this.pocketAccountMappingReadPlatformService.retrieveAll());
}

private boolean is(final String commandParam, final String commandValue) {
return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue);
}

}
Loading

0 comments on commit 0a24570

Please sign in to comment.