Review comments addressed

This commit is contained in:
VenuShyam
2015-09-03 19:51:07 +05:30
parent 5a990af553
commit 670b6eef19
10 changed files with 1153 additions and 58 deletions
+820
View File
@@ -381,6 +381,64 @@
<td></td>
<td></td>
</tr>
<tr>
<td><a href="#client_charge">Client Charge</a></td>
<td>clients/{clientId}/charges</td>
<td><a href="#add_clientCharge">Add Client Charge</a></td>
<td><a href="#list_clientCharges">List Client Charges</a></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>clients/{clientId}</td>
<td></td>
<td></td>
<td></td>
<td><a href="#delete_clientCharge">Delete Client Charge</a></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>clients/{clientId}/charges/{chargeid}?command=pay</td>
<td><a href="#pay_clientCharge">Pay Client Charge</a></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>clients/{clientId}/charges/{chargeid}?command=waive</td>
<td><a href="#waive_clientCharge">Waive Client Charge</a></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td ><a href="#client_transactions">Client Ttransactions</td>
<td>clients/{clientId}/transactions/{transactionId}?command=undo</td>
<td><a href="#revert_clientCharge">Revert Client Charge Transaction</a></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td ></td>
<td>clients/{clientId}/transactions</td>
<td><a href="#list_clientTransactions">List Client Charge Transactions</a></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</table>
</div>
</div>
@@ -35558,7 +35616,769 @@ Request Body:
</code>
</div>
</div>
<!----------------Client charge API starts ------------>
<a id="client_charge" name="client_charge" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h3>Client Charge</h3>
<p>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.
</p>
<table class=matrixHeading>
<tr class="matrixHeadingBG">
<td><div class="mifosXHeading2">Field Descriptions</div></td>
</tr>
<tr class=alt>
<td>chargeId</td>
</tr>
<tr>
<td class=fielddesc>This ia an unique Id associate with client charge.
</td>
</tr>
<tr class=alt>
<td>name</td>
</tr>
<tr>
<td class=fielddesc>Name given to the client charge.</td>
</tr>
<tr class=alt>
<td>active</td>
</tr>
<tr>
<td class=fielddesc>Indicates whether this charge is to be created as active</b>. If active=true, then <b>activationDate</b> must be provided. If active=false, then the charge is created as <b>pending</b>.
</td>
</tr>
<tr class=alt>
<td>amountPaid</td>
</tr>
<tr>
<td class=fielddesc>amount paid as client charge</b>.
</td>
</tr>
<tr class=alt>
<td>amountWaived</td>
</tr>
<tr>
<td class=fielddesc>amount waive from client charge</td>
</tr>
<tr class=alt>
<td>amountOutstanding</td>
</tr>
<tr>
<td class=fielddesc>The left over amount to pay .</td>
</tr>
<tr class=alt>
<td>dueDate</td>
</tr>
<tr>
<td class=fielddesc>it specifies the due date</td>
</tr>
</table>
</div>
</div>
<a id="client_transaction" name="client_transaction" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h3>Client Transaction</h3>
<p>Client Charge transactions are get created when a client pays/waives off client charge.this client charge transaction shows
<br>the unit of amount paid as client charge.
</p>
<table class=matrixHeading>
<tr class="matrixHeadingBG">
<td><div class="mifosXHeading2">Field Descriptions</div></td>
</tr>
<tr class=alt>
<td>transactionId</td>
</tr>
<tr>
<td class=fielddesc>This ia an unique Id associate with client charge Transaction.
</td>
</tr>
<tr class=alt>
<td>clientId</td>
</tr>
<tr>
<td class=fielddesc>clientId on which client transaction got created</td>
</tr>
<tr class=alt>
<td>isReverse</td>
</tr>
<tr>
<td class=fielddesc>Indicates whether this client charge transaction is reversed or not.
</td>
</tr>
<tr class=alt>
<td>amountPaid</td>
</tr>
<tr>
<td class=fielddesc>amount paid as client charge</b>.
</td>
</tr>
<tr class=alt>
<td>currency code</td>
</tr>
<tr>
<td class=fielddesc>currency type</td>
</tr>
<tr class=alt>
<td>transaction date</td>
</tr>
<tr>
<td class=fielddesc>date on which transaction happened</td>
</tr>
</table>
</div>
</div>
<a id="list_clientTransactions" name="list_clientTransactions" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>List client Transactions</h4>
<p>The <i>list</i> capability of client charge transaction can support <b>pagination</b> and <b>sorting</b>.</p>
<h5>Mandatory Arguments</h5>
<dl class="argument-list">
<dt>offset</dt>
<dd>
Integer <span>Mandatory</span>, defaults to 0
</dd>
<dd>Indicates the result from which pagination starts</dd>
<dt>limit</dt>
<dd>
Integer <span>Mandatory</span>, defaults to 200
</dd>
<dd>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</dd>
</dl>
</dl>
<p>Example Requests:</p>
<div class=apiClick>clients/189/transactions</div>
<div class=apiClick>clients/189/transactions?offset=10&limit=50</div>
</div>
<div class="method-example">
<code class="method-declaration">
GET https://DomainName/api/v1/clients/{clientId}/transactions?limit=5&offset=0
</code>
<code class="method-request">
GET clients/226/transactions?limit=5&offset=0
Content-Type: application/json
Request Body:
{
chargeId="226"
}
</code>
<code class="method-response">
{
"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
}
]
}
</code>
</div>
</div>
<a id="add_clientCharge" name="add_clientCharge" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Add Client Charge</h4>
<p>
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.
</p>
<table class=matrixHeading>
<tr class="matrixHeadingBG">
<td><div class="mifosXHeading2">Mandatory Fields</div></td>
</tr>
<tr class=alt>
<td>clientId,chargeId and activationDate </td>
</tr>
</table>
<br />
<table class=matrixHeading>
<tr class="matrixHeadingBG">
<td><div class="mifosXHeading2">Optional Fields</div></td>
</tr>
<tr class=alt>
<td>externalId, accountNo,genderId, clientTypeId, clientClassificationId</td>
</tr>
</table>
</div>
<div class="method-example">
<code class="method-declaration">
POST https://DomainName/api/v1/clients/{clientId}/charges
</code>
<code class="method-request">
POST clients/226/charges
Content-Type: application/json
Request Body:
{
"amount"="100"
chargeId="226"
dateFormat="dd MMMM yyyy"
dueDate="01 September 2015"
locale="en"
}
</code>
<code class="method-response">
{
"officeId": 1,
"clientId": 189,
"resourceId":164
}
</code>
</div>
</div>
<a id="list_clientCharges" name="list_clientCharges" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>List Client Charges</h4>
<p>The <i>list</i> capability of client charges can support <b>pagination</b> and <b>sorting</b>.</p>
<h5>Mandatory Arguments</h5>
<dl class="argument-list">
<dt>offset</dt>
<dd>
Integer <span>Mandatory</span>, defaults to 0
</dd>
<dd>Indicates the result from which pagination starts</dd>
<dt>limit</dt>
<dd>
Integer <span>Mandatory</span>, defaults to 200
</dd>
<dd>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</dd>
</dl>
</dl>
<p>Example Requests:</p>
<div class=apiClick>clients/189/charges</div>
<div class=apiClick>clients/189/charges?offset=0&limit=5</div>
</div>
<div class="method-example">
<code class="method-declaration">
GET https://DomainName/api/v1/clients/{clientId}/charges?limit=5&offset=0
</code>
<code class="method-request">
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
}
</code>
<code class="method-response">
{
"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
}
</code>
</div>
</div>
<a id="delete_clientCharge" name="delete_clientCharge" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Delete Client Charge</h4>
<p>
<br>A client can be associated with more than one client charge and this API enables to delete a charge from client.
</p>
<table class=matrixHeading>
<tr class="matrixHeadingBG">
<td><div class="mifosXHeading2">Mandatory Fields</div></td>
</tr>
<tr class=alt>
<td>chargeId
</td>
</tr>
</table>
</div>
<div class="method-example">
<code class="method-declaration">
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
</code>
<code class="method-response">
{
"officeId": 1,
"clientId": 189,
"resourceId":164
}
</code>
</div>
</div>
<a id="pay_clientCharge" name="pay_clientCharge" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Pay Client Charge</h4>
<p>
<br>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.
</p>
<table class=matrixHeading>
<tr class="matrixHeadingBG">
<td><div class="mifosXHeading2">Mandatory Fields</div></td>
</tr>
<tr >
<td>
<br>transactionDate and amount<br>
</td>
</tr>
</table>
<br />
</div>
<div class="method-example">
<code class="method-declaration">
POST https://localhost:8443/mifosng-provider/api/v1/clients/189/charges/157?command=paycharge
</code>
<code class="method-request">
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"
}
</code>
<code class="method-response">
{
"officeId":1,
"clientId":189,
"resourceId":157,
"transactionId":"221"
}
</code>
</div>
</div>
<a id="waive_clientCharge" name="waive_clientCharge" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Waive Client Charge</h4>
<p>
<br>This API provieds the facility of waiving off the client charge of a client.
</p>
<table class=matrixHeading>
<tr class="matrixHeadingBG">
<td><div class="mifosXHeading2">Mandatory Fields</div></td>
</tr>
<tr class=alt>
<td>clientId and chargeId
</td>
</tr>
</table>
<br />
</div>
<div class="method-example">
<code class="method-declaration">
POST https://localhost:8443/mifosng-provider/api/v1/clients/189/charges/157?command=waive
</code>
<code class="method-request">
POST clients/189/charges/157?command=waive
Content-Type: application/json
Request Body:
{
"clientId"="189"
"resourceType"="164"
}
</code>
<code class="method-response">
{
"clientId":"189",
"resourceType":"164"
}
</code>
</div>
</div>
<a id="revert_clientCharge" name="revert_clientCharge" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Revert Client Charge Transaction</h4>
<p>
<br>This API exists to revert the client transactions which have got created after paying the client charge
<br>or after waiving off the client charge.
</p>
<table class=matrixHeading>
<tr class="matrixHeadingBG">
<td><div class="mifosXHeading2">Mandatory Fields</div></td>
</tr>
<tr class=alt>
<td>clientId ,chargeId and transactionId
</td>
</tr>
</table>
<br />
</div>
<div class="method-example">
<code class="method-declaration">
POST https://localhost:8443/mifosng-provider/api/v1/clients/189/charges/157?command=undo
</code>
<code class="method-request">
POST clients/189/transactions/222
Content-Type: application/json
Request Body:
{
clientId="189"
transactionId=222
}
</code>
<code class="method-response">
{
"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
}
]
}
</code>
</div>
</div>
<a id="resources_deletetemplate" name="resources_deletetemplate"
class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
@@ -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);
}
}
@@ -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<String, String> 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<String, String> 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<String, String> 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<String, Object> 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");
}
}
@@ -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<String, Object> populateDefaultsClientCharge() {
final HashMap<String, Object> 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<String, Object> 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");
}
}
@@ -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<ClientChargeData> 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<ClientChargeData> 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<String> associationParameters = ApiParameterHelper.extractAssociationsForResponseIfProvided(uriInfo.getQueryParameters());
if (!associationParameters.isEmpty()) {
@@ -136,13 +134,11 @@ public class ClientChargesApiResource {
if (associationParameters.contains(ClientApiConstants.CLIENT_CHARGE_ASSOCIATIONS_TRANSACTIONS)) {
Collection<ClientTransactionData> 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);
}
@@ -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<ClientTransactionData> clientTransactions = this.clientTransactionReadPlatformService
.retrieveAllTransactions(clientId);
@@ -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<ClientChargeData> retrieveClientCharges(Long clientId, String status, Boolean isPaid);
Page<ClientChargeData> retrieveClientCharges(Long clientId, String status, Boolean isPaid, Integer limit, Integer offset);
ClientChargeData retrieveClientCharge(Long clientId, Long clientChargeId);
@@ -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<ClientChargeData> 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<ClientChargeData> {
@@ -97,10 +102,25 @@ public class ClientChargeReadPlatformServiceImpl implements ClientChargeReadPlat
}
@Override
public Collection<ClientChargeData> 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<ClientChargeData> 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);
}
}
@@ -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 <br>
* charge is active <br>
* transaction date is valid (between client activation and todays date)
* <br>
* transaction date is valid (between client activation and todays date) <br>
* charge is not already paid or waived <br>
* amount is not more than total due
*
@@ -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<ClientTransactionData> {
private final String schemaSql;
public ClientTransactionMapper() {
@@ -119,8 +119,8 @@ public class ClientTransactionReadPlatformServiceImpl implements ClientTransacti
@Override
public Collection<ClientTransactionData> retrieveAllTransactions(Long clientId) {
Long chargeId = null;
return retrieveAllTransactions(clientId, chargeId);
Long chargeId=null;
return retrieveAllTransactions(clientId,chargeId);
}
@Override