From 670b6eef193545e10480543341645ac82f2f28d1 Mon Sep 17 00:00:00 2001 From: VenuShyam Date: Thu, 3 Sep 2015 19:50:41 +0530 Subject: [PATCH] Review comments addressed --- api-docs/apiLive.htm | 820 ++++++++++++++++++ .../common/ClientChargesTest.java | 160 ++++ .../integrationtests/common/ClientHelper.java | 92 +- .../common/charges/ChargesHelper.java | 28 + .../client/api/ClientChargesApiResource.java | 38 +- .../api/ClientTransactionsApiResource.java | 1 - .../ClientChargeReadPlatformService.java | 6 +- .../ClientChargeReadPlatformServiceImpl.java | 47 +- ...WritePlatformServiceJpaRepositoryImpl.java | 9 +- ...entTransactionReadPlatformServiceImpl.java | 10 +- 10 files changed, 1153 insertions(+), 58 deletions(-) create mode 100644 mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/ClientChargesTest.java diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm index 1145847f6..df6da74f0 100644 --- a/api-docs/apiLive.htm +++ b/api-docs/apiLive.htm @@ -381,6 +381,64 @@ + + Client Charge + clients/{clientId}/charges + Add Client Charge + List Client Charges + + + + + + + + clients/{clientId} + + + + Delete Client Charge + + + + + + clients/{clientId}/charges/{chargeid}?command=pay + Pay Client Charge + + + + + + + + clients/{clientId}/charges/{chargeid}?command=waive + Waive Client Charge + + + + + + + Client Ttransactions + clients/{clientId}/transactions/{transactionId}?command=undo + Revert Client Charge Transaction + + + + + + + + clients/{clientId}/transactions + List Client Charge Transactions + + + + + + + @@ -35558,7 +35616,769 @@ Request Body: + + + +   +
+
+

Client Charge

+

Client Charge is a type of charge which is directlly applied on client.One client can have more than one client charge and client charge is created with charge time type as specified due date and calculation type as flat. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Field Descriptions
chargeId
This ia an unique Id associate with client charge. +
name
Name given to the client charge.
active
Indicates whether this charge is to be created as active. If active=true, then activationDate must be provided. If active=false, then the charge is created as pending. +
amountPaid
amount paid as client charge. +
amountWaived
amount waive from client charge
amountOutstanding
The left over amount to pay .
dueDate
it specifies the due date
+
+
+ +   +
+
+

Client Transaction

+

Client Charge transactions are get created when a client pays/waives off client charge.this client charge transaction shows +
the unit of amount paid as client charge. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Field Descriptions
transactionId
This ia an unique Id associate with client charge Transaction. +
clientId
clientId on which client transaction got created
isReverse
Indicates whether this client charge transaction is reversed or not. +
amountPaid
amount paid as client charge. +
currency code
currency type
transaction date
date on which transaction happened
+
+
+   +
+
+

List client Transactions

+

The list capability of client charge transaction can support pagination and sorting.

+
Mandatory Arguments
+
+
offset
+
+ Integer Mandatory, defaults to 0 +
+
Indicates the result from which pagination starts
+ +
limit
+
+ Integer Mandatory, defaults to 200 +
+
Restricts the size of results returned. To override the default and return all entries you must explicitly pass a non-positive integer value for limit e.g. limit=0, or limit=-1
+
+ +

Example Requests:

+
clients/189/transactions
+
clients/189/transactions?offset=10&limit=50
+
+
+ +GET https://DomainName/api/v1/clients/{clientId}/transactions?limit=5&offset=0 + + +GET clients/226/transactions?limit=5&offset=0 +Content-Type: application/json +Request Body: +{ + chargeId="226" + +} + + +{ + "totalFilteredRecords": 20, + "pageItems": [ + { + "id": 226, + "officeId": 1, + "officeName": "Head Office", + "type": { + "id": 1, + "code": "clientTransactionType.payCharge", + "value": "PAY_CHARGE" + }, + "date": [ + 2015, + 9, + 2 + ], + "currency": { + "code": "USD", + "name": "US Dollar", + "decimalPlaces": 2, + "displaySymbol": "$", + "nameCode": "currency.USD", + "displayLabel": "US Dollar ($)" + }, + "amount": 22, + "submittedOnDate": [ + 2015, + 9, + 2 + ], + "reversed": false + }, + { + "id": 208, + "officeId": 1, + "officeName": "Head Office", + "type": { + "id": 1, + "code": "clientTransactionType.payCharge", + "value": "PAY_CHARGE" + }, + "date": [ + 2015, + 8, + 28 + ], + "currency": { + "code": "USD", + "name": "US Dollar", + "decimalPlaces": 2, + "displaySymbol": "$", + "nameCode": "currency.USD", + "displayLabel": "US Dollar ($)" + }, + "amount": 3, + "submittedOnDate": [ + 2015, + 8, + 28 + ], + "reversed": false + }, + { + "id": 207, + "officeId": 1, + "officeName": "Head Office", + "type": { + "id": 1, + "code": "clientTransactionType.payCharge", + "value": "PAY_CHARGE" + }, + "date": [ + 2015, + 8, + 28 + ], + "currency": { + "code": "USD", + "name": "US Dollar", + "decimalPlaces": 2, + "displaySymbol": "$", + "nameCode": "currency.USD", + "displayLabel": "US Dollar ($)" + }, + "amount": 5, + "submittedOnDate": [ + 2015, + 8, + 28 + ], + "reversed": false + }, + { + "id": 206, + "officeId": 1, + "officeName": "Head Office", + "type": { + "id": 1, + "code": "clientTransactionType.payCharge", + "value": "PAY_CHARGE" + }, + "date": [ + 2015, + 8, + 28 + ], + "currency": { + "code": "USD", + "name": "US Dollar", + "decimalPlaces": 2, + "displaySymbol": "$", + "nameCode": "currency.USD", + "displayLabel": "US Dollar ($)" + }, + "amount": 5, + "submittedOnDate": [ + 2015, + 8, + 28 + ], + "reversed": false + }, + { + "id": 205, + "officeId": 1, + "officeName": "Head Office", + "type": { + "id": 1, + "code": "clientTransactionType.payCharge", + "value": "PAY_CHARGE" + }, + "date": [ + 2015, + 8, + 28 + ], + "currency": { + "code": "USD", + "name": "US Dollar", + "decimalPlaces": 2, + "displaySymbol": "$", + "nameCode": "currency.USD", + "displayLabel": "US Dollar ($)" + }, + "amount": 5, + "submittedOnDate": [ + 2015, + 8, + 28 + ], + "reversed": false + } + ] +} + +
+
+   +
+
+

Add Client Charge

+

+ It is one among the charges.It is created chargeTime type as specified due date and calculation type as flat and it can only be applied client.This API enables to add client charge to client. +

+ + + + + + + +
Mandatory Fields
clientId,chargeId and activationDate
+
+ + + + + + + +
Optional Fields
externalId, accountNo,genderId, clientTypeId, clientClassificationId
+
+
+ +POST https://DomainName/api/v1/clients/{clientId}/charges + + +POST clients/226/charges +Content-Type: application/json +Request Body: +{ + "amount"="100" + chargeId="226" + dateFormat="dd MMMM yyyy" + dueDate="01 September 2015" + locale="en" +} + + +{ + "officeId": 1, + "clientId": 189, + "resourceId":164 +} + +
+
+   +
+
+

List Client Charges

+ +

The list capability of client charges can support pagination and sorting.

+
Mandatory Arguments
+
+
offset
+
+ Integer Mandatory, defaults to 0 +
+
Indicates the result from which pagination starts
+ +
limit
+
+ Integer Mandatory, defaults to 200 +
+
Restricts the size of results returned. To override the default and return all entries you must explicitly pass a non-positive integer value for limit e.g. limit=0, or limit=-1
+
+ +

Example Requests:

+
clients/189/charges
+
clients/189/charges?offset=0&limit=5
+
+
+ +GET https://DomainName/api/v1/clients/{clientId}/charges?limit=5&offset=0 + + +GET https://localhost:8443/mifosng-provider/api/v1/clients/189/charges?limit=5&offset=0 + +GET clients/189/charges?limit=5&offset=0 +Content-Type: application/json +Request Body: +{ + "clientId":189 + } + + + { + "id": 151, + "clientId": 182, + "chargeId": 228, + "name": "Charge_client_1WA4XRZ1", + "chargeTimeType": { + "id": 2, + "code": "chargeTimeType.specifiedDueDate", + "value": "Specified due date" + }, + "dueDate": [ + 2011, + 10, + 29 + ], + "chargeCalculationType": { + "id": 1, + "code": "chargeCalculationType.flat", + "value": "Flat" + }, + "currency": { + "code": "USD", + "name": "US Dollar", + "decimalPlaces": 2, + "displaySymbol": "$", + "nameCode": "currency.USD", + "displayLabel": "US Dollar ($)" + }, + "amount": 200, + "amountPaid": 183, + "amountWaived": 0, + "amountWrittenOff": 0, + "amountOutstanding": 17, + "penalty": false, + "isActive": true, + "isPaid": false + }, + { + "id": 160, + "clientId": 182, + "chargeId": 239, + "name": "Charge_client_09UC3HYL", + "chargeTimeType": { + "id": 2, + "code": "chargeTimeType.specifiedDueDate", + "value": "Specified due date" + }, + "dueDate": [ + 2015, + 8, + 14 + ], + "chargeCalculationType": { + "id": 1, + "code": "chargeCalculationType.flat", + "value": "Flat" + }, + "currency": { + "code": "USD", + "name": "US Dollar", + "decimalPlaces": 2, + "displaySymbol": "$", + "nameCode": "currency.USD", + "displayLabel": "US Dollar ($)" + }, + "amount": 100, + "amountPaid": 0, + "amountWaived": 0, + "amountWrittenOff": 0, + "amountOutstanding": 100, + "penalty": false, + "isActive": true, + "isPaid": false + }, + { + "id": 163, + "clientId": 182, + "chargeId": 161, + "name": "Charge_client_12J3LSPO", + "chargeTimeType": { + "id": 2, + "code": "chargeTimeType.specifiedDueDate", + "value": "Specified due date" + }, + "dueDate": [ + 2015, + 9, + 1 + ], + "chargeCalculationType": { + "id": 1, + "code": "chargeCalculationType.flat", + "value": "Flat" + }, + "currency": { + "code": "USD", + "name": "US Dollar", + "decimalPlaces": 2, + "displaySymbol": "$", + "nameCode": "currency.USD", + "displayLabel": "US Dollar ($)" + }, + "amount": 100, + "amountPaid": 0, + "amountWaived": 0, + "amountWrittenOff": 0, + "amountOutstanding": 100, + "penalty": false, + "isActive": true, + "isPaid": false + } + +
+
+ + +   +
+
+

Delete Client Charge

+

+
A client can be associated with more than one client charge and this API enables to delete a charge from client. +

+ + + + + + + +
Mandatory Fields
chargeId +
+
+
+ +DELETE https://localhost:8443/mifosng-provider/api/v1/clients/189/charges?command=delete + +POST clients/189/charges/164?command=delete +Content-Type: application/json +No Request Body + + + + + +{ + "officeId": 1, + "clientId": 189, + "resourceId":164 +} + +
+
+   +
+
+

Pay Client Charge

+

+
Total or Some amount of the client charge can be paid by specifying transaction date and which should not be below or above the specifed due date. +

+ + + + + + + +
Mandatory Fields
+
transactionDate and amount
+
+
+
+
+ +POST https://localhost:8443/mifosng-provider/api/v1/clients/189/charges/157?command=paycharge + + +POST clients/189/charges/157?command=paycharge +Content-Type: application/json +Request Body: +{ + + "amount":200, + "locale":"en", + "dateFormat":"dd MMMM yyyy", + "transactionDate":"01 September 2015" + +} + + + +{ + "officeId":1, + "clientId":189, + "resourceId":157, + "transactionId":"221" +} + +
+
+   +
+
+

Waive Client Charge

+

+
This API provieds the facility of waiving off the client charge of a client. +

+ + + + + + + +
Mandatory Fields
clientId and chargeId +
+
+
+
+ +POST https://localhost:8443/mifosng-provider/api/v1/clients/189/charges/157?command=waive + + +POST clients/189/charges/157?command=waive +Content-Type: application/json +Request Body: +{ + "clientId"="189" + "resourceType"="164" + +} + + + +{ + "clientId":"189", + "resourceType":"164" +} + +
+
+ +   +
+
+

Revert Client Charge Transaction

+

+
This API exists to revert the client transactions which have got created after paying the client charge +
or after waiving off the client charge. +

+ + + + + + + +
Mandatory Fields
clientId ,chargeId and transactionId +
+
+
+
+ +POST https://localhost:8443/mifosng-provider/api/v1/clients/189/charges/157?command=undo + + +POST clients/189/transactions/222 +Content-Type: application/json +Request Body: +{ +clientId="189" +transactionId=222 + +} + + + +{ +"officeId":1, +"clientId":189, +"resourceId":222 +} + +GET https://localhost:8443/mifosng-provider/api/v1/clients/189/charges/164?associations=all +Content-Type: application/json +Resonse Body: + { + "id": 164, + "clientId": 189, + "chargeId": 226, + "name": "Charge_client_0RC9TLF4", + "chargeTimeType": { + "id": 2, + "code": "chargeTimeType.specifiedDueDate", + "value": "Specified due date" + }, + "dueDate": [ + 2015, + 9, + 1 + ], + "chargeCalculationType": { + "id": 1, + "code": "chargeCalculationType.flat", + "value": "Flat" + }, + "currency": { + "code": "USD", + "name": "US Dollar", + "decimalPlaces": 2, + "displaySymbol": "$", + "nameCode": "currency.USD", + "displayLabel": "US Dollar ($)" + }, + "amount": 100, + "amountPaid": 0, + "amountWaived": 0, + "amountWrittenOff": 0, + "amountOutstanding": 100, + "penalty": false, + "isActive": true, + "isPaid": false, + "clientTransactionDatas": [ + { + "id": 222, + "officeId": 1, + "officeName": "Head Office", + "type": { + "id": 2, + "code": "clientTransactionType.waiveCharge", + "value": "WAIVE_CHARGE" + }, + "date": [ + 2015, + 9, + 1 + ], + "currency": { + "code": "USD", + "name": "US Dollar", + "decimalPlaces": 2, + "displaySymbol": "$", + "nameCode": "currency.USD", + "displayLabel": "US Dollar ($)" + }, + "amount": 100, + "submittedOnDate": [ + 2015, + 9, + 1 + ], + "reversed": true + } + ] +} + +
+
+  
diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/ClientChargesTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/ClientChargesTest.java new file mode 100644 index 000000000..965fef0d5 --- /dev/null +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/ClientChargesTest.java @@ -0,0 +1,160 @@ +/** + * 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.integrationtests.common; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mifosplatform.integrationtests.common.charges.ChargesHelper; + +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; + +/** + * + * IntegrationTest for ClientCharges. + * + */ +/** + * @author lenovo + * + */ +public class ClientChargesTest { + + private ResponseSpecification responseSpec; + private RequestSpecification requestSpec; + + @Before + public void setup() { + Utils.initializeRESTAssured(); + this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build(); + this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey()); + this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build(); + } + + @Test + public void clientChargeTest() { + + // Creates clientCharge + final Integer chargeId = ChargesHelper.createCharges(this.requestSpec, this.responseSpec, + ChargesHelper.getChargeSpecifiedDueDateJSON()); + Assert.assertNotNull(chargeId); + + // creates client with activation date + final Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec, "01 November 2012"); + Assert.assertNotNull(clientId); + + /** + * create a charge for loan and try to associate to client created in + * the above lines.it will be an invalid scenario the reason is client + * is not allowed to have only client charge. + * + */ + final Integer loanChargeId = ChargesHelper.createCharges(this.requestSpec, this.responseSpec, + ChargesHelper.getLoanSpecifiedDueDateJSON()); + Assert.assertNotNull(loanChargeId); + ResponseSpecification responseLoanChargeFailure = new ResponseSpecBuilder().expectStatusCode(403).build(); + final Integer clientLoanChargeId = ClientHelper.addChargesForClient(this.requestSpec, responseLoanChargeFailure, clientId, + ClientHelper.getSpecifiedDueDateChargesClientAsJSON(loanChargeId.toString(), "29 October 2011")); + Assert.assertNull(clientLoanChargeId); + + /** + * associates a clientCharge to a client and pay client charge for 10 + * USD--success scenario + **/ + final Integer clientChargeId = ClientHelper.addChargesForClient(this.requestSpec, this.responseSpec, clientId, + ClientHelper.getSpecifiedDueDateChargesClientAsJSON(chargeId.toString(), "29 October 2011")); + Assert.assertNotNull(clientChargeId); + final String clientChargePaidTransactionId = ClientHelper.payChargesForClients(this.requestSpec, this.responseSpec, clientId, + clientChargeId, ClientHelper.getPayChargeJSON("25 AUGUST 2015", "10")); + Assert.assertNotNull(clientChargePaidTransactionId); + isValidOutstandingAmount(ClientHelper.getClientCharge(requestSpec, responseSpec, clientId.toString()), (float) 190.0); + + /** + * Revert the paid client charge transaction by passing the + * clientChargePaidTransactionId and ensure the same is reverted. + */ + final Integer undoTrxnId = ClientHelper.revertClientChargeTransaction(this.requestSpec, this.responseSpec, clientId.toString(), + clientChargePaidTransactionId); + Assert.assertNotNull(undoTrxnId); + isReversedTransaction(clientId.toString(), undoTrxnId.toString()); + /** + * Now pay client charge for 20 USD and ensure the outstanding amount is + * updated properly + */ + ResponseSpecification responseSpecFailure = new ResponseSpecBuilder().expectStatusCode(400).build(); + final String responseId_futureDate_failure = ClientHelper.payChargesForClients(this.requestSpec, responseSpecFailure, clientId, + clientChargeId, ClientHelper.getPayChargeJSON("28 AUGUST 2016", "20")); + Assert.assertNull(responseId_futureDate_failure); + + // waived off the outstanding client charge + final String waiveOffClientChargeTransactionId = ClientHelper.waiveChargesForClients(this.requestSpec, this.responseSpec, clientId, + clientChargeId, ClientHelper.getWaiveChargeJSON("100", clientChargeId.toString())); + Assert.assertNotNull(waiveOffClientChargeTransactionId); + + /** + * Revert the waived off client charge transaction by passing the + * waiveOffClientChargeTransactionId and ensured the transaction is + * reversed. + */ + final Integer undoWaiveTrxnId = ClientHelper.revertClientChargeTransaction(this.requestSpec, this.responseSpec, + clientId.toString(), waiveOffClientChargeTransactionId); + Assert.assertNotNull(undoWaiveTrxnId); + isReversedTransaction(clientId.toString(), undoWaiveTrxnId.toString()); + /** + * pay client charge before client activation date and ensured its a + * failure test case + */ + + final String responseId_activationDate_failure = ClientHelper.payChargesForClients(this.requestSpec, responseSpecFailure, clientId, + clientChargeId, ClientHelper.getPayChargeJSON("30 October 2011", "20")); + Assert.assertNull(responseId_activationDate_failure); + /** + * pay client charge more than outstanding amount amount and ensured its + * a failure test case + */ + final String responseId_moreAmount_failure = ClientHelper.payChargesForClients(this.requestSpec, responseSpecFailure, clientId, + clientChargeId, ClientHelper.getPayChargeJSON("25 AUGUST 2015", "300")); + Assert.assertNull(responseId_moreAmount_failure); + /** + * pay client charge for 10 USD and ensure outstanding amount is updated + * properly + */ + final String chargePaid_responseId = ClientHelper.payChargesForClients(this.requestSpec, this.responseSpec, clientId, + clientChargeId, ClientHelper.getPayChargeJSON("25 AUGUST 2015", "100")); + Assert.assertNotNull(chargePaid_responseId); + + isValidOutstandingAmount(ClientHelper.getClientCharge(requestSpec, responseSpec, clientId.toString()), (float) 100.0); + + } + + /** + * It checks whether the client charge transaction is reversed or not. + * + * @param clientId + * @param transactionId + */ + private void isReversedTransaction(String clientId, String transactionId) { + final Boolean isReversed = ClientHelper.getClientTransactions(this.requestSpec, this.responseSpec, clientId.toString(), + transactionId); + Assert.assertTrue(isReversed); + } + + /** + * Check whether the outStandingAmount is equal to expected Amount or not after + * paying or after waiving off the client charge. + * + * @param outStandingAmount + * @param expectedAmount + */ + private void isValidOutstandingAmount(Object outStandingAmount, Object expectedAmount) { + Assert.assertEquals((float) outStandingAmount, expectedAmount); + } + +} diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/ClientHelper.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/ClientHelper.java index 689e1c00a..80ba4bfa9 100755 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/ClientHelper.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/ClientHelper.java @@ -7,6 +7,7 @@ package org.mifosplatform.integrationtests.common; import static org.junit.Assert.assertEquals; +import java.util.ArrayList; import java.util.HashMap; import org.mifosplatform.integrationtests.common.system.CodeHelper; @@ -33,6 +34,7 @@ public class ClientHelper { public static final String CREATED_DATE_MINUS_ONE = "27 November 2014"; public static final String TRANSACTION_DATE = "01 March 2013"; public static final String LAST_TRANSACTION_DATE = "01 March 2013"; + public static final String DATE_FORMAT = "dd MMMM yyyy"; public ClientHelper(final RequestSpecification requestSpec, final ResponseSpecification responseSpec) { this.requestSpec = requestSpec; @@ -85,7 +87,7 @@ public class ClientHelper { map.put("firstname", Utils.randomNameGenerator("Client_FirstName_", 5)); map.put("lastname", Utils.randomNameGenerator("Client_LastName_", 4)); map.put("externalId", randomIDGenerator("ID_", 7)); - map.put("dateFormat", "dd MMMM yyyy"); + map.put("dateFormat", DATE_FORMAT); map.put("locale", "en"); map.put("active", "true"); map.put("activationDate", dateOfJoining); @@ -99,7 +101,7 @@ public class ClientHelper { map.put("firstname", Utils.randomNameGenerator("Client_FirstName_", 5)); map.put("lastname", Utils.randomNameGenerator("Client_LastName_", 4)); map.put("externalId", randomIDGenerator("ID_", 7)); - map.put("dateFormat", "dd MMMM yyyy"); + map.put("dateFormat", DATE_FORMAT); map.put("locale", "en"); map.put("active", "true"); map.put("activationDate", dateOfJoining); @@ -231,6 +233,38 @@ public class ClientHelper { } + public static String getSpecifiedDueDateChargesClientAsJSON(final String chargeId, final String dueDate) { + final HashMap map = new HashMap<>(); + map.put("locale", "en_GB"); + map.put("dateFormat", DATE_FORMAT); + map.put("dueDate", dueDate); + map.put("chargeId", chargeId); + map.put("amount", "200"); + String json = new Gson().toJson(map); + return json; + } + + public static String getPayChargeJSON(final String date, String amount) { + final HashMap map = new HashMap<>(); + map.put("locale", "en_GB"); + map.put("dateFormat", DATE_FORMAT); + map.put("transactionDate", date); + map.put("amount", amount); + String json = new Gson().toJson(map); + System.out.println(json); + return json; + } + + public static String getWaiveChargeJSON(final String amount, String clientChargeId) { + final HashMap map = new HashMap<>(); + map.put("locale", "en_GB"); + map.put("amount", amount); + map.put("clientChargeId", clientChargeId); + String json = new Gson().toJson(map); + System.out.println(json); + return json; + } + public HashMap closeClient(final Integer clientId) { System.out.println("--------------------------------- CLOSE CLIENT -------------------------------"); return performClientActions(createClientOperationURL(CLOSE_CLIENT_COMMAND, clientId), getCloseClientAsJSON(), clientId); @@ -267,4 +301,58 @@ public class ClientHelper { return response; } + public static Integer addChargesForClient(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, + final Integer clientId, final String request) { + System.out.println("--------------------------------- ADD CHARGES FOR Client --------------------------------"); + final String ADD_CHARGES_URL = "/mifosng-provider/api/v1/clients/" + clientId + "/charges?" + Utils.TENANT_IDENTIFIER; + final HashMap response = Utils.performServerPost(requestSpec, responseSpec, ADD_CHARGES_URL, request, ""); + return (Integer) response.get("resourceId"); + } + + public static String payChargesForClients(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, + final Integer clientId, final Integer clientChargeId, final String json) { + System.out.println("--------------------------------- PAY CHARGES FOR CLIENT --------------------------------"); + final String CHARGES_URL = "/mifosng-provider/api/v1/clients/" + clientId + "/charges/" + clientChargeId + "?command=paycharge&" + + Utils.TENANT_IDENTIFIER; + final HashMap response = Utils.performServerPost(requestSpec, responseSpec, CHARGES_URL, json, ""); + return response.get("transactionId") != null ? response.get("transactionId").toString() : null; + } + + public static String waiveChargesForClients(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, + final Integer clientId, final Integer clientChargeId, final String json) { + System.out.println("--------------------------------- WAIVE CHARGES FOR CLIENT --------------------------------"); + final String CHARGES_URL = "/mifosng-provider/api/v1/clients/" + clientId + "/charges/" + clientChargeId + "?command=waive&" + + Utils.TENANT_IDENTIFIER; + + final HashMap response = Utils.performServerPost(requestSpec, responseSpec, CHARGES_URL, json, ""); + return response.get("transactionId").toString(); + } + + public static Integer revertClientChargeTransaction(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, + final String clientId, String clientChargeId) { + System.out.println("---------------------------------UNDO TRANSACTION---------------------------------------------"); + final String CHARGES_URL = "/mifosng-provider/api/v1/clients/" + clientId + "/transactions/" + clientChargeId + "?command=undo&" + + Utils.TENANT_IDENTIFIER; + + final HashMap response = Utils.performServerPost(requestSpec, responseSpec, CHARGES_URL, "", ""); + return (Integer) response.get("resourceId"); + + } + + public static Object getClientCharge(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, + final String clientId) { + System.out.println("---------------------------------GET CLIENT CHARGE---------------------------------------------"); + final String CHARGES_URL = "/mifosng-provider/api/v1/clients/" + clientId + "/charges?paid=false&" + Utils.TENANT_IDENTIFIER; + ArrayList list = Utils.performServerGet(requestSpec, responseSpec, CHARGES_URL, "amountOutstanding"); + return list != null && !list.isEmpty() ? list.get(0) : null; + } + + public static Boolean getClientTransactions(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, + final String clientId, final String transactionId) { + System.out.println("---------------------------------GET CLIENT CHARGE TRANSACTIONS---------------------------------------------"); + final String CHARGES_URL = "/mifosng-provider/api/v1/clients/" + clientId + "/transactions/" + transactionId + "?" + + Utils.TENANT_IDENTIFIER; + return Utils.performServerGet(requestSpec, responseSpec, CHARGES_URL, "reversed"); + } + } \ No newline at end of file diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/charges/ChargesHelper.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/charges/ChargesHelper.java index 702341d89..6489da21f 100755 --- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/charges/ChargesHelper.java +++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/charges/ChargesHelper.java @@ -23,6 +23,7 @@ public class ChargesHelper { private static final Integer CHARGE_APPLIES_TO_LOAN = 1; private static final Integer CHARGE_APPLIES_TO_SAVINGS = 2; + private static final Integer CHARGE_APPLIES_TO_CLIENT = 3; private static final Integer CHARGE_DISBURSEMENT_FEE = 1; private static final Integer CHARGE_SPECIFIED_DUE_DATE = 2; @@ -34,6 +35,8 @@ public class ChargesHelper { private static final Integer CHARGE_OVERDUE_INSTALLMENT_FEE = 9; private static final Integer CHARGE_OVERDRAFT_FEE = 10; private static final Integer WEEKLY_FEE = 11; + + private static final Integer CHARGE_CLIENT_SPECIFIED_DUE_DATE = 1; public static final Integer CHARGE_CALCULATION_TYPE_FLAT = 1; public static final Integer CHARGE_CALCULATION_TYPE_PERCENTAGE_AMOUNT = 2; @@ -247,6 +250,20 @@ public class ChargesHelper { map.put("name", Utils.randomNameGenerator("Charge_Loans_", 6)); return map; } + + public static HashMap populateDefaultsClientCharge() { + final HashMap map = new HashMap<>(); + map.put("active", ChargesHelper.active); + map.put("amount", ChargesHelper.amount); + map.put("chargeAppliesTo", ChargesHelper.CHARGE_APPLIES_TO_CLIENT); + map.put("chargeCalculationType", ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT); + map.put("chargeTimeType",ChargesHelper.CHARGE_SPECIFIED_DUE_DATE); + map.put("currencyCode", ChargesHelper.currencyCode); + map.put("locale", CommonConstants.locale); + map.put("monthDayFormat", ChargesHelper.monthDayFormat); + map.put("name", Utils.randomNameGenerator("Charge_client_", 8)); + return map; + } public static Integer createCharges(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, final String request) { @@ -367,5 +384,16 @@ public class ChargesHelper { System.out.println(json); return json; } + + public static String getChargeSpecifiedDueDateJSON() { + final HashMap map = populateDefaultsClientCharge(); + String chargesCreateJson = new Gson().toJson(map); + System.out.println("chargesCreateJson:"+chargesCreateJson); + return chargesCreateJson; + } + public static String applyCharge(RequestSpecification requestSpec,ResponseSpecification responseSpec, String chargeId,String json) { + return Utils.performServerPost(requestSpec, responseSpec, CHARGES_URL + "/" + chargeId + "?" + Utils.TENANT_IDENTIFIER, json,"status"); + + } } \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientChargesApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientChargesApiResource.java index c30e362fc..476e532e6 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientChargesApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientChargesApiResource.java @@ -32,6 +32,7 @@ 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.DefaultToApiJsonSerializer; +import org.mifosplatform.infrastructure.core.service.Page; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.portfolio.charge.data.ChargeData; import org.mifosplatform.portfolio.charge.service.ChargeReadPlatformService; @@ -74,24 +75,23 @@ public class ClientChargesApiResource { @GET @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) - public String retrieveAllClientCharges(@PathParam("clientId") final Long clientId, + public String retrieveAllClientCharges( + @PathParam("clientId") final Long clientId, @DefaultValue(ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_ALL) @QueryParam(ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS) final String chargeStatus, - @QueryParam("paid") final Boolean paid, @Context final UriInfo uriInfo) { + @QueryParam("paid") final Boolean paid, @Context final UriInfo uriInfo, @QueryParam("limit") final Integer limit, + @QueryParam("offset") final Integer offset) { this.context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_CHARGES_RESOURCE_NAME); - - if (!(is(chargeStatus, ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_ALL) - || is(chargeStatus, ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_ACTIVE) - || is(chargeStatus, - ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_INACTIVE))) { throw new UnrecognizedQueryParamException( - ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS, chargeStatus, - new Object[] { ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_ALL, - ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_ACTIVE, - ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_INACTIVE }); } - - final Collection clientCharges = this.clientChargeReadPlatformService.retrieveClientCharges(clientId, - chargeStatus, paid); - final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); + if (!(is(chargeStatus, ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_ALL) + || is(chargeStatus, ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_ACTIVE) || is(chargeStatus, + ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_INACTIVE))) { throw new UnrecognizedQueryParamException( + ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS, chargeStatus, new Object[] { + ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_ALL, + ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_ACTIVE, + ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_INACTIVE }); } + + final Page clientCharges = this.clientChargeReadPlatformService.retrieveClientCharges(clientId, chargeStatus, + paid, limit, offset); return this.toApiJsonSerializer.serialize(settings, clientCharges, ClientApiConstants.CLIENT_CHARGES_RESPONSE_DATA_PARAMETERS); } @@ -123,9 +123,7 @@ public class ClientChargesApiResource { @Context final UriInfo uriInfo) { this.context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_CHARGES_RESOURCE_NAME); - ClientChargeData clientCharge = this.clientChargeReadPlatformService.retrieveClientCharge(clientId, chargeId); - // extract associations final Set associationParameters = ApiParameterHelper.extractAssociationsForResponseIfProvided(uriInfo.getQueryParameters()); if (!associationParameters.isEmpty()) { @@ -136,13 +134,11 @@ public class ClientChargesApiResource { if (associationParameters.contains(ClientApiConstants.CLIENT_CHARGE_ASSOCIATIONS_TRANSACTIONS)) { Collection clientTransactionDatas = this.clientTransactionReadPlatformService .retrieveAllTransactions(clientId, chargeId); - if (CollectionUtils.isEmpty(clientTransactionDatas)) { - clientTransactionDatas = null; + if (!CollectionUtils.isEmpty(clientTransactionDatas)) { + clientCharge = ClientChargeData.addAssociations(clientCharge, clientTransactionDatas); } - clientCharge = ClientChargeData.addAssociations(clientCharge, clientTransactionDatas); } } - final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); return this.toApiJsonSerializer.serialize(settings, clientCharge, ClientApiConstants.CLIENT_CHARGES_RESPONSE_DATA_PARAMETERS); } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientTransactionsApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientTransactionsApiResource.java index 1382dfe59..38e512836 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientTransactionsApiResource.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/api/ClientTransactionsApiResource.java @@ -61,7 +61,6 @@ public class ClientTransactionsApiResource { @Produces({ MediaType.APPLICATION_JSON }) public String retrieveAllClientTransactions(@PathParam("clientId") final Long clientId, @Context final UriInfo uriInfo) { this.context.authenticatedUser().validateHasReadPermission(ClientApiConstants.CLIENT_CHARGES_RESOURCE_NAME); - final Collection clientTransactions = this.clientTransactionReadPlatformService .retrieveAllTransactions(clientId); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeReadPlatformService.java index 0a2acb80e..197661d47 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeReadPlatformService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeReadPlatformService.java @@ -5,13 +5,13 @@ */ package org.mifosplatform.portfolio.client.service; -import java.util.Collection; - +import org.mifosplatform.infrastructure.core.service.Page; import org.mifosplatform.portfolio.client.data.ClientChargeData; public interface ClientChargeReadPlatformService { - Collection retrieveClientCharges(Long clientId, String status, Boolean isPaid); + + Page retrieveClientCharges(Long clientId, String status, Boolean isPaid, Integer limit, Integer offset); ClientChargeData retrieveClientCharge(Long clientId, Long clientChargeId); diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeReadPlatformServiceImpl.java index c97c1dd06..106bd5cc1 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeReadPlatformServiceImpl.java @@ -13,6 +13,8 @@ import java.util.Collection; import org.joda.time.LocalDate; import org.mifosplatform.infrastructure.core.data.EnumOptionData; import org.mifosplatform.infrastructure.core.domain.JdbcSupport; +import org.mifosplatform.infrastructure.core.service.Page; +import org.mifosplatform.infrastructure.core.service.PaginationHelper; import org.mifosplatform.infrastructure.core.service.RoutingDataSource; import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; import org.mifosplatform.organisation.monetary.data.CurrencyData; @@ -30,13 +32,16 @@ import org.springframework.stereotype.Service; @Service public class ClientChargeReadPlatformServiceImpl implements ClientChargeReadPlatformService { + private final PaginationHelper paginationHelper = new PaginationHelper<>(); private final JdbcTemplate jdbcTemplate; private final PlatformSecurityContext context; + private final ClientChargeMapper clientChargeMapper; @Autowired public ClientChargeReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource) { this.context = context; this.jdbcTemplate = new JdbcTemplate(dataSource); + this.clientChargeMapper = new ClientChargeMapper(); } public static final class ClientChargeMapper implements RowMapper { @@ -97,10 +102,25 @@ public class ClientChargeReadPlatformServiceImpl implements ClientChargeReadPlat } @Override - public Collection retrieveClientCharges(Long clientId, String status, Boolean isPaid) { + public ClientChargeData retrieveClientCharge(Long clientId, Long clientChargeId) { + try { + this.context.authenticatedUser(); + + final ClientChargeMapper rm = new ClientChargeMapper(); + + final String sql = "select " + rm.schema() + " where cc.client_id=? and cc.id=? "; + + return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { clientId, clientChargeId }); + } catch (final EmptyResultDataAccessException e) { + throw new ClientChargeNotFoundException(clientChargeId, clientId); + } + } + + @Override + public Page retrieveClientCharges(Long clientId, String status, Boolean isPaid,Integer limit,Integer offset) { final ClientChargeMapper rm = new ClientChargeMapper(); final StringBuilder sqlBuilder = new StringBuilder(); - sqlBuilder.append("select ").append(rm.schema()).append(" where cc.client_id=? "); + sqlBuilder.append("select SQL_CALC_FOUND_ROWS ").append(rm.schema()).append(" where cc.client_id=? "); // filter for active charges if (status.equalsIgnoreCase(ClientApiConstants.CLIENT_CHARGE_QUERY_PARAM_STATUS_VALUE_ACTIVE)) { @@ -115,25 +135,10 @@ public class ClientChargeReadPlatformServiceImpl implements ClientChargeReadPlat } else if (isPaid != null && !isPaid) { sqlBuilder.append(" and (cc.is_paid_derived = 0 and cc.waived = 0) "); } - - sqlBuilder.append(" order by cc.charge_time_enum ASC, cc.charge_due_date ASC, cc.is_penalty ASC"); - - return this.jdbcTemplate.query(sqlBuilder.toString(), rm, new Object[] { clientId }); - } - - @Override - public ClientChargeData retrieveClientCharge(Long clientId, Long clientChargeId) { - try { - this.context.authenticatedUser(); - - final ClientChargeMapper rm = new ClientChargeMapper(); - - final String sql = "select " + rm.schema() + " where cc.client_id=? and cc.id=? "; - - return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { clientId, clientChargeId }); - } catch (final EmptyResultDataAccessException e) { - throw new ClientChargeNotFoundException(clientChargeId, clientId); - } + + sqlBuilder.append(" order by cc.charge_time_enum ASC, cc.charge_due_date ASC, cc.is_penalty ASC "+"limit "+limit+" offset "+offset); + final String sqlCountRows = "SELECT FOUND_ROWS()"; + return this.paginationHelper.fetchPage(this.jdbcTemplate,sqlCountRows, sqlBuilder.toString(),new Object[] { clientId },this.clientChargeMapper); } } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeWritePlatformServiceJpaRepositoryImpl.java index 45aee37ed..901bb2b09 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientChargeWritePlatformServiceJpaRepositoryImpl.java @@ -148,10 +148,10 @@ public class ClientChargeWritePlatformServiceJpaRepositoryImpl implements Client generateAccountingEntries(clientTransaction); return new CommandProcessingResultBuilder() // + .withTransactionId(clientTransaction.getId().toString())// .withEntityId(clientCharge.getId()) // .withOfficeId(clientCharge.getClient().getOffice().getId()) // - .withClientId(clientCharge.getClient().getId()) // - .build(); + .withClientId(clientCharge.getClient().getId()).build(); } @@ -181,7 +181,7 @@ public class ClientChargeWritePlatformServiceJpaRepositoryImpl implements Client final ClientChargePaidBy chargePaidBy = ClientChargePaidBy.instance(clientTransaction, clientCharge, waivedAmount.getAmount()); clientTransaction.getClientChargePaidByCollection().add(chargePaidBy); - return new CommandProcessingResultBuilder() // + return new CommandProcessingResultBuilder().withTransactionId(clientTransaction.getId().toString())// .withEntityId(clientCharge.getId()) // .withOfficeId(clientCharge.getClient().getOffice().getId()) // .withClientId(clientCharge.getClient().getId()) // @@ -209,8 +209,7 @@ public class ClientChargeWritePlatformServiceJpaRepositoryImpl implements Client /** * Validates transaction to ensure that
* charge is active
- * transaction date is valid (between client activation and todays date) - *
+ * transaction date is valid (between client activation and todays date)
* charge is not already paid or waived
* amount is not more than total due * diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientTransactionReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientTransactionReadPlatformServiceImpl.java index 1960ed6bf..a9940cb9c 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientTransactionReadPlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientTransactionReadPlatformServiceImpl.java @@ -29,7 +29,7 @@ import org.springframework.stereotype.Service; @Service public class ClientTransactionReadPlatformServiceImpl implements ClientTransactionReadPlatformService { - + private final JdbcTemplate jdbcTemplate; private final ClientTransactionMapper clientTransactionMapper; @@ -37,11 +37,11 @@ public class ClientTransactionReadPlatformServiceImpl implements ClientTransacti public ClientTransactionReadPlatformServiceImpl(final RoutingDataSource dataSource) { this.jdbcTemplate = new JdbcTemplate(dataSource); this.clientTransactionMapper = new ClientTransactionMapper(); - } private static final class ClientTransactionMapper implements RowMapper { - + + private final String schemaSql; public ClientTransactionMapper() { @@ -119,8 +119,8 @@ public class ClientTransactionReadPlatformServiceImpl implements ClientTransacti @Override public Collection retrieveAllTransactions(Long clientId) { - Long chargeId = null; - return retrieveAllTransactions(clientId, chargeId); + Long chargeId=null; + return retrieveAllTransactions(clientId,chargeId); } @Override