diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm index 7984b8c38..47d63f55a 100644 --- a/api-docs/apiLive.htm +++ b/api-docs/apiLive.htm @@ -11198,17 +11198,19 @@ POST reports Content-Type: application/json Request Body: { - reportName: "myReport", - reportType: "Table", - reportCategory: "My Category", - description: "sample non-core report", - reportSql: "select 'hello'", - useReport: false + "reportName":"Completely New Report", + "reportType":"Table", + "reportSubType":"", + "reportCategory":"Loan", + "useReport":"false", + "description":"Just\nAn\nExample", + "reportSql":"select 'very good sql' as AComment", + "reportParameters":[{"id":"","parameterId":"5","reportParameterName":""},{"id":"","parameterId":"6","reportParameterName":""}] } { - "resourceId": 100 + "resourceId": 132 } @@ -11239,7 +11241,8 @@ GET https://DomainName/api/v1/reports "useReport": true, "reportParameters": [ { - "id": 5, + "id": 1, + "parameterId": 5, "parameterName": "OfficeIdSelectOne" } ] @@ -11249,32 +11252,38 @@ GET https://DomainName/api/v1/reports "reportName": "Client Loans Listing", "reportType": "Table", "reportCategory": "Client", - "description": "Individual Client Report\r\n\r\nPretty \n\nwide report that lists the basic details of client loans. \r\n\r\nCan be run for any size MFI but you\u0027d expect it only to be run within a branch for larger ones. \n\nThere is probably is a limit of about 20/50k clients returned for html display (export to excel doesn\u0027t have that client browser/memory impact).", - "coreReport": true, + "description": "Individual Client Report\n\nPretty \n\nwide report that lists the basic details of client loans. \n\nCan be run for any size MFI but you\u0027d expect it only to be run within a branch for larger ones. \n\nThere is probably is a limit of about 20/50k clients returned for html display (export to excel doesn\u0027t have that client browser/memory impact).", + "coreReport": false, "useReport": true, "reportParameters": [ { - "id": 5, + "id": 2, + "parameterId": 5, "parameterName": "OfficeIdSelectOne" }, { - "id": 6, + "id": 3, + "parameterId": 6, "parameterName": "loanOfficerIdSelectAll" }, { - "id": 10, + "id": 4, + "parameterId": 10, "parameterName": "currencyIdSelectAll" }, { - "id": 20, + "id": 5, + "parameterId": 20, "parameterName": "fundIdSelectAll" }, { - "id": 25, + "id": 6, + "parameterId": 25, "parameterName": "loanProductIdSelectAll" }, { - "id": 26, + "id": 7, + "parameterId": 26, "parameterName": "loanPurposeIdSelectAll" } ] @@ -11304,12 +11313,13 @@ GET https://DomainName/api/v1/reports/{id} "reportType": "Table", "reportCategory": "Client", "description": "Individual Client Report\r\n\r\nLists the small number of defined fields on the client table. Would expect to copy this \n\nreport and add any \u0027one to one\u0027 additional data for specific tenant needs.\r\n\r\nCan be run for any size MFI but you\u0027d expect it only to be run within a branch for \n\nlarger ones. Depending on how many columns are displayed, there is probably is a limit of about 20/50k clients returned for html display (export to excel doesn\u0027t \n\nhave that client browser/memory impact).", - "reportSql": "select \r\nconcat(repeat(\"..\", \r\n ((LENGTH(ounder.`hierarchy`) - LENGTH(REPLACE(ounder.`hierarchy`, \u0027.\u0027, \u0027\u0027)) - 1))), ounder.`name`) as \"Office/Branch\",\r\n c.account_no as \"Client Account No.\", \r\nc.display_name as \"Name\", \n\nc.joined_date as \"Joined\", c.external_id as \"External Id\"\r\nfrom m_office o \r\njoin m_office ounder on ounder.hierarchy like concat(o.hierarchy, \u0027%\u0027)\r\nand \n\nounder.hierarchy like concat(\u0027${currentUserHierarchy}\u0027, \u0027%\u0027)\r\njoin m_client c on c.office_id \u003d ounder.id\r\nwhere o.id \u003d ${officeId}\r\nand c.is_deleted\u003d0\r\n\n\norder by ounder.hierarchy, c.account_no", + "reportSql": "select \nconcat(repeat(\"..\", \n ((LENGTH(ounder.`hierarchy`) - LENGTH(REPLACE(ounder.`hierarchy`, \u0027.\u0027, \u0027\u0027)) - 1))), ounder.`name`) as \"Office/Branch\",\n c.account_no as \"Client Account No.\", \nc.display_name as \"Name\", \nr.enum_message_property as \"Status\",\nc.activation_date as \"Activation\", c.external_id as \"External Id\"\nfrom m_office o \njoin m_office ounder on ounder.hierarchy like concat(o.hierarchy, \u0027%\u0027)\nand ounder.hierarchy like concat(\u0027${currentUserHierarchy}\u0027, \u0027%\u0027)\njoin m_client c on c.office_id \u003d ounder.id\nleft join r_enum_value r on r.enum_name \u003d \u0027status_enum\u0027 and r.enum_id \u003d c.status_enum\nwhere o.id \u003d ${officeId}\norder by ounder.hierarchy, c.account_no", "coreReport": true, "useReport": true, "reportParameters": [ { - "id": 5, + "id": 1, + "parameterId": 5, "parameterName": "OfficeIdSelectOne" } ] @@ -11331,20 +11341,26 @@ GET https://DomainName/api/v1/reports/{id} PUT https://DomainName/api/v1/reports/{id} -PUT reports/100 +PUT reports/129 Content-Type: application/json Request Body: { - reportCategory: "My Category updated", - useReport: true + "reportName": "New rpt name", + "reportParameters": [ + { + "id": 194, + "parameterId": 5, + "reportParameterName": "m" + } + ] } { - "resourceId": 100, + "resourceId": 129, "changes": { - "reportCategory": "My Category updated", - "useReport": true + "reportName": "New rpt name", + "reportParameters": "[{\"id\":194,\"parameterId\":5,\"reportParameterName\":\"m\"}]" } } diff --git a/mifosng-db/migrations/core_db/V34__add_unique_check_on_stretchy_report_parameter.sql b/mifosng-db/migrations/core_db/V34__add_unique_check_on_stretchy_report_parameter.sql new file mode 100644 index 000000000..d58790b60 --- /dev/null +++ b/mifosng-db/migrations/core_db/V34__add_unique_check_on_stretchy_report_parameter.sql @@ -0,0 +1,3 @@ +ALTER TABLE stretchy_report_parameter + ADD UNIQUE INDEX `report_parameter_unique` (`report_id` ASC, `parameter_id` ASC) ; + diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/domain/Report.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/domain/Report.java index 420e9991e..7e058de03 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/domain/Report.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/domain/Report.java @@ -6,6 +6,7 @@ package org.mifosplatform.infrastructure.dataqueries.domain; import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; @@ -59,13 +60,12 @@ public class Report extends AbstractPersistable { @Column(name = "report_sql") private String reportSql; - + @LazyCollection(LazyCollectionOption.FALSE) @OneToMany(cascade = CascadeType.ALL, mappedBy = "report", orphanRemoval = true) private Set reportParameterUsages = new HashSet(); - public static Report fromJson( - final JsonCommand command) { + public static Report fromJson(final JsonCommand command) { String reportName = null; String reportType = null; @@ -173,14 +173,16 @@ public class Report extends AbstractPersistable { this.reportSql = StringUtils.defaultIfEmpty(newValue, null); } - final String reportParametersParamName = "reportParameters"; - if (command.hasParameter(reportParametersParamName)) { - JsonArray jsonArray = command.arrayOfParameterNamed(reportParametersParamName); - if (jsonArray != null) { - actualChanges.put(reportParametersParamName, command.jsonFragment(reportParametersParamName)); - } - } - + final String reportParametersParamName = "reportParameters"; + if (command.hasParameter(reportParametersParamName)) { + JsonArray jsonArray = command + .arrayOfParameterNamed(reportParametersParamName); + if (jsonArray != null) { + actualChanges.put(reportParametersParamName, + command.jsonFragment(reportParametersParamName)); + } + } + validate(); if (!actualChanges.isEmpty()) { @@ -294,18 +296,61 @@ public class Report extends AbstractPersistable { return false; boolean updated = false; - if (this.reportParameterUsages != null) { - if (!(this.reportParameterUsages.equals(newReportParameterUsages))) { - updated = true; - this.reportParameterUsages.clear(); - - this.reportParameterUsages.addAll(newReportParameterUsages); - } - } else { + if (changeInReportParameters(newReportParameterUsages)) { updated = true; - this.reportParameterUsages = newReportParameterUsages; + this.reportParameterUsages.clear(); + this.reportParameterUsages.addAll(newReportParameterUsages); } return updated; } + + private boolean changeInReportParameters( + Set newReportParameterUsages) { + + if (!(this.reportParameterUsages.equals(newReportParameterUsages))) return true; + + Map currentRPUs = new HashMap(); + for (ReportParameterUsage rpu : this.reportParameterUsages) { + currentRPUs.put(rpu.getId(), rpu); + } + + Map newRPUs = new HashMap(); + for (ReportParameterUsage rpu : newReportParameterUsages) { + newRPUs.put(rpu.getId(), rpu); + } + + ReportParameterUsage currentRPU = null; + ReportParameterUsage newRPU = null; + for (Long key : currentRPUs.keySet()) { + currentRPU = currentRPUs.get(key); + newRPU = newRPUs.get(key); + + if (existingEntryChanged(currentRPU, newRPU)) return true; + } + + + + return false; + } + + + private boolean existingEntryChanged( + final ReportParameterUsage currentRPU, final ReportParameterUsage newRPU) { + + if (!(currentRPU.getParameter().getId() + .equals(newRPU.getParameter().getId()))) + return true; + + if ((currentRPU.getReportParameterName() == null) + && (newRPU.getReportParameterName() == null)) + return false; + + if (!(currentRPU.getReportParameterName() + .equals(newRPU.getReportParameterName()))) + return true; + + return false; + } + } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/domain/ReportParameterUsage.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/domain/ReportParameterUsage.java index 0a9b05967..57f3c2aae 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/domain/ReportParameterUsage.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/domain/ReportParameterUsage.java @@ -41,6 +41,14 @@ public class ReportParameterUsage extends AbstractPersistable { this.parameter = parameter; this.reportParameterName = reportParameterName; } + + public ReportParameterUsage(final ReportParameterUsage currentReportParameterUsage, final Report report, + final ReportParameter parameter, final String reportParameterName) { + this.setId(currentReportParameterUsage.getId()); + this.report = report; + this.parameter = parameter; + this.reportParameterName = reportParameterName; + } public void setReport(Report report) { this.report = report; @@ -50,6 +58,14 @@ public class ReportParameterUsage extends AbstractPersistable { this.parameter = parameter; } + public ReportParameter getParameter() { + return parameter; + } + + public String getReportParameterName() { + return reportParameterName; + } + public void setReportParameterName(String reportParameterName) { this.reportParameterName = reportParameterName; } diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/service/ReportWritePlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/service/ReportWritePlatformServiceImpl.java index 258e32f3f..7bbc01a50 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/service/ReportWritePlatformServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/dataqueries/service/ReportWritePlatformServiceImpl.java @@ -223,33 +223,28 @@ public class ReportWritePlatformServiceImpl implements "reportParameterName").getAsString(); } - ReportParameterUsage reportParameterUsage = null; if (jsonObject.has("id")) { final String idStr = jsonObject.get("id").getAsString(); if (!(idStr.equals(""))) id = Long.parseLong(idStr); } - + + ReportParameterUsage reportParameterUsage = null; if (id == null) { reportParameterUsage = new ReportParameterUsage(report, parameter, reportParameterName); } else { - reportParameterUsage = rpuById(report, id); + ReportParameterUsage currentReportParameterUsage = rpuById( + report, id); - if (reportParameterUsage == null) { - throw new PlatformDataIntegrityException( - "error.msg.supplied.parameter.id.doesnt.exist", - "Supplied parameterId column doesn't Exist", - id); - } - - if (parameter != null) - reportParameterUsage.setParameter(parameter); - - if (reportParameterName != null) { - reportParameterUsage - .setReportParameterName(reportParameterName); - } + if (existingEntryChanged(currentReportParameterUsage, + parameter.getId(), reportParameterName)) { + reportParameterUsage = new ReportParameterUsage( + currentReportParameterUsage, report, + parameter, reportParameterName); + } else { + reportParameterUsage = currentReportParameterUsage; + } } reportParameterUsages.add(reportParameterUsage); @@ -261,6 +256,25 @@ public class ReportWritePlatformServiceImpl implements return null; } + private boolean existingEntryChanged( + final ReportParameterUsage currentReportParameterUsage, + final Long parameterId, final String reportParameterName) { + + if (!(currentReportParameterUsage.getParameter().getId() + .equals(parameterId))) + return true; + + if ((reportParameterName == null) + && (currentReportParameterUsage.getReportParameterName() == null)) + return false; + + if (!(currentReportParameterUsage.getReportParameterName() + .equals(reportParameterName))) + return true; + + return false; + } + private ReportParameterUsage rpuById(final Report report, final Long id) { for (ReportParameterUsage rpu : report.getReportParameterUsages()) { @@ -268,7 +282,8 @@ public class ReportWritePlatformServiceImpl implements return rpu; } - return null; - + throw new PlatformDataIntegrityException( + "error.msg.supplied.parameter.id.doesnt.exist", + "Supplied parameterId column doesn't Exist", id); } } \ No newline at end of file