Skip to content

Commit

Permalink
Merge pull request #479 from ShruthiRajaram/FINERACT-628-reports
Browse files Browse the repository at this point in the history
FINERACT-628 self service user reports
  • Loading branch information
ShruthiRajaram committed Nov 27, 2018
2 parents cb83166 + 11b6296 commit f5a0146
Show file tree
Hide file tree
Showing 8 changed files with 213 additions and 29 deletions.
137 changes: 137 additions & 0 deletions api-docs/apiLive.htm
Original file line number Diff line number Diff line change
Expand Up @@ -3872,6 +3872,14 @@ <h2 class="flybar-button">Self Service</h2>
<td>self/clients/{clientId}/obligeedetails</td>
<td></td>
<td><a href="#self_obligee_list">Obligee list</a></td>
</td>
</td>
</tr>
<tr>
<td><a href="#self_service_user_reports">Run Report</a></td>
<td>self/runreports/{reportName}</td>
<td></td>
<td><a href="#self_service_user_reports">Run a Report</a></td>
<td></td>
<td></td>
</tr>
Expand Down Expand Up @@ -49299,6 +49307,7 @@ <h4>Delete an client's Image</h4>
} </code>
</div>
</div>

<a id="self_loanproducts" name="self_loanproducts" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
Expand Down Expand Up @@ -50554,6 +50563,134 @@ <h2>Retrieve Survey records</h2>
</div>
</div>

<a id="self_service_user_reports" name="self_service_user_reports" class="old-syle-anchor">&nbsp;</a>
<div class="method-section">
<div class="method-description">
<h4>Running a Report</h4>
<p>This resource allows you to run and receive output from pre-defined Apache Fineract reports. </p>
<p>
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.</p>
<p>If Pentaho reports have been pre-defined, they can also be
run through this resource. Pentaho reports can return HTML, PDF or
CSV formats.</p>
<p>The Apache Fineract reference application uses a
JQuery plugin called stretchyreporting which, itself, uses this
reports resource to provide a pretty flexible reporting User
Interface (UI).</p>
<h5>Arguments</h5>
<dl class="argument-list">
<dt>R_'parameter names' ...</dt>
<dd>
optional, <span>No defaults</span>
</dd>
<dd>The number and names of the parameters depend on the
specific report and how it has been configured. R_officeId is an
example parameter name.</dd>
<dd>Note: the prefix R_ stands for Reporting</dd>
<dt>genericResultSet</dt>
<dd>
<span>optional, defaults to true</span>
</dd>
<dd>If 'true' an optimised JSON format is returned suitable for tabular display of data.
<dd>If 'false' a simple JSON format is returned.
<dt>parameterType</dt>
<dd>
optional, <span>The only valid value is 'true'. If any
other value is provided the argument will be ignored</span>
</dd>
<dd>Determines whether the request looks in the list of
reports or the list of parameters for its data. Doesn't apply to
Pentaho reports.</dd>
<dt>exportCSV</dt>
<dd>
optional, <span>The only valid value is 'true'. If any
other value is provided the argument will be ignored</span>
</dd>
<dd>Output will be delivered as a CSV file instead of JSON.
Doesn't apply to Pentaho reports.</dd>
<dt>output-type</dt>
<dd>
optional, <span>Defaults to HTML.</span>
</dd>
<dd>Valid Values are HTML, XLS, XSLX, CSV and PDF for html, Excel, Excel 2007+,
CSV and PDF formats respectively.</dd>
<dd>Only applies to Pentaho reports.</dd>
<dt>locale</dt>
<dd>
optional
</dd>
<dd>Any valid locale Ex: en_US, en_IN, fr_FR etc</dd>
<dd>Only applies to Pentaho reports.</dd>
</dl>
<p>Example Requests:</p>
<div class=apiClick>self/runreports/Client%20Details?R_officeId=1</div>
<br>
<br>
<div class=apiClick>self/runreports/Client%20Details?R_officeId=1&exportCSV=true</div>
<br>
<br>
</div>
<div class="method-example">
<code class="method-declaration">
GET https://DomainName/api/v1/self/runreports/{reportName}
</code>
<code class="method-response">
{
"columnHeaders": [
{
"columnName": "Office/Branch",
"columnType": "VARCHAR",
"isColumnNullable": false,
"isColumnPrimaryKey": false,
"columnValues": []
},
{
"columnName": "Client Account No.",
"columnType": "VARCHAR",
"isColumnNullable": false,
"isColumnPrimaryKey": false,
"columnValues": []
},
{
"columnName": "Name",
"columnType": "VARCHAR",
"isColumnNullable": false,
"isColumnPrimaryKey": false,
"columnValues": []
},
{
"columnName": "Joined",
"columnType": "DATE",
"isColumnNullable": false,
"isColumnPrimaryKey": false,
"columnValues": []
},
{
"columnName": "External Id",
"columnType": "VARCHAR",
"isColumnNullable": false,
"isColumnPrimaryKey": false,
"columnValues": []
}
],
"data": [
{
"row": [
"Head Office",
"000000001",
"John Doe",
"2017-03-04",
"786YYH7"
]
}
]
}
</code>
</div>
</div>
<!-- end of Customer Self Service APIs-->
</div>
<!-- main-content-wrapper -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@
import java.util.Set;

import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
Expand Down Expand Up @@ -82,9 +84,11 @@ public RunreportsApiResource(final PlatformSecurityContext context, final ReadRe
@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" +
"\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")
@ApiResponses({@ApiResponse(code = 200, message = "", response = RunreportsApiResourceSwagger.GetReportNameResponse.class)})
public Response runReport(@PathParam("reportName") @ApiParam(value = "reportName") final String reportName, @Context final UriInfo uriInfo) {
public Response runReport(@PathParam("reportName") @ApiParam(value = "reportName") final String reportName,
@Context final UriInfo uriInfo,
@DefaultValue("false") @QueryParam("isSelfServiceUserReport") @ApiParam(value = "isSelfServiceUserReport") final boolean isSelfServiceUserReport) {

final MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters();
final MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters();

final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters());
final boolean exportCsv = ApiParameterHelper.exportCsv(uriInfo.getQueryParameters());
Expand All @@ -96,7 +100,7 @@ public Response runReport(@PathParam("reportName") @ApiParam(value = "reportName
String parameterTypeValue = null;
if (!parameterType) {
parameterTypeValue = "report";
String reportType = this.readExtraDataAndReportingService.getReportType(reportName);
String reportType = this.readExtraDataAndReportingService.getReportType(reportName, isSelfServiceUserReport);
ReportingProcessService reportingProcessService = this.reportingProcessServiceProvider.findReportingProcessService(reportType);
if (reportingProcessService != null) { return reportingProcessService.processRequest(reportName, queryParams); }
} else {
Expand All @@ -108,7 +112,7 @@ public Response runReport(@PathParam("reportName") @ApiParam(value = "reportName
if (exportPdf) {
final Map<String, String> reportParams = getReportParams(queryParams);
final String pdfFileName = this.readExtraDataAndReportingService
.retrieveReportPDF(reportName, parameterTypeValue, reportParams);
.retrieveReportPDF(reportName, parameterTypeValue, reportParams, isSelfServiceUserReport);

final File file = new File(pdfFileName);

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

final GenericResultsetData result = this.readExtraDataAndReportingService.retrieveGenericResultset(reportName,
parameterTypeValue, reportParams);
parameterTypeValue, reportParams, isSelfServiceUserReport);

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

return Response.ok().entity(result).type("text/csv")
.header("Content-Disposition", "attachment;filename=" + reportName.replaceAll(" ", "") + ".csv").build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ public final class Report extends AbstractPersistableCustom<Long> {

@OneToMany(cascade = CascadeType.ALL, mappedBy = "report", orphanRemoval = true, fetch=FetchType.EAGER)
private Set<ReportParameterUsage> reportParameterUsages = new HashSet<>();

@Column(name = "self_service_user_report")
private boolean isSelfServiceUserReport;

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

Expand Down Expand Up @@ -278,6 +281,7 @@ private boolean changeInReportParameters(final Set<ReportParameterUsage> newRepo
}

public Set<ReportParameterUsage> getReportParameterUsages() {
return this.reportParameterUsages;
}
return this.reportParameterUsages;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@

public interface ReadReportingService {

StreamingOutput retrieveReportCSV(String name, String type, Map<String, String> extractedQueryParams);
StreamingOutput retrieveReportCSV(String name, String type, Map<String, String> extractedQueryParams, boolean isSelfServiceUserReport);

GenericResultsetData retrieveGenericResultset(String name, String type, Map<String, String> extractedQueryParams);
GenericResultsetData retrieveGenericResultset(String name, String type, Map<String, String> extractedQueryParams, boolean isSelfServiceUserReport);

String retrieveReportPDF(String name, String type, Map<String, String> extractedQueryParams);
String retrieveReportPDF(String name, String type, Map<String, String> extractedQueryParams, boolean isSelfServiceUserReport);

String getReportType(String reportName);
String getReportType(String reportName, boolean isSelfServiceUserReport);

Collection<ReportData> retrieveReportList();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,16 @@ public ReadReportingServiceImpl(final PlatformSecurityContext context, final Rou
}

@Override
public StreamingOutput retrieveReportCSV(final String name, final String type, final Map<String, String> queryParams) {
public StreamingOutput retrieveReportCSV(final String name, final String type,
final Map<String, String> queryParams, final boolean isSelfServiceUserReport) {

return new StreamingOutput() {
return new StreamingOutput() {

@Override
public void write(final OutputStream out) {
try {

final GenericResultsetData result = retrieveGenericResultset(name, type, queryParams);
final GenericResultsetData result = retrieveGenericResultset(name, type, queryParams, isSelfServiceUserReport);
final StringBuffer sb = generateCsvFileBuffer(result);

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

@Override
public GenericResultsetData retrieveGenericResultset(final String name, final String type, final Map<String, String> queryParams) {
public GenericResultsetData retrieveGenericResultset(final String name, final String type,
final Map<String, String> queryParams, final boolean isSelfServiceUserReport) {

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

final String sql = getSQLtoRun(name, type, queryParams);
final String sql = getSQLtoRun(name, type, queryParams, isSelfServiceUserReport);

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

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

private String getSQLtoRun(final String name, final String type, final Map<String, String> queryParams) {
private String getSQLtoRun(final String name, final String type, final Map<String, String> queryParams,
final boolean isSelfServiceUserReport) {

String sql = getSql(name, type);

Expand All @@ -203,40 +206,45 @@ private String getSQLtoRun(final String name, final String type, final Map<Strin
// (typically used to return report lists containing only reports
// permitted to be run by the user
sql = this.genericDataService.replace(sql, "${currentUserId}", currentUser.getId().toString());

sql = this.genericDataService.replace(sql, "${isSelfServiceUser}",
Integer.toString(isSelfServiceUserReport ? 1 : 0));

sql = this.genericDataService.wrapSQL(sql);
sql = this.genericDataService.wrapSQL(sql);

return sql;
return sql;

}
}

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

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

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

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

@Override
public String getReportType(final String reportName) {
public String getReportType(final String reportName, final boolean isSelfServiceUserReport) {

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

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

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

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

@Override
public String retrieveReportPDF(final String reportName, final String type, final Map<String, String> queryParams) {
public String retrieveReportPDF(final String reportName, final String type, final Map<String, String> queryParams,
final boolean isSelfServiceUserReport) {

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

try {
final GenericResultsetData result = retrieveGenericResultset(reportName, type, queryParams);
final GenericResultsetData result = retrieveGenericResultset(reportName, type, queryParams, isSelfServiceUserReport);

final List<ResultsetColumnHeaderData> columnHeaders = result.getColumnHeaders();
final List<ResultsetRowData> data = result.getData();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,8 @@ private StringBuilder generateReportOutputStream(final ReportMailingJob reportMa
final MultivaluedMap<String, String> reportParams, final String reportName, final StringBuilder errorLog) {

try {
final String reportType = this.readReportingService.getReportType(reportName);
final boolean isSelfServiceUserReport = false;
final String reportType = this.readReportingService.getReportType(reportName, isSelfServiceUserReport);
final ReportingProcessService reportingProcessService = this.reportingProcessServiceProvider.findReportingProcessService(reportType);

if (reportingProcessService != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ public SelfRunReportApiResource(final PlatformSecurityContext context, final Run
@Produces({ MediaType.APPLICATION_JSON, "text/csv", "application/vnd.ms-excel", "application/pdf", "text/html" })
public Response runReport(@PathParam("reportName") final String reportName, @Context final UriInfo uriInfo) {
this.context.authenticatedUser();
return this.runreportsApiResource.runReport(reportName, uriInfo);
final boolean isSelfServiceUserReport = true;
return this.runreportsApiResource.runReport(reportName, uriInfo, isSelfServiceUserReport);
}

}
Loading

0 comments on commit f5a0146

Please sign in to comment.