MIFOSX-213: support pending, active, closed status for clients.

This commit is contained in:
Keith Woodlock
2013-04-17 13:05:24 +01:00
parent 3001cc3582
commit 1180200ca3
61 changed files with 1596 additions and 1256 deletions
+283 -150
View File
@@ -176,6 +176,14 @@
<td></td>
<td><a href="#clients_retrieve">Retrieve a Client</a></td>
<td><a href="#clients_update">Update a Client</a></td>
<td><a href="#clients_delete">Delete a Client</a></td>
</tr>
<tr class="alt">
<td></td>
<td>clients/{clientId}?command=activate</td>
<td><a href="#clients_activate">Activate a Client</a></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr class="alt">
@@ -1697,8 +1705,8 @@ function executeAjaxRequest(url, verbType, jsonData, basicAuthKey, successFuncti
<div class="method-section">
<div class="method-description">
<h3>Clients</h3>
<p>Clients are people and businesses that have applied (or may
apply) to an MFI for loans.</p>
<p>Clients are people and businesses that have applied (or may apply) to an MFI for loans.</p>
<p>Clients can be created in <b>Pending</b> state (as opposed to <b>Active</b> state) if global configuration for <i>allow-pending-client-status</i> is enabled.</p>
<table class=matrixHeading>
<tr class="matrixHeadingBG">
<td><div class="mifosXHeading2">Field Descriptions</div></td>
@@ -1712,6 +1720,29 @@ function executeAjaxRequest(url, verbType, jsonData, basicAuthKey, successFuncti
auto generated account no. is put in place based on the
configured strategy.</td>
</tr>
<tr class=alt>
<td>externalId</td>
</tr>
<tr>
<td class=fielddesc>A place to put an external reference for
this client e.g. The ID another system uses.<br> If
provided, it must be unique.
</td>
</tr>
<tr class=alt>
<td>active</td>
</tr>
<tr>
<td class=fielddesc>Indicates whether this client is to be created as <b>active</b> client. If active=true, then <b>activationDate</b> must be provided. If active=false, then the client is created as <b>pending</b> but this must be allowed through configuration.
</td>
</tr>
<tr class=alt>
<td>activationDate</td>
</tr>
<tr>
<td class=fielddesc>The date on which the client became <b>active</b>.
</td>
</tr>
<tr class=alt>
<td>firstname</td>
</tr>
@@ -1741,63 +1772,11 @@ function executeAjaxRequest(url, verbType, jsonData, basicAuthKey, successFuncti
business that doesnt suit the firstname,middlename,lastname
structure.</td>
</tr>
<tr class=alt>
<td>externalId</td>
</tr>
<tr>
<td class=fielddesc>A place to put an external reference for
this client e.g. The ID another system uses.<br> If
provided, it must be unique.
</td>
</tr>
</table>
</div>
</div>
<a id="client_list" name="clients_list" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>List Clients</h4>
<p>Example Requests:</p>
<div class=apiClick>clients</div>
<br>
<br>
<div class=apiClick>clients?fields=displayName,officeName,joinedDate</div>
</div>
<div class="method-example">
<code class="method-declaration">
GET https://DomainName/api/v1/clients
</code>
<code class="method-response">
[
{
"id": 2,
"accountNo": "000000002",
"externalId": "one/78",
"fullname": "New Business to Create",
"displayName": "New Business to Create",
"officeId": 1,
"officeName": "Head Office",
"joinedDate": [2006,6,13]
},
{
"id": 1,
"accountNo": "000000001",
"externalId": "786YYH7",
"firstname": "Petra",
"lastname": "Yton",
"displayName": "Petra Yton",
"officeId": 1,
"officeName": "Head Office",
"joinedDate": [2009,3,4]
}
]
</code>
</div>
</div>
<a id="clients_template" name="clients_template"
class="old-syle-anchor">&nbsp;</a>
<a id="clients_template" name="clients_template" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Retrieve Client Details Template</h4>
@@ -1819,58 +1798,20 @@ GET https://DomainName/api/v1/clients/template
</code>
<code class="method-response">
{
"officeId": 1,
"joinedDate": [
2013,
2,
5
],
"allowedOffices": [
{
"id": 1,
"name": "Head Office",
"nameDecorated": "Head Office"
}
]
}
</code>
</div>
</div>
<a id="clients_retrieve" name="clients_retrieve"
class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Retrieve a Client</h4>
<p>Example Requests:</p>
<div class=apiClick>clients/1</div>
<br>
<br>
<div class=apiClick>clients/1?template=true</div>
<br>
<br>
<div class=apiClick>clients/1?fields=id,displayName,officeName</div>
</div>
<div class="method-example">
<code class="method-declaration">
GET https://DomainName/api/v1/clients/{clientId}
</code>
<code class="method-response">
{
"id": 1,
"accountNo": "000000001",
"externalId": "786YYH7",
"firstname": "Petra",
"lastname": "Yton",
"displayName": "Petra Yton",
"officeId": 1,
"officeName": "Head Office",
"joinedDate": [
2009,
3,
4
]
"activationDate": [
2013,
4,
17
],
"officeId": 1,
"clientPendingApprovalAllowed": false,
"officeOptions": [
{
"id": 1,
"name": "Head Office",
"nameDecorated": "Head Office"
}
]
}
</code>
</div>
@@ -1891,11 +1832,19 @@ GET https://DomainName/api/v1/clients/{clientId}
<td><div class="mifosXHeading2">Mandatory Fields</div></td>
</tr>
<tr class=alt>
<td>firstname and lastname OR fullname<br>, joinedDate,
officeId
<td>firstname and lastname OR fullname,<br> officeId,<br> active=true and activationDate OR active=false,<br>
</td>
</tr>
</table>
<br />
<table class=matrixHeading>
<tr class="matrixHeadingBG">
<td><div class="mifosXHeading2">Optional Fields</div></td>
</tr>
<tr class=alt>
<td>groupId, externalId, accountNo</td>
</tr>
</table>
</div>
<div class="method-example">
<code class="method-declaration">
@@ -1904,14 +1853,15 @@ POST https://DomainName/api/v1/clients
<code class="method-request">
POST clients
Content-Type: application/json Request Body:
{
"officeId": 1,
"firstname": "Petra",
"lastname": "Yton",
"externalId": "786YYH7",
"dateFormat": "dd MMMM yyyy",
"locale": "en",
"joinedDate": "04 March 2009"
{
"officeId": 1,
"firstname": "Petra",
"lastname": "Yton",
"externalId": "786YYH7",
"dateFormat": "dd MMMM yyyy",
"locale": "en",
"active": true,
"activationDate": "04 March 2009"
}
</code>
<code class="method-response">
@@ -1926,30 +1876,166 @@ Content-Type: application/json Request Body:
<code class="method-request">
POST clients
Content-Type: application/json
Request Body:
{
"officeId": 1,
"fullname": "New Business to Create",
"externalId": "one/78",
"dateFormat": "dd MMMM yyyy",
"locale": "en",
"joinedDate": "13 June 2006"
Request Body:
{
"officeId": 1,
"fullname": "Client of group",
"groupId": 1,
"dateFormat": "dd MMMM yyyy",
"locale": "en",
"active": true,
"activationDate": "04 March 2009"
}
</code>
<code class="method-response">
{
"officeId": 1,
"clientId": 2,
"resourceId": 2
"officeId": 1,
"groupId": 1,
"clientId": 2,
"resourceId": 2
}
</code>
</div>
</div>
<a id="clients_activate" name="clients_activate" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h2>Activate a Client</h2>
<p>Clients can be created in a <i>Pending</i> state if configuration is enabled. This API exists to enable client activation (for when a client becomes approved member of microfinance institue.</p>
<p>If the client happens to be alrady active this API will result in an error.</p>
</div>
<div class="method-example">
<code class="method-declaration">POST https://Domain Name/api/v1/clients/{clientId}?command=activate</code>
<code class="method-request">POST clients/1?command=activate
Content-Type: application/json
Request Body:
{
"locale": "en",
"dateFormat": "dd MMMM yyyy",
"activationDate": "01 March 2011"
}
</code>
<code class="method-response">
{
"officeId": 1,
"clientId": 1,
"resourceId": 1
}
</code>
</div>
</div>
<a id="clients_retrieve" name="clients_retrieve" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Retrieve a Client</h4>
<p>Example Requests:</p>
<div class=apiClick>clients/1</div>
<br>
<br>
<div class=apiClick>clients/1?template=true</div>
<br>
<br>
<div class=apiClick>clients/1?fields=id,displayName,officeName</div>
</div>
<div class="method-example">
<code class="method-declaration">
GET https://DomainName/api/v1/clients/{clientId}
</code>
<code class="method-response">
{
"id": 2,
"accountNo": "000000002",
"status": {
"id": 300,
"code": "clientStatusType.active",
"value": "Active"
},
"activationDate": [
2009,
3,
4
],
"fullname": "Client of group",
"displayName": "Client of group",
"officeId": 1,
"officeName": "Head Office",
"groups": [
{
"id": 1,
"name": "Example Group"
}
]
}
</code>
</div>
</div>
<a id="client_list" name="clients_list" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>List Clients</h4>
<p>Example Requests:</p>
<div class=apiClick>clients</div>
<br>
<br>
<div class=apiClick>clients?fields=displayName,officeName,joinedDate</div>
</div>
<div class="method-example">
<code class="method-declaration">
GET https://DomainName/api/v1/clients
</code>
<code class="method-response">
[
{
"id": 2,
"accountNo": "000000002",
"status": {
"id": 300,
"code": "clientStatusType.active",
"value": "Active"
},
"activationDate": [
2009,
3,
4
],
"fullname": "Client of group",
"displayName": "Client of group",
"officeId": 1,
"officeName": "Head Office"
},
{
"id": 1,
"accountNo": "000000001",
"externalId": "786YYH7",
"status": {
"id": 300,
"code": "clientStatusType.active",
"value": "Active"
},
"activationDate": [
2009,
3,
4
],
"firstname": "Petra",
"lastname": "Yton",
"displayName": "Petra Yton",
"officeId": 1,
"officeName": "Head Office"
}
]
</code>
</div>
</div>
<a id="clients_update" name="clients_update" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Update a Client</h4>
<p>You can update any attribute of a client except for its association with <i>groups</i>. The relationship between a client and a group must be removed through the <b>Groups</b> API.</p>
</div>
<div class="method-example">
<code class="method-declaration">
@@ -1960,10 +2046,7 @@ PUT clients/1
Content-Type: application/json
Request Body:
{
"externalId": "786444UUUYYH7",
"dateFormat": "dd MMMM yyyy",
"locale": "en",
"joinedDate": "09 June 2006"
"externalId": "786444UUUYYH7"
}
</code>
<code class="method-response">
@@ -1972,18 +2055,41 @@ Request Body:
"clientId": 1,
"resourceId": 1,
"changes": {
"externalId": "786444UUUYYH7",
"joinedDate": "09 June 2006",
"dateFormat": "dd MMMM yyyy",
"locale": "en"
"externalId": "786444UUUYYH7"
}
}
</code>
</div>
</div>
<a id="clients_loansummary" name="clients_loansummary"
class="old-syle-anchor">&nbsp;</a>
<a id="clients_delete" name="clients_delete" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Delete a Client</h4>
<p>If a client is in <i>Pending</i> state you are allowed to <b>Delete</b> it. The delete is a 'hard delete' and cannot be recovered from. Once clients become active or have loans or savings associated with it, you cannot delete the client but you may <b>Close</b> the client if they have died or exited the program.</p>
</div>
<div class="method-example">
<code class="method-declaration">
DELETE https://DomainName/api/v1/clients/{clientId}
</code>
<code class="method-request">
DELETE clients/3
Content-Type: application/json
Request Body:
{
}
</code>
<code class="method-response">
{
"officeId": 1,
"clientId": 3,
"resourceId": 3
}
</code>
</div>
</div>
<a id="clients_loansummary" name="clients_loansummary" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Retrieve a Client's Loan Account Summary</h4>
@@ -7066,13 +7172,16 @@ Request Body:
<div class="method-section">
<div class="method-description">
<h3>Global Configuration</h3>
<p>Global configuration related to set of supported
enable/disable configurations e.g. maker-checker.</p>
<p>Global configuration related to set of supported enable/disable configurations:</p>
<ol>
<li><b>maker-checker</b> - defaults to false - if true turns on maker-checker functionality</li>
<li><b>allow-pending-client-status</b> - defaults to false - if true allows clients to be created in 'Pending' state</li>
<li><b>allow-pending-group-status</b> - defaults to false - if true allows groups to be created in 'Pending' state</li>
</ol>
</div>
</div>
<a id="configs_globalconfig_retrieve"
name="configs_globalconfig_retrieve" class="old-syle-anchor">&nbsp;</a>
<a id="configs_globalconfig_retrieve" name="configs_globalconfig_retrieve" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Retrieve Global Configuration</h4>
@@ -7086,12 +7195,20 @@ GET https://DomainName/api/v1/configurations
</code>
<code class="method-response">
{
"globalConfiguration": [
{
"name": "maker-checker",
"enabled": false
}
]
"globalConfiguration": [
{
"name": "maker-checker",
"enabled": false
},
{
"name": "allow-pending-client-status",
"enabled": false
},
{
"name": "allow-pending-group-status",
"enabled": false
}
]
}
</code>
</div>
@@ -7105,14 +7222,22 @@ GET https://DomainName/api/v1/configurations
</div>
<div class="method-example">
<code class="method-declaration">
PUT https://DomainName/api/v1/configurations?maker-checker=false
PUT https://DomainName/api/v1/configurations?allow-pending-client-status=false
</code>
<code class="method-request">
PUT configurations
Content-Type: application/json
Request Body: { }
</code>
<code class="method-response">{ "changes": {} } </code>
<code class="method-response">
{
"changes": {
"globalConfiguration": {
"allow-pending-client-status": false
}
}
}
</code>
</div>
</div>
@@ -12884,6 +13009,14 @@ GET https://DomainName/api/v1/search?query=000000111
<td></td>
<td><a href="#clients_retrieve">Retrieve a Client</a></td>
<td><a href="#clients_update">Update a Client</a></td>
<td><a href="#clients_delete">Delete a Client</a></td>
</tr>
<tr class="alt">
<td></td>
<td>clients/{clientId}?command=activate</td>
<td><a href="#clients_activate">Activate a Client</a></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr class="alt">
@@ -0,0 +1,8 @@
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'ACTIVATE_CLIENT', 'CLIENT', 'ACTIVATE', 1);
INSERT INTO `m_permission` (`grouping`, `code`, `entity_name`, `action_name`, `can_maker_checker`) VALUES ('portfolio', 'ACTIVATE_CLIENT_CHECKER', 'CLIENT', 'ACTIVATE', 0);
ALTER TABLE `m_client`
CHANGE COLUMN `external_id` `external_id` VARCHAR(100) NULL DEFAULT NULL AFTER `account_no`,
CHANGE COLUMN `status_enum` `status_enum` INT(5) NOT NULL DEFAULT '300' AFTER `external_id`,
CHANGE COLUMN `joined_date` `activation_date` DATE NULL DEFAULT NULL AFTER `status_enum`;
@@ -1,29 +1,28 @@
package org.mifosplatform.integrationtests;
import com.jayway.restassured.builder.RequestSpecBuilder;
import com.jayway.restassured.builder.ResponseSpecBuilder;
import com.jayway.restassured.http.ContentType;
import com.jayway.restassured.specification.RequestSpecification;
import com.jayway.restassured.specification.ResponseSpecification;
import java.util.HashMap;
import org.junit.Before;
import org.junit.Test;
import org.mifosplatform.integrationtests.common.*;
import org.mifosplatform.integrationtests.common.ClientHelper;
import org.mifosplatform.integrationtests.common.Utils;
import org.mifosplatform.integrationtests.common.accounting.Account;
import org.mifosplatform.integrationtests.common.accounting.JournalEntry;
import org.mifosplatform.integrationtests.common.accounting.AccountHelper;
import org.mifosplatform.integrationtests.common.accounting.JournalEntry;
import org.mifosplatform.integrationtests.common.accounting.JournalEntryHelper;
import org.mifosplatform.integrationtests.common.loans.LoanApplicationTestBuilder;
import org.mifosplatform.integrationtests.common.loans.LoanProductTestBuilder;
import org.mifosplatform.integrationtests.common.loans.LoanStatusChecker;
import org.mifosplatform.integrationtests.common.loans.LoanTransactionHelper;
import java.util.HashMap;
import static org.junit.Assert.assertThat;
import com.jayway.restassured.builder.RequestSpecBuilder;
import com.jayway.restassured.builder.ResponseSpecBuilder;
import com.jayway.restassured.http.ContentType;
import com.jayway.restassured.specification.RequestSpecification;
import com.jayway.restassured.specification.ResponseSpecification;
@SuppressWarnings("rawtypes")
public class AccountingScenario {
private RequestSpecification requestSpec;
private ResponseSpecification responseSpec;
@@ -170,12 +169,12 @@ public class AccountingScenario {
System.out.println("Repayment 5 Done ......");
}
private Integer createLoanProduct(Account ... accounts) {
private Integer createLoanProduct(final Account ... accounts) {
System.out.println("------------------------------CREATING NEW LOAN PRODUCT ---------------------------------------");
String loanProductJSON = new LoanProductTestBuilder().withPrincipal(LP_PRINCIPAL.toString()).withRepaymentTypeAsMonth()
.withRepaymentAfterEvery(LP_REPAYMENT_PERIOD).withNumberOfRepayments(LP_REPAYMENTS).withRepaymentTypeAsMonth()
.withinterestRatePerPeriod(LP_INTEREST_RATE).withInterestRateFrequencyTypeAsMonths()
.withAmortizationTypeAsEqualPrinciplePayment().withInterestTypeAsFlat()
.withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsFlat()
.withAccountingRuleAsAccrualBased(accounts)
.build();
return loanTransactionHelper.getLoanProductId(loanProductJSON);
@@ -1,17 +1,15 @@
package org.mifosplatform.integrationtests;
//import static org.junit.Assert.assertEquals;
import java.util.HashMap;
import org.junit.Before;
import org.junit.Test;
import org.mifosplatform.integrationtests.common.ClientHelper;
import org.mifosplatform.integrationtests.common.Utils;
import org.mifosplatform.integrationtests.common.loans.LoanApplicationTestBuilder;
import org.mifosplatform.integrationtests.common.loans.LoanProductTestBuilder;
import org.mifosplatform.integrationtests.common.loans.LoanStatusChecker;
import org.mifosplatform.integrationtests.common.loans.LoanTransactionHelper;
import org.mifosplatform.integrationtests.common.Utils;
import com.jayway.restassured.builder.RequestSpecBuilder;
import com.jayway.restassured.builder.ResponseSpecBuilder;
@@ -19,13 +17,11 @@ import com.jayway.restassured.http.ContentType;
import com.jayway.restassured.specification.RequestSpecification;
import com.jayway.restassured.specification.ResponseSpecification;
import static org.junit.Assert.assertEquals;
/**
* Client Loan Integration Test for checking Loan Disbursement with Waive
* Interest and Write-Off.
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
@SuppressWarnings({ "rawtypes" })
public class LoanWithWaiveInterestAndWriteOffIntegrationTest {
private ResponseSpecification responseSpec;
@@ -120,7 +116,8 @@ public class LoanWithWaiveInterestAndWriteOffIntegrationTest {
String loanProductJSON = new LoanProductTestBuilder().withPrincipal(LP_PRINCIPAL).withRepaymentTypeAsMonth()
.withRepaymentAfterEvery(LP_REPAYMENT_PERIOD).withNumberOfRepayments(LP_REPAYMENTS).withRepaymentTypeAsMonth()
.withinterestRatePerPeriod(LP_INTEREST_RATE).withInterestRateFrequencyTypeAsMonths()
.withAmortizationTypeAsEqualPrinciplePayment().withInterestTypeAsFlat().build();
.withAmortizationTypeAsEqualPrincipalPayment().withInterestTypeAsFlat().build();
return loanTransactionHelper.getLoanProductId(loanProductJSON);
}
@@ -1,22 +1,25 @@
package org.mifosplatform.integrationtests;
import java.util.HashMap;
import org.junit.Before;
import org.junit.Test;
import org.mifosplatform.integrationtests.common.ClientHelper;
import org.mifosplatform.integrationtests.common.Utils;
import org.mifosplatform.integrationtests.common.loans.LoanApplicationTestBuilder;
import org.mifosplatform.integrationtests.common.loans.LoanProductTestBuilder;
import org.mifosplatform.integrationtests.common.loans.LoanStatusChecker;
import org.mifosplatform.integrationtests.common.loans.LoanTransactionHelper;
import com.jayway.restassured.builder.RequestSpecBuilder;
import com.jayway.restassured.builder.ResponseSpecBuilder;
import com.jayway.restassured.http.ContentType;
import com.jayway.restassured.specification.RequestSpecification;
import com.jayway.restassured.specification.ResponseSpecification;
import org.junit.Before;
import org.junit.Test;
import org.mifosplatform.integrationtests.common.*;
import org.mifosplatform.integrationtests.common.loans.LoanApplicationTestBuilder;
import org.mifosplatform.integrationtests.common.loans.LoanProductTestBuilder;
import org.mifosplatform.integrationtests.common.loans.LoanStatusChecker;
import org.mifosplatform.integrationtests.common.loans.LoanTransactionHelper;
import java.util.HashMap;
@SuppressWarnings("rawtypes")
public class LoanWithdrawnByApplicant {
private ResponseSpecification responseSpec;
private RequestSpecification requestSpec;
private LoanTransactionHelper loanTransactionHelper;
@@ -28,32 +31,29 @@ public class LoanWithdrawnByApplicant {
requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
loanTransactionHelper = new LoanTransactionHelper(requestSpec,responseSpec);
loanTransactionHelper = new LoanTransactionHelper(requestSpec, responseSpec);
}
@Test
public void loanWithdrawnByApplicant(){
Integer clientID = ClientHelper.createClient(requestSpec,responseSpec,"01 January 2012");
public void loanWithdrawnByApplicant() {
Integer clientID = ClientHelper.createClient(requestSpec, responseSpec, "01 January 2012");
Integer loanProductID = loanTransactionHelper.getLoanProductId(new LoanProductTestBuilder().build());
Integer loanID = applyForLoanApplication(clientID, loanProductID);
Integer loanID = applyForLoanApplication(clientID, loanProductID);
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
HashMap loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
loanTransactionHelper.withdrawLoanApplicationByClient("03 April 2012",loanID);
loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec,responseSpec,loanID);
LoanStatusChecker.verifyLoanAccountIsNotActive(loanStatusHashMap);
loanTransactionHelper.withdrawLoanApplicationByClient("03 April 2012", loanID);
loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
LoanStatusChecker.verifyLoanAccountIsNotActive(loanStatusHashMap);
}
private Integer applyForLoanApplication(Integer clientID, Integer loanProductID){
String loanApplication = new LoanApplicationTestBuilder()
.withPrincipal("5000").withLoanTermFrequency("5").withLoanTermFrequencyAsMonths()
.withNumberOfRepayments("5").withRepaymentEveryAfter("1").withRepaymentFrequencyTypeAsMonths()
.withInterestRatePerPeriod("2")
.withExpectedDisbursementDate("04 April 2012")
.withSubmittedOnDate("02 April 2012")
.build(clientID.toString(),loanProductID.toString());
private Integer applyForLoanApplication(final Integer clientID, final Integer loanProductID) {
String loanApplication = new LoanApplicationTestBuilder().withPrincipal("5000").withLoanTermFrequency("5")
.withLoanTermFrequencyAsMonths().withNumberOfRepayments("5").withRepaymentEveryAfter("1")
.withRepaymentFrequencyTypeAsMonths().withInterestRatePerPeriod("2").withExpectedDisbursementDate("04 April 2012")
.withSubmittedOnDate("02 April 2012").build(clientID.toString(), loanProductID.toString());
return loanTransactionHelper.getLoanId(loanApplication);
}
}
@@ -1,81 +1,92 @@
package org.mifosplatform.integrationtests.common.accounting;
import com.google.gson.Gson;
import org.mifosplatform.integrationtests.common.ClientHelper;
import org.mifosplatform.integrationtests.common.Utils;
import java.util.Calendar;
import java.util.HashMap;
import org.mifosplatform.integrationtests.common.Utils;
import com.google.gson.Gson;
public class GLAccountBuilder {
public static final String ASSET_ACCOUNT="1";
public static final String LIABILITY_ACCOUNT="2";
public static final String EQUITY_ACCOUNT="3";
public static final String INCOME_ACCOUNT="4";
public static final String EXPENSE_ACCOUNT="5";
public static final String ASSET_ACCOUNT = "1";
public static final String LIABILITY_ACCOUNT = "2";
public static final String EQUITY_ACCOUNT = "3";
public static final String INCOME_ACCOUNT = "4";
public static final String EXPENSE_ACCOUNT = "5";
private static final String ACCOUNT_USAGE_DETAIL="1";
private static final String ACCOUNT_USAGE_HEADER="2";
private static final String MANUAL_ENTRIES_ALLOW="true";
private static final String MANUAL_ENTRIES_NOT_ALLOW="false";
private static final String ACCOUNT_USAGE_DETAIL = "1";
private static final String ACCOUNT_USAGE_HEADER = "2";
private static final String MANUAL_ENTRIES_ALLOW = "true";
private static final String MANUAL_ENTRIES_NOT_ALLOW = "false";
private static String name = Utils.randomStringGenerator("ACCOUNT_NAME_", 5);
private static String GLCode="";
private static String accountType="";
private static String accountUsage=ACCOUNT_USAGE_DETAIL;
private static String manualEntriesAllowed=MANUAL_ENTRIES_ALLOW;
private static String GLCode = "";
private static String accountType = "";
private static String accountUsage = ACCOUNT_USAGE_DETAIL;
private static String manualEntriesAllowed = MANUAL_ENTRIES_ALLOW;
private static String description = "DEFAULT_DESCRIPTION";
public String build(){
public String build() {
HashMap<String, String> map = new HashMap<String, String>();
map.put("name",this.name);
map.put("glCode",this.GLCode);
map.put("manualEntriesAllowed",this.manualEntriesAllowed);
map.put("type",this.accountType);
map.put("usage",this.accountUsage);
map.put("description",this.description);
map.put("name", GLAccountBuilder.name);
map.put("glCode", GLAccountBuilder.GLCode);
map.put("manualEntriesAllowed", GLAccountBuilder.manualEntriesAllowed);
map.put("type", GLAccountBuilder.accountType);
map.put("usage", GLAccountBuilder.accountUsage);
map.put("description", GLAccountBuilder.description);
return new Gson().toJson(map);
}
public GLAccountBuilder withAccountTypeAsAsset(){
this.accountType= ASSET_ACCOUNT;
this.GLCode= Utils.randomStringGenerator("ASSET_",2);
this.GLCode+= Calendar.getInstance().getTimeInMillis()+""; //Added unique timestamp for avoiding random collisions
return this;
}
public GLAccountBuilder withAccountTypeAsLiability(){
this.accountType=LIABILITY_ACCOUNT;
this.GLCode=Utils.randomStringGenerator("LIABILITY_",2);
this.GLCode+= Calendar.getInstance().getTimeInMillis()+"";
return this;
}
public GLAccountBuilder withAccountTypeAsAsEquity(){
this.accountType=EQUITY_ACCOUNT;
this.GLCode=Utils.randomStringGenerator("EQUITY_",2);
this.GLCode+= Calendar.getInstance().getTimeInMillis()+"";
return this;
}
public GLAccountBuilder withAccountTypeAsIncome(){
this.accountType=INCOME_ACCOUNT;
this.GLCode=Utils.randomStringGenerator("INCOME_",2);
this.GLCode+= Calendar.getInstance().getTimeInMillis()+"";
return this;
}
public GLAccountBuilder withAccountTypeAsExpense(){
this.accountType=EXPENSE_ACCOUNT;
this.GLCode=Utils.randomStringGenerator("EXPENSE_",2);
this.GLCode+= Calendar.getInstance().getTimeInMillis()+"";
return this;
}
public GLAccountBuilder withAccountUsageAsHeader(){
this.accountUsage = ACCOUNT_USAGE_HEADER;
public GLAccountBuilder withAccountTypeAsAsset() {
GLAccountBuilder.accountType = ASSET_ACCOUNT;
GLAccountBuilder.GLCode = Utils.randomStringGenerator("ASSET_", 2);
GLAccountBuilder.GLCode += Calendar.getInstance().getTimeInMillis() + ""; // Added
// unique
// timestamp
// for
// avoiding
// random
// collisions
return this;
}
public GLAccountBuilder withMaualEntriesNotAllowed(){
this.manualEntriesAllowed = MANUAL_ENTRIES_NOT_ALLOW;
public GLAccountBuilder withAccountTypeAsLiability() {
GLAccountBuilder.accountType = LIABILITY_ACCOUNT;
GLAccountBuilder.GLCode = Utils.randomStringGenerator("LIABILITY_", 2);
GLAccountBuilder.GLCode += Calendar.getInstance().getTimeInMillis() + "";
return this;
}
public GLAccountBuilder withAccountTypeAsAsEquity() {
GLAccountBuilder.accountType = EQUITY_ACCOUNT;
GLAccountBuilder.GLCode = Utils.randomStringGenerator("EQUITY_", 2);
GLAccountBuilder.GLCode += Calendar.getInstance().getTimeInMillis() + "";
return this;
}
public GLAccountBuilder withAccountTypeAsIncome() {
GLAccountBuilder.accountType = INCOME_ACCOUNT;
GLAccountBuilder.GLCode = Utils.randomStringGenerator("INCOME_", 2);
GLAccountBuilder.GLCode += Calendar.getInstance().getTimeInMillis() + "";
return this;
}
public GLAccountBuilder withAccountTypeAsExpense() {
GLAccountBuilder.accountType = EXPENSE_ACCOUNT;
GLAccountBuilder.GLCode = Utils.randomStringGenerator("EXPENSE_", 2);
GLAccountBuilder.GLCode += Calendar.getInstance().getTimeInMillis() + "";
return this;
}
public GLAccountBuilder withAccountUsageAsHeader() {
GLAccountBuilder.accountUsage = ACCOUNT_USAGE_HEADER;
return this;
}
public GLAccountBuilder withMaualEntriesNotAllowed() {
GLAccountBuilder.manualEntriesAllowed = MANUAL_ENTRIES_NOT_ALLOW;
return this;
}
}
@@ -1,48 +1,50 @@
package org.mifosplatform.integrationtests.common.accounting;
import com.jayway.restassured.specification.RequestSpecification;
import com.jayway.restassured.specification.ResponseSpecification;
import org.mifosplatform.integrationtests.common.Utils;
import java.util.ArrayList;
import java.util.HashMap;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
import java.util.ArrayList;
import java.util.HashMap;
import org.mifosplatform.integrationtests.common.Utils;
import com.jayway.restassured.specification.RequestSpecification;
import com.jayway.restassured.specification.ResponseSpecification;
@SuppressWarnings("rawtypes")
public class JournalEntryHelper {
private RequestSpecification requestSpec;
private ResponseSpecification responseSpec;
private final RequestSpecification requestSpec;
private final ResponseSpecification responseSpec;
public JournalEntryHelper(RequestSpecification requestSpec, ResponseSpecification responseSpec) {
public JournalEntryHelper(final RequestSpecification requestSpec, final ResponseSpecification responseSpec) {
this.requestSpec = requestSpec;
this.responseSpec = responseSpec;
}
public void checkJournalEntryForExpenseAccount(Account expenseAccount, String date, JournalEntry accountEntries) {
public void checkJournalEntryForExpenseAccount(final Account expenseAccount, final String date, final JournalEntry accountEntries) {
checkJournalEntry(expenseAccount, Utils.convertDateToURLFormat(date),accountEntries);
}
public void checkJournalEntryForAssetAccount(Account assetAccount, String date, JournalEntry... accountEntries) {
public void checkJournalEntryForAssetAccount(final Account assetAccount, final String date, final JournalEntry... accountEntries) {
checkJournalEntry(assetAccount,Utils.convertDateToURLFormat(date),accountEntries);
}
public void checkJournalEntryForIncomeAccount(Account incomeAccount, String date, JournalEntry accountEntries) {
public void checkJournalEntryForIncomeAccount(final Account incomeAccount, final String date, final JournalEntry accountEntries) {
checkJournalEntry(incomeAccount, Utils.convertDateToURLFormat(date), accountEntries);
}
private String getEntryValueFromJournalEntry(ArrayList<HashMap> entryResponse, int entryNumber) {
private String getEntryValueFromJournalEntry(final ArrayList<HashMap> entryResponse, final int entryNumber) {
HashMap map = (HashMap) entryResponse.get(entryNumber).get("entryType");
return (String) map.get("value");
}
private Float getTransactionAmountFromJournalEntry(ArrayList<HashMap> entryResponse, int entryNumber) {
private Float getTransactionAmountFromJournalEntry(final ArrayList<HashMap> entryResponse, final int entryNumber) {
return (Float) entryResponse.get(entryNumber).get("amount");
}
private void checkJournalEntry(Account account, String date, JournalEntry... accountEntries){
private void checkJournalEntry(final Account account, final String date, final JournalEntry... accountEntries){
String url = createURLForGettingAccountEntries(account,date);
ArrayList<HashMap> response = Utils.performServerGet(requestSpec, responseSpec, url, "");
for (int i = 0; i < accountEntries.length; i++) {
@@ -51,7 +53,7 @@ public class JournalEntryHelper {
}
}
private String createURLForGettingAccountEntries (Account account,String date){
private String createURLForGettingAccountEntries (final Account account,final String date){
return new String ("/mifosng-provider/api/v1/journalentries?glAccountId=" + account.getAccountID() + "&type=" +account.getAccountType()
+ "&fromDate=" + date + "&toDate=" + date + "&tenantIdentifier=default");
}
@@ -12,7 +12,7 @@ public class LoanApplicationTestBuilder {
private static final String YEARS = "3";
private static final String DECLINING_BALANCE = "0";
private static final String FLAT_BALANCE = "1";
private static final String EQUAL_PRINCIPLE_PAYMENTS = "0";
private static final String EQUAL_PRINCIPAL_PAYMENTS = "0";
private static final String EQUAL_INSTALLMENTS = "1";
private static final String CALCULATION_PERIOD_SAME_AS_REPAYMENT_PERIOD = "1";
private static final String MIFOS_STANDARD_STRATEGY = "1";
@@ -26,7 +26,7 @@ public class LoanApplicationTestBuilder {
private String interestRate = "2";
private String interestType = FLAT_BALANCE;
private String amortizationType = EQUAL_PRINCIPLE_PAYMENTS;
private String amortizationType = EQUAL_PRINCIPAL_PAYMENTS;
private String interestCalculationPeriodType = CALCULATION_PERIOD_SAME_AS_REPAYMENT_PERIOD;
private final String transactionProcessingID = MIFOS_STANDARD_STRATEGY;
private String expectedDisbursmentDate = "";
@@ -131,7 +131,7 @@ public class LoanApplicationTestBuilder {
}
public LoanApplicationTestBuilder withAmortizationTypeAsEqualPrincipalPayments() {
this.amortizationType = EQUAL_PRINCIPLE_PAYMENTS;
this.amortizationType = EQUAL_PRINCIPAL_PAYMENTS;
return this;
}
@@ -16,7 +16,7 @@ public class LoanProductTestBuilder {
private static final String MONTHS = "2";
private static final String YEARS = "3";
private static final String CALCULATION_PERIOD_SAME_AS_REPAYMENT_PERIOD="1";
private static final String EQUAL_PRINCIPLE_PAYMENTS="0";
private static final String EQUAL_PRINCIPAL_PAYMENTS="0";
private static final String EQUAL_INSTALLMENTS="1";
private static final String DECLINING_BALANCE="0";
private static final String FLAT_BALANCE="1";
@@ -137,8 +137,8 @@ public class LoanProductTestBuilder {
return this;
}
public LoanProductTestBuilder withAmortizationTypeAsEqualPrinciplePayment(){
this.amortizationType = EQUAL_PRINCIPLE_PAYMENTS;
public LoanProductTestBuilder withAmortizationTypeAsEqualPrincipalPayment(){
this.amortizationType = EQUAL_PRINCIPAL_PAYMENTS;
return this;
}
@@ -1,20 +1,21 @@
package org.mifosplatform.integrationtests.common.loans;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.HashMap;
import org.mifosplatform.integrationtests.common.Utils;
import com.google.gson.Gson;
import com.jayway.restassured.specification.RequestSpecification;
import com.jayway.restassured.specification.ResponseSpecification;
import org.mifosplatform.integrationtests.common.Utils;
import static org.junit.Assert.assertEquals;
@SuppressWarnings("rawtypes")
public class LoanTransactionHelper {
private RequestSpecification requestSpec;
private ResponseSpecification responseSpec;
private final RequestSpecification requestSpec;
private final ResponseSpecification responseSpec;
private static final String CREATE_LOAN_PRODUCT_URL = "/mifosng-provider/api/v1/loanproducts?tenantIdentifier=default";
private static final String APPLY_LOAN_URL = "/mifosng-provider/api/v1/loans?tenantIdentifier=default";
@@ -28,7 +29,7 @@ public class LoanTransactionHelper {
private static final String WITHDRAW_LOAN_APPLICATION_COMMAND = "withdrawnByApplicant";
public LoanTransactionHelper(RequestSpecification requestSpec,ResponseSpecification responseSpec){
public LoanTransactionHelper(final RequestSpecification requestSpec,final ResponseSpecification responseSpec){
this.requestSpec = requestSpec;
this.responseSpec = responseSpec;
}
@@ -182,6 +183,7 @@ public class LoanTransactionHelper {
return (HashMap) response.get("status");
}
@SuppressWarnings("unchecked")
public void verifyRepaymentScheduleEntryFor(final int repaymentNumber, final float expectedPrincipalOutstanding, final Integer loanID) {
System.out.println("---------------------------GETTING LOAN REPAYMENT SCHEDULE--------------------------------");
ArrayList<HashMap> repaymentPeriods = getLoanRepaymentSchedule(requestSpec, responseSpec, loanID);
@@ -22,7 +22,7 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
}
@Override
public void createJournalEntriesForLoan(LoanDTO loanDTO) {
public void createJournalEntriesForLoan(final LoanDTO loanDTO) {
final GLClosure latestGLClosure = this.helper.getLatestClosureByBranch(loanDTO.getOfficeId());
final Office office = this.helper.getOfficeById(loanDTO.getOfficeId());
for (final LoanTransactionDTO loanTransactionDTO : loanDTO.getNewLoanTransactions()) {
@@ -175,7 +175,7 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
BigDecimal totalDebitAmount = new BigDecimal(0);
// handle principle payment or writeOff (and reversals)
// handle principal payment or writeOff (and reversals)
if (principalAmount != null && !(principalAmount.compareTo(BigDecimal.ZERO) == 0)) {
totalDebitAmount = totalDebitAmount.add(principalAmount);
helper.createCreditJournalEntryOrReversalForLoan(office, ACCRUAL_ACCOUNTS_FOR_LOAN.LOAN_PORTFOLIO, loanProductId, loanId,
@@ -25,7 +25,6 @@ import javax.ws.rs.core.UriInfo;
import org.apache.commons.lang.StringUtils;
import org.mifosplatform.commands.data.AuditData;
import org.mifosplatform.commands.data.AuditSearchData;
import org.mifosplatform.commands.data.CommandSourceData;
import org.mifosplatform.commands.service.AuditReadPlatformService;
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
import org.mifosplatform.infrastructure.core.api.ApiParameterHelper;
@@ -43,183 +42,146 @@ import org.springframework.stereotype.Component;
@Scope("singleton")
public class MakercheckersApiResource {
private final Set<String> RESPONSE_DATA_PARAMETERS = new HashSet<String>(
Arrays.asList("id", "actionName", "entityName", "resourceId",
"subresourceId", "maker", "madeOnDate", "checker",
"checkedOnDate", "processingResult", "commandAsJson",
"officeName", "groupLevelName", "groupName", "clientName",
"loanAccountNo", "savingsAccountNo"));
//Next line removed because read permissions checks part of read services
//private final String resourceNameForPermissions = "MAKERCHECKER";
private final Set<String> RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("id", "actionName", "entityName", "resourceId",
"subresourceId", "maker", "madeOnDate", "checker", "checkedOnDate", "processingResult", "commandAsJson", "officeName",
"groupLevelName", "groupName", "clientName", "loanAccountNo", "savingsAccountNo"));
private final AuditReadPlatformService readPlatformService;
private final DefaultToApiJsonSerializer<CommandSourceData> toApiJsonSerializer;
private final DefaultToApiJsonSerializer<AuditData> toApiJsonSerializerAudit;
private final DefaultToApiJsonSerializer<AuditSearchData> toApiJsonSerializerSearchTemplate;
private final ApiRequestParameterHelper apiRequestParameterHelper;
private final PortfolioCommandSourceWritePlatformService writePlatformService;
private final AuditReadPlatformService readPlatformService;
private final DefaultToApiJsonSerializer<AuditData> toApiJsonSerializerAudit;
private final DefaultToApiJsonSerializer<AuditSearchData> toApiJsonSerializerSearchTemplate;
private final ApiRequestParameterHelper apiRequestParameterHelper;
private final PortfolioCommandSourceWritePlatformService writePlatformService;
@Autowired
public MakercheckersApiResource(
final AuditReadPlatformService readPlatformService,
final DefaultToApiJsonSerializer<CommandSourceData> toApiJsonSerializer,
final DefaultToApiJsonSerializer<AuditData> toApiJsonSerializerAudit,
final DefaultToApiJsonSerializer<AuditSearchData> toApiJsonSerializerSearchTemplate,
final ApiRequestParameterHelper apiRequestParameterHelper,
final PortfolioCommandSourceWritePlatformService writePlatformService) {
this.readPlatformService = readPlatformService;
this.toApiJsonSerializer = toApiJsonSerializer;
this.apiRequestParameterHelper = apiRequestParameterHelper;
this.toApiJsonSerializerAudit = toApiJsonSerializerAudit;
this.toApiJsonSerializerSearchTemplate = toApiJsonSerializerSearchTemplate;
this.writePlatformService = writePlatformService;
}
@Autowired
public MakercheckersApiResource(final AuditReadPlatformService readPlatformService,
final DefaultToApiJsonSerializer<AuditData> toApiJsonSerializerAudit,
final DefaultToApiJsonSerializer<AuditSearchData> toApiJsonSerializerSearchTemplate,
final ApiRequestParameterHelper apiRequestParameterHelper, final PortfolioCommandSourceWritePlatformService writePlatformService) {
this.readPlatformService = readPlatformService;
this.apiRequestParameterHelper = apiRequestParameterHelper;
this.toApiJsonSerializerAudit = toApiJsonSerializerAudit;
this.toApiJsonSerializerSearchTemplate = toApiJsonSerializerSearchTemplate;
this.writePlatformService = writePlatformService;
}
@GET
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveCommands(@Context final UriInfo uriInfo,
@QueryParam("actionName") final String actionName,
@QueryParam("entityName") final String entityName,
@QueryParam("resourceId") final Long resourceId,
@QueryParam("makerId") final Long makerId,
@QueryParam("makerDateTimeFrom") final String makerDateTimeFrom,
@QueryParam("makerDateTimeTo") final String makerDateTimeTo,
@QueryParam("officeId") final Integer officeId,
@QueryParam("groupId") final Integer groupId,
@QueryParam("clientId") final Integer clientId,
@QueryParam("loanid") final Integer loanId,
@QueryParam("savingsAccountId") final Integer savingsAccountId) {
@GET
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveCommands(@Context final UriInfo uriInfo, @QueryParam("actionName") final String actionName,
@QueryParam("entityName") final String entityName, @QueryParam("resourceId") final Long resourceId,
@QueryParam("makerId") final Long makerId, @QueryParam("makerDateTimeFrom") final String makerDateTimeFrom,
@QueryParam("makerDateTimeTo") final String makerDateTimeTo, @QueryParam("officeId") final Integer officeId,
@QueryParam("groupId") final Integer groupId, @QueryParam("clientId") final Integer clientId,
@QueryParam("loanid") final Integer loanId, @QueryParam("savingsAccountId") final Integer savingsAccountId) {
final String extraCriteria = getExtraCriteria(actionName, entityName,
resourceId, makerId, makerDateTimeFrom, makerDateTimeTo,
officeId, groupId, clientId, loanId, savingsAccountId);
final String extraCriteria = getExtraCriteria(actionName, entityName, resourceId, makerId, makerDateTimeFrom, makerDateTimeTo,
officeId, groupId, clientId, loanId, savingsAccountId);
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper
.process(uriInfo.getQueryParameters());
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
final Collection<AuditData> entries = this.readPlatformService
.retrieveAllEntriesToBeChecked(extraCriteria,
settings.isIncludeJson());
final Collection<AuditData> entries = this.readPlatformService.retrieveAllEntriesToBeChecked(extraCriteria,
settings.isIncludeJson());
return this.toApiJsonSerializerAudit.serialize(settings, entries,
RESPONSE_DATA_PARAMETERS);
}
return this.toApiJsonSerializerAudit.serialize(settings, entries, RESPONSE_DATA_PARAMETERS);
}
@GET
@Path("/searchtemplate")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveAuditSearchTemplate(@Context final UriInfo uriInfo) {
@GET
@Path("/searchtemplate")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveAuditSearchTemplate(@Context final UriInfo uriInfo) {
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper
.process(uriInfo.getQueryParameters());
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
final AuditSearchData auditSearchData = this.readPlatformService
.retrieveSearchTemplate("makerchecker");
final AuditSearchData auditSearchData = this.readPlatformService.retrieveSearchTemplate("makerchecker");
final Set<String> RESPONSE_DATA_PARAMETERS_SEARCH_TEMPLATE = new HashSet<String>(
Arrays.asList("appUsers", "actionNames", "entityNames"));
final Set<String> RESPONSE_DATA_PARAMETERS_SEARCH_TEMPLATE = new HashSet<String>(Arrays.asList("appUsers", "actionNames",
"entityNames"));
return this.toApiJsonSerializerSearchTemplate.serialize(settings,
auditSearchData, RESPONSE_DATA_PARAMETERS_SEARCH_TEMPLATE);
}
return this.toApiJsonSerializerSearchTemplate.serialize(settings, auditSearchData, RESPONSE_DATA_PARAMETERS_SEARCH_TEMPLATE);
}
@POST
@Path("{auditId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String approveMakerCheckerEntry(
@PathParam("auditId") final Long auditId,
@QueryParam("command") final String commandParam) {
@POST
@Path("{auditId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String approveMakerCheckerEntry(@PathParam("auditId") final Long auditId, @QueryParam("command") final String commandParam) {
CommandProcessingResult result = null;
if (is(commandParam, "approve")) {
result = this.writePlatformService.approveEntry(auditId);
} else {
throw new UnrecognizedQueryParamException("command", commandParam);
}
CommandProcessingResult result = null;
if (is(commandParam, "approve")) {
result = this.writePlatformService.approveEntry(auditId);
} else {
throw new UnrecognizedQueryParamException("command", commandParam);
}
return this.toApiJsonSerializer.serialize(result);
}
return this.toApiJsonSerializerAudit.serialize(result);
}
private boolean is(final String commandParam, final String commandValue) {
return StringUtils.isNotBlank(commandParam)
&& commandParam.trim().equalsIgnoreCase(commandValue);
}
private boolean is(final String commandParam, final String commandValue) {
return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue);
}
@DELETE
@Path("{auditId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String deleteMakerCheckerEntry(
@PathParam("auditId") final Long auditId) {
@DELETE
@Path("{auditId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String deleteMakerCheckerEntry(@PathParam("auditId") final Long auditId) {
final Long id = this.writePlatformService.deleteEntry(auditId);
final Long id = this.writePlatformService.deleteEntry(auditId);
return this.toApiJsonSerializer.serialize(CommandProcessingResult
.commandOnlyResult(id));
}
return this.toApiJsonSerializerAudit.serialize(CommandProcessingResult.commandOnlyResult(id));
}
private String getExtraCriteria(final String actionName,
final String entityName, final Long resourceId, final Long makerId,
final String makerDateTimeFrom, final String makerDateTimeTo,
final Integer officeId, final Integer groupId,
final Integer clientId, final Integer loanId,
final Integer savingsAccountId) {
private String getExtraCriteria(final String actionName, final String entityName, final Long resourceId, final Long makerId,
final String makerDateTimeFrom, final String makerDateTimeTo, final Integer officeId, final Integer groupId,
final Integer clientId, final Integer loanId, final Integer savingsAccountId) {
String extraCriteria = "";
String extraCriteria = "";
if (actionName != null) {
extraCriteria += " and aud.action_name = "
+ ApiParameterHelper.sqlEncodeString(actionName);
}
if (entityName != null) {
extraCriteria += " and aud.entity_name like "
+ ApiParameterHelper.sqlEncodeString(entityName + "%");
}
if (actionName != null) {
extraCriteria += " and aud.action_name = " + ApiParameterHelper.sqlEncodeString(actionName);
}
if (entityName != null) {
extraCriteria += " and aud.entity_name like " + ApiParameterHelper.sqlEncodeString(entityName + "%");
}
if (resourceId != null) {
extraCriteria += " and aud.resource_id = " + resourceId;
}
if (makerId != null) {
extraCriteria += " and aud.maker_id = " + makerId;
}
if (makerDateTimeFrom != null) {
extraCriteria += " and aud.made_on_date >= "
+ ApiParameterHelper.sqlEncodeString(makerDateTimeFrom);
}
if (makerDateTimeTo != null) {
extraCriteria += " and aud.made_on_date <= "
+ ApiParameterHelper.sqlEncodeString(makerDateTimeTo);
}
if (resourceId != null) {
extraCriteria += " and aud.resource_id = " + resourceId;
}
if (makerId != null) {
extraCriteria += " and aud.maker_id = " + makerId;
}
if (makerDateTimeFrom != null) {
extraCriteria += " and aud.made_on_date >= " + ApiParameterHelper.sqlEncodeString(makerDateTimeFrom);
}
if (makerDateTimeTo != null) {
extraCriteria += " and aud.made_on_date <= " + ApiParameterHelper.sqlEncodeString(makerDateTimeTo);
}
if (officeId != null) {
extraCriteria += " and aud.office_id = " + officeId;
}
if (officeId != null) {
extraCriteria += " and aud.office_id = " + officeId;
}
if (groupId != null) {
extraCriteria += " and aud.group_id = " + groupId;
}
if (groupId != null) {
extraCriteria += " and aud.group_id = " + groupId;
}
if (clientId != null) {
extraCriteria += " and aud.client_id = " + clientId;
}
if (clientId != null) {
extraCriteria += " and aud.client_id = " + clientId;
}
if (loanId != null) {
extraCriteria += " and aud.loan_id = " + loanId;
}
if (loanId != null) {
extraCriteria += " and aud.loan_id = " + loanId;
}
if (savingsAccountId != null) {
extraCriteria += " and aud.savings_account_id = "
+ savingsAccountId;
}
if (savingsAccountId != null) {
extraCriteria += " and aud.savings_account_id = " + savingsAccountId;
}
if (StringUtils.isNotBlank(extraCriteria)) {
extraCriteria = extraCriteria.substring(4);
}
if (StringUtils.isNotBlank(extraCriteria)) {
extraCriteria = extraCriteria.substring(4);
}
return extraCriteria;
}
return extraCriteria;
}
}
@@ -10,6 +10,7 @@ import org.joda.time.LocalDate;
/**
* Immutable data object representing maker-checker entry
*/
@Deprecated
final public class CommandSourceData {
@SuppressWarnings("unused")
@@ -22,7 +23,7 @@ final public class CommandSourceData {
private final Long entityId;
@SuppressWarnings("unused")
private final String entityHref;
private String commandJson;
private final String commandJson;
@SuppressWarnings("unused")
private final LocalDate madeOnDate;
@@ -261,6 +261,10 @@ public class CommandWrapper {
return this.entityName.equalsIgnoreCase("CLIENT");
}
public boolean isClientActivation() {
return this.actionName.equalsIgnoreCase("ACTIVATE") && this.entityName.equalsIgnoreCase("CLIENT");
}
public boolean isClientIdentifierResource() {
return this.entityName.equals("CLIENTIDENTIFIER");
}
@@ -483,5 +487,4 @@ public class CommandWrapper {
public boolean isReportResource() {
return this.entityName.equalsIgnoreCase("REPORT");
}
}
@@ -206,7 +206,7 @@ public class CommandWrapperBuilder {
this.href = "/reports/template";
return this;
}
public CommandWrapperBuilder updateReport(final Long id) {
this.actionName = "UPDATE";
this.entityName = "REPORT";
@@ -214,7 +214,7 @@ public class CommandWrapperBuilder {
this.href = "/reports/" + id;
return this;
}
public CommandWrapperBuilder deleteReport(final Long id) {
this.actionName = "DELETE";
this.entityName = "REPORT";
@@ -222,7 +222,7 @@ public class CommandWrapperBuilder {
this.href = "/reports/" + id;
return this;
}
public CommandWrapperBuilder updateCurrencies() {
this.actionName = "UPDATE";
this.entityName = "CURRENCY";
@@ -328,10 +328,20 @@ public class CommandWrapperBuilder {
return this;
}
public CommandWrapperBuilder activateClient(final Long clientId) {
this.actionName = "ACTIVATE";
this.entityName = "CLIENT";
this.entityId = clientId;
this.clientId = clientId;
this.href = "/clients/" + clientId + "?command=activate&template=true";
return this;
}
public CommandWrapperBuilder updateClient(final Long clientId) {
this.actionName = "UPDATE";
this.entityName = "CLIENT";
this.entityId = clientId;
this.clientId = clientId;
this.href = "/clients/" + clientId;
return this;
}
@@ -340,6 +350,7 @@ public class CommandWrapperBuilder {
this.actionName = "DELETE";
this.entityName = "CLIENT";
this.entityId = clientId;
this.clientId = clientId;
this.href = "/clients/" + clientId;
this.json = "{}";
return this;
@@ -868,7 +879,7 @@ public class CommandWrapperBuilder {
this.loanId = loanId;
this.href = "/loans/" + loanId + "/collaterals/" + collateralId;
return this;
}
}
public CommandWrapperBuilder updateCollectionSheet(final Long groupId) {
this.actionName = "UPDATE";
@@ -878,26 +889,26 @@ public class CommandWrapperBuilder {
return this;
}
public CommandWrapperBuilder createCenter() {
public CommandWrapperBuilder createCenter() {
this.actionName = "CREATE";
this.entityName = "CENTER";
this.href = "/centers/template";
return this;
}
}
public CommandWrapperBuilder updateCenter(Long centerId) {
public CommandWrapperBuilder updateCenter(final Long centerId) {
this.actionName = "UPDATE";
this.entityName = "CENTER";
this.entityId = centerId;
this.href = "/centers/" + centerId;
return this;
}
}
public CommandWrapperBuilder deleteCenter(Long centerId) {
public CommandWrapperBuilder deleteCenter(final Long centerId) {
this.actionName = "DELETE";
this.entityName = "CENTER";
this.entityId = centerId;
this.href = "/centers/" + centerId;
return this;
}
}
}
@@ -1,17 +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.commands.service;
import java.util.Collection;
import org.mifosplatform.commands.data.CommandSourceData;
public interface PortfolioCommandsReadPlatformService {
CommandSourceData retrieveById(Long id);
Collection<CommandSourceData> retrieveUnprocessChangesByEntityNameAndId(String entityName, Long entityId);
}
@@ -1,72 +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.commands.service;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import org.joda.time.LocalDate;
import org.mifosplatform.commands.data.CommandSourceData;
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;
@Service
public class PortfolioCommandsReadPlatformServiceImpl implements PortfolioCommandsReadPlatformService {
private final JdbcTemplate jdbcTemplate;
@Autowired
public PortfolioCommandsReadPlatformServiceImpl(final TenantAwareRoutingDataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
private static final class CommandSourceMapper implements RowMapper<CommandSourceData> {
public String schema() {
return " mc.id as id, mc.action_name as actionName, mc.entity_name as entityName, mc.resource_id as entityId, mc.api_get_url as getHref, "
+ "mc.command_as_json as taskJson, mc.made_on_date as madeOnDate from m_portfolio_command_source mc ";
}
@Override
public CommandSourceData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final Long id = rs.getLong("id");
final String actionName = rs.getString("actionName");
final String entityName = rs.getString("entityName");
final Long entityId = JdbcSupport.getLong(rs, "entityId");
final String taskJson = rs.getString("taskJson");
final String getHref = rs.getString("getHref");
final LocalDate madeOnDate = JdbcSupport.getLocalDate(rs, "madeOnDate");
return new CommandSourceData(id, actionName, entityName, entityId, getHref, taskJson, madeOnDate);
}
}
@Override
public CommandSourceData retrieveById(final Long id) {
final CommandSourceMapper rm = new CommandSourceMapper();
final String sql = "select " + rm.schema() + " where mc.id=?";
return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { id });
}
@Override
public Collection<CommandSourceData> retrieveUnprocessChangesByEntityNameAndId(final String entityName, final Long entityId) {
final CommandSourceMapper rm = new CommandSourceMapper();
final String sql = "select "
+ rm.schema()
+ " where mc.entity_name like ? and mc.resource_id = ? and mc.checker_id is null and mc.processing_result_enum = 2 order by mc.made_on_date DESC, mc.action_name ASC";
return this.jdbcTemplate.query(sql, rm, new Object[] { entityName, entityId });
}
}
@@ -149,6 +149,10 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
handler = applicationContext.getBean("updateClientCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isDelete()) {
handler = applicationContext.getBean("deleteClientCommandHandler", NewCommandSourceHandler.class);
} else if (wrapper.isClientActivation()) {
handler = applicationContext.getBean("activateClientCommandHandler", NewCommandSourceHandler.class);
} else {
throw new UnsupportedCommandException(wrapper.commandName());
}
// end of client
} else if (wrapper.isUpdateRolePermissions()) {
@@ -9,4 +9,5 @@ public interface ConfigurationDomainService {
boolean isMakerCheckerEnabledForTask(String taskPermissionCode);
}
boolean isClientPendingApprovalAllowedEnabled();
}
@@ -39,4 +39,13 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService
return thisTask.hasMakerCheckerEnabled() && property.isEnabled();
}
@Override
public boolean isClientPendingApprovalAllowedEnabled() {
final String propertyKey = "allow-pending-client-status";
final GlobalConfigurationProperty property = this.globalConfigurationRepository.findOneByName(propertyKey);
if (property == null) { throw new GlobalConfigurationPropertyNotFoundException(propertyKey); }
return property.isEnabled();
}
}
@@ -35,12 +35,10 @@ public class ApiRequestParameterHelper {
}
final boolean prettyPrint = ApiParameterHelper.prettyPrint(queryParameters);
final boolean template = ApiParameterHelper.template(queryParameters);
final Long commandId = ApiParameterHelper.commandId(queryParameters);
final boolean makerCheckerable = ApiParameterHelper.makerCheckerable(queryParameters);
final boolean includeJson = ApiParameterHelper.includeJson(queryParameters);
return ApiRequestJsonSerializationSettings
.from(prettyPrint, responseParameters, template, commandId, makerCheckerable, includeJson);
return ApiRequestJsonSerializationSettings.from(prettyPrint, responseParameters, template, makerCheckerable, includeJson);
}
public ApiRequestJsonSerializationSettings process(final MultivaluedMap<String, String> queryParameters) {
@@ -48,11 +46,9 @@ public class ApiRequestParameterHelper {
final Set<String> responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(queryParameters);
final boolean prettyPrint = ApiParameterHelper.prettyPrint(queryParameters);
final boolean template = ApiParameterHelper.template(queryParameters);
final Long commandId = ApiParameterHelper.commandId(queryParameters);
final boolean makerCheckerable = ApiParameterHelper.makerCheckerable(queryParameters);
final boolean includeJson = ApiParameterHelper.includeJson(queryParameters);
return ApiRequestJsonSerializationSettings
.from(prettyPrint, responseParameters, template, commandId, makerCheckerable, includeJson);
return ApiRequestJsonSerializationSettings.from(prettyPrint, responseParameters, template, makerCheckerable, includeJson);
}
}
@@ -75,6 +75,15 @@ public class DataValidatorBuilder {
return this;
}
public void failWithCode(final String errorCode) {
StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(resource).append(".").append(this.parameter)
.append(errorCode);
StringBuilder defaultEnglishMessage = new StringBuilder("Failed data validation due to: ").append(errorCode).append(".");
ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(), defaultEnglishMessage.toString(),
this.parameter, this.value);
dataValidationErrors.add(error);
}
public DataValidatorBuilder equalToParameter(final String linkedParameterName, final Object linkedValue) {
if (value == null && linkedValue == null && ignoreNullValue) { return this; }
@@ -523,5 +532,5 @@ public class DataValidatorBuilder {
}
}
return this;
}
}
}
@@ -16,28 +16,25 @@ public class ApiRequestJsonSerializationSettings {
private final boolean prettyPrint;
private final Set<String> parametersForPartialResponse;
private final boolean template;
private final Long commandId;
private final boolean makerCheckerable;
private final boolean includeJson;
public ApiRequestJsonSerializationSettings(final boolean prettyPrint, final Set<String> parametersForPartialResponse,
final boolean template, final Long commandId, final boolean makerCheckerable, final boolean includeJson) {
final boolean template, final boolean makerCheckerable, final boolean includeJson) {
this.prettyPrint = prettyPrint;
this.parametersForPartialResponse = parametersForPartialResponse;
this.template = template;
this.commandId = commandId;
this.makerCheckerable = makerCheckerable;
this.includeJson = includeJson;
}
public static ApiRequestJsonSerializationSettings from(final boolean prettyPrint, final Set<String> parametersForPartialResponse,
final boolean template, final Long commandId, final boolean makerCheckerable, final boolean includeJson) {
final boolean template, final boolean makerCheckerable, final boolean includeJson) {
// FIXME - KW - rather than always creating new objects for this could
// just send by common ones like, prettyprint=false, empty response
// parameters
return new ApiRequestJsonSerializationSettings(prettyPrint, parametersForPartialResponse, template, commandId, makerCheckerable,
includeJson);
return new ApiRequestJsonSerializationSettings(prettyPrint, parametersForPartialResponse, template, makerCheckerable, includeJson);
}
public boolean isPrettyPrint() {
@@ -56,10 +53,6 @@ public class ApiRequestJsonSerializationSettings {
return this.includeJson;
}
public Long getCommandId() {
return this.commandId;
}
public Set<String> getParametersForPartialResponse() {
return this.parametersForPartialResponse;
}
@@ -67,8 +60,4 @@ public class ApiRequestJsonSerializationSettings {
public boolean isPartialResponseRequired() {
return !this.parametersForPartialResponse.isEmpty();
}
public boolean isCommandIdPassed() {
return this.commandId != null;
}
}
@@ -8,13 +8,14 @@ package org.mifosplatform.organisation.office.data;
/**
* Immutable data object used for office lookups (will remove eventually and just use {@link OfficeData}.
*/
@Deprecated
public class OfficeLookup {
private Long id;
private final Long id;
@SuppressWarnings("unused")
private String name;
private final String name;
@SuppressWarnings("unused")
private String nameDecorated;
private final String nameDecorated;
public OfficeLookup(final Long id, final String name, final String nameDecorated) {
this.id = id;
@@ -21,6 +21,7 @@ public interface OfficeReadPlatformService {
* Deprecated so cane eventually remove need for OfficeLookup type - so use
* retrieveAllOfficesForDropdown instead.
*/
@Deprecated
Collection<OfficeLookup> retrieveAllOfficesForLookup();
OfficeData retrieveOffice(Long officeId);
@@ -0,0 +1,63 @@
package org.mifosplatform.portfolio.client.api;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import org.mifosplatform.portfolio.client.data.ClientData;
public class ClientApiConstants {
public static final String CLIENT_RESOURCE_NAME = "client";
// general
public static final String localeParamName = "locale";
public static final String dateFormatParamName = "dateFormat";
// request parameters
public static final String idParamName = "id";
public static final String groupIdParamName = "groupId";
public static final String accountNoParamName = "accountNo";
public static final String externalIdParamName = "externalId";
public static final String firstnameParamName = "firstname";
public static final String middlenameParamName = "middlename";
public static final String lastnameParamName = "lastname";
public static final String fullnameParamName = "fullname";
public static final String officeIdParamName = "officeId";
public static final String staffIdParamName = "staffId";
public static final String activeParamName = "active";
public static final String activationDateParamName = "activationDate";
// response parameters
public static final String statusParamName = "status";
public static final String hierarchyParamName = "hierarchy";
public static final String displayNameParamName = "displayName";
public static final String officeNameParamName = "officeName";
public static final String staffNameParamName = "staffName";
public static final String imageKeyParamName = "imageKey";
public static final String imagePresentParamName = "imagePresent";
// associations related part of response
public static final String parentGroupsParamName = "groups";
// template related part of response
public static final String officeOptionsParamName = "officeOptions";
public static final String staffOptionsParamName = "staffOptions";
public static final Set<String> CLIENT_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
dateFormatParamName, groupIdParamName, accountNoParamName, externalIdParamName, firstnameParamName, middlenameParamName,
lastnameParamName, fullnameParamName, officeIdParamName, staffIdParamName, activeParamName, activationDateParamName));
/**
* These parameters will match the class level parameters of
* {@link ClientData}. Where possible, we try to get response parameters to
* match those of request parameters.
*/
public static final Set<String> CLIENT_RESPONSE_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(idParamName, accountNoParamName,
externalIdParamName, statusParamName, firstnameParamName, middlenameParamName, lastnameParamName, fullnameParamName,
displayNameParamName, officeIdParamName, officeNameParamName, staffIdParamName, staffNameParamName, hierarchyParamName,
officeOptionsParamName, staffOptionsParamName));
public static final Set<String> ACTIVATION_REQUEST_DATA_PARAMETERS = new HashSet<String>(Arrays.asList(localeParamName,
dateFormatParamName, activationDateParamName));
}
@@ -111,7 +111,7 @@ public class ClientImagesApiResource {
context.authenticatedUser().validateHasReadPermission("CLIENTIMAGE");
final ClientData clientData = this.clientReadPlatformService.retrieveIndividualClient(clientId);
final ClientData clientData = this.clientReadPlatformService.retrieveOne(clientId);
if (clientData.imageKeyDoesNotExist()) { throw new ImageNotFoundException("clients", clientId); }
@@ -134,7 +134,7 @@ public class ClientImagesApiResource {
public Response downloadClientImage(@PathParam("clientId") final Long clientId) {
context.authenticatedUser().validateHasReadPermission("CLIENTIMAGE");
final ClientData clientData = this.clientReadPlatformService.retrieveIndividualClient(clientId);
final ClientData clientData = this.clientReadPlatformService.retrieveOne(clientId);
if (clientData.imageKeyDoesNotExist()) { throw new ImageNotFoundException("clients", clientId); }
@@ -26,24 +26,21 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo;
import org.apache.commons.lang.StringUtils;
import org.mifosplatform.commands.data.CommandSourceData;
import org.mifosplatform.commands.domain.CommandWrapper;
import org.mifosplatform.commands.service.CommandWrapperBuilder;
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
import org.mifosplatform.commands.service.PortfolioCommandsReadPlatformService;
import org.mifosplatform.infrastructure.core.api.ApiParameterHelper;
import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.infrastructure.core.exception.UnrecognizedQueryParamException;
import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
import org.mifosplatform.infrastructure.core.serialization.ToApiJsonSerializer;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.organisation.office.data.OfficeLookup;
import org.mifosplatform.organisation.office.data.OfficeData;
import org.mifosplatform.organisation.office.service.OfficeReadPlatformService;
import org.mifosplatform.portfolio.client.command.ClientCommand;
import org.mifosplatform.portfolio.client.data.ClientAccountSummaryCollectionData;
import org.mifosplatform.portfolio.client.data.ClientData;
import org.mifosplatform.portfolio.client.serialization.ClientCommandFromApiJsonDeserializer;
import org.mifosplatform.portfolio.client.service.ClientReadPlatformService;
import org.mifosplatform.portfolio.group.service.SearchParameters;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@@ -53,185 +50,84 @@ import org.springframework.stereotype.Component;
@Scope("singleton")
public class ClientsApiResource {
private final Set<String> CLIENT_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("id", "accountNo", "externalId", "firstname",
"middlename", "lastname", "fullname", "displayName", "officeId", "officeName", "joinedDate", "imageKey", "imagePresent",
"parentGroups", "allowedOffices", "currentChange", "allChanges"));
private final PlatformSecurityContext context;
private final ClientReadPlatformService clientReadPlatformService;
private final OfficeReadPlatformService officeReadPlatformService;
private final ToApiJsonSerializer<ClientData> toApiJsonSerializer;
private final ToApiJsonSerializer<ClientAccountSummaryCollectionData> clientAccountSummaryToApiJsonSerializer;
private final ApiRequestParameterHelper apiRequestParameterHelper;
private final PortfolioCommandsReadPlatformService commandSourceReadPlatformService;
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
private final ClientCommandFromApiJsonDeserializer clientCommandFromApiJsonDeserializer;
@Autowired
public ClientsApiResource(final PlatformSecurityContext context, final ClientReadPlatformService readPlatformService,
final OfficeReadPlatformService officeReadPlatformService, final ToApiJsonSerializer<ClientData> toApiJsonSerializer,
final ClientCommandFromApiJsonDeserializer clientCommandFromApiJsonDeserializer,
final ToApiJsonSerializer<ClientAccountSummaryCollectionData> clientAccountSummaryToApiJsonSerializer,
final ApiRequestParameterHelper apiRequestParameterHelper,
final PortfolioCommandsReadPlatformService commandsReadPlatformService,
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) {
this.context = context;
this.clientReadPlatformService = readPlatformService;
this.officeReadPlatformService = officeReadPlatformService;
this.toApiJsonSerializer = toApiJsonSerializer;
this.clientCommandFromApiJsonDeserializer = clientCommandFromApiJsonDeserializer;
this.clientAccountSummaryToApiJsonSerializer = clientAccountSummaryToApiJsonSerializer;
this.apiRequestParameterHelper = apiRequestParameterHelper;
this.commandSourceReadPlatformService = commandsReadPlatformService;
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
}
@GET
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveAllIndividualClients(@Context final UriInfo uriInfo, @QueryParam("sqlSearch") final String sqlSearch,
@QueryParam("officeId") final Long officeId, @QueryParam("externalId") final String externalId,
@QueryParam("displayName") final String displayName, @QueryParam("firstName") final String firstName,
@QueryParam("lastName") final String lastName, @QueryParam("underHierarchy") final String hierarchy) {
context.authenticatedUser().validateHasReadPermission("CLIENT");
// FIXME - kw - rather than exposing SQL through the api can we not just
// pass parameter we want to search by and build up sql like is done for
// other parameters?
final String extraCriteria = buildSqlStringFromClientCriteria(sqlSearch, officeId, externalId, displayName, firstName, lastName,
hierarchy);
final Collection<ClientData> clients = this.clientReadPlatformService.retrieveAllIndividualClients(extraCriteria);
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, clients, CLIENT_DATA_PARAMETERS);
}
private String buildSqlStringFromClientCriteria(final String sqlSearch, final Long officeId, final String externalId,
final String displayName, final String firstName, final String lastName, final String hierarchy) {
String extraCriteria = "";
if (sqlSearch != null) {
extraCriteria = " and (" + sqlSearch + ")";
}
if (officeId != null) {
extraCriteria += " and office_id = " + officeId;
}
if (externalId != null) {
extraCriteria += " and external_id like " + ApiParameterHelper.sqlEncodeString(externalId);
}
if (displayName != null) {
extraCriteria += " and concat(ifnull(firstname, ''), if(firstname > '',' ', '') , ifnull(lastname, '')) like "
+ ApiParameterHelper.sqlEncodeString(displayName);
}
if (firstName != null) {
extraCriteria += " and firstname like " + ApiParameterHelper.sqlEncodeString(firstName);
}
if (lastName != null) {
extraCriteria += " and lastname like " + ApiParameterHelper.sqlEncodeString(lastName);
}
if (hierarchy != null) {
extraCriteria += " and o.hierarchy like " + ApiParameterHelper.sqlEncodeString(hierarchy + "%");
}
if (StringUtils.isNotBlank(extraCriteria)) {
extraCriteria = extraCriteria.substring(4);
}
return extraCriteria;
}
@GET
@Path("{clientId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveClient(@PathParam("clientId") final Long clientId, @Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission("CLIENT");
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
ClientData clientData = this.clientReadPlatformService.retrieveIndividualClient(clientId);
if (settings.isTemplate()) {
// FIXME - KW - no need for special OfficeLookup object, just use
// OfficeData and only populate with id, name, nameDecorated
final List<OfficeLookup> allowedOffices = new ArrayList<OfficeLookup>(officeReadPlatformService.retrieveAllOfficesForLookup());
clientData = ClientData.templateOnTop(clientData, allowedOffices);
}
if (settings.isCommandIdPassed()) {
clientData = handleRequestToIntegrateProposedChangesFromCommand(clientId, settings.getCommandId(), clientData);
}
// pick up possibility of changes by default - might push down a layer
// into the retrieve client method
final Collection<ClientData> dataChanges = retrieveAllUnprocessedDataChanges(clientId);
clientData = ClientData.integrateChanges(clientData, clientData.currentChange(), dataChanges);
return this.toApiJsonSerializer.serialize(settings, clientData, CLIENT_DATA_PARAMETERS);
}
private ClientData handleRequestToIntegrateProposedChangesFromCommand(final Long clientId, final Long commandId,
final ClientData clientData) {
final CommandSourceData entry = this.commandSourceReadPlatformService.retrieveById(commandId);
final ClientCommand command = this.clientCommandFromApiJsonDeserializer.commandFromApiJson(entry.json());
final ClientData currentChange = ClientData.dataChangeInstance(clientId, command.getOfficeId(), command.getExternalId(),
command.getFirstname(), command.getMiddlename(), command.getLastname(), command.getFullname(), command.getJoiningDate());
final Collection<ClientData> dataChanges = null; // retrieveAllUnprocessedDataChanges(clientId);
return ClientData.integrateChanges(clientData, currentChange, dataChanges);
}
private Collection<ClientData> retrieveAllUnprocessedDataChanges(final Long clientId) {
Collection<ClientData> dataChanges = new ArrayList<ClientData>();
Collection<CommandSourceData> unprocessedChanges = this.commandSourceReadPlatformService.retrieveUnprocessChangesByEntityNameAndId(
"CLIENT", clientId);
for (CommandSourceData commandSourceData : unprocessedChanges) {
final ClientCommand command = this.clientCommandFromApiJsonDeserializer.commandFromApiJson(commandSourceData.json());
final ClientData change = ClientData
.dataChangeInstance(clientId, command.getOfficeId(), command.getExternalId(), command.getFirstname(),
command.getMiddlename(), command.getLastname(), command.getFullname(), command.getJoiningDate());
dataChanges.add(change);
}
if (dataChanges.isEmpty()) {
dataChanges = null;
}
return dataChanges;
}
@GET
@Path("template")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String newClientDetails(@Context final UriInfo uriInfo) {
public String retrieveTemplate(@Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission("CLIENT");
context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_RESOURCE_NAME);
final ClientData clientData = this.clientReadPlatformService.retrieveTemplate();
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, clientData, ClientApiConstants.CLIENT_RESPONSE_DATA_PARAMETERS);
}
@GET
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveAll(@Context final UriInfo uriInfo, @QueryParam("sqlSearch") final String sqlSearch,
@QueryParam("officeId") final Long officeId, @QueryParam("externalId") final String externalId,
@QueryParam("displayName") final String displayName, @QueryParam("firstName") final String firstname,
@QueryParam("lastName") final String lastname, @QueryParam("underHierarchy") final String hierarchy) {
context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_RESOURCE_NAME);
final SearchParameters searchParameters = SearchParameters.forClients(sqlSearch, officeId, externalId, displayName, firstname,
lastname, hierarchy);
final Collection<ClientData> clients = this.clientReadPlatformService.retrieveAll(searchParameters);
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, clients, ClientApiConstants.CLIENT_RESPONSE_DATA_PARAMETERS);
}
@GET
@Path("{clientId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveOne(@PathParam("clientId") final Long clientId, @Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_RESOURCE_NAME);
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
ClientData clientData = this.clientReadPlatformService.retrieveNewClientDetails();
if (settings.isCommandIdPassed()) {
clientData = handleRequestToIntegrateProposedChangesFromCommand(null, settings.getCommandId(), clientData);
ClientData clientData = this.clientReadPlatformService.retrieveOne(clientId);
if (settings.isTemplate()) {
final List<OfficeData> allowedOffices = new ArrayList<OfficeData>(officeReadPlatformService.retrieveAllOfficesForDropdown());
clientData = ClientData.templateOnTop(clientData, allowedOffices);
}
return this.toApiJsonSerializer.serialize(settings, clientData, CLIENT_DATA_PARAMETERS);
return this.toApiJsonSerializer.serialize(settings, clientData, ClientApiConstants.CLIENT_RESPONSE_DATA_PARAMETERS);
}
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String createClient(final String apiRequestBodyAsJson) {
public String create(final String apiRequestBodyAsJson) {
final CommandWrapper commandRequest = new CommandWrapperBuilder() //
.createClient() //
@@ -247,7 +143,7 @@ public class ClientsApiResource {
@Path("{clientId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String updateClient(@PathParam("clientId") final Long clientId, final String apiRequestBodyAsJson) {
public String update(@PathParam("clientId") final Long clientId, final String apiRequestBodyAsJson) {
final CommandWrapper commandRequest = new CommandWrapperBuilder() //
.updateClient(clientId) //
@@ -263,7 +159,7 @@ public class ClientsApiResource {
@Path("{clientId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String deleteClient(@PathParam("clientId") final Long clientId) {
public String delete(@PathParam("clientId") final Long clientId) {
final CommandWrapper commandRequest = new CommandWrapperBuilder() //
.deleteClient(clientId) //
@@ -274,26 +170,49 @@ public class ClientsApiResource {
return this.toApiJsonSerializer.serialize(result);
}
@POST
@Path("{clientId}")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String activate(@PathParam("clientId") final Long clientId, @QueryParam("command") final String commandParam,
final String apiRequestBodyAsJson) {
final CommandWrapperBuilder builder = new CommandWrapperBuilder().withJson(apiRequestBodyAsJson);
CommandProcessingResult result = null;
if (is(commandParam, "activate")) {
final CommandWrapper commandRequest = builder.activateClient(clientId).build();
result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
}
if (result == null) {
//
throw new UnrecognizedQueryParamException("command", commandParam, new Object[] { "activate" });
}
return this.toApiJsonSerializer.serialize(result);
}
private boolean is(final String commandParam, final String commandValue) {
return StringUtils.isNotBlank(commandParam) && commandParam.trim().equalsIgnoreCase(commandValue);
}
@GET
@Path("{clientId}/loans")
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
public String retrieveClientAccounts(@PathParam("clientId") final Long clientId, @Context final UriInfo uriInfo) {
public String retrieveAssociatedAccounts(@PathParam("clientId") final Long clientId, @Context final UriInfo uriInfo) {
context.authenticatedUser().validateHasReadPermission("CLIENT");
context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_RESOURCE_NAME);
final ClientAccountSummaryCollectionData clientAccount = this.clientReadPlatformService.retrieveClientAccountDetails(clientId);
final Set<String> CLIENT_ACCOUNTS_DATA_PARAMETERS = new HashSet<String>(Arrays.asList("pendingApprovalLoans",
"awaitingDisbursalLoans", "openLoans", "closedLoans", "anyLoanCount", "pendingApprovalLoanCount",
"awaitingDisbursalLoanCount", "activeLoanCount", "closedLoanCount", "pendingApprovalDepositAccountsCount",
"pendingApprovalDepositAccounts", "approvedDepositAccountsCount", "approvedDepositAccounts",
"withdrawnByClientDepositAccountsCount", "withdrawnByClientDepositAccounts", "closedDepositAccountsCount",
"closedDepositAccounts", "maturedDepositAccountsCount", "maturedDepositAccounts", "rejectedDepositAccountsCount",
"rejectedDepositAccounts", "preclosedDepositAccountsCount", "preclosedDepositAccounts",
"pendingApprovalSavingAccountsCount", "pendingApprovalSavingAccounts", "approvedSavingAccountsCount",
"approvedSavingAccounts", "withdrawnByClientSavingAccountsCount", "withdrawnByClientSavingAccounts",
"rejectedSavingAccountsCount", "rejectedSavingAccounts", "closedSavingAccountsCount", "closedSavingAccounts"));
"awaitingDisbursalLoanCount", "activeLoanCount", "closedLoanCount", "pendingApprovalSavingAccountsCount",
"pendingApprovalSavingAccounts", "approvedSavingAccountsCount", "approvedSavingAccounts",
"withdrawnByClientSavingAccountsCount", "withdrawnByClientSavingAccounts", "rejectedSavingAccountsCount",
"rejectedSavingAccounts", "closedSavingAccountsCount", "closedSavingAccounts"));
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.clientAccountSummaryToApiJsonSerializer.serialize(settings, clientAccount, CLIENT_ACCOUNTS_DATA_PARAMETERS);
@@ -13,7 +13,8 @@ import org.apache.commons.lang.builder.CompareToBuilder;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.joda.time.LocalDate;
import org.mifosplatform.organisation.office.data.OfficeLookup;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.organisation.office.data.OfficeData;
import org.mifosplatform.portfolio.group.data.GroupGeneralData;
/**
@@ -24,78 +25,70 @@ final public class ClientData implements Comparable<ClientData> {
private final Long id;
private final String accountNo;
private final String externalId;
private final EnumOptionData status;
private final LocalDate activationDate;
private final String firstname;
private final String middlename;
private final String lastname;
private final String fullname;
private final String displayName;
private final Long officeId;
private final String officeName;
private final LocalDate joinedDate;
private final String imageKey;
@SuppressWarnings("unused")
private final Boolean imagePresent;
private final Boolean clientPendingApprovalAllowed;
// associations
private final Collection<GroupGeneralData> parentGroups;
private final Collection<GroupGeneralData> groups;
// template
private final List<OfficeLookup> allowedOffices;
private final ClientData currentChange;
private final Collection<ClientData> allChanges;
private final Collection<OfficeData> officeOptions;
public static ClientData dataChangeInstance(final Long id, final Long officeId, final String externalId, final String firstname,
final String middlename, final String lastname, final String fullname, final LocalDate joiningDate) {
String localDisplayName = null;
return new ClientData(null, officeId, null, id, firstname, middlename, lastname, fullname, localDisplayName, externalId,
joiningDate, null, null, null, null, null);
public static ClientData template(final Long officeId, final LocalDate joinedDate, final Boolean clientPendingApprovalAllowed,
final Collection<OfficeData> allowedOffices) {
return new ClientData(null, null, officeId, null, null, null, null, null, null, null, null, joinedDate, null,
clientPendingApprovalAllowed, allowedOffices, null);
}
public static ClientData integrateChanges(final ClientData clientData, final ClientData currentChange,
final Collection<ClientData> allChanges) {
return new ClientData(clientData.accountNo, clientData.officeId, clientData.officeName, clientData.id, clientData.firstname,
clientData.middlename, clientData.lastname, clientData.fullname, clientData.displayName, clientData.externalId,
clientData.joinedDate, clientData.imageKey, clientData.allowedOffices, currentChange, allChanges, clientData.parentGroups);
}
public static ClientData templateOnTop(final ClientData clientData, final List<OfficeData> allowedOffices) {
public static ClientData template(final Long officeId, final LocalDate joinedDate, final List<OfficeLookup> allowedOffices) {
return new ClientData(null, officeId, null, null, null, null, null, null, null, null, joinedDate, null, allowedOffices, null, null,
null);
}
public static ClientData templateOnTop(final ClientData clientData, final List<OfficeLookup> allowedOffices) {
return new ClientData(clientData.accountNo, clientData.officeId, clientData.officeName, clientData.id, clientData.firstname,
clientData.middlename, clientData.lastname, clientData.fullname, clientData.displayName, clientData.externalId,
clientData.joinedDate, clientData.imageKey, allowedOffices, clientData.currentChange, clientData.allChanges,
clientData.parentGroups);
return new ClientData(clientData.accountNo, clientData.status, clientData.officeId, clientData.officeName, clientData.id,
clientData.firstname, clientData.middlename, clientData.lastname, clientData.fullname, clientData.displayName,
clientData.externalId, clientData.activationDate, clientData.imageKey, clientData.clientPendingApprovalAllowed,
allowedOffices, clientData.groups);
}
public static ClientData setParentGroups(final ClientData clientData, final Collection<GroupGeneralData> parentGroups) {
return new ClientData(clientData.accountNo, clientData.officeId, clientData.officeName, clientData.id, clientData.firstname,
clientData.middlename, clientData.lastname, clientData.fullname, clientData.displayName, clientData.externalId,
clientData.joinedDate, clientData.imageKey, clientData.allowedOffices, clientData.currentChange, clientData.allChanges,
parentGroups);
return new ClientData(clientData.accountNo, clientData.status, clientData.officeId, clientData.officeName, clientData.id,
clientData.firstname, clientData.middlename, clientData.lastname, clientData.fullname, clientData.displayName,
clientData.externalId, clientData.activationDate, clientData.imageKey, clientData.clientPendingApprovalAllowed,
clientData.officeOptions, parentGroups);
}
public static ClientData clientIdentifier(final Long id, final String accountIdentifier, final String firstname,
public static ClientData clientIdentifier(final Long id, final String accountNo, final EnumOptionData status, final String firstname,
final String middlename, final String lastname, final String fullname, final String displayName, final Long officeId,
final String officeName) {
return new ClientData(accountIdentifier, officeId, officeName, id, firstname, middlename, lastname, fullname, displayName, null,
null, null, null, null, null, null);
return new ClientData(accountNo, status, officeId, officeName, id, firstname, middlename, lastname, fullname, displayName, null,
null, null, null, null, null);
}
public static ClientData lookup(final Long id, final String displayName, final Long officeId, final String officeName) {
return new ClientData(null, officeId, officeName, id, null, null, null, null, displayName, null, null, null, null, null, null, null);
return new ClientData(null, null, officeId, officeName, id, null, null, null, null, displayName, null, null, null, null, null, null);
}
public ClientData(final String accountNo, final Long officeId, final String officeName, final Long id, final String firstname,
final String middlename, final String lastname, final String fullname, final String displayName, final String externalId,
final LocalDate joinedDate, final String imageKey, final List<OfficeLookup> allowedOffices, final ClientData currentChange,
final Collection<ClientData> allChanges, final Collection<GroupGeneralData> parentGroups) {
public ClientData(final String accountNo, final EnumOptionData status, final Long officeId, final String officeName, final Long id,
final String firstname, final String middlename, final String lastname, final String fullname, final String displayName,
final String externalId, final LocalDate activationDate, final String imageKey, final Boolean clientPendingApprovalAllowed,
final Collection<OfficeData> allowedOffices, final Collection<GroupGeneralData> groups) {
this.accountNo = accountNo;
this.status = status;
this.officeId = officeId;
this.officeName = officeName;
this.id = id;
@@ -105,17 +98,49 @@ final public class ClientData implements Comparable<ClientData> {
this.fullname = StringUtils.defaultIfEmpty(fullname, null);
this.displayName = StringUtils.defaultIfEmpty(displayName, null);
this.externalId = StringUtils.defaultIfEmpty(externalId, null);
this.joinedDate = joinedDate;
this.activationDate = activationDate;
this.imageKey = imageKey;
if (imageKey != null) {
this.imagePresent = Boolean.TRUE;
} else {
this.imagePresent = null;
}
this.allowedOffices = allowedOffices;
this.currentChange = currentChange;
this.allChanges = allChanges;
this.parentGroups = parentGroups;
this.clientPendingApprovalAllowed = clientPendingApprovalAllowed;
// associations
this.groups = groups;
// template
this.officeOptions = allowedOffices;
}
public Long id() {
return this.id;
}
public String displayName() {
return this.displayName;
}
public Long officeId() {
return this.officeId;
}
public String officeName() {
return this.officeName;
}
public String imageKey() {
return this.imageKey;
}
public boolean imageKeyDoesNotExist() {
return !imageKeyExists();
}
private boolean imageKeyExists() {
return StringUtils.isNotBlank(this.imageKey);
}
@Override
@@ -147,38 +172,7 @@ final public class ClientData implements Comparable<ClientData> {
.toHashCode();
}
public String displayName() {
return this.displayName;
}
public String officeName() {
return this.officeName;
}
private boolean imageKeyExists() {
return StringUtils.isNotBlank(this.imageKey);
}
public boolean imageKeyDoesNotExist() {
return !imageKeyExists();
}
public String imageKey() {
return this.imageKey;
}
public Long id() {
return this.id;
}
public Long officeId() {
return this.officeId;
}
public ClientData currentChange() {
return this.currentChange;
}
// TODO - kw - look into removing usage of the getters below
public String getExternalId() {
return this.externalId;
}
@@ -191,15 +185,7 @@ final public class ClientData implements Comparable<ClientData> {
return this.lastname;
}
public Long getOfficeId() {
return this.officeId;
}
public String getOfficeName() {
return this.officeName;
}
public LocalDate getJoinedDate() {
return this.joinedDate;
public LocalDate getActivationDate() {
return this.activationDate;
}
}
@@ -0,0 +1,186 @@
/**
* 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.data;
import static org.mifosplatform.portfolio.savings.api.SavingsApiConstants.activationDateParamName;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
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.mifosplatform.portfolio.client.api.ClientApiConstants;
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 final class ClientDataValidator {
private final FromJsonHelper fromApiJsonHelper;
@Autowired
public ClientDataValidator(final FromJsonHelper fromApiJsonHelper) {
this.fromApiJsonHelper = fromApiJsonHelper;
}
public void validateForCreate(final String json, final boolean isPendingApprovalEnabled) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, ClientApiConstants.CLIENT_REQUEST_DATA_PARAMETERS);
final JsonElement element = fromApiJsonHelper.parse(json);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(ClientApiConstants.CLIENT_RESOURCE_NAME);
if (fromApiJsonHelper.parameterExists(ClientApiConstants.accountNoParamName, element)) {
final String accountNo = fromApiJsonHelper.extractStringNamed(ClientApiConstants.accountNoParamName, element);
baseDataValidator.reset().parameter(ClientApiConstants.accountNoParamName).value(accountNo).notBlank().notExceedingLengthOf(20);
}
if (fromApiJsonHelper.parameterExists(ClientApiConstants.externalIdParamName, element)) {
final String externalId = fromApiJsonHelper.extractStringNamed(ClientApiConstants.externalIdParamName, element);
baseDataValidator.reset().parameter(ClientApiConstants.externalIdParamName).value(externalId).ignoreIfNull()
.notExceedingLengthOf(100);
}
final Long officeId = fromApiJsonHelper.extractLongNamed(ClientApiConstants.officeIdParamName, element);
baseDataValidator.reset().parameter(ClientApiConstants.officeIdParamName).value(officeId).notNull().integerGreaterThanZero();
if (fromApiJsonHelper.parameterExists(ClientApiConstants.groupIdParamName, element)) {
final Long groupId = fromApiJsonHelper.extractLongNamed(ClientApiConstants.groupIdParamName, element);
baseDataValidator.reset().parameter(ClientApiConstants.groupIdParamName).value(groupId).notNull().integerGreaterThanZero();
}
final Boolean active = fromApiJsonHelper.extractBooleanNamed(ClientApiConstants.activeParamName, element);
if (active != null) {
if (active.booleanValue()) {
final LocalDate joinedDate = fromApiJsonHelper.extractLocalDateNamed(ClientApiConstants.activationDateParamName, element);
baseDataValidator.reset().parameter(ClientApiConstants.activationDateParamName).value(joinedDate).notNull();
} else {
if (!isPendingApprovalEnabled) {
baseDataValidator.reset().parameter(ClientApiConstants.activeParamName).failWithCode(".pending.status.not.allowed");
}
}
} else {
baseDataValidator.reset().parameter(ClientApiConstants.activeParamName).value(active).trueOrFalseRequired(false);
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
public void validateForUpdate(final String json, final boolean isPendingApprovalEnabled) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, ClientApiConstants.CLIENT_REQUEST_DATA_PARAMETERS);
final JsonElement element = fromApiJsonHelper.parse(json);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(ClientApiConstants.CLIENT_RESOURCE_NAME);
boolean atLeastOneParameterPassedForUpdate = false;
if (fromApiJsonHelper.parameterExists(ClientApiConstants.accountNoParamName, element)) {
atLeastOneParameterPassedForUpdate = true;
final String accountNo = fromApiJsonHelper.extractStringNamed(ClientApiConstants.accountNoParamName, element);
baseDataValidator.reset().parameter(ClientApiConstants.accountNoParamName).value(accountNo).notBlank().notExceedingLengthOf(20);
}
if (fromApiJsonHelper.parameterExists(ClientApiConstants.externalIdParamName, element)) {
atLeastOneParameterPassedForUpdate = true;
final String externalId = fromApiJsonHelper.extractStringNamed(ClientApiConstants.externalIdParamName, element);
baseDataValidator.reset().parameter(ClientApiConstants.externalIdParamName).value(externalId).notExceedingLengthOf(100);
}
if (fromApiJsonHelper.parameterExists(ClientApiConstants.fullnameParamName, element)) {
atLeastOneParameterPassedForUpdate = true;
}
if (fromApiJsonHelper.parameterExists(ClientApiConstants.lastnameParamName, element)) {
atLeastOneParameterPassedForUpdate = true;
}
if (fromApiJsonHelper.parameterExists(ClientApiConstants.middlenameParamName, element)) {
atLeastOneParameterPassedForUpdate = true;
}
if (fromApiJsonHelper.parameterExists(ClientApiConstants.firstnameParamName, element)) {
atLeastOneParameterPassedForUpdate = true;
}
if (fromApiJsonHelper.parameterExists(ClientApiConstants.officeIdParamName, element)) {
atLeastOneParameterPassedForUpdate = true;
final Long officeId = fromApiJsonHelper.extractLongNamed(ClientApiConstants.officeIdParamName, element);
baseDataValidator.reset().parameter(ClientApiConstants.officeIdParamName).value(officeId).notNull().integerGreaterThanZero();
}
final Boolean active = fromApiJsonHelper.extractBooleanNamed(ClientApiConstants.activeParamName, element);
if (active != null) {
if (active.booleanValue()) {
final LocalDate joinedDate = fromApiJsonHelper.extractLocalDateNamed(ClientApiConstants.activationDateParamName, element);
baseDataValidator.reset().parameter(ClientApiConstants.activationDateParamName).value(joinedDate).notNull();
} else {
if (!isPendingApprovalEnabled) {
baseDataValidator.reset().parameter(ClientApiConstants.activeParamName).failWithCode(".pending.status.not.allowed");
}
}
} else {
baseDataValidator.reset().parameter(ClientApiConstants.activeParamName).value(active).trueOrFalseRequired(false);
}
if (!atLeastOneParameterPassedForUpdate) {
final Object forceError = null;
baseDataValidator.reset().anyOfNotNull(forceError);
}
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
public void validateActivation(final JsonCommand command) {
final String json = command.json();
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, ClientApiConstants.ACTIVATION_REQUEST_DATA_PARAMETERS);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
.resource(ClientApiConstants.CLIENT_RESOURCE_NAME);
final JsonElement element = command.parsedJson();
final LocalDate activationDate = fromApiJsonHelper.extractLocalDateNamed(activationDateParamName, element);
baseDataValidator.reset().parameter(activationDateParamName).value(activationDate).notNull();
throwExceptionIfValidationWarningsExist(dataValidationErrors);
}
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
if (!dataValidationErrors.isEmpty()) {
//
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors);
}
}
}
@@ -27,18 +27,21 @@ import javax.persistence.UniqueConstraint;
import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormatter;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.ApiParameterError;
import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
import org.mifosplatform.infrastructure.core.service.DateUtils;
import org.mifosplatform.infrastructure.security.service.RandomPasswordGenerator;
import org.mifosplatform.organisation.office.domain.Office;
import org.mifosplatform.portfolio.client.api.ClientApiConstants;
import org.mifosplatform.portfolio.group.domain.Group;
import org.springframework.data.jpa.domain.AbstractPersistable;
@Entity
@Table(name = "m_client", uniqueConstraints = { @UniqueConstraint(columnNames = { "account_no" }, name = "account_no_UNIQUE") })
public class Client extends AbstractPersistable<Long> {
public final class Client extends AbstractPersistable<Long> {
@Column(name = "account_no", length = 20, unique = true, nullable = false)
private String accountNumber;
@@ -47,6 +50,12 @@ public class Client extends AbstractPersistable<Long> {
@JoinColumn(name = "office_id", nullable = false)
private Office office;
/**
* A value from {@link ClientStatus}.
*/
@Column(name = "status_enum", nullable = false)
private Integer status;
@Column(name = "firstname", length = 50)
private String firstname;
@@ -60,61 +69,80 @@ public class Client extends AbstractPersistable<Long> {
private String fullname;
@SuppressWarnings("unused")
@Column(name = "display_name", length = 100)
@Column(name = "display_name", length = 100, nullable = false)
private String displayName;
@Column(name = "joined_date")
@Column(name = "activation_date", nullable = true)
@Temporal(TemporalType.DATE)
private Date joinedDate;
private Date activationDate;
@Column(name = "external_id", length = 100, unique = true)
@Column(name = "external_id", length = 100, nullable = true, unique = true)
private String externalId;
@Column(name = "is_deleted", nullable = false)
private boolean deleted = false;
@Column(name = "image_key", length = 500)
@Column(name = "image_key", length = 500, nullable = true)
private String imageKey;
@ManyToMany
@JoinTable(name = "m_group_client", joinColumns = @JoinColumn(name = "client_id"), inverseJoinColumns = @JoinColumn(name = "group_id"))
private Set<Group> parentGroups;
private Set<Group> groups;
@Transient
private boolean accountNumberRequiresAutoGeneration = false;
public static Client fromJson(final Office clientOffice, final Group clientParentGroup, final JsonCommand command) {
public static Client createNew(final Office clientOffice, final Group clientParentGroup, final JsonCommand command,
final boolean isPendingStateAllowed) {
final String accountNo = command.stringValueOfParameterNamed("accountNo");
final String firstname = command.stringValueOfParameterNamed("firstname");
final String middlename = command.stringValueOfParameterNamed("middlename");
final String lastname = command.stringValueOfParameterNamed("lastname");
final String fullname = command.stringValueOfParameterNamed("fullname");
final LocalDate joiningDate = command.localDateValueOfParameterNamed("joinedDate");
final String externalId = command.stringValueOfParameterNamed("externalId");
final String accountNo = command.stringValueOfParameterNamed(ClientApiConstants.accountNoParamName);
final String externalId = command.stringValueOfParameterNamed(ClientApiConstants.externalIdParamName);
return new Client(clientOffice, clientParentGroup, accountNo, firstname, middlename, lastname, fullname, joiningDate, externalId);
final String firstname = command.stringValueOfParameterNamed(ClientApiConstants.firstnameParamName);
final String middlename = command.stringValueOfParameterNamed(ClientApiConstants.middlenameParamName);
final String lastname = command.stringValueOfParameterNamed(ClientApiConstants.lastnameParamName);
final String fullname = command.stringValueOfParameterNamed(ClientApiConstants.fullnameParamName);
ClientStatus status = ClientStatus.ACTIVE;
boolean active = true;
if (isPendingStateAllowed && command.hasParameter("active")) {
active = command.booleanPrimitiveValueOfParameterNamed(ClientApiConstants.activeParamName);
}
LocalDate activationDate = null;
if (active) {
activationDate = command.localDateValueOfParameterNamed(ClientApiConstants.activationDateParamName);
} else {
status = ClientStatus.PENDING;
}
return new Client(status, clientOffice, clientParentGroup, accountNo, firstname, middlename, lastname, fullname, activationDate,
externalId);
}
protected Client() {
//
}
private Client(final Office office, final Group clientParentGroup, final String accountNo, final String firstname,
final String middlename, final String lastname, final String fullname, final LocalDate openingDate, final String externalId) {
private Client(final ClientStatus status, final Office office, final Group clientParentGroup, final String accountNo,
final String firstname, final String middlename, final String lastname, final String fullname, final LocalDate activationDate,
final String externalId) {
if (StringUtils.isBlank(accountNo)) {
this.accountNumber = new RandomPasswordGenerator(19).generate();
this.accountNumberRequiresAutoGeneration = true;
} else {
this.accountNumber = accountNo;
}
this.status = status.getValue();
this.office = office;
if (StringUtils.isNotBlank(externalId)) {
this.externalId = externalId.trim();
} else {
this.externalId = null;
}
this.joinedDate = openingDate.toDateMidnight().toDate();
if (activationDate != null) {
this.activationDate = activationDate.toDateMidnight().toDate();
}
if (StringUtils.isNotBlank(firstname)) {
this.firstname = firstname.trim();
} else {
@@ -140,8 +168,8 @@ public class Client extends AbstractPersistable<Long> {
}
if (clientParentGroup != null) {
this.parentGroups = new HashSet<Group>();
this.parentGroups.add(clientParentGroup);
this.groups = new HashSet<Group>();
this.groups.add(clientParentGroup);
}
deriveDisplayName();
@@ -173,10 +201,65 @@ public class Client extends AbstractPersistable<Long> {
this.accountNumberRequiresAutoGeneration = false;
}
public void activate(final DateTimeFormatter formatter, final LocalDate activationLocalDate) {
if (isActive()) {
final String defaultUserMessage = "Cannot activate client. Client is already active.";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.clients.already.active", defaultUserMessage,
"activationDate", activationLocalDate.toString(formatter));
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
dataValidationErrors.add(error);
throw new PlatformApiDataValidationException(dataValidationErrors);
}
if (isDateInTheFuture(activationLocalDate)) {
final String defaultUserMessage = "Activation date cannot be in the future.";
final ApiParameterError error = ApiParameterError.parameterError("error.msg.clients.activationDate.in.the.future",
defaultUserMessage, "activationDate", activationLocalDate);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
dataValidationErrors.add(error);
throw new PlatformApiDataValidationException(dataValidationErrors);
}
this.activationDate = activationLocalDate.toDate();
this.status = ClientStatus.ACTIVE.getValue();
}
public boolean isNotActive() {
return !isActive();
}
public boolean isActive() {
return ClientStatus.fromInt(this.status).isActive();
}
public boolean isNotPending() {
return !isPending();
}
public boolean isPending() {
return ClientStatus.fromInt(this.status).isPending();
}
private boolean isDateInTheFuture(final LocalDate localDate) {
return localDate.isAfter(DateUtils.getLocalDateOfTenant());
}
public Map<String, Object> update(final JsonCommand command) {
final Map<String, Object> actualChanges = new LinkedHashMap<String, Object>(9);
final String statusEnumParamName = "status";
if (command.isChangeInIntegerParameterNamed(statusEnumParamName, this.status)) {
final Integer newValue = command.integerValueOfParameterNamed(statusEnumParamName);
actualChanges.put(statusEnumParamName, ClientEnumerations.status(newValue));
this.status = ClientStatus.fromInt(newValue).getValue();
}
final String accountNoParamName = "accountNo";
if (command.isChangeInStringParameterNamed(accountNoParamName, this.accountNumber)) {
final String newValue = command.stringValueOfParameterNamed(accountNoParamName);
@@ -238,7 +321,7 @@ public class Client extends AbstractPersistable<Long> {
actualChanges.put("locale", localeAsInput);
final LocalDate newValue = command.localDateValueOfParameterNamed(joiningDateParamName);
this.joinedDate = newValue.toDate();
this.activationDate = newValue.toDate();
}
deriveDisplayName();
@@ -297,8 +380,8 @@ public class Client extends AbstractPersistable<Long> {
private LocalDate getJoiningLocalDate() {
LocalDate joiningLocalDate = null;
if (this.joinedDate != null) {
joiningLocalDate = LocalDate.fromDateFields(this.joinedDate);
if (this.activationDate != null) {
joiningLocalDate = LocalDate.fromDateFields(this.activationDate);
}
return joiningLocalDate;
}
@@ -335,7 +418,7 @@ public class Client extends AbstractPersistable<Long> {
}
public Date getJoiningDate() {
return joinedDate;
return activationDate;
}
public String getExternalId() {
@@ -0,0 +1,36 @@
/**
* 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.mifosplatform.infrastructure.core.data.EnumOptionData;
public class ClientEnumerations {
public static EnumOptionData status(final Integer statusId) {
return status(ClientStatus.fromInt(statusId));
}
public static EnumOptionData status(final ClientStatus status) {
EnumOptionData optionData = new EnumOptionData(ClientStatus.INVALID.getValue().longValue(), ClientStatus.INVALID.getCode(),
"Invalid");
switch (status) {
case INVALID:
optionData = new EnumOptionData(ClientStatus.INVALID.getValue().longValue(), ClientStatus.INVALID.getCode(), "Invalid");
break;
case PENDING:
optionData = new EnumOptionData(ClientStatus.PENDING.getValue().longValue(), ClientStatus.PENDING.getCode(), "Pending");
break;
case ACTIVE:
optionData = new EnumOptionData(ClientStatus.ACTIVE.getValue().longValue(), ClientStatus.ACTIVE.getCode(), "Active");
break;
case CLOSED:
optionData = new EnumOptionData(ClientStatus.CLOSED.getValue().longValue(), ClientStatus.CLOSED.getCode(), "Closed");
break;
}
return optionData;
}
}
@@ -27,8 +27,19 @@ public class ClientRepositoryWrapper {
public Client findOneWithNotFoundDetection(final Long id) {
final Client client = this.repository.findOne(id);
if (client == null) { throw new ClientNotFoundException(id); }
if (client == null || client.isDeleted()) { throw new ClientNotFoundException(id); }
return client;
}
public void save(final Client client) {
this.repository.save(client);
}
public void saveAndFlush(final Client client) {
this.repository.saveAndFlush(client);
}
public void delete(final Client client) {
this.repository.delete(client);
}
}
@@ -0,0 +1,66 @@
/**
* 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;
/**
* Enum representation of client status states.
*/
public enum ClientStatus {
INVALID(0, "clientStatusType.invalid"), //
PENDING(100, "clientStatusType.pending"), //
ACTIVE(300, "clientStatusType.active"), //
CLOSED(600, "clientStatusType.closed");
private final Integer value;
private final String code;
public static ClientStatus fromInt(final Integer statusValue) {
ClientStatus enumeration = ClientStatus.INVALID;
switch (statusValue) {
case 100:
enumeration = ClientStatus.PENDING;
break;
case 300:
enumeration = ClientStatus.ACTIVE;
break;
case 600:
enumeration = ClientStatus.CLOSED;
break;
}
return enumeration;
}
private ClientStatus(final Integer value, final String code) {
this.value = value;
this.code = code;
}
public boolean hasStateOf(final ClientStatus state) {
return this.value.equals(state.getValue());
}
public Integer getValue() {
return this.value;
}
public String getCode() {
return code;
}
public boolean isPending() {
return this.value.equals(ClientStatus.PENDING.getValue());
}
public boolean isActive() {
return this.value.equals(ClientStatus.ACTIVE.getValue());
}
public boolean isClosed() {
return this.value.equals(ClientStatus.CLOSED.getValue());
}
}
@@ -11,12 +11,9 @@ import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceN
* A {@link RuntimeException} thrown when client Identifier resources are not
* found.
*/
public class ClientIdentifierNotFoundException extends
AbstractPlatformResourceNotFoundException {
public class ClientIdentifierNotFoundException extends AbstractPlatformResourceNotFoundException {
public ClientIdentifierNotFoundException(Long id) {
super("error.msg.clientIdentifier.id.invalid",
"Client Identifier with the primary key " + id
+ " does not exist", id);
}
public ClientIdentifierNotFoundException(final Long id) {
super("error.msg.clientIdentifier.id.invalid", "Client Identifier with the primary key " + id + " does not exist", id);
}
}
@@ -0,0 +1,19 @@
/**
* 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.exception;
import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException;
/**
* A {@link RuntimeException} thrown when attempting to delete clients
*/
public class ClientMustBePendingToBeDeletedException extends AbstractPlatformDomainRuleException {
public ClientMustBePendingToBeDeletedException(final Long id) {
super("error.msg.clients.cannot.be.deleted",
"Client with identifier " + id + " cannot be deleted as it is not in `Pending` state.", id);
}
}
@@ -12,7 +12,7 @@ import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceN
*/
public class ClientNotFoundException extends AbstractPlatformResourceNotFoundException {
public ClientNotFoundException(Long id) {
super("error.msg.client.id.invalid", "Client with identifier " + id + " does not exist", id);
}
public ClientNotFoundException(final Long id) {
super("error.msg.client.id.invalid", "Client with identifier " + id + " does not exist", id);
}
}
@@ -0,0 +1,32 @@
/**
* 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.handler;
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.portfolio.client.service.ClientWritePlatformService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class ActivateClientCommandHandler implements NewCommandSourceHandler {
private final ClientWritePlatformService clientWritePlatformService;
@Autowired
public ActivateClientCommandHandler(final ClientWritePlatformService clientWritePlatformService) {
this.clientWritePlatformService = clientWritePlatformService;
}
@Transactional
@Override
public CommandProcessingResult processCommand(final JsonCommand command) {
return this.clientWritePlatformService.activateClient(command.entityId(), command);
}
}
@@ -1,196 +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.serialization;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
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.AbstractFromApiJsonDeserializer;
import org.mifosplatform.infrastructure.core.serialization.FromApiJsonDeserializer;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.portfolio.client.command.ClientCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.google.gson.JsonElement;
import com.google.gson.reflect.TypeToken;
/**
* Implementation of {@link FromApiJsonDeserializer} for {@link ClientCommand}
* 's.
*/
@Component
public final class ClientCommandFromApiJsonDeserializer extends AbstractFromApiJsonDeserializer<ClientCommand> {
/**
* The parameters supported for this command.
*/
private final Set<String> supportedParameters = new HashSet<String>(Arrays.asList("id", "accountNo", "externalId", "firstname",
"middlename", "lastname", "fullname", "officeId", "joinedDate", "locale", "dateFormat", "groupId"));
private final FromJsonHelper fromApiJsonHelper;
@Autowired
public ClientCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper) {
this.fromApiJsonHelper = fromApiJsonHelper;
}
@Override
public ClientCommand commandFromApiJson(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters);
final JsonElement element = fromApiJsonHelper.parse(json);
final String accountNo = fromApiJsonHelper.extractStringNamed("accountNo", element);
final String externalId = fromApiJsonHelper.extractStringNamed("externalId", element);
final String firstname = fromApiJsonHelper.extractStringNamed("firstname", element);
final String middlename = fromApiJsonHelper.extractStringNamed("middlename", element);
final String lastname = fromApiJsonHelper.extractStringNamed("lastname", element);
final String fullname = fromApiJsonHelper.extractStringNamed("fullname", element);
final Long officeId = fromApiJsonHelper.extractLongNamed("officeId", element);
final LocalDate joiningDate = fromApiJsonHelper.extractLocalDateNamed("joinedDate", element);
return new ClientCommand(accountNo, externalId, firstname, middlename, lastname, fullname, officeId, joiningDate);
}
public void validateForUpdate(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters);
final JsonElement element = fromApiJsonHelper.parse(json);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("client");
boolean atLeastOneParameterPassedForUpdate = false;
final String accountNoParameterName = "accountNo";
if (fromApiJsonHelper.parameterExists(accountNoParameterName, element)) {
atLeastOneParameterPassedForUpdate = true;
final String accountNo = fromApiJsonHelper.extractStringNamed(accountNoParameterName, element);
baseDataValidator.reset().parameter(accountNoParameterName).value(accountNo).notBlank().notExceedingLengthOf(20);
}
final String externalIdParameterName = "externalId";
if (fromApiJsonHelper.parameterExists(externalIdParameterName, element)) {
atLeastOneParameterPassedForUpdate = true;
final String externalId = fromApiJsonHelper.extractStringNamed(externalIdParameterName, element);
baseDataValidator.reset().parameter(externalIdParameterName).value(externalId).ignoreIfNull().notExceedingLengthOf(100);
}
final String fullnameParameterName = "fullname";
if (fromApiJsonHelper.parameterExists(fullnameParameterName, element)) {
atLeastOneParameterPassedForUpdate = true;
}
final String lastNameParameterName = "lastname";
if (fromApiJsonHelper.parameterExists(lastNameParameterName, element)) {
atLeastOneParameterPassedForUpdate = true;
}
final String middleNameParameterName = "middlename";
if (fromApiJsonHelper.parameterExists(middleNameParameterName, element)) {
atLeastOneParameterPassedForUpdate = true;
}
final String firstNameParameterName = "firstname";
if (fromApiJsonHelper.parameterExists(firstNameParameterName, element)) {
atLeastOneParameterPassedForUpdate = true;
}
final String officeIdParameterName = "officeId";
if (fromApiJsonHelper.parameterExists(officeIdParameterName, element)) {
atLeastOneParameterPassedForUpdate = true;
final Long officeId = fromApiJsonHelper.extractLongNamed(officeIdParameterName, element);
baseDataValidator.reset().parameter(officeIdParameterName).value(officeId).notNull().integerGreaterThanZero();
}
final String joinedDateParameterName = "joinedDate";
if (fromApiJsonHelper.parameterExists(joinedDateParameterName, element)) {
atLeastOneParameterPassedForUpdate = true;
final String joinedDateStr = fromApiJsonHelper.extractStringNamed(joinedDateParameterName, element);
baseDataValidator.reset().parameter(joinedDateParameterName).value(joinedDateStr).notBlank();
final LocalDate joinedDate = fromApiJsonHelper.extractLocalDateNamed(joinedDateParameterName, element);
baseDataValidator.reset().parameter(joinedDateParameterName).value(joinedDate).notNull();
}
if (!atLeastOneParameterPassedForUpdate) {
final Object forceError = null;
baseDataValidator.reset().anyOfNotNull(forceError);
}
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); }
}
public void validateForCreate(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters);
final JsonElement element = fromApiJsonHelper.parse(json);
final List<ApiParameterError> dataValidationErrors = new ArrayList<ApiParameterError>();
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("client");
final String accountNoParameterName = "accountNo";
if (fromApiJsonHelper.parameterExists(accountNoParameterName, element)) {
final String accountNo = fromApiJsonHelper.extractStringNamed(accountNoParameterName, element);
baseDataValidator.reset().parameter(accountNoParameterName).value(accountNo).notBlank().notExceedingLengthOf(20);
}
final String externalIdParameterName = "externalId";
if (fromApiJsonHelper.parameterExists(externalIdParameterName, element)) {
final String externalId = fromApiJsonHelper.extractStringNamed(externalIdParameterName, element);
baseDataValidator.reset().parameter(externalIdParameterName).value(externalId).ignoreIfNull().notExceedingLengthOf(100);
}
final String officeIdParameterName = "officeId";
if (fromApiJsonHelper.parameterExists(officeIdParameterName, element)) {
final Long officeId = fromApiJsonHelper.extractLongNamed(officeIdParameterName, element);
baseDataValidator.reset().parameter(officeIdParameterName).value(officeId).notNull().integerGreaterThanZero();
}
final String groupIdParameterName = "groupId";
if (fromApiJsonHelper.parameterExists(groupIdParameterName, element)) {
final Long groupId = fromApiJsonHelper.extractLongNamed(groupIdParameterName, element);
baseDataValidator.reset().parameter(groupIdParameterName).value(groupId).notNull().integerGreaterThanZero();
}
final String joinedDateParameterName = "joinedDate";
if (fromApiJsonHelper.parameterExists(joinedDateParameterName, element)) {
final String joinedDateStr = fromApiJsonHelper.extractStringNamed(joinedDateParameterName, element);
baseDataValidator.reset().parameter(joinedDateParameterName).value(joinedDateStr).notBlank();
final LocalDate joinedDate = fromApiJsonHelper.extractLocalDateNamed(joinedDateParameterName, element);
baseDataValidator.reset().parameter(joinedDateParameterName).value(joinedDate).notNull();
}
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); }
}
}
@@ -10,18 +10,19 @@ import java.util.Collection;
import org.mifosplatform.portfolio.client.data.ClientAccountSummaryCollectionData;
import org.mifosplatform.portfolio.client.data.ClientAccountSummaryData;
import org.mifosplatform.portfolio.client.data.ClientData;
import org.mifosplatform.portfolio.group.service.SearchParameters;
public interface ClientReadPlatformService {
Collection<ClientData> retrieveAllIndividualClients(String extraCriteria);
ClientData retrieveTemplate();
ClientData retrieveIndividualClient(Long clientId);
Collection<ClientData> retrieveAll(SearchParameters searchParameters);
ClientData retrieveNewClientDetails();
ClientData retrieveOne(Long clientId);
Collection<ClientData> retrieveAllIndividualClientsForLookup(String extraCriteria);
Collection<ClientData> retrieveAllForLookup(String extraCriteria);
Collection<ClientData> retrieveAllIndividualClientsForLookupByOfficeId(Long officeId);
Collection<ClientData> retrieveAllForLookupByOfficeId(Long officeId);
ClientAccountSummaryCollectionData retrieveClientAccountDetails(Long clientId);
@@ -13,16 +13,21 @@ import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService;
import org.mifosplatform.infrastructure.core.api.ApiParameterHelper;
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.organisation.office.data.OfficeLookup;
import org.mifosplatform.organisation.office.data.OfficeData;
import org.mifosplatform.organisation.office.service.OfficeReadPlatformService;
import org.mifosplatform.portfolio.client.data.ClientAccountSummaryCollectionData;
import org.mifosplatform.portfolio.client.data.ClientAccountSummaryData;
import org.mifosplatform.portfolio.client.data.ClientData;
import org.mifosplatform.portfolio.client.domain.ClientEnumerations;
import org.mifosplatform.portfolio.client.exception.ClientNotFoundException;
import org.mifosplatform.portfolio.group.data.GroupGeneralData;
import org.mifosplatform.portfolio.group.service.SearchParameters;
import org.mifosplatform.portfolio.loanaccount.data.LoanStatusEnumData;
import org.mifosplatform.portfolio.loanproduct.service.LoanEnumerations;
import org.mifosplatform.useradministration.domain.AppUser;
@@ -37,61 +42,126 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
private final JdbcTemplate jdbcTemplate;
private final PlatformSecurityContext context;
private final ConfigurationDomainService configurationDomainService;
private final OfficeReadPlatformService officeReadPlatformService;
// data mappers
private final ClientMapper clientMapper = new ClientMapper();
private final ClientLookupMapper lookupMapper = new ClientLookupMapper();
private final ClientMembersOfGroupMapper membersOfGroupMapper = new ClientMembersOfGroupMapper();
private final ParentGroupsMapper clientGroupsMapper = new ParentGroupsMapper();
@Autowired
public ClientReadPlatformServiceImpl(final PlatformSecurityContext context, final TenantAwareRoutingDataSource dataSource,
final OfficeReadPlatformService officeReadPlatformService) {
final ConfigurationDomainService configurationDomainService, final OfficeReadPlatformService officeReadPlatformService) {
this.context = context;
this.configurationDomainService = configurationDomainService;
this.officeReadPlatformService = officeReadPlatformService;
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
@Override
public Collection<ClientData> retrieveAllIndividualClients(final String extraCriteria) {
public ClientData retrieveTemplate() {
AppUser currentUser = context.authenticatedUser();
String hierarchy = currentUser.getOffice().getHierarchy();
String hierarchySearchString = hierarchy + "%";
final AppUser currentUser = context.authenticatedUser();
ClientMapper rm = new ClientMapper();
final Collection<OfficeData> offices = officeReadPlatformService.retrieveAllOfficesForDropdown();
String sql = "select " + rm.clientSchema();
final boolean clientPendingApprovalAllowed = this.configurationDomainService.isClientPendingApprovalAllowedEnabled();
final Long officeId = currentUser.getOffice().getId();
return ClientData.template(officeId, new LocalDate(), clientPendingApprovalAllowed, offices);
}
@Override
public Collection<ClientData> retrieveAll(final SearchParameters searchParameters) {
final AppUser currentUser = context.authenticatedUser();
final String hierarchy = currentUser.getOffice().getHierarchy();
final String hierarchySearchString = hierarchy + "%";
String sql = "select " + this.clientMapper.schema() + " where o.hierarchy like ? and c.is_deleted=0";
final String extraCriteria = buildSqlStringFromClientCriteria(searchParameters);
if (StringUtils.isNotBlank(extraCriteria)) sql += " and (" + extraCriteria + ")";
sql += " order by c.display_name ASC, c.account_no ASC";
return this.jdbcTemplate.query(sql, rm, new Object[] { hierarchySearchString });
return this.jdbcTemplate.query(sql, clientMapper, new Object[] { hierarchySearchString });
}
private String buildSqlStringFromClientCriteria(final SearchParameters searchParameters) {
final String sqlSearch = searchParameters.getSqlSearch();
final Long officeId = searchParameters.getOfficeId();
final String externalId = searchParameters.getExternalId();
final String displayName = searchParameters.getName();
final String firstname = searchParameters.getFirstname();
final String lastname = searchParameters.getLastname();
final String hierarchy = searchParameters.getHierarchy();
String extraCriteria = "";
if (sqlSearch != null) {
extraCriteria = " and (" + sqlSearch + ")";
}
if (officeId != null) {
extraCriteria += " and office_id = " + officeId;
}
if (externalId != null) {
extraCriteria += " and external_id like " + ApiParameterHelper.sqlEncodeString(externalId);
}
if (displayName != null) {
extraCriteria += " and concat(ifnull(firstname, ''), if(firstname > '',' ', '') , ifnull(lastname, '')) like "
+ ApiParameterHelper.sqlEncodeString(displayName);
}
if (firstname != null) {
extraCriteria += " and firstname like " + ApiParameterHelper.sqlEncodeString(firstname);
}
if (lastname != null) {
extraCriteria += " and lastname like " + ApiParameterHelper.sqlEncodeString(lastname);
}
if (hierarchy != null) {
extraCriteria += " and o.hierarchy like " + ApiParameterHelper.sqlEncodeString(hierarchy + "%");
}
if (StringUtils.isNotBlank(extraCriteria)) {
extraCriteria = extraCriteria.substring(4);
}
return extraCriteria;
}
@Override
public ClientData retrieveIndividualClient(final Long clientId) {
public ClientData retrieveOne(final Long clientId) {
try {
AppUser currentUser = context.authenticatedUser();
String hierarchy = currentUser.getOffice().getHierarchy();
String hierarchySearchString = hierarchy + "%";
ClientMapper rm = new ClientMapper();
String sql = "select " + rm.clientSchema() + " and c.id = " + clientId;
ClientData clientData = this.jdbcTemplate.queryForObject(sql, rm, new Object[] { hierarchySearchString });
String sql = "select " + this.clientMapper.schema() + " where o.hierarchy like ? and c.is_deleted=0 and c.id = ?";
ClientData clientData = this.jdbcTemplate.queryForObject(sql, this.clientMapper,
new Object[] { hierarchySearchString, clientId });
ParentGroupsMapper cgrm = new ParentGroupsMapper();
String cgSql = "select " + cgrm.parentGroupsSchema();
Collection<GroupGeneralData> parentGroups = this.jdbcTemplate.query(cgSql, cgrm, new Object[] { clientId });
return ClientData.setParentGroups(clientData , parentGroups);
String clientGroupsSql = "select " + this.clientGroupsMapper.parentGroupsSchema();
Collection<GroupGeneralData> parentGroups = this.jdbcTemplate.query(clientGroupsSql, this.clientGroupsMapper, new Object[] { clientId });
return ClientData.setParentGroups(clientData, parentGroups);
} catch (EmptyResultDataAccessException e) {
throw new ClientNotFoundException(clientId);
}
}
@Override
public Collection<ClientData> retrieveAllIndividualClientsForLookup(final String extraCriteria) {
public Collection<ClientData> retrieveAllForLookup(final String extraCriteria) {
String sql = "select " + this.lookupMapper.schema();
@@ -103,24 +173,13 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
}
@Override
public Collection<ClientData> retrieveAllIndividualClientsForLookupByOfficeId(final Long officeId) {
public Collection<ClientData> retrieveAllForLookupByOfficeId(final Long officeId) {
final String sql = "select " + this.lookupMapper.schema() + " and c.office_id = ?";
return this.jdbcTemplate.query(sql, this.lookupMapper, new Object[] { officeId });
}
@Override
public ClientData retrieveNewClientDetails() {
final AppUser currentUser = context.authenticatedUser();
final List<OfficeLookup> offices = new ArrayList<OfficeLookup>(officeReadPlatformService.retrieveAllOfficesForLookup());
final Long officeId = currentUser.getOffice().getId();
return ClientData.template(officeId, new LocalDate(), offices);
}
@Override
public Collection<ClientData> retrieveClientMembersOfGroup(final Long groupId) {
@@ -140,16 +199,16 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
public ClientMembersOfGroupMapper() {
final StringBuilder sqlBuilder = new StringBuilder(200);
sqlBuilder.append("c.id as id, c.account_no as accountNo, c.external_id as externalId, ");
sqlBuilder.append("c.office_id as officeId, o.name as officeName, ");
sqlBuilder.append("c.firstname as firstname, c.middlename as middlename, c.lastname as lastname, ");
sqlBuilder.append("c.fullname as fullname, c.display_name as displayName, ");
sqlBuilder.append("c.joined_date as joinedDate, c.image_key as imagekey ");
sqlBuilder.append("c.activation_date as activationDate, c.image_key as imagekey ");
sqlBuilder.append("from m_client c ");
sqlBuilder.append("join m_office o on o.id = c.office_id ");
sqlBuilder.append("join m_group_client pgc on pgc.client_id = c.id");
this.schema = sqlBuilder.toString();
}
@@ -161,6 +220,9 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
public ClientData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final String accountNo = rs.getString("accountNo");
final EnumOptionData status = null;
final Long officeId = JdbcSupport.getLong(rs, "officeId");
final Long id = JdbcSupport.getLong(rs, "id");
final String firstname = rs.getString("firstname");
@@ -169,29 +231,46 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
final String fullname = rs.getString("fullname");
final String displayName = rs.getString("displayName");
final String externalId = rs.getString("externalId");
final LocalDate joinedDate = JdbcSupport.getLocalDate(rs, "joinedDate");
final LocalDate activationDate = JdbcSupport.getLocalDate(rs, "activationDate");
final String imageKey = rs.getString("imageKey");
final String officeName = rs.getString("officeName");
return new ClientData(accountNo, officeId, officeName, id, firstname, middlename, lastname, fullname, displayName, externalId,
joinedDate, imageKey, null, null, null, null);
return new ClientData(accountNo, status, officeId, officeName, id, firstname, middlename, lastname, fullname, displayName,
externalId, activationDate, imageKey, null, null, null);
}
}
private static final class ClientMapper implements RowMapper<ClientData> {
public String clientSchema() {
return "c.account_no as accountNo, c.office_id as officeId, o.name as officeName, c.id as id, "
+ "c.firstname as firstname, c.middlename as middlename, c.lastname as lastname, "
+ "c.fullname as fullname, c.display_name as displayName, "
+ "c.external_id as externalId, c.joined_date as joinedDate, c.image_key as imagekey from m_client c join m_office o on o.id = c.office_id "
+ " where o.hierarchy like ? and c.is_deleted=0 ";
private final String schema;
public ClientMapper() {
StringBuilder builder = new StringBuilder(400);
builder.append("c.id as id, c.account_no as accountNo, c.external_id as externalId, c.status_enum as statusEnum, ");
builder.append("c.office_id as officeId, o.name as officeName, ");
builder.append("c.office_id as officeId, o.name as officeName, ");
builder.append("c.firstname as firstname, c.middlename as middlename, c.lastname as lastname, ");
builder.append("c.fullname as fullname, c.display_name as displayName, ");
builder.append("c.activation_date as activationDate, c.image_key as imagekey ");
builder.append("from m_client c ");
builder.append("join m_office o on o.id = c.office_id ");
this.schema = builder.toString();
}
public String schema() {
return this.schema;
}
@Override
public ClientData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
final String accountNo = rs.getString("accountNo");
final Integer statusEnum = JdbcSupport.getInteger(rs, "statusEnum");
final EnumOptionData status = ClientEnumerations.status(statusEnum);
final Long officeId = JdbcSupport.getLong(rs, "officeId");
final Long id = JdbcSupport.getLong(rs, "id");
final String firstname = rs.getString("firstname");
@@ -200,12 +279,12 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
final String fullname = rs.getString("fullname");
final String displayName = rs.getString("displayName");
final String externalId = rs.getString("externalId");
final LocalDate joinedDate = JdbcSupport.getLocalDate(rs, "joinedDate");
final LocalDate activationDate = JdbcSupport.getLocalDate(rs, "activationDate");
final String imageKey = rs.getString("imageKey");
final String officeName = rs.getString("officeName");
return new ClientData(accountNo, officeId, officeName, id, firstname, middlename, lastname, fullname, displayName, externalId,
joinedDate, imageKey, null, null, null ,null);
return new ClientData(accountNo, status, officeId, officeName, id, firstname, middlename, lastname, fullname, displayName,
externalId, activationDate, imageKey, null, null, null);
}
}
@@ -215,7 +294,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
public String parentGroupsSchema() {
return "gp.id As groupId , gp.name As groupName from m_client cl JOIN m_group_client gc ON cl.id = gc.client_id "
+ "JOIN m_group gp ON gp.id = gc.group_id WHERE cl.id = ? AND gp.is_deleted = 0 ";
}
}
@Override
public GroupGeneralData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
@@ -266,7 +345,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
this.context.authenticatedUser();
// Check if client exists
retrieveIndividualClient(clientId);
retrieveOne(clientId);
List<ClientAccountSummaryData> pendingApprovalLoans = new ArrayList<ClientAccountSummaryData>();
List<ClientAccountSummaryData> awaitingDisbursalLoans = new ArrayList<ClientAccountSummaryData>();
@@ -332,7 +411,7 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
this.context.authenticatedUser();
// Check if client exists
retrieveIndividualClient(clientId);
retrieveOne(clientId);
ClientLoanAccountSummaryDataMapper rm = new ClientLoanAccountSummaryDataMapper();
@@ -417,9 +496,11 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
private static final class ClientIdentifierMapper implements RowMapper<ClientData> {
public String clientLookupByIdentifierSchema() {
return "c.id as id, c.account_no as accountNo, c.firstname as firstname, c.middlename as middlename, c.lastname as lastname, "
+ "c.fullname as fullname, c.display_name as displayName," + "c.office_id as officeId, o.name as officeName "
+ " from m_client c, m_office o, m_client_identifier ci " + "where o.id = c.office_id and c.id=ci.client_id "
return "c.id as id, c.account_no as accountNo, c.status_enum as statusEnum, c.firstname as firstname, c.middlename as middlename, c.lastname as lastname, "
+ "c.fullname as fullname, c.display_name as displayName,"
+ "c.office_id as officeId, o.name as officeName "
+ " from m_client c, m_office o, m_client_identifier ci "
+ "where o.id = c.office_id and c.id=ci.client_id "
+ "and ci.document_type_id= ? and ci.document_key like ?";
}
@@ -428,6 +509,10 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
final Long id = rs.getLong("id");
final String accountNo = rs.getString("accountNo");
final Integer statusEnum = JdbcSupport.getInteger(rs, "statusEnum");
final EnumOptionData status = ClientEnumerations.status(statusEnum);
final String firstname = rs.getString("firstname");
final String middlename = rs.getString("middlename");
final String lastname = rs.getString("lastname");
@@ -437,7 +522,8 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService
final Long officeId = rs.getLong("officeId");
final String officeName = rs.getString("officeName");
return ClientData.clientIdentifier(id, accountNo, firstname, middlename, lastname, fullname, displayName, officeId, officeName);
return ClientData.clientIdentifier(id, accountNo, status, firstname, middlename, lastname, fullname, displayName, officeId,
officeName);
}
}
}
@@ -18,6 +18,8 @@ public interface ClientWritePlatformService {
CommandProcessingResult updateClient(Long clientId, JsonCommand command);
CommandProcessingResult activateClient(Long clientId, JsonCommand command);
CommandProcessingResult deleteClient(Long clientId);
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'CREATE_CLIENTIMAGE')")
@@ -28,5 +30,4 @@ public interface ClientWritePlatformService {
@PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'DELETE_CLIENTIMAGE')")
CommandProcessingResult deleteClientImage(Long clientId);
}
@@ -8,9 +8,15 @@ package org.mifosplatform.portfolio.client.service;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
@@ -22,15 +28,19 @@ import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext
import org.mifosplatform.organisation.office.domain.Office;
import org.mifosplatform.organisation.office.domain.OfficeRepository;
import org.mifosplatform.organisation.office.exception.OfficeNotFoundException;
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.ClientRepository;
import org.mifosplatform.portfolio.client.domain.ClientRepositoryWrapper;
import org.mifosplatform.portfolio.client.exception.ClientMustBePendingToBeDeletedException;
import org.mifosplatform.portfolio.client.exception.ClientNotFoundException;
import org.mifosplatform.portfolio.client.serialization.ClientCommandFromApiJsonDeserializer;
import org.mifosplatform.portfolio.group.domain.Group;
import org.mifosplatform.portfolio.group.domain.GroupRepository;
import org.mifosplatform.portfolio.group.exception.GroupNotFoundException;
import org.mifosplatform.portfolio.note.domain.Note;
import org.mifosplatform.portfolio.note.domain.NoteRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -44,37 +54,51 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
private final static Logger logger = LoggerFactory.getLogger(ClientWritePlatformServiceJpaRepositoryImpl.class);
private final PlatformSecurityContext context;
private final ClientRepository clientRepository;
private final ClientRepositoryWrapper clientRepository;
private final OfficeRepository officeRepository;
private final NoteRepository noteRepository;
private final GroupRepository groupRepository;
private final ClientCommandFromApiJsonDeserializer fromApiJsonDeserializer;
private final ClientDataValidator fromApiJsonDeserializer;
private final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory;
private final ConfigurationDomainService configurationDomainService;
@Autowired
public ClientWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final ClientRepository clientRepository,
final OfficeRepository officeRepository, final ClientCommandFromApiJsonDeserializer fromApiJsonDeserializer,
final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory, final GroupRepository groupRepository) {
public ClientWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context,
final ClientRepositoryWrapper clientRepository, final OfficeRepository officeRepository, final NoteRepository noteRepository,
final ClientDataValidator fromApiJsonDeserializer,
final AccountNumberGeneratorFactory accountIdentifierGeneratorFactory, final GroupRepository groupRepository,
final ConfigurationDomainService configurationDomainService) {
this.context = context;
this.clientRepository = clientRepository;
this.officeRepository = officeRepository;
this.noteRepository = noteRepository;
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
this.accountIdentifierGeneratorFactory = accountIdentifierGeneratorFactory;
this.groupRepository = groupRepository;
this.configurationDomainService = configurationDomainService;
}
@Transactional
@Override
public CommandProcessingResult deleteClient(final Long clientId) {
final Client client = this.clientRepository.findOne(clientId);
if (client == null || client.isDeleted()) { throw new ClientNotFoundException(clientId); }
final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId);
final Long officeId = client.getOffice().getId();
client.delete();
this.clientRepository.save(client);
if (client.isNotPending()) { throw new ClientMustBePendingToBeDeletedException(clientId); }
return new CommandProcessingResultBuilder().withOfficeId(officeId).withClientId(clientId).withEntityId(clientId).build();
List<Note> relatedNotes = this.noteRepository.findByClientId(clientId);
this.noteRepository.deleteInBatch(relatedNotes);
// client.delete();
this.clientRepository.delete(client);
return new CommandProcessingResultBuilder() //
.withOfficeId(officeId) //
.withClientId(clientId) //
.withEntityId(clientId) //
.build();
}
/*
@@ -107,23 +131,24 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
try {
context.authenticatedUser();
this.fromApiJsonDeserializer.validateForCreate(command.json());
final boolean isPendingApprovalEnabled = this.configurationDomainService.isClientPendingApprovalAllowedEnabled();
this.fromApiJsonDeserializer.validateForCreate(command.json(), isPendingApprovalEnabled);
final Long officeId = command.longValueOfParameterNamed("officeId");
final Long officeId = command.longValueOfParameterNamed(ClientApiConstants.officeIdParamName);
final Office clientOffice = this.officeRepository.findOne(officeId);
if (clientOffice == null) { throw new OfficeNotFoundException(officeId); }
final Long groupId = command.longValueOfParameterNamed("groupId");
final Long groupId = command.longValueOfParameterNamed(ClientApiConstants.groupIdParamName);
Group clientParentGroup = null;
if (groupId != null) {
clientParentGroup = this.groupRepository.findOne(groupId);
if (clientParentGroup == null) { throw new GroupNotFoundException(groupId); }
}
final Client newClient = Client.fromJson(clientOffice, clientParentGroup, command);
final Client newClient = Client.createNew(clientOffice, clientParentGroup, command, isPendingApprovalEnabled);
this.clientRepository.save(newClient);
if (newClient.isAccountNumberRequiresAutoGeneration()) {
@@ -137,6 +162,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
.withCommandId(command.commandId()) //
.withOfficeId(clientOffice.getId()) //
.withClientId(newClient.getId()) //
.withGroupId(groupId) //
.withEntityId(newClient.getId()) //
.build();
} catch (DataIntegrityViolationException dve) {
@@ -152,10 +178,10 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
try {
context.authenticatedUser();
this.fromApiJsonDeserializer.validateForUpdate(command.json());
final boolean isPendingApprovalEnabled = this.configurationDomainService.isClientPendingApprovalAllowedEnabled();
this.fromApiJsonDeserializer.validateForUpdate(command.json(), isPendingApprovalEnabled);
final Client clientForUpdate = this.clientRepository.findOne(clientId);
if (clientForUpdate == null || clientForUpdate.isDeleted()) { throw new ClientNotFoundException(clientId); }
final Client clientForUpdate = this.clientRepository.findOneWithNotFoundDetection(clientId);
final Map<String, Object> changes = clientForUpdate.update(command);
@@ -173,7 +199,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withOfficeId(clientForUpdate.getOffice().getId()) //
.withOfficeId(clientForUpdate.officeId()) //
.withClientId(clientId) //
.withEntityId(clientId) //
.with(changes) //
@@ -186,9 +212,37 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
@Transactional
@Override
public CommandProcessingResult saveOrUpdateClientImage(Long clientId, String imageName, InputStream inputStream) {
public CommandProcessingResult activateClient(final Long clientId, final JsonCommand command) {
try {
final Client client = this.clientRepository.findOne(clientId);
this.fromApiJsonDeserializer.validateActivation(command);
final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId);
final Locale locale = command.extractLocale();
final DateTimeFormatter fmt = DateTimeFormat.forPattern(command.dateFormat()).withLocale(locale);
final LocalDate activationDate = command.localDateValueOfParameterNamed("activationDate");
client.activate(fmt, activationDate);
this.clientRepository.saveAndFlush(client);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withOfficeId(client.officeId()) //
.withClientId(clientId) //
.withEntityId(clientId) //
.build();
} catch (DataIntegrityViolationException dve) {
handleDataIntegrityIssues(command, dve);
return new CommandProcessingResult(Long.valueOf(-1));
}
}
@Transactional
@Override
public CommandProcessingResult saveOrUpdateClientImage(final Long clientId, final String imageName, final InputStream inputStream) {
try {
final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId);
String imageUploadLocation = setupForClientImageUpdate(clientId, client);
String imageLocation = FileUtils.saveToFileSystem(inputStream, imageUploadLocation, imageName);
@@ -204,8 +258,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
@Override
public CommandProcessingResult deleteClientImage(final Long clientId) {
final Client client = this.clientRepository.findOne(clientId);
if (client == null || client.isDeleted()) { throw new ClientNotFoundException(clientId); }
final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId);
// delete image from the file system
if (StringUtils.isNotEmpty(client.getImageKey())) {
@@ -217,7 +270,7 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
@Override
public CommandProcessingResult saveOrUpdateClientImage(final Long clientId, final Base64EncodedImage encodedImage) {
try {
final Client client = this.clientRepository.findOne(clientId);
final Client client = this.clientRepository.findOneWithNotFoundDetection(clientId);
final String imageUploadLocation = setupForClientImageUpdate(clientId, client);
final String imageLocation = FileUtils.saveToFileSystem(encodedImage, imageUploadLocation, "image");
@@ -255,5 +308,4 @@ public class ClientWritePlatformServiceJpaRepositoryImpl implements ClientWriteP
private void logAsErrorUnexpectedDataIntegrityException(final DataIntegrityViolationException dve) {
logger.error(dve.getMessage(), dve);
}
}
@@ -252,7 +252,7 @@ public class CenterReadPlatformServiceImpl implements CenterReadPlatformService
}
Collection<ClientData> clientOptions = this.clientReadPlatformService
.retrieveAllIndividualClientsForLookupByOfficeId(centerOfficeId);
.retrieveAllForLookupByOfficeId(centerOfficeId);
if (CollectionUtils.isEmpty(clientOptions)) {
clientOptions = null;
}
@@ -82,7 +82,7 @@ public class GroupReadPlatformServiceImpl implements GroupReadPlatformService {
}
Collection<ClientData> clientOptions = this.clientReadPlatformService
.retrieveAllIndividualClientsForLookupByOfficeId(defaultOfficeId);
.retrieveAllForLookupByOfficeId(defaultOfficeId);
if (CollectionUtils.isEmpty(clientOptions)) {
clientOptions = null;
}
@@ -7,18 +7,28 @@ public class SearchParameters {
private final String externalId;
private final String name;
private final String hierarchy;
private final String firstname;
private final String lastname;
public static SearchParameters from(final String sqlSearch, final Long officeId, final String externalId, final String name,
final String hierarchy) {
return new SearchParameters(sqlSearch, officeId, externalId, name, hierarchy);
return new SearchParameters(sqlSearch, officeId, externalId, name, hierarchy, null, null);
}
private SearchParameters(final String sqlSearch, final Long officeId, final String externalId, final String name, final String hierarchy) {
public static SearchParameters forClients(final String sqlSearch, final Long officeId, final String externalId,
final String displayName, final String firstname, final String lastname, final String hierarchy) {
return new SearchParameters(sqlSearch, officeId, externalId, displayName, hierarchy, firstname, lastname);
}
private SearchParameters(final String sqlSearch, final Long officeId, final String externalId, final String name,
final String hierarchy, final String firstname, final String lastname) {
this.sqlSearch = sqlSearch;
this.officeId = officeId;
this.externalId = externalId;
this.name = name;
this.hierarchy = hierarchy;
this.firstname = firstname;
this.lastname = lastname;
}
public String getSqlSearch() {
@@ -40,4 +50,12 @@ public class SearchParameters {
public String getHierarchy() {
return this.hierarchy;
}
public String getFirstname() {
return this.firstname;
}
public String getLastname() {
return this.lastname;
}
}
@@ -67,24 +67,24 @@ public class GuarantorData {
allowedClientRelationshipTypes);
}
public static GuarantorData mergeClientData(ClientData clientData, GuarantorData guarantorData) {
public static GuarantorData mergeClientData(final ClientData clientData, final GuarantorData guarantorData) {
return new GuarantorData(guarantorData.id, guarantorData.loanId, guarantorData.clientRelationshipType, guarantorData.entityId,
guarantorData.guarantorType, clientData.getFirstname(), clientData.getLastname(), null, null, null, null, null, null, null,
null, null, null, clientData.getOfficeName(), clientData.getJoinedDate(), clientData.getExternalId(), null,
null, null, null, clientData.officeName(), clientData.getActivationDate(), clientData.getExternalId(), null,
guarantorData.allowedClientRelationshipTypes);
}
public static GuarantorData mergeStaffData(StaffData staffData, GuarantorData guarantorData) {
public static GuarantorData mergeStaffData(final StaffData staffData, final GuarantorData guarantorData) {
return new GuarantorData(guarantorData.id, guarantorData.loanId, guarantorData.clientRelationshipType, guarantorData.entityId,
guarantorData.guarantorType, staffData.getFirstname(), staffData.getLastname(), null, null, null, null, null, null, null,
null, null, null, staffData.getOfficeName(), null, null, null, guarantorData.allowedClientRelationshipTypes);
}
public GuarantorData(Long id, Long loanId, final CodeValueData clientRelationshipType, Long entityId, EnumOptionData guarantorType,
String firstname, String lastname, LocalDate dob, String addressLine1, String addressLine2, String city, String state,
String zip, String country, String mobileNumber, String housePhoneNumber, String comment, String officeName,
LocalDate joinedDate, String externalId, List<EnumOptionData> guarantorTypeOptions,
Collection<CodeValueData> allowedClientRelationshipTypes) {
public GuarantorData(final Long id, final Long loanId, final CodeValueData clientRelationshipType, final Long entityId, final EnumOptionData guarantorType,
final String firstname, final String lastname, final LocalDate dob, final String addressLine1, final String addressLine2, final String city, final String state,
final String zip, final String country, final String mobileNumber, final String housePhoneNumber, final String comment, final String officeName,
final LocalDate joinedDate, final String externalId, final List<EnumOptionData> guarantorTypeOptions,
final Collection<CodeValueData> allowedClientRelationshipTypes) {
this.id = id;
this.loanId = loanId;
this.clientRelationshipType = clientRelationshipType;
@@ -127,7 +127,7 @@ public class GuarantorReadPlatformServiceImpl implements GuarantorReadPlatformSe
*/
private GuarantorData mergeDetailsForClientOrStaffGuarantor(GuarantorData guarantorData) {
if (guarantorData.isExistingClient()) {
ClientData clientData = clientReadPlatformService.retrieveIndividualClient(guarantorData.getEntityId());
ClientData clientData = clientReadPlatformService.retrieveOne(guarantorData.getEntityId());
return GuarantorData.mergeClientData(clientData, guarantorData);
} else if (guarantorData.isStaffMember()) {
StaffData staffData = staffReadPlatformService.retrieveStaff(guarantorData.getEntityId());
@@ -84,7 +84,7 @@ public class GuarantorWritePlatformServiceJpaRepositoryIImpl implements Guaranto
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withOfficeId(guarantor.getOfficeId())
.withEntityId(guarantor.getId()).withLoanId(loanId).build();
} catch (DataIntegrityViolationException dve) {
handleGuarantorDataIntegrityIssues(command, dve);
handleGuarantorDataIntegrityIssues(dve);
return CommandProcessingResult.empty();
}
}
@@ -124,7 +124,7 @@ public class GuarantorWritePlatformServiceJpaRepositoryIImpl implements Guaranto
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withOfficeId(guarantorForUpdate.getOfficeId())
.withEntityId(guarantorForUpdate.getId()).withOfficeId(guarantorForUpdate.getLoanId()).with(changesOnly).build();
} catch (DataIntegrityViolationException dve) {
handleGuarantorDataIntegrityIssues(command, dve);
handleGuarantorDataIntegrityIssues(dve);
return CommandProcessingResult.empty();
}
}
@@ -142,32 +142,22 @@ public class GuarantorWritePlatformServiceJpaRepositoryIImpl implements Guaranto
.withOfficeId(guarantorForDelete.getOfficeId()).build();
}
/**
* @param loanId
* @param loan
* @param guarantor
*/
private void validateGuarantorBusinessRules(Guarantor guarantor) {
private void validateGuarantorBusinessRules(final Guarantor guarantor) {
// validate guarantor conditions
if (guarantor.isExistingCustomer()) {
// check client exists
clientRepositoryWrapper.findOneWithNotFoundDetection(guarantor.getEntityId());
// validate that the client is not set as a self guarantor
if (guarantor.getClientId().equals(guarantor.getEntityId())) { throw new InvalidGuarantorException(guarantor.getEntityId(),
guarantor.getLoanId()); }
if (guarantor.getClientId().equals(guarantor.getEntityId())) {
//
throw new InvalidGuarantorException(guarantor.getEntityId(), guarantor.getLoanId());
}
} else if (guarantor.isExistingEmployee()) {
staffRepositoryWrapper.findOneWithNotFoundDetection(guarantor.getEntityId());
}
}
/**
* Throws an exception for any data Integrity issue
*
* @param command
* @param dve
*/
@SuppressWarnings("unused")
private void handleGuarantorDataIntegrityIssues(final JsonCommand command, DataIntegrityViolationException dve) {
private void handleGuarantorDataIntegrityIssues(final DataIntegrityViolationException dve) {
Throwable realCause = dve.getMostSpecificCause();
logger.error(dve.getMessage(), dve);
throw new PlatformDataIntegrityException("error.msg.guarantor.unknown.data.integrity.issue",
@@ -148,7 +148,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
context.authenticatedUser();
final ClientData clientAccount = this.clientReadPlatformService.retrieveIndividualClient(clientId);
final ClientData clientAccount = this.clientReadPlatformService.retrieveOne(clientId);
final LocalDate expectedDisbursementDate = DateUtils.getLocalDateOfTenant();
LoanAccountData loanTemplateDetails = LoanAccountData.clientDefaults(clientAccount.id(), clientAccount.displayName(),
clientAccount.officeId(), expectedDisbursementDate);
@@ -666,14 +666,14 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService {
if (fromDate == null) {
fromDate = this.lastDueDate;
}
final BigDecimal outstandingPrincipleBalanceOfLoan = outstandingLoanPrincipalBalance.subtract(principalDue);
final BigDecimal outstandingPrincipalBalanceOfLoan = outstandingLoanPrincipalBalance.subtract(principalDue);
// update based on current period values
this.lastDueDate = dueDate;
outstandingLoanPrincipalBalance = outstandingLoanPrincipalBalance.subtract(principalDue);
final LoanSchedulePeriodData periodData = LoanSchedulePeriodData.repaymentPeriodWithPayments(loanId, period, fromDate,
dueDate, principalDue, principalPaid, principalWrittenOff, principalOutstanding, outstandingPrincipleBalanceOfLoan,
dueDate, principalDue, principalPaid, principalWrittenOff, principalOutstanding, outstandingPrincipalBalanceOfLoan,
interestExpectedDue, interestPaid, interestWaived, interestWrittenOff, interestOutstanding, feeChargesExpectedDue,
feeChargesPaid, feeChargesWaived, feeChargesWrittenOff, feeChargesOutstanding, penaltyChargesExpectedDue,
penaltyChargesPaid, penaltyChargesWaived, penaltyChargesWrittenOff, penaltyChargesOutstanding, totalDueForPeriod,
@@ -147,7 +147,7 @@ public class LoanEnumerations {
break;
case EQUAL_PRINCIPAL:
optionData = new EnumOptionData(AmortizationMethod.EQUAL_PRINCIPAL.getValue().longValue(),
AmortizationMethod.EQUAL_PRINCIPAL.getCode(), "Equal principle payments");
AmortizationMethod.EQUAL_PRINCIPAL.getCode(), "Equal principal payments");
break;
default:
optionData = new EnumOptionData(AmortizationMethod.INVALID.getValue().longValue(), AmortizationMethod.INVALID.getCode(),
@@ -295,7 +295,10 @@ public class SavingsAccountDataValidator {
}
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); }
if (!dataValidationErrors.isEmpty()) {
//
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors);
}
}
}
@@ -82,7 +82,10 @@ public class SavingsAccountTransactionDataValidator {
}
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); }
if (!dataValidationErrors.isEmpty()) {
//
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors);
}
}
}
@@ -207,7 +207,7 @@ public class SavingsAccountReadPlatformServiceImpl implements SavingsAccountRead
ClientData client = null;
if (clientId != null) {
client = this.clientReadPlatformService.retrieveIndividualClient(clientId);
client = this.clientReadPlatformService.retrieveOne(clientId);
}
GroupGeneralData group = null;
@@ -5,7 +5,6 @@
*/
package org.mifosplatform.useradministration.api;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
@@ -22,23 +21,17 @@ import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo;
import org.mifosplatform.commands.data.CommandSourceData;
import org.mifosplatform.commands.domain.CommandWrapper;
import org.mifosplatform.commands.service.CommandWrapperBuilder;
import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
import org.mifosplatform.commands.service.PortfolioCommandsReadPlatformService;
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.DefaultToApiJsonSerializer;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.useradministration.command.PermissionsCommand;
import org.mifosplatform.useradministration.command.RoleCommand;
import org.mifosplatform.useradministration.data.PermissionData;
import org.mifosplatform.useradministration.data.RoleData;
import org.mifosplatform.useradministration.data.RolePermissionsData;
import org.mifosplatform.useradministration.serialization.PermissionsCommandFromApiJsonDeserializer;
import org.mifosplatform.useradministration.serialization.RoleCommandFromApiJsonDeserializer;
import org.mifosplatform.useradministration.service.PermissionReadPlatformService;
import org.mifosplatform.useradministration.service.RoleReadPlatformService;
import org.springframework.beans.factory.annotation.Autowired;
@@ -67,33 +60,24 @@ public class RolesApiResource {
private final PlatformSecurityContext context;
private final RoleReadPlatformService roleReadPlatformService;
private final PermissionReadPlatformService permissionReadPlatformService;
private final RoleCommandFromApiJsonDeserializer fromApiJsonDeserializer;
private final PermissionsCommandFromApiJsonDeserializer permissionsFromApiJsonDeserializer;
private final DefaultToApiJsonSerializer<RoleData> toApiJsonSerializer;
private final DefaultToApiJsonSerializer<RolePermissionsData> permissionsToApiJsonSerializer;
private final ApiRequestParameterHelper apiRequestParameterHelper;
private final PortfolioCommandsReadPlatformService commandSourceReadPlatformService;
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
@Autowired
public RolesApiResource(final PlatformSecurityContext context, final RoleReadPlatformService readPlatformService,
final PermissionReadPlatformService permissionReadPlatformService,
final RoleCommandFromApiJsonDeserializer fromApiJsonDeserializer,
final PermissionsCommandFromApiJsonDeserializer permissionsFromApiJsonDeserializer,
final DefaultToApiJsonSerializer<RoleData> toApiJsonSerializer,
final DefaultToApiJsonSerializer<RolePermissionsData> permissionsToApiJsonSerializer,
final ApiRequestParameterHelper apiRequestParameterHelper,
final PortfolioCommandsReadPlatformService commandSourceReadPlatformService,
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService) {
this.context = context;
this.roleReadPlatformService = readPlatformService;
this.permissionReadPlatformService = permissionReadPlatformService;
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
this.permissionsFromApiJsonDeserializer = permissionsFromApiJsonDeserializer;
this.toApiJsonSerializer = toApiJsonSerializer;
this.permissionsToApiJsonSerializer = permissionsToApiJsonSerializer;
this.apiRequestParameterHelper = apiRequestParameterHelper;
this.commandSourceReadPlatformService = commandSourceReadPlatformService;
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
}
@@ -135,13 +119,7 @@ public class RolesApiResource {
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
RoleData role = this.roleReadPlatformService.retrieveOne(roleId);
if (settings.isCommandIdPassed()) {
final CommandSourceData entry = this.commandSourceReadPlatformService.retrieveById(settings.getCommandId());
final RoleCommand changesOnly = this.fromApiJsonDeserializer.commandFromApiJson(entry.json());
RoleData currentChanges = RoleData.changes(changesOnly.getName(), changesOnly.getDescription());
role = RoleData.integrateChanges(role, currentChanges);
}
final RoleData role = this.roleReadPlatformService.retrieveOne(roleId);
return this.toApiJsonSerializer.serialize(settings, role, RESPONSE_DATA_PARAMETERS);
}
@@ -174,18 +152,7 @@ public class RolesApiResource {
final RoleData role = this.roleReadPlatformService.retrieveOne(roleId);
final Collection<PermissionData> permissionUsageData = this.permissionReadPlatformService.retrieveAllRolePermissions(roleId);
Collection<PermissionData> currentChanges = null;
if (settings.isCommandIdPassed()) {
final CommandSourceData entry = this.commandSourceReadPlatformService.retrieveById(settings.getCommandId());
PermissionsCommand command = permissionsFromApiJsonDeserializer.commandFromApiJson(entry.json());
currentChanges = new ArrayList<PermissionData>();
for (String key : command.getPermissions().keySet()) {
currentChanges.add(PermissionData.from(key, command.getPermissions().get(key)));
}
}
final RolePermissionsData permissionsData = role.toRolePermissionData(permissionUsageData, currentChanges);
final RolePermissionsData permissionsData = role.toRolePermissionData(permissionUsageData);
return this.permissionsToApiJsonSerializer.serialize(settings, permissionsData, PERMISSIONS_RESPONSE_DATA_PARAMETERS);
}
@@ -15,27 +15,15 @@ public class RoleData {
private final Long id;
private final String name;
private final String description;
@SuppressWarnings("unused")
private final RoleData currentChanges;
public RolePermissionsData toRolePermissionData(final Collection<PermissionData> permissionUsageData,
final Collection<PermissionData> currentChanges) {
return new RolePermissionsData(id, name, description, permissionUsageData, currentChanges);
public RolePermissionsData toRolePermissionData(final Collection<PermissionData> permissionUsageData) {
return new RolePermissionsData(id, name, description, permissionUsageData);
}
public static RoleData changes(final String name, final String description) {
return new RoleData(null, name, description, null);
}
public static RoleData integrateChanges(final RoleData role, final RoleData currentChanges) {
return new RoleData(role.id, role.name, role.description, currentChanges);
}
public RoleData(final Long id, final String name, final String description, final RoleData currentChanges) {
public RoleData(final Long id, final String name, final String description) {
this.id = id;
this.name = name;
this.description = description;
this.currentChanges = currentChanges;
}
@Override
@@ -21,15 +21,12 @@ public class RolePermissionsData {
@SuppressWarnings("unused")
private final Collection<PermissionData> permissionUsageData;
@SuppressWarnings("unused")
private final Collection<PermissionData> currentChanges;
public RolePermissionsData(final Long id, final String name, final String description,
final Collection<PermissionData> permissionUsageData, final Collection<PermissionData> currentChanges) {
final Collection<PermissionData> permissionUsageData) {
this.id = id;
this.name = name;
this.description = description;
this.permissionUsageData = permissionUsageData;
this.currentChanges = currentChanges;
}
}
@@ -36,7 +36,7 @@ public class Role extends AbstractPersistable<Long> {
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "m_role_permission", joinColumns = @JoinColumn(name = "role_id"), inverseJoinColumns = @JoinColumn(name = "permission_id"))
private Set<Permission> permissions = new HashSet<Permission>();
private final Set<Permission> permissions = new HashSet<Permission>();
public static Role fromJson(final JsonCommand command) {
final String name = command.stringValueOfParameterNamed("name");
@@ -109,6 +109,6 @@ public class Role extends AbstractPersistable<Long> {
}
public RoleData toData() {
return new RoleData(this.getId(), this.name, this.description, null);
return new RoleData(this.getId(), this.name, this.description);
}
}
@@ -18,21 +18,15 @@ 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.AbstractFromApiJsonDeserializer;
import org.mifosplatform.infrastructure.core.serialization.FromApiJsonDeserializer;
import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
import org.mifosplatform.useradministration.command.RoleCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.google.gson.JsonElement;
import com.google.gson.reflect.TypeToken;
/**
* Implementation of {@link FromApiJsonDeserializer} for {@link RoleCommand}'s.
*/
@Component
public final class RoleCommandFromApiJsonDeserializer extends AbstractFromApiJsonDeserializer<RoleCommand> {
public final class RoleCommandValidator {
/**
* The parameters supported for this command.
@@ -42,25 +36,10 @@ public final class RoleCommandFromApiJsonDeserializer extends AbstractFromApiJso
private final FromJsonHelper fromApiJsonHelper;
@Autowired
public RoleCommandFromApiJsonDeserializer(final FromJsonHelper fromApiJsonHelper) {
public RoleCommandValidator(final FromJsonHelper fromApiJsonHelper) {
this.fromApiJsonHelper = fromApiJsonHelper;
}
@Override
public RoleCommand commandFromApiJson(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters);
final JsonElement element = fromApiJsonHelper.parse(json);
final String name = fromApiJsonHelper.extractStringNamed("name", element);
final String description = fromApiJsonHelper.extractStringNamed("description", element);
return new RoleCommand(name, description);
}
public void validateForCreate(final String json) {
if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
@@ -106,7 +85,10 @@ public final class RoleCommandFromApiJsonDeserializer extends AbstractFromApiJso
}
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist",
"Validation errors exist.", dataValidationErrors); }
if (!dataValidationErrors.isEmpty()) {
//
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors);
}
}
}
@@ -59,7 +59,7 @@ public class RoleReadPlatformServiceImpl implements RoleReadPlatformService {
final String name = rs.getString("name");
final String description = rs.getString("description");
return new RoleData(id, name, description, null);
return new RoleData(id, name, description);
}
public String schema() {
@@ -22,7 +22,7 @@ import org.mifosplatform.useradministration.domain.RoleRepository;
import org.mifosplatform.useradministration.exception.PermissionNotFoundException;
import org.mifosplatform.useradministration.exception.RoleNotFoundException;
import org.mifosplatform.useradministration.serialization.PermissionsCommandFromApiJsonDeserializer;
import org.mifosplatform.useradministration.serialization.RoleCommandFromApiJsonDeserializer;
import org.mifosplatform.useradministration.serialization.RoleCommandValidator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -37,12 +37,12 @@ public class RoleWritePlatformServiceJpaRepositoryImpl implements RoleWritePlatf
private final PlatformSecurityContext context;
private final RoleRepository roleRepository;
private final PermissionRepository permissionRepository;
private final RoleCommandFromApiJsonDeserializer roleCommandFromApiJsonDeserializer;
private final RoleCommandValidator roleCommandFromApiJsonDeserializer;
private final PermissionsCommandFromApiJsonDeserializer permissionsFromApiJsonDeserializer;
@Autowired
public RoleWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final RoleRepository roleRepository,
final PermissionRepository permissionRepository, final RoleCommandFromApiJsonDeserializer roleCommandFromApiJsonDeserializer,
final PermissionRepository permissionRepository, final RoleCommandValidator roleCommandFromApiJsonDeserializer,
final PermissionsCommandFromApiJsonDeserializer fromApiJsonDeserializer) {
this.context = context;
this.roleRepository = roleRepository;