diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm index 7bee3c5f0..31cad5e87 100644 --- a/api-docs/apiLive.htm +++ b/api-docs/apiLive.htm @@ -176,6 +176,14 @@ Retrieve a Client Update a Client + Delete a Client + + + + clients/{clientId}?command=activate + Activate a Client + + @@ -1697,8 +1705,8 @@ function executeAjaxRequest(url, verbType, jsonData, basicAuthKey, successFuncti

Clients

-

Clients are people and businesses that have applied (or may - apply) to an MFI for loans.

+

Clients are people and businesses that have applied (or may apply) to an MFI for loans.

+

Clients can be created in Pending state (as opposed to Active state) if global configuration for allow-pending-client-status is enabled.

@@ -1712,6 +1720,29 @@ function executeAjaxRequest(url, verbType, jsonData, basicAuthKey, successFuncti auto generated account no. is put in place based on the configured strategy. + + + + + + + + + + + + + + + + + + @@ -1741,63 +1772,11 @@ function executeAjaxRequest(url, verbType, jsonData, basicAuthKey, successFuncti business that doesnt suit the firstname,middlename,lastname structure. - - - - - -
Field Descriptions
externalId
A place to put an external reference for + this client e.g. The ID another system uses.
If + provided, it must be unique. +
active
Indicates whether this client is to be created as active client. If active=true, then activationDate must be provided. If active=false, then the client is created as pending but this must be allowed through configuration. +
activationDate
The date on which the client became active. +
firstname
externalId
A place to put an external reference for - this client e.g. The ID another system uses.
If - provided, it must be unique. -
-   -
-
-

List Clients

-

Example Requests:

-
clients
-
-
-
clients?fields=displayName,officeName,joinedDate
-
-
- -GET https://DomainName/api/v1/clients - - -[ - { - "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] - } -] - -
-
- -   +  

Retrieve Client Details Template

@@ -1819,58 +1798,20 @@ GET https://DomainName/api/v1/clients/template { - "officeId": 1, - "joinedDate": [ - 2013, - 2, - 5 - ], - "allowedOffices": [ - { - "id": 1, - "name": "Head Office", - "nameDecorated": "Head Office" - } - ] -} - -
-
- - -   -
-
-

Retrieve a Client

-

Example Requests:

-
clients/1
-
-
-
clients/1?template=true
-
-
-
clients/1?fields=id,displayName,officeName
-
-
- -GET https://DomainName/api/v1/clients/{clientId} - - -{ - "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" + } + ] }
@@ -1891,11 +1832,19 @@ GET https://DomainName/api/v1/clients/{clientId}
Mandatory Fields
- firstname and lastname OR fullname
, joinedDate, - officeId + firstname and lastname OR fullname,
officeId,
active=true and activationDate OR active=false,
+
+ + + + + + + +
Optional Fields
groupId, externalId, accountNo
@@ -1904,14 +1853,15 @@ POST https://DomainName/api/v1/clients 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" } @@ -1926,30 +1876,166 @@ Content-Type: application/json Request Body: 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" } { - "officeId": 1, - "clientId": 2, - "resourceId": 2 + "officeId": 1, + "groupId": 1, + "clientId": 2, + "resourceId": 2 }
+   +
+
+

Activate a Client

+

Clients can be created in a Pending state if configuration is enabled. This API exists to enable client activation (for when a client becomes approved member of microfinance institue.

+

If the client happens to be alrady active this API will result in an error.

+
+
+ POST https://Domain Name/api/v1/clients/{clientId}?command=activate + POST clients/1?command=activate +Content-Type: application/json +Request Body: +{ + "locale": "en", + "dateFormat": "dd MMMM yyyy", + "activationDate": "01 March 2011" +} + + +{ + "officeId": 1, + "clientId": 1, + "resourceId": 1 +} + +
+
+ +   +
+
+

Retrieve a Client

+

Example Requests:

+
clients/1
+
+
+
clients/1?template=true
+
+
+
clients/1?fields=id,displayName,officeName
+
+
+ +GET https://DomainName/api/v1/clients/{clientId} + + +{ + "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" + } + ] +} + +
+
+ +   +
+
+

List Clients

+

Example Requests:

+
clients
+
+
+
clients?fields=displayName,officeName,joinedDate
+
+
+ +GET https://DomainName/api/v1/clients + + +[ + { + "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" + } +] + +
+
+  

Update a Client

+

You can update any attribute of a client except for its association with groups. The relationship between a client and a group must be removed through the Groups API.

@@ -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" } @@ -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" } }
-   +   +
+
+

Delete a Client

+

If a client is in Pending state you are allowed to Delete 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 Close the client if they have died or exited the program.

+
+
+ +DELETE https://DomainName/api/v1/clients/{clientId} + + +DELETE clients/3 +Content-Type: application/json +Request Body: +{ +} + + +{ + "officeId": 1, + "clientId": 3, + "resourceId": 3 +} + +
+
+ +  

Retrieve a Client's Loan Account Summary

@@ -7066,13 +7172,16 @@ Request Body:

Global Configuration

-

Global configuration related to set of supported - enable/disable configurations e.g. maker-checker.

+

Global configuration related to set of supported enable/disable configurations:

+
    +
  1. maker-checker - defaults to false - if true turns on maker-checker functionality
  2. +
  3. allow-pending-client-status - defaults to false - if true allows clients to be created in 'Pending' state
  4. +
  5. allow-pending-group-status - defaults to false - if true allows groups to be created in 'Pending' state
  6. +
-   +  

Retrieve Global Configuration

@@ -7086,12 +7195,20 @@ GET https://DomainName/api/v1/configurations
{ - "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 + } + ] }
@@ -7105,14 +7222,22 @@ GET https://DomainName/api/v1/configurations
-PUT https://DomainName/api/v1/configurations?maker-checker=false +PUT https://DomainName/api/v1/configurations?allow-pending-client-status=false PUT configurations Content-Type: application/json Request Body: { } - { "changes": {} } + +{ + "changes": { + "globalConfiguration": { + "allow-pending-client-status": false + } + } +} +
@@ -12884,6 +13009,14 @@ GET https://DomainName/api/v1/search?query=000000111 Retrieve a Client Update a Client + Delete a Client + + + + clients/{clientId}?command=activate + Activate a Client + + diff --git a/mifosng-db/migrations/core_db/V21__activation-permissions-for-clients.sql b/mifosng-db/migrations/core_db/V21__activation-permissions-for-clients.sql new file mode 100644 index 000000000..c42f2a555 --- /dev/null +++ b/mifosng-db/migrations/core_db/V21__activation-permissions-for-clients.sql @@ -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`; \ No newline at end of file diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/AccountingScenario.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/AccountingScenario.java index 5922366bb..1d65ee261 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/AccountingScenario.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/AccountingScenario.java @@ -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); diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/LoanWithWaiveInterestAndWriteOffIntegrationTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/LoanWithWaiveInterestAndWriteOffIntegrationTest.java index 47f823743..e2200f7a9 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/LoanWithWaiveInterestAndWriteOffIntegrationTest.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/LoanWithWaiveInterestAndWriteOffIntegrationTest.java @@ -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); } diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/LoanWithdrawnByApplicant.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/LoanWithdrawnByApplicant.java index aec47a7da..eae6b42d7 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/LoanWithdrawnByApplicant.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/LoanWithdrawnByApplicant.java @@ -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); } } diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/accounting/GLAccountBuilder.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/accounting/GLAccountBuilder.java index b005716e7..83c468a65 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/accounting/GLAccountBuilder.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/accounting/GLAccountBuilder.java @@ -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 map = new HashMap(); - 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; } } diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/accounting/JournalEntryHelper.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/accounting/JournalEntryHelper.java index 068ac4628..b7fc9fdca 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/accounting/JournalEntryHelper.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/accounting/JournalEntryHelper.java @@ -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 entryResponse, int entryNumber) { + private String getEntryValueFromJournalEntry(final ArrayList entryResponse, final int entryNumber) { HashMap map = (HashMap) entryResponse.get(entryNumber).get("entryType"); return (String) map.get("value"); } - private Float getTransactionAmountFromJournalEntry(ArrayList entryResponse, int entryNumber) { + private Float getTransactionAmountFromJournalEntry(final ArrayList 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 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"); } diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanApplicationTestBuilder.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanApplicationTestBuilder.java index 7f1c29582..5bf85ef72 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanApplicationTestBuilder.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanApplicationTestBuilder.java @@ -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; } diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanProductTestBuilder.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanProductTestBuilder.java index 15a29c0de..f815f5676 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanProductTestBuilder.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanProductTestBuilder.java @@ -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; } diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanTransactionHelper.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanTransactionHelper.java index a1bf5ea81..e54b09282 100644 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanTransactionHelper.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/loans/LoanTransactionHelper.java @@ -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 repaymentPeriods = getLoanRepaymentSchedule(requestSpec, responseSpec, loanID); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java index 084d661f0..57dae8a6f 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/accounting/journalentry/service/AccrualBasedAccountingProcessorForLoan.java @@ -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, diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/api/MakercheckersApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/api/MakercheckersApiResource.java index 8c47d705c..061907a8e 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/api/MakercheckersApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/api/MakercheckersApiResource.java @@ -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 RESPONSE_DATA_PARAMETERS = new HashSet( - 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 RESPONSE_DATA_PARAMETERS = new HashSet(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 toApiJsonSerializer; - private final DefaultToApiJsonSerializer toApiJsonSerializerAudit; - private final DefaultToApiJsonSerializer toApiJsonSerializerSearchTemplate; - private final ApiRequestParameterHelper apiRequestParameterHelper; - private final PortfolioCommandSourceWritePlatformService writePlatformService; + private final AuditReadPlatformService readPlatformService; + private final DefaultToApiJsonSerializer toApiJsonSerializerAudit; + private final DefaultToApiJsonSerializer toApiJsonSerializerSearchTemplate; + private final ApiRequestParameterHelper apiRequestParameterHelper; + private final PortfolioCommandSourceWritePlatformService writePlatformService; - @Autowired - public MakercheckersApiResource( - final AuditReadPlatformService readPlatformService, - final DefaultToApiJsonSerializer toApiJsonSerializer, - final DefaultToApiJsonSerializer toApiJsonSerializerAudit, - final DefaultToApiJsonSerializer 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 toApiJsonSerializerAudit, + final DefaultToApiJsonSerializer 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 entries = this.readPlatformService - .retrieveAllEntriesToBeChecked(extraCriteria, - settings.isIncludeJson()); + final Collection 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 RESPONSE_DATA_PARAMETERS_SEARCH_TEMPLATE = new HashSet( - Arrays.asList("appUsers", "actionNames", "entityNames")); + final Set RESPONSE_DATA_PARAMETERS_SEARCH_TEMPLATE = new HashSet(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; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/data/CommandSourceData.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/data/CommandSourceData.java index 0e2875c11..402a60cd2 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/data/CommandSourceData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/data/CommandSourceData.java @@ -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; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java index 44b6c1140..0fb231e2a 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java @@ -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"); } - } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java index 8fed138eb..434ba0983 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java @@ -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; - } + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/PortfolioCommandsReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/PortfolioCommandsReadPlatformService.java deleted file mode 100644 index def300550..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/PortfolioCommandsReadPlatformService.java +++ /dev/null @@ -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 retrieveUnprocessChangesByEntityNameAndId(String entityName, Long entityId); -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/PortfolioCommandsReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/PortfolioCommandsReadPlatformServiceImpl.java deleted file mode 100644 index 1a6279b54..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/PortfolioCommandsReadPlatformServiceImpl.java +++ /dev/null @@ -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 { - - 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 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 }); - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java index f98d0f464..2a8003cce 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java @@ -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()) { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/domain/ConfigurationDomainService.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/domain/ConfigurationDomainService.java index c6b9d1c8b..4f3e775dc 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/domain/ConfigurationDomainService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/domain/ConfigurationDomainService.java @@ -9,4 +9,5 @@ public interface ConfigurationDomainService { boolean isMakerCheckerEnabledForTask(String taskPermissionCode); -} + boolean isClientPendingApprovalAllowedEnabled(); +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java index 110c66b42..03c03079a 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java @@ -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(); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/api/ApiRequestParameterHelper.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/api/ApiRequestParameterHelper.java index 81262c71b..b73492ee0 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/api/ApiRequestParameterHelper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/api/ApiRequestParameterHelper.java @@ -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 queryParameters) { @@ -48,11 +46,9 @@ public class ApiRequestParameterHelper { final Set 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); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/data/DataValidatorBuilder.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/data/DataValidatorBuilder.java index 48449c38a..8162cb0d5 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/data/DataValidatorBuilder.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/data/DataValidatorBuilder.java @@ -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; - } + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/serialization/ApiRequestJsonSerializationSettings.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/serialization/ApiRequestJsonSerializationSettings.java index d46fcc2c1..ea6253f96 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/serialization/ApiRequestJsonSerializationSettings.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/serialization/ApiRequestJsonSerializationSettings.java @@ -16,28 +16,25 @@ public class ApiRequestJsonSerializationSettings { private final boolean prettyPrint; private final Set parametersForPartialResponse; private final boolean template; - private final Long commandId; private final boolean makerCheckerable; private final boolean includeJson; public ApiRequestJsonSerializationSettings(final boolean prettyPrint, final Set 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 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 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; - } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/data/OfficeLookup.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/data/OfficeLookup.java index 775dc912c..8ff0cf2e3 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/data/OfficeLookup.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/data/OfficeLookup.java @@ -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; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/service/OfficeReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/service/OfficeReadPlatformService.java index 8e584986b..e6b83dd8c 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/service/OfficeReadPlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/office/service/OfficeReadPlatformService.java @@ -21,6 +21,7 @@ public interface OfficeReadPlatformService { * Deprecated so cane eventually remove need for OfficeLookup type - so use * retrieveAllOfficesForDropdown instead. */ + @Deprecated Collection retrieveAllOfficesForLookup(); OfficeData retrieveOffice(Long officeId); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientApiConstants.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientApiConstants.java new file mode 100644 index 000000000..880478375 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientApiConstants.java @@ -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 CLIENT_REQUEST_DATA_PARAMETERS = new HashSet(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 CLIENT_RESPONSE_DATA_PARAMETERS = new HashSet(Arrays.asList(idParamName, accountNoParamName, + externalIdParamName, statusParamName, firstnameParamName, middlenameParamName, lastnameParamName, fullnameParamName, + displayNameParamName, officeIdParamName, officeNameParamName, staffIdParamName, staffNameParamName, hierarchyParamName, + officeOptionsParamName, staffOptionsParamName)); + + public static final Set ACTIVATION_REQUEST_DATA_PARAMETERS = new HashSet(Arrays.asList(localeParamName, + dateFormatParamName, activationDateParamName)); +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientImagesApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientImagesApiResource.java index 8c7ea0736..dccf49f26 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientImagesApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientImagesApiResource.java @@ -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); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientsApiResource.java index 487920348..2727f61b9 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientsApiResource.java @@ -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 CLIENT_DATA_PARAMETERS = new HashSet(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 toApiJsonSerializer; private final ToApiJsonSerializer 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 toApiJsonSerializer, - final ClientCommandFromApiJsonDeserializer clientCommandFromApiJsonDeserializer, final ToApiJsonSerializer 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 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 allowedOffices = new ArrayList(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 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 dataChanges = null; // retrieveAllUnprocessedDataChanges(clientId); - return ClientData.integrateChanges(clientData, currentChange, dataChanges); - } - - private Collection retrieveAllUnprocessedDataChanges(final Long clientId) { - Collection dataChanges = new ArrayList(); - - Collection 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 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 allowedOffices = new ArrayList(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 CLIENT_ACCOUNTS_DATA_PARAMETERS = new HashSet(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); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/data/ClientData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/data/ClientData.java index 99b0ec534..1126638fa 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/data/ClientData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/data/ClientData.java @@ -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 { 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 parentGroups; + private final Collection groups; // template - private final List allowedOffices; - private final ClientData currentChange; - private final Collection allChanges; + private final Collection 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 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 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 allowedOffices) { - public static ClientData template(final Long officeId, final LocalDate joinedDate, final List 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 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 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 allowedOffices, final ClientData currentChange, - final Collection allChanges, final Collection 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 allowedOffices, final Collection 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 { 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 { .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 { 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; } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/data/ClientDataValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/data/ClientDataValidator.java new file mode 100644 index 000000000..cd87eb052 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/data/ClientDataValidator.java @@ -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>() {}.getType(); + fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, ClientApiConstants.CLIENT_REQUEST_DATA_PARAMETERS); + final JsonElement element = fromApiJsonHelper.parse(json); + + final List dataValidationErrors = new ArrayList(); + + 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>() {}.getType(); + fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, ClientApiConstants.CLIENT_REQUEST_DATA_PARAMETERS); + final JsonElement element = fromApiJsonHelper.parse(json); + + final List dataValidationErrors = new ArrayList(); + + 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>() {}.getType(); + fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, ClientApiConstants.ACTIVATION_REQUEST_DATA_PARAMETERS); + + final List dataValidationErrors = new ArrayList(); + 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 dataValidationErrors) { + if (!dataValidationErrors.isEmpty()) { + // + throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.", + dataValidationErrors); + } + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/Client.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/Client.java index 3f7f59cae..7fa322196 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/Client.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/Client.java @@ -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 { +public final class Client extends AbstractPersistable { @Column(name = "account_no", length = 20, unique = true, nullable = false) private String accountNumber; @@ -47,6 +50,12 @@ public class Client extends AbstractPersistable { @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 { 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 parentGroups; + private Set 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 { } if (clientParentGroup != null) { - this.parentGroups = new HashSet(); - this.parentGroups.add(clientParentGroup); + this.groups = new HashSet(); + this.groups.add(clientParentGroup); } deriveDisplayName(); @@ -173,10 +201,65 @@ public class Client extends AbstractPersistable { 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 dataValidationErrors = new ArrayList(); + 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 dataValidationErrors = new ArrayList(); + 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 update(final JsonCommand command) { final Map actualChanges = new LinkedHashMap(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 { 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 { 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 { } public Date getJoiningDate() { - return joinedDate; + return activationDate; } public String getExternalId() { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientEnumerations.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientEnumerations.java new file mode 100644 index 000000000..40aa1fb38 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientEnumerations.java @@ -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; + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientRepositoryWrapper.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientRepositoryWrapper.java index d485b0b87..6551370e5 100755 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientRepositoryWrapper.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientRepositoryWrapper.java @@ -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); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientStatus.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientStatus.java new file mode 100644 index 000000000..47088c1a5 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/domain/ClientStatus.java @@ -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()); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/exception/ClientIdentifierNotFoundException.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/exception/ClientIdentifierNotFoundException.java index f55ecfdd8..7a5107cd5 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/exception/ClientIdentifierNotFoundException.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/exception/ClientIdentifierNotFoundException.java @@ -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); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/exception/ClientMustBePendingToBeDeletedException.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/exception/ClientMustBePendingToBeDeletedException.java new file mode 100644 index 000000000..86261de79 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/exception/ClientMustBePendingToBeDeletedException.java @@ -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); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/exception/ClientNotFoundException.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/exception/ClientNotFoundException.java index 9a97bd1ce..7d6d572dd 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/exception/ClientNotFoundException.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/exception/ClientNotFoundException.java @@ -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); + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/handler/ActivateClientCommandHandler.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/handler/ActivateClientCommandHandler.java new file mode 100644 index 000000000..06de0a45b --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/handler/ActivateClientCommandHandler.java @@ -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); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/serialization/ClientCommandFromApiJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/serialization/ClientCommandFromApiJsonDeserializer.java deleted file mode 100644 index 8a284bb2c..000000000 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/serialization/ClientCommandFromApiJsonDeserializer.java +++ /dev/null @@ -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 { - - /** - * The parameters supported for this command. - */ - private final Set supportedParameters = new HashSet(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>() {}.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>() {}.getType(); - fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); - final JsonElement element = fromApiJsonHelper.parse(json); - - final List dataValidationErrors = new ArrayList(); - - 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>() {}.getType(); - fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, supportedParameters); - final JsonElement element = fromApiJsonHelper.parse(json); - - final List dataValidationErrors = new ArrayList(); - - 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); } - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientReadPlatformService.java index fa22c0165..de2649cbe 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientReadPlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientReadPlatformService.java @@ -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 retrieveAllIndividualClients(String extraCriteria); + ClientData retrieveTemplate(); - ClientData retrieveIndividualClient(Long clientId); + Collection retrieveAll(SearchParameters searchParameters); - ClientData retrieveNewClientDetails(); + ClientData retrieveOne(Long clientId); - Collection retrieveAllIndividualClientsForLookup(String extraCriteria); + Collection retrieveAllForLookup(String extraCriteria); - Collection retrieveAllIndividualClientsForLookupByOfficeId(Long officeId); + Collection retrieveAllForLookupByOfficeId(Long officeId); ClientAccountSummaryCollectionData retrieveClientAccountDetails(Long clientId); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientReadPlatformServiceImpl.java index 1c69bccfa..dca9a1ee4 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientReadPlatformServiceImpl.java @@ -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 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 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 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 parentGroups = this.jdbcTemplate.query(cgSql, cgrm, new Object[] { clientId }); - - return ClientData.setParentGroups(clientData , parentGroups); - + String clientGroupsSql = "select " + this.clientGroupsMapper.parentGroupsSchema(); + + Collection 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 retrieveAllIndividualClientsForLookup(final String extraCriteria) { + public Collection retrieveAllForLookup(final String extraCriteria) { String sql = "select " + this.lookupMapper.schema(); @@ -103,24 +173,13 @@ public class ClientReadPlatformServiceImpl implements ClientReadPlatformService } @Override - public Collection retrieveAllIndividualClientsForLookupByOfficeId(final Long officeId) { + public Collection 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 offices = new ArrayList(officeReadPlatformService.retrieveAllOfficesForLookup()); - final Long officeId = currentUser.getOffice().getId(); - - return ClientData.template(officeId, new LocalDate(), offices); - } - @Override public Collection 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 { - 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 pendingApprovalLoans = new ArrayList(); List awaitingDisbursalLoans = new ArrayList(); @@ -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 { 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); } } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformService.java index 575d7fde2..9f8d5b43e 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformService.java @@ -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); - } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java index e351c355e..0335b8335 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java @@ -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 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 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); } - } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/CenterReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/CenterReadPlatformServiceImpl.java index 567d48c57..5aaccd048 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/CenterReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/CenterReadPlatformServiceImpl.java @@ -252,7 +252,7 @@ public class CenterReadPlatformServiceImpl implements CenterReadPlatformService } Collection clientOptions = this.clientReadPlatformService - .retrieveAllIndividualClientsForLookupByOfficeId(centerOfficeId); + .retrieveAllForLookupByOfficeId(centerOfficeId); if (CollectionUtils.isEmpty(clientOptions)) { clientOptions = null; } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupReadPlatformServiceImpl.java index 2b60e20ea..4d47966aa 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/GroupReadPlatformServiceImpl.java @@ -82,7 +82,7 @@ public class GroupReadPlatformServiceImpl implements GroupReadPlatformService { } Collection clientOptions = this.clientReadPlatformService - .retrieveAllIndividualClientsForLookupByOfficeId(defaultOfficeId); + .retrieveAllForLookupByOfficeId(defaultOfficeId); if (CollectionUtils.isEmpty(clientOptions)) { clientOptions = null; } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/SearchParameters.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/SearchParameters.java index df47e8d34..75dc1563f 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/SearchParameters.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/group/service/SearchParameters.java @@ -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; + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/guarantor/data/GuarantorData.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/guarantor/data/GuarantorData.java index 44c91aaae..823c3a46c 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/guarantor/data/GuarantorData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/guarantor/data/GuarantorData.java @@ -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 guarantorTypeOptions, - Collection 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 guarantorTypeOptions, + final Collection allowedClientRelationshipTypes) { this.id = id; this.loanId = loanId; this.clientRelationshipType = clientRelationshipType; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/guarantor/service/GuarantorReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/guarantor/service/GuarantorReadPlatformServiceImpl.java index aa2307059..40197e2f9 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/guarantor/service/GuarantorReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/guarantor/service/GuarantorReadPlatformServiceImpl.java @@ -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()); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/guarantor/service/GuarantorWritePlatformServiceJpaRepositoryIImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/guarantor/service/GuarantorWritePlatformServiceJpaRepositoryIImpl.java index 35e5cf19d..efff482cf 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/guarantor/service/GuarantorWritePlatformServiceJpaRepositoryIImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/guarantor/service/GuarantorWritePlatformServiceJpaRepositoryIImpl.java @@ -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", diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java index 771a35b8c..5694abfad 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java @@ -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, diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanEnumerations.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanEnumerations.java index 2f3cb75ff..612556005 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanEnumerations.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/loanproduct/service/LoanEnumerations.java @@ -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(), diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountDataValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountDataValidator.java index 16eaa012b..5a9c2c683 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountDataValidator.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountDataValidator.java @@ -295,7 +295,10 @@ public class SavingsAccountDataValidator { } private void throwExceptionIfValidationWarningsExist(final List 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); + } } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountTransactionDataValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountTransactionDataValidator.java index aa53e092a..c05fa17c4 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountTransactionDataValidator.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/data/SavingsAccountTransactionDataValidator.java @@ -82,7 +82,10 @@ public class SavingsAccountTransactionDataValidator { } private void throwExceptionIfValidationWarningsExist(final List 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); + } } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java index d13257b27..73def8220 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/savings/service/SavingsAccountReadPlatformServiceImpl.java @@ -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; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/api/RolesApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/api/RolesApiResource.java index 1e0ffaf14..e2f56da4f 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/api/RolesApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/api/RolesApiResource.java @@ -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 toApiJsonSerializer; private final DefaultToApiJsonSerializer 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 toApiJsonSerializer, final DefaultToApiJsonSerializer 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 permissionUsageData = this.permissionReadPlatformService.retrieveAllRolePermissions(roleId); - Collection currentChanges = null; - - if (settings.isCommandIdPassed()) { - final CommandSourceData entry = this.commandSourceReadPlatformService.retrieveById(settings.getCommandId()); - PermissionsCommand command = permissionsFromApiJsonDeserializer.commandFromApiJson(entry.json()); - currentChanges = new ArrayList(); - 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); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/data/RoleData.java b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/data/RoleData.java index 6e3befd7b..e821f8106 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/data/RoleData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/data/RoleData.java @@ -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 permissionUsageData, - final Collection currentChanges) { - return new RolePermissionsData(id, name, description, permissionUsageData, currentChanges); + public RolePermissionsData toRolePermissionData(final Collection 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 diff --git a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/data/RolePermissionsData.java b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/data/RolePermissionsData.java index f8c04c5f1..3b5539df7 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/data/RolePermissionsData.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/data/RolePermissionsData.java @@ -21,15 +21,12 @@ public class RolePermissionsData { @SuppressWarnings("unused") private final Collection permissionUsageData; - @SuppressWarnings("unused") - private final Collection currentChanges; public RolePermissionsData(final Long id, final String name, final String description, - final Collection permissionUsageData, final Collection currentChanges) { + final Collection permissionUsageData) { this.id = id; this.name = name; this.description = description; this.permissionUsageData = permissionUsageData; - this.currentChanges = currentChanges; } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/domain/Role.java b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/domain/Role.java index 99ffe5204..d1216ac09 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/domain/Role.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/domain/Role.java @@ -36,7 +36,7 @@ public class Role extends AbstractPersistable { @ManyToMany(fetch = FetchType.EAGER) @JoinTable(name = "m_role_permission", joinColumns = @JoinColumn(name = "role_id"), inverseJoinColumns = @JoinColumn(name = "permission_id")) - private Set permissions = new HashSet(); + private final Set permissions = new HashSet(); public static Role fromJson(final JsonCommand command) { final String name = command.stringValueOfParameterNamed("name"); @@ -109,6 +109,6 @@ public class Role extends AbstractPersistable { } public RoleData toData() { - return new RoleData(this.getId(), this.name, this.description, null); + return new RoleData(this.getId(), this.name, this.description); } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/serialization/RoleCommandFromApiJsonDeserializer.java b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/serialization/RoleCommandValidator.java similarity index 73% rename from mifosng-provider/src/main/java/org/mifosplatform/useradministration/serialization/RoleCommandFromApiJsonDeserializer.java rename to mifosng-provider/src/main/java/org/mifosplatform/useradministration/serialization/RoleCommandValidator.java index f2e2d4833..64d65a8be 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/serialization/RoleCommandFromApiJsonDeserializer.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/serialization/RoleCommandValidator.java @@ -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 { +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>() {}.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 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); + } } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/service/RoleReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/service/RoleReadPlatformServiceImpl.java index 24718b90c..739a9f3d2 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/service/RoleReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/service/RoleReadPlatformServiceImpl.java @@ -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() { diff --git a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/service/RoleWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/service/RoleWritePlatformServiceJpaRepositoryImpl.java index 2ec3e8942..a2ac05bb0 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/useradministration/service/RoleWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/useradministration/service/RoleWritePlatformServiceJpaRepositoryImpl.java @@ -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;