Skip to content

Commit f5a0146

Browse files
Merge pull request #479 from ShruthiRajaram/FINERACT-628-reports
FINERACT-628 self service user reports
2 parents cb83166 + 11b6296 commit f5a0146

File tree

8 files changed

+213
-29
lines changed

8 files changed

+213
-29
lines changed

api-docs/apiLive.htm

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3872,6 +3872,14 @@ <h2 class="flybar-button">Self Service</h2>
38723872
<td>self/clients/{clientId}/obligeedetails</td>
38733873
<td></td>
38743874
<td><a href="#self_obligee_list">Obligee list</a></td>
3875+
</td>
3876+
</td>
3877+
</tr>
3878+
<tr>
3879+
<td><a href="#self_service_user_reports">Run Report</a></td>
3880+
<td>self/runreports/{reportName}</td>
3881+
<td></td>
3882+
<td><a href="#self_service_user_reports">Run a Report</a></td>
38753883
<td></td>
38763884
<td></td>
38773885
</tr>
@@ -49299,6 +49307,7 @@ <h4>Delete an client's Image</h4>
4929949307
} </code>
4930049308
</div>
4930149309
</div>
49310+
4930249311
<a id="self_loanproducts" name="self_loanproducts" class="old-syle-anchor">&nbsp;</a>
4930349312
<div class="method-section">
4930449313
<div class="method-description">
@@ -50554,6 +50563,134 @@ <h2>Retrieve Survey records</h2>
5055450563
</div>
5055550564
</div>
5055650565

50566+
<a id="self_service_user_reports" name="self_service_user_reports" class="old-syle-anchor">&nbsp;</a>
50567+
<div class="method-section">
50568+
<div class="method-description">
50569+
<h4>Running a Report</h4>
50570+
<p>This resource allows you to run and receive output from pre-defined Apache Fineract reports. </p>
50571+
<p>
50572+
The default output is a JSON formatted "Generic Resultset". The Generic Resultset contains
50573+
Column Heading as well as Data information. However, you can
50574+
export to CSV format by simply adding "&exportCSV=true" to the end
50575+
of your URL.</p>
50576+
<p>If Pentaho reports have been pre-defined, they can also be
50577+
run through this resource. Pentaho reports can return HTML, PDF or
50578+
CSV formats.</p>
50579+
<p>The Apache Fineract reference application uses a
50580+
JQuery plugin called stretchyreporting which, itself, uses this
50581+
reports resource to provide a pretty flexible reporting User
50582+
Interface (UI).</p>
50583+
<h5>Arguments</h5>
50584+
<dl class="argument-list">
50585+
<dt>R_'parameter names' ...</dt>
50586+
<dd>
50587+
optional, <span>No defaults</span>
50588+
</dd>
50589+
<dd>The number and names of the parameters depend on the
50590+
specific report and how it has been configured. R_officeId is an
50591+
example parameter name.</dd>
50592+
<dd>Note: the prefix R_ stands for Reporting</dd>
50593+
<dt>genericResultSet</dt>
50594+
<dd>
50595+
<span>optional, defaults to true</span>
50596+
</dd>
50597+
<dd>If 'true' an optimised JSON format is returned suitable for tabular display of data.
50598+
<dd>If 'false' a simple JSON format is returned.
50599+
<dt>parameterType</dt>
50600+
<dd>
50601+
optional, <span>The only valid value is 'true'. If any
50602+
other value is provided the argument will be ignored</span>
50603+
</dd>
50604+
<dd>Determines whether the request looks in the list of
50605+
reports or the list of parameters for its data. Doesn't apply to
50606+
Pentaho reports.</dd>
50607+
<dt>exportCSV</dt>
50608+
<dd>
50609+
optional, <span>The only valid value is 'true'. If any
50610+
other value is provided the argument will be ignored</span>
50611+
</dd>
50612+
<dd>Output will be delivered as a CSV file instead of JSON.
50613+
Doesn't apply to Pentaho reports.</dd>
50614+
<dt>output-type</dt>
50615+
<dd>
50616+
optional, <span>Defaults to HTML.</span>
50617+
</dd>
50618+
<dd>Valid Values are HTML, XLS, XSLX, CSV and PDF for html, Excel, Excel 2007+,
50619+
CSV and PDF formats respectively.</dd>
50620+
<dd>Only applies to Pentaho reports.</dd>
50621+
<dt>locale</dt>
50622+
<dd>
50623+
optional
50624+
</dd>
50625+
<dd>Any valid locale Ex: en_US, en_IN, fr_FR etc</dd>
50626+
<dd>Only applies to Pentaho reports.</dd>
50627+
</dl>
50628+
<p>Example Requests:</p>
50629+
<div class=apiClick>self/runreports/Client%20Details?R_officeId=1</div>
50630+
<br>
50631+
<br>
50632+
<div class=apiClick>self/runreports/Client%20Details?R_officeId=1&exportCSV=true</div>
50633+
<br>
50634+
<br>
50635+
</div>
50636+
<div class="method-example">
50637+
<code class="method-declaration">
50638+
GET https://DomainName/api/v1/self/runreports/{reportName}
50639+
</code>
50640+
<code class="method-response">
50641+
{
50642+
"columnHeaders": [
50643+
{
50644+
"columnName": "Office/Branch",
50645+
"columnType": "VARCHAR",
50646+
"isColumnNullable": false,
50647+
"isColumnPrimaryKey": false,
50648+
"columnValues": []
50649+
},
50650+
{
50651+
"columnName": "Client Account No.",
50652+
"columnType": "VARCHAR",
50653+
"isColumnNullable": false,
50654+
"isColumnPrimaryKey": false,
50655+
"columnValues": []
50656+
},
50657+
{
50658+
"columnName": "Name",
50659+
"columnType": "VARCHAR",
50660+
"isColumnNullable": false,
50661+
"isColumnPrimaryKey": false,
50662+
"columnValues": []
50663+
},
50664+
{
50665+
"columnName": "Joined",
50666+
"columnType": "DATE",
50667+
"isColumnNullable": false,
50668+
"isColumnPrimaryKey": false,
50669+
"columnValues": []
50670+
},
50671+
{
50672+
"columnName": "External Id",
50673+
"columnType": "VARCHAR",
50674+
"isColumnNullable": false,
50675+
"isColumnPrimaryKey": false,
50676+
"columnValues": []
50677+
}
50678+
],
50679+
"data": [
50680+
{
50681+
"row": [
50682+
"Head Office",
50683+
"000000001",
50684+
"John Doe",
50685+
"2017-03-04",
50686+
"786YYH7"
50687+
]
50688+
}
50689+
]
50690+
}
50691+
</code>
50692+
</div>
50693+
</div>
5055750694
<!-- end of Customer Self Service APIs-->
5055850695
</div>
5055950696
<!-- main-content-wrapper -->

fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/api/RunreportsApiResource.java

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,12 @@
2424
import java.util.Set;
2525

2626
import javax.ws.rs.Consumes;
27+
import javax.ws.rs.DefaultValue;
2728
import javax.ws.rs.GET;
2829
import javax.ws.rs.Path;
2930
import javax.ws.rs.PathParam;
3031
import javax.ws.rs.Produces;
32+
import javax.ws.rs.QueryParam;
3133
import javax.ws.rs.core.Context;
3234
import javax.ws.rs.core.MediaType;
3335
import javax.ws.rs.core.MultivaluedMap;
@@ -82,9 +84,11 @@ public RunreportsApiResource(final PlatformSecurityContext context, final ReadRe
8284
@ApiOperation(value = "Running a Report", notes = "This resource allows you to run and receive output from pre-defined Apache Fineract reports.\n" + "\n" + "Reports can also be used to provide data for searching and workflow functionality.\n" + "\n" + "The default output is a JSON formatted \"Generic Resultset\". The Generic Resultset contains Column Heading as well as Data information. However, you can export to CSV format by simply adding \"&exportCSV=true\" to the end of your URL.\n" + "\n" + "If Pentaho reports have been pre-defined, they can also be run through this resource. Pentaho reports can return HTML, PDF or CSV formats.\n" + "\n" + "The Apache Fineract reference application uses a JQuery plugin called stretchy reporting which, itself, uses this reports resource to provide a pretty flexible reporting User Interface (UI).\n\n" + "\n" +
8385
"\n" + "Example Requests:\n" + "\n" + "runreports/Client%20Listing?R_officeId=1\n" + "\n" + "\n" + "runreports/Client%20Listing?R_officeId=1&exportCSV=true\n" + "\n" + "\n" + "runreports/OfficeIdSelectOne?R_officeId=1&parameterType=true\n" + "\n" + "\n" + "runreports/OfficeIdSelectOne?R_officeId=1&parameterType=true&exportCSV=true\n" + "\n" + "\n" + "runreports/Expected%20Payments%20By%20Date%20-%20Formatted?R_endDate=2013-04-30&R_loanOfficerId=-1&R_officeId=1&R_startDate=2013-04-16&output-type=HTML&R_officeId=1\n" + "\n" + "\n" + "runreports/Expected%20Payments%20By%20Date%20-%20Formatted?R_endDate=2013-04-30&R_loanOfficerId=-1&R_officeId=1&R_startDate=2013-04-16&output-type=XLS&R_officeId=1\n" + "\n" + "\n" + "runreports/Expected%20Payments%20By%20Date%20-%20Formatted?R_endDate=2013-04-30&R_loanOfficerId=-1&R_officeId=1&R_startDate=2013-04-16&output-type=CSV&R_officeId=1\n" + "\n" + "\n" + "runreports/Expected%20Payments%20By%20Date%20-%20Formatted?R_endDate=2013-04-30&R_loanOfficerId=-1&R_officeId=1&R_startDate=2013-04-16&output-type=PDF&R_officeId=1")
8486
@ApiResponses({@ApiResponse(code = 200, message = "", response = RunreportsApiResourceSwagger.GetReportNameResponse.class)})
85-
public Response runReport(@PathParam("reportName") @ApiParam(value = "reportName") final String reportName, @Context final UriInfo uriInfo) {
87+
public Response runReport(@PathParam("reportName") @ApiParam(value = "reportName") final String reportName,
88+
@Context final UriInfo uriInfo,
89+
@DefaultValue("false") @QueryParam("isSelfServiceUserReport") @ApiParam(value = "isSelfServiceUserReport") final boolean isSelfServiceUserReport) {
8690

87-
final MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters();
91+
final MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters();
8892

8993
final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
9094
final boolean exportCsv = ApiParameterHelper.exportCsv(uriInfo.getQueryParameters());
@@ -96,7 +100,7 @@ public Response runReport(@PathParam("reportName") @ApiParam(value = "reportName
96100
String parameterTypeValue = null;
97101
if (!parameterType) {
98102
parameterTypeValue = "report";
99-
String reportType = this.readExtraDataAndReportingService.getReportType(reportName);
103+
String reportType = this.readExtraDataAndReportingService.getReportType(reportName, isSelfServiceUserReport);
100104
ReportingProcessService reportingProcessService = this.reportingProcessServiceProvider.findReportingProcessService(reportType);
101105
if (reportingProcessService != null) { return reportingProcessService.processRequest(reportName, queryParams); }
102106
} else {
@@ -108,7 +112,7 @@ public Response runReport(@PathParam("reportName") @ApiParam(value = "reportName
108112
if (exportPdf) {
109113
final Map<String, String> reportParams = getReportParams(queryParams);
110114
final String pdfFileName = this.readExtraDataAndReportingService
111-
.retrieveReportPDF(reportName, parameterTypeValue, reportParams);
115+
.retrieveReportPDF(reportName, parameterTypeValue, reportParams, isSelfServiceUserReport);
112116

113117
final File file = new File(pdfFileName);
114118

@@ -124,7 +128,7 @@ public Response runReport(@PathParam("reportName") @ApiParam(value = "reportName
124128
final Map<String, String> reportParams = getReportParams(queryParams);
125129

126130
final GenericResultsetData result = this.readExtraDataAndReportingService.retrieveGenericResultset(reportName,
127-
parameterTypeValue, reportParams);
131+
parameterTypeValue, reportParams, isSelfServiceUserReport);
128132

129133
String json = "";
130134
final boolean genericResultSetIsPassed = ApiParameterHelper.genericResultSetPassed(uriInfo.getQueryParameters());
@@ -145,7 +149,7 @@ public Response runReport(@PathParam("reportName") @ApiParam(value = "reportName
145149
// CSV Export
146150
final Map<String, String> reportParams = getReportParams(queryParams);
147151
final StreamingOutput result = this.readExtraDataAndReportingService
148-
.retrieveReportCSV(reportName, parameterTypeValue, reportParams);
152+
.retrieveReportCSV(reportName, parameterTypeValue, reportParams, isSelfServiceUserReport);
149153

150154
return Response.ok().entity(result).type("text/csv")
151155
.header("Content-Disposition", "attachment;filename=" + reportName.replaceAll(" ", "") + ".csv").build();

fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/domain/Report.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ public final class Report extends AbstractPersistableCustom<Long> {
7575

7676
@OneToMany(cascade = CascadeType.ALL, mappedBy = "report", orphanRemoval = true, fetch=FetchType.EAGER)
7777
private Set<ReportParameterUsage> reportParameterUsages = new HashSet<>();
78+
79+
@Column(name = "self_service_user_report")
80+
private boolean isSelfServiceUserReport;
7881

7982
public static Report fromJson(final JsonCommand command, final Collection<String> reportTypes) {
8083

@@ -278,6 +281,7 @@ private boolean changeInReportParameters(final Set<ReportParameterUsage> newRepo
278281
}
279282

280283
public Set<ReportParameterUsage> getReportParameterUsages() {
281-
return this.reportParameterUsages;
282-
}
284+
return this.reportParameterUsages;
285+
}
286+
283287
}

fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadReportingService.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,13 @@
3232

3333
public interface ReadReportingService {
3434

35-
StreamingOutput retrieveReportCSV(String name, String type, Map<String, String> extractedQueryParams);
35+
StreamingOutput retrieveReportCSV(String name, String type, Map<String, String> extractedQueryParams, boolean isSelfServiceUserReport);
3636

37-
GenericResultsetData retrieveGenericResultset(String name, String type, Map<String, String> extractedQueryParams);
37+
GenericResultsetData retrieveGenericResultset(String name, String type, Map<String, String> extractedQueryParams, boolean isSelfServiceUserReport);
3838

39-
String retrieveReportPDF(String name, String type, Map<String, String> extractedQueryParams);
39+
String retrieveReportPDF(String name, String type, Map<String, String> extractedQueryParams, boolean isSelfServiceUserReport);
4040

41-
String getReportType(String reportName);
41+
String getReportType(String reportName, boolean isSelfServiceUserReport);
4242

4343
Collection<ReportData> retrieveReportList();
4444

fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/ReadReportingServiceImpl.java

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -90,15 +90,16 @@ public ReadReportingServiceImpl(final PlatformSecurityContext context, final Rou
9090
}
9191

9292
@Override
93-
public StreamingOutput retrieveReportCSV(final String name, final String type, final Map<String, String> queryParams) {
93+
public StreamingOutput retrieveReportCSV(final String name, final String type,
94+
final Map<String, String> queryParams, final boolean isSelfServiceUserReport) {
9495

95-
return new StreamingOutput() {
96+
return new StreamingOutput() {
9697

9798
@Override
9899
public void write(final OutputStream out) {
99100
try {
100101

101-
final GenericResultsetData result = retrieveGenericResultset(name, type, queryParams);
102+
final GenericResultsetData result = retrieveGenericResultset(name, type, queryParams, isSelfServiceUserReport);
102103
final StringBuffer sb = generateCsvFileBuffer(result);
103104

104105
final InputStream in = new ByteArrayInputStream(sb.toString().getBytes("UTF-8"));
@@ -171,12 +172,13 @@ private StringBuffer generateCsvFileBuffer(final GenericResultsetData result) {
171172
}
172173

173174
@Override
174-
public GenericResultsetData retrieveGenericResultset(final String name, final String type, final Map<String, String> queryParams) {
175+
public GenericResultsetData retrieveGenericResultset(final String name, final String type,
176+
final Map<String, String> queryParams, final boolean isSelfServiceUserReport) {
175177

176178
final long startTime = System.currentTimeMillis();
177179
logger.info("STARTING REPORT: " + name + " Type: " + type);
178180

179-
final String sql = getSQLtoRun(name, type, queryParams);
181+
final String sql = getSQLtoRun(name, type, queryParams, isSelfServiceUserReport);
180182

181183
final GenericResultsetData result = this.genericDataService.fillGenericResultSet(sql);
182184

@@ -185,7 +187,8 @@ public GenericResultsetData retrieveGenericResultset(final String name, final St
185187
return result;
186188
}
187189

188-
private String getSQLtoRun(final String name, final String type, final Map<String, String> queryParams) {
190+
private String getSQLtoRun(final String name, final String type, final Map<String, String> queryParams,
191+
final boolean isSelfServiceUserReport) {
189192

190193
String sql = getSql(name, type);
191194

@@ -203,40 +206,45 @@ private String getSQLtoRun(final String name, final String type, final Map<Strin
203206
// (typically used to return report lists containing only reports
204207
// permitted to be run by the user
205208
sql = this.genericDataService.replace(sql, "${currentUserId}", currentUser.getId().toString());
209+
210+
sql = this.genericDataService.replace(sql, "${isSelfServiceUser}",
211+
Integer.toString(isSelfServiceUserReport ? 1 : 0));
206212

207-
sql = this.genericDataService.wrapSQL(sql);
213+
sql = this.genericDataService.wrapSQL(sql);
208214

209-
return sql;
215+
return sql;
210216

211-
}
217+
}
212218

213219
private String getSql(final String name, final String type) {
214220

215-
final String inputSql = "select " + type + "_sql as the_sql from stretchy_" + type + " where " + type + "_name = '" + name + "'";
221+
final String inputSql = "select " + type + "_sql as the_sql from stretchy_" + type + " where " + type + "_name = '" + name + "'" ;
216222
final String inputSqlWrapped = this.genericDataService.wrapSQL(inputSql);
217223

224+
// the return statement contains the exact sql required
218225
final SqlRowSet rs = this.jdbcTemplate.queryForRowSet(inputSqlWrapped);
219226

220227
if (rs.next() && rs.getString("the_sql") != null) { return rs.getString("the_sql"); }
221228
throw new ReportNotFoundException(inputSql);
222229
}
223230

224231
@Override
225-
public String getReportType(final String reportName) {
232+
public String getReportType(final String reportName, final boolean isSelfServiceUserReport) {
226233

227-
final String sql = "SELECT ifnull(report_type,'') as report_type FROM `stretchy_report` where report_name = '" + reportName + "'";
234+
final String sql = "SELECT ifnull(report_type,'') as report_type FROM `stretchy_report` where report_name = '" + reportName + "' and self_service_user_report = ?";
228235
this.columnValidator.validateSqlInjection(sql, reportName);
229236

230237
final String sqlWrapped = this.genericDataService.wrapSQL(sql);
231238

232-
final SqlRowSet rs = this.jdbcTemplate.queryForRowSet(sqlWrapped);
239+
final SqlRowSet rs = this.jdbcTemplate.queryForRowSet(sqlWrapped, new Object [] {isSelfServiceUserReport});
233240

234241
if (rs.next()) { return rs.getString("report_type"); }
235242
throw new ReportNotFoundException(sql);
236243
}
237244

238245
@Override
239-
public String retrieveReportPDF(final String reportName, final String type, final Map<String, String> queryParams) {
246+
public String retrieveReportPDF(final String reportName, final String type, final Map<String, String> queryParams,
247+
final boolean isSelfServiceUserReport) {
240248

241249
final String fileLocation = FileSystemContentRepository.FINERACT_BASE_DIR + File.separator + "";
242250
if (!new File(fileLocation).isDirectory()) {
@@ -246,7 +254,7 @@ public String retrieveReportPDF(final String reportName, final String type, fina
246254
final String genaratePdf = fileLocation + File.separator + reportName + ".pdf";
247255

248256
try {
249-
final GenericResultsetData result = retrieveGenericResultset(reportName, type, queryParams);
257+
final GenericResultsetData result = retrieveGenericResultset(reportName, type, queryParams, isSelfServiceUserReport);
250258

251259
final List<ResultsetColumnHeaderData> columnHeaders = result.getColumnHeaders();
252260
final List<ResultsetRowData> data = result.getData();

fineract-provider/src/main/java/org/apache/fineract/infrastructure/reportmailingjob/service/ReportMailingJobWritePlatformServiceImpl.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,8 @@ private StringBuilder generateReportOutputStream(final ReportMailingJob reportMa
422422
final MultivaluedMap<String, String> reportParams, final String reportName, final StringBuilder errorLog) {
423423

424424
try {
425-
final String reportType = this.readReportingService.getReportType(reportName);
425+
final boolean isSelfServiceUserReport = false;
426+
final String reportType = this.readReportingService.getReportType(reportName, isSelfServiceUserReport);
426427
final ReportingProcessService reportingProcessService = this.reportingProcessServiceProvider.findReportingProcessService(reportType);
427428

428429
if (reportingProcessService != null) {

fineract-provider/src/main/java/org/apache/fineract/portfolio/self/runreport/SelfRunReportApiResource.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ public SelfRunReportApiResource(final PlatformSecurityContext context, final Run
5454
@Produces({ MediaType.APPLICATION_JSON, "text/csv", "application/vnd.ms-excel", "application/pdf", "text/html" })
5555
public Response runReport(@PathParam("reportName") final String reportName, @Context final UriInfo uriInfo) {
5656
this.context.authenticatedUser();
57-
return this.runreportsApiResource.runReport(reportName, uriInfo);
57+
final boolean isSelfServiceUserReport = true;
58+
return this.runreportsApiResource.runReport(reportName, uriInfo, isSelfServiceUserReport);
5859
}
5960

6061
}

0 commit comments

Comments
 (0)