From e4e1062f35b3b1c6a5bebec53fd250fdf0d27c75 Mon Sep 17 00:00:00 2001 From: John Woodlock Date: Thu, 17 May 2012 00:00:24 +1000 Subject: [PATCH] WIP Additional Fields API --- APIFolder/api.htm | 124 ++-- ...atasetRow.java => AdditionalFieldSet.java} | 6 +- .../org/mifosng/data/AdditionalFieldSets.java | 29 + .../java/org/mifosng/data/ExtraDatasets.java | 29 - .../data/reports/GenericResultset.java | 8 - .../WEB-INF/static/stretchydata-0.92.js | 535 ++++++++++++++++++ .../ReadExtraDataAndReportingService.java | 4 +- .../ReadExtraDataAndReportingServiceImpl.java | 14 +- .../api/AdditionalFieldsApiResource.java | 131 +++++ 9 files changed, 747 insertions(+), 133 deletions(-) rename mifosng-data/src/main/java/org/mifosng/data/{ExtraDatasetRow.java => AdditionalFieldSet.java} (77%) create mode 100644 mifosng-data/src/main/java/org/mifosng/data/AdditionalFieldSets.java delete mode 100644 mifosng-data/src/main/java/org/mifosng/data/ExtraDatasets.java create mode 100644 mifosng-individual-lending-app/src/main/webapp/WEB-INF/static/stretchydata-0.92.js create mode 100644 mifosng-provider/src/main/java/org/mifosng/platform/api/AdditionalFieldsApiResource.java diff --git a/APIFolder/api.htm b/APIFolder/api.htm index 8c1500267..9ed6c0be6 100644 --- a/APIFolder/api.htm +++ b/APIFolder/api.htm @@ -40,7 +40,7 @@

 

Additional Fields

@@ -315,9 +315,14 @@ error is parameter-specific. You can use this to display a message near

Additional Fields

-The additional fields resource allows you to run and receive output from pre-defined Mifos X additional fieldsreports. +In Mifos X, any number of "Sets" of "Additional Fields" can be configured for a Mifos X database table ("Type"). +

+

For example, portfolio_client is the database table that holds client data. Typically, MFI's want more client related fields than is provided by Mifos X out-of-the-box. +The MFI might add a Set called "Additional Info" containing some fields that are typically input when creating a client. They might then add another Set called "Highly Improbable Info" containing some fields that are only input in exceptional circumstances. +

+

+The additional fields resource allows you to retrieve and update any Additional Fields data that has been configured in Mifos X.

-

The Mifos X Individual Lending client application uses a JQuery plugin called stretchydata which, itself, uses this additional fields resource to provide a pretty flexible additional fields User Interface (UI). Put a link to an example here.

@@ -328,94 +333,45 @@ The Mifos X Individual Lending client application uses a JQuery plugin called st -   -
-
-

List Additional Fields

-

- Lists the types of additional field data that has been defined in Mifox X. If an Additional Data Type has more than one Addition Data Set it will be listed the same number of times as it has Sets. -

+  +
+
+

List Additional Fields Sets

+

+ Lists the Sets of additional fields have been defined in Mifos X. +

-
Arguments
-
-
exportCSV
-
optional, The only valid value is 'true'. If any other value is provided the argument will be ignored
-
Output will be delivered as a CSV file instead of JSON.
-
-

Example Request: - http://localhost:8080/mifosng-provider/api/v1/reports -

+
Arguments
+
+
type
+
optional
+
The Additional Field Type (Mifos X database table) to restrict the output to
+
-
+

Example Request: + http://localhost:8080/mifosng-provider/api/v1/additionalfields?type=portfolio_client +

-
- GET https://thedomainname/v1/reports - { - "columnHeaders": [ +
+ +
+ GET https://thedomainname/v1/additionalfields + { + "additionalFieldsSets": [ { - "columnName": "report_id", - "columnType": "INT", - "columnLength": null, - "columnDisplayType": null, - "columnValues": [] + "id": 1, + "name": "Additional Information", + "type": "portfolio_client" }, { - "columnName": "report_name", - "columnType": "VARCHAR", - "columnLength": null, - "columnDisplayType": null, - "columnValues": [] - }, - { - "columnName": "report_type", - "columnType": "VARCHAR", - "columnLength": null, - "columnDisplayType": null, - "columnValues": [] - }, -... more "columnHeaders" entries - ], - "data": [ - { - "row": [ - "29", - "Client Listing", - "Table", - null, - null, - "5", - null, - "selectOfficeId" - ] - }, - { - "row": [ - "42", - "Client Listing - Additional and Unlikely", - "Table", - null, - null, - "5", - null, - "selectOfficeId" - ] - }, - { - "row": [ - "30", - "Client Loans Listing", - "Table", - null, - null, - "5", - null, - "selectOfficeId" - ] - }, -... more "Row" entries + "id": 9, + "name": "Highly Improbable Info", + "type": "portfolio_client" + } ] -} -
+} +
+
diff --git a/mifosng-data/src/main/java/org/mifosng/data/ExtraDatasetRow.java b/mifosng-data/src/main/java/org/mifosng/data/AdditionalFieldSet.java similarity index 77% rename from mifosng-data/src/main/java/org/mifosng/data/ExtraDatasetRow.java rename to mifosng-data/src/main/java/org/mifosng/data/AdditionalFieldSet.java index 437117419..2f9890ca7 100644 --- a/mifosng-data/src/main/java/org/mifosng/data/ExtraDatasetRow.java +++ b/mifosng-data/src/main/java/org/mifosng/data/AdditionalFieldSet.java @@ -3,16 +3,16 @@ package org.mifosng.data; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement -public class ExtraDatasetRow { +public class AdditionalFieldSet { private Integer id; private String name; private String type; - protected ExtraDatasetRow() { + protected AdditionalFieldSet() { // } - public ExtraDatasetRow(final Integer id, final String name, final String type) { + public AdditionalFieldSet(final Integer id, final String name, final String type) { this.id = id; this.name = name; this.type = type; diff --git a/mifosng-data/src/main/java/org/mifosng/data/AdditionalFieldSets.java b/mifosng-data/src/main/java/org/mifosng/data/AdditionalFieldSets.java new file mode 100644 index 000000000..843a6baa5 --- /dev/null +++ b/mifosng-data/src/main/java/org/mifosng/data/AdditionalFieldSets.java @@ -0,0 +1,29 @@ +package org.mifosng.data; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement +public class AdditionalFieldSets { + + private List additionalFieldsSets = new ArrayList(); + + protected AdditionalFieldSets() { + // + } + + public AdditionalFieldSets(final List additionalFieldsSets) { + this.additionalFieldsSets = additionalFieldsSets; + } + + public List getAdditionalFieldsSets() { + return additionalFieldsSets; + } + + public void setAdditionalFieldsSets(List additionalFieldsSets) { + this.additionalFieldsSets = additionalFieldsSets; + } + +} \ No newline at end of file diff --git a/mifosng-data/src/main/java/org/mifosng/data/ExtraDatasets.java b/mifosng-data/src/main/java/org/mifosng/data/ExtraDatasets.java deleted file mode 100644 index 1793c931b..000000000 --- a/mifosng-data/src/main/java/org/mifosng/data/ExtraDatasets.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.mifosng.data; - -import java.util.ArrayList; -import java.util.List; - -import javax.xml.bind.annotation.XmlRootElement; - -@XmlRootElement -public class ExtraDatasets { - - private List extraDatasetRow = new ArrayList(); - - protected ExtraDatasets() { - // - } - - public ExtraDatasets(final List extraDatasetRow) { - this.extraDatasetRow = extraDatasetRow; - } - - public List getExtraDatasetRow() { - return extraDatasetRow; - } - - public void setExtraDatasetRow(List extraDatasetRow) { - this.extraDatasetRow = extraDatasetRow; - } - -} \ No newline at end of file diff --git a/mifosng-data/src/main/java/org/mifosng/data/reports/GenericResultset.java b/mifosng-data/src/main/java/org/mifosng/data/reports/GenericResultset.java index 48150d3ce..0b0ab6b89 100644 --- a/mifosng-data/src/main/java/org/mifosng/data/reports/GenericResultset.java +++ b/mifosng-data/src/main/java/org/mifosng/data/reports/GenericResultset.java @@ -8,14 +8,6 @@ import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class GenericResultset { - // [ - // [contact_email, field 2, field 3], - // [ - // ["abb.net", "r2", "x"], ["abb.net", "r3"] - // ] - // ] - - // create types for these private List columnHeaders = new ArrayList(); private List data = new ArrayList(); diff --git a/mifosng-individual-lending-app/src/main/webapp/WEB-INF/static/stretchydata-0.92.js b/mifosng-individual-lending-app/src/main/webapp/WEB-INF/static/stretchydata-0.92.js new file mode 100644 index 000000000..58f98f312 --- /dev/null +++ b/mifosng-individual-lending-app/src/main/webapp/WEB-INF/static/stretchydata-0.92.js @@ -0,0 +1,535 @@ +(function($) { + + $.stretchyData = {}; + + $.stretchyData.displayAllExtraData = function(params) { + + if (!(params.url)) { + alert(doI18N("reportingInitError - url parameter")); + return; + } + if (!(params.datasetType)) { + alert(doI18N("reportingInitError - datasetType parameter")); + return; + } + if (!(params.datasetPKValue)) { + alert(doI18N("reportingInitError - datasetPKValue parameter")); + return; + } + if (!(params.datasetTypeDiv)) { + alert(doI18N("reportingInitError - datasetTypeDiv parameter")); + return; + } + + var headingPrefix = ""; + if (params.headingPrefix) + headingPrefix = params.headingPrefix; + var headingClass = ""; + if (params.headingClass) + headingClass = params.headingClass; + var labelClass = ""; + if (params.labelClass) + labelClass = params.labelClass; + var valueClass = ""; + if (params.valueClass) + valueClass = params.valueClass; + displayAllExtraData(params.url, params.datasetType, + params.datasetPKValue, params.datasetTypeDiv, headingPrefix, + headingClass, labelClass, valueClass); + }; + + $.stretchyData.popupEditDialog = function(url, datasetType, datasetName, + datasetPKValue, dsnDivName, title, width, height) { + popupEditDialog(url, datasetType, datasetName, datasetPKValue, + dsnDivName, title, width, height); + }; + + displayAllSuccessFunction = function(data, textStatus, jqXHR) { + + var headingClassStr = ""; + if (displayAllVars.headingClass > "") + headingClassStr = ' class="' + displayAllVars.headingClass + '" '; + + var extraDataNamesVar = ""; + for ( var i in data.additionalFieldsSets) { + var dsnDivName = generateDsnDivName(displayAllVars.datasetType, i, displayAllVars.datasetTypeDiv); + extraDataNamesVar += '
' + + doI18N(displayAllVars.headingPrefix) + + doI18N(data.additionalFieldsSets[i].name) + ' - '; + + extraDataNamesVar += editExtraDataLink(displayAllVars.url, + displayAllVars.datasetType, data.additionalFieldsSets[i].name, + displayAllVars.datasetPKValue, dsnDivName); + + extraDataNamesVar += '
'; + extraDataNamesVar += '
'; + } + $('#' + displayAllVars.datasetTypeDiv).html(extraDataNamesVar); + for ( var i in data.additionalFieldsSets) { + var dsnDivName = generateDsnDivName(displayAllVars.datasetType, i, displayAllVars.datasetTypeDiv); + viewExtraData(displayAllVars.url, displayAllVars.datasetType, + data.additionalFieldsSets[i].name, displayAllVars.datasetPKValue, dsnDivName); + } + + }; + + displayAllErrorFunction = function(jqXHR, textStatus, errorThrown) { + alert(jqXHR.responseText); + }; + + function displayAllExtraData(url, datasetType, datasetPKValue, + datasetTypeDiv, headingPrefix, headingClass, labelClass, valueClass) { + + displayAllVars = { + url : url, + datasetType : datasetType, + datasetPKValue : datasetPKValue, + datasetTypeDiv : datasetTypeDiv, + headingPrefix : headingPrefix, + headingClass : headingClass, + labelClass : labelClass, + valueClass : valueClass + }; + + displayAllUrl = url + "api/v1/additionalfields?type=" + + encodeURIComponent(datasetType); + getData(displayAllUrl, displayAllSuccessFunction, + displayAllErrorFunction); + } + + function editExtraDataLink(url, datasetType, datasetName, datasetPKValue, + dsnDivName) { + + var popupVar = "jQuery.stretchyData.popupEditDialog('" + url + "', '" + + datasetType + "', '" + datasetName + "', " + datasetPKValue + + ", '" + dsnDivName + "', '" + doI18N("Edit") + " " + + doI18N(datasetName) + "', 900, 500)"; + var editLink = '' + + doI18N("Edit") + '
'; + // alert(editLink); + return editLink; + } + + function viewExtraDataset(data, dsnDivName) { + + var dataLength = data.data.length; + var extraDataViewVar = ''; + + var colsPerRow = 2; + var colsPerRowCount = 0; + var labelClassStr = ""; + var valueClassStr = ""; + if (displayAllVars.labelClass > "") + labelClassStr = ' class="' + displayAllVars.labelClass + '" '; + if (displayAllVars.valueClass > "") + valueClassStr = ' class="' + displayAllVars.valueClass + '" '; + + for ( var i in data.columnHeaders) { + if (!(data.columnHeaders[i].columnName == "id")) { + colsPerRowCount += 1; + if (colsPerRowCount > colsPerRow) { + extraDataViewVar += ''; + colsPerRowCount = 1; + } + var colVal = ""; + if (dataLength > 0) + colVal = data.data[0].row[i]; + if (colVal == null) + colVal = ""; + + if (colVal > "" && data.columnHeaders[i].columnType == "Text") + colVal = ''; + extraDataViewVar += ''; + } + } + extraDataViewVar += '
' + doI18N(data.columnHeaders[i].columnName) + + ':' + colVal + '
'; + $('#' + dsnDivName).html(extraDataViewVar); + // alert(dsnDivName + ": " + dsnDivName + extraDataViewVar); + } + ; + viewExtraDataErrorFunction = function(jqXHR, textStatus, errorThrown) { + alert(jqXHR.responseText); + }; + + function viewExtraData(url, datasetType, datasetName, datasetPKValue, + dsnDivName) { + var viewExtraDataUrl = url + "api/v1/additionalfields/" + encodeURIComponent(datasetType) + + "/" + encodeURIComponent(datasetName) + "/" + + encodeURIComponent(datasetPKValue); + + var evalViewExtraDataSuccessFunction = "var viewExtraDataSuccessFunction = function(data, textStatus, jqXHR){ viewExtraDataset(data, '" + + dsnDivName + "'); };" + eval(evalViewExtraDataSuccessFunction); + getData(viewExtraDataUrl, viewExtraDataSuccessFunction, + viewExtraDataErrorFunction); + } + + popupEditErrorFunction = function(jqXHR, textStatus, errorThrown) { + alert("error"); + handleXhrError(jqXHR, textStatus, errorThrown, "#formErrorsTemplate", + "#formerrors"); + }; + popupEditSuccessFunction = function(data, textStatus, jqXHR) { + currentEditPopup.dialogDiv.append(extraDataBuildTemplate(data)); + extraDataOpenDialog(currentEditPopup.url); + extraDataFormatDates(data.columnHeaders); + }; + function popupEditDialog(url, datasetType, datasetName, datasetPKValue, + dsnDivName, title, width, height) { + + currentEditPopup = { + dialogDiv : $("
"), + dsnDivName : dsnDivName, + title : title, + width : width, + height : height, + datasetType : datasetType, + datasetName : datasetName, + datasetPKValue : datasetPKValue, + baseUrl : url, + url : url + "api/v1/additionalfields/" + encodeURIComponent(datasetType) + "/" + + encodeURIComponent(datasetName) + "/" + + encodeURIComponent(datasetPKValue) + }; + getData(currentEditPopup.url, popupEditSuccessFunction, + popupEditErrorFunction); + } + + function generateDsnDivName(datasetType, i, uniqueDivid) { + return extraDataUnderscore(datasetType) + "_" + i + "_" + extraDataUnderscore(uniqueDivid); + } + + /* start of code to fill data in edit form */ + + function extraDataUnderscore(colName) { + return colName.replace(/ /g, "_") + } + + function extraDataColDisplayHTML(colName, colType, colLength, + colDisplayType, colAllowedValues, colVal) { + var displayHTML = ''; + var valueAttr = "" + if (colVal != null) + valueAttr = 'value="' + colVal.replace(/"/g, """) + '"'; + var colNameUnderscore = extraDataUnderscore(colName); + + switch (colType) { + case "String": + var colAllowedValuesLength = colAllowedValues.length; + if (colDisplayType != "List") { + var colSize = 40; + if (colLength < colSize) + colSize = colLength; + displayHTML += '' + } else + displayHTML += extraDataSelectTag(colNameUnderscore, + colAllowedValues, colVal); + break; + case "Text": + var textVal = ""; + if (colVal != null) + textVal = colVal; + displayHTML += ''; + break; + case "Date": + displayHTML += ''; + break; + case "Decimal": + displayHTML += ''; + break; + case "Integer": + displayHTML += ''; + break; + default: + displayHTML += "'" + colType + "'"; + } + displayHTML += ''; + return displayHTML; + } + + function extraDataSelectTag(colName, colAllowedValues, colVal) { + + var selectedVal = ""; + var selectHtml = ''; + // alert(selectHtml); + return selectHtml; + } + + function extraDataBuildTemplate(data) { + + var dataLength = data.data.length; + var transType = 'E'; + if (dataLength == 0) + transType = 'A'; + + var extraDataTemplateVar = '
'; + extraDataTemplateVar += ''; + + extraDataTemplateVar += ''; + + var colsPerRow = 2; + var colsPerRowCount = 0; + + for ( var i in data.columnHeaders) { + + if (!(data.columnHeaders[i].columnName == "id")) { + colsPerRowCount += 1; + if (colsPerRowCount > colsPerRow) { + extraDataTemplateVar += ''; + colsPerRowCount = 1; + } + var colVal = ""; + if (dataLength > 0) + colVal = data.data[0].row[i]; + extraDataTemplateVar += extraDataColDisplayHTML( + data.columnHeaders[i].columnName, + data.columnHeaders[i].columnType, + data.columnHeaders[i].columnLength, + data.columnHeaders[i].columnDisplayType, + data.columnHeaders[i].columnValues, colVal); + } + } + extraDataTemplateVar += ''; + return extraDataTemplateVar += '
'; + } + + function extraDataFormatDates(columnHeaders) { + + for ( var i in columnHeaders) { + // alert("in loop: " + + // extraDataUnderscore(columnHeaders[i].columnName) + " Type: " + + // columnHeaders[i].columnType); + switch (columnHeaders[i].columnType) { + case "Date": + $('#' + extraDataUnderscore(columnHeaders[i].columnName)) + .datepicker({ + + changeMonth : true, + changeYear : true, + dateFormat : 'yy-mm-dd' + }); + + break; + default: + } + } + } + + $.fn.serializeObject = function() + { + var o = {}; + var a = this.serializeArray(); + $.each(a, function() { + if (o[this.name] !== undefined) { + if (!o[this.name].push) { + o[this.name] = [o[this.name]]; + } + o[this.name].push(this.value || ''); + } else { + o[this.name] = this.value || ''; + } + }); + return o; + }; + + function extraDataOpenDialog(url) { + + // var saveButton = jQuery.i18n.prop('dialog.button.save'); + // var cancelButton = jQuery.i18n.prop('dialog.button.cancel'); + var saveButton = "save"; + var cancelButton = "cancel" + + var buttonsOpts = {}; + buttonsOpts[saveButton] = function() { + $('.multiSelectedItems option').each(function(i) { + $(this).attr("selected", "selected"); + }); + + var form_data = JSON.stringify($('#entityform').serializeObject()); + //console.log(form_data); + var jqxhr = $.ajax({ + url : url, + type : 'POST', + contentType : "application/json; charset=utf-8", + // dataType : 'jsonp', + // crossDomain : true, + dataType : 'json', + data : form_data, + success : function(data, textStatus, jqXHR) { + currentEditPopup.dialogDiv.dialog("close"); + viewExtraData(currentEditPopup.baseUrl, + currentEditPopup.datasetType, + currentEditPopup.datasetName, + currentEditPopup.datasetPKValue, + currentEditPopup.dsnDivName) + }, + error : function(jqXHR, textStatus, errorThrown) { + handleXhrError(jqXHR, textStatus, errorThrown, + "#formErrorsTemplate", "#formerrors"); + } + }); + }; + + buttonsOpts[cancelButton] = function() { + $(this).dialog("close"); + }; + + currentEditPopup.dialogDiv + .dialog( + { + // title: jQuery.i18n.prop(titleCode), + title : currentEditPopup.title, + width : currentEditPopup.width, + height : currentEditPopup.height, + modal : true, + buttons : buttonsOpts, + close : function() { + // if i dont do this, theres a problem with + // errors being appended to dialog view second + // time round + $(this).remove(); + }, + open : function(event, ui) { + $('.multiadd') + .click( + function() { + return !$( + '.multiNotSelectedItems option:selected') + .remove() + .appendTo( + '#selectedItems'); + }); + + $('.multiremove') + .click( + function() { + return !$( + '.multiSelectedItems option:selected') + .remove() + .appendTo( + '#notSelectedItems'); + }); + } + }).dialog('open'); + } + + /* end of code to fill data in edit form and display it */ + + function getData(url, successFunction, errorFunction) { + + $.ajax({ + url : url, + cache : false, + type : 'GET', + contentType : "application/json; charset=utf-8", + // dataType : 'jsonp', + // crossDomain : true, + dataType : 'json', + //crossDomain : false, + success : successFunction, + error : errorFunction + }); + } + + function handleXhrError(jqXHR, textStatus, errorThrown, templateSelector, + placeholderDiv) { + if (jqXHR.status === 0) { + alert('Not connect.\n Verify Network.'); + } else if (jqXHR.status == 404) { + alert('Requested page not found. [404]'); + } else if (jqXHR.status == 500) { + alert('Internal Server Error [500].'); + } else if (errorThrown === 'parsererror') { + alert('Requested JSON parse failed.'); + } else if (errorThrown === 'timeout') { + alert('Time out error.'); + } else if (errorThrown === 'abort') { + alert('Ajax request aborted.'); + } else { + // remove error class from all input fields + var $inputs = $('#entityform :input'); + + $inputs.each(function() { + $(this).removeClass("ui-state-error"); + }); + + $(placeholderDiv).html(""); + + var jsonErrors = JSON.parse(jqXHR.responseText); + + var errorArray = new Array(); + var arrayIndex = 0; + $.each(jsonErrors, function() { + var fieldId = '#' + this.field; + $(fieldId).addClass("ui-state-error"); + + var errorObj = new Object(); + errorObj.field = this.field; + errorObj.code = this.code; + errorObj.message = this.code; + errorObj.value = this.value; + + errorArray[arrayIndex] = errorObj; + arrayIndex++ + }); + + var templateArray = new Array(); + var templateErrorObj = new Object(); + templateErrorObj.title = "You have the following errors:"; + templateErrorObj.errors = errorArray; + + templateArray[0] = templateErrorObj; + + var formErrorsHtml = $(templateSelector).render(templateArray); + + $(placeholderDiv).append(formErrorsHtml); + } + } + + function doI18N(xlateStr, params) { + /* + * if (I18N_Needed == "Y") { if (highlightMissingXlations == "Y") return + * jQuery.i18n.prop(xlateStr, params) else { var xlated = + * jQuery.i18n.prop(xlateStr, params); if (xlated.substr(0,1) == "[" && + * xlated.substr(xlated.length - 1, 1) == "]") return xlated.substr(1, + * xlated.length - 2) else return xlated; } } else { var retStr = + * xlateStr; if (retStr == 'rpt_select_one') retStr = 'Select One'; if + * (retStr == 'rpt_select_all') retStr = 'Select All'; return retStr; } + */ + return xlateStr; + } + +})(jQuery); diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/ReadExtraDataAndReportingService.java b/mifosng-provider/src/main/java/org/mifosng/platform/ReadExtraDataAndReportingService.java index cb873d5b7..d694b59ef 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/ReadExtraDataAndReportingService.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/ReadExtraDataAndReportingService.java @@ -4,7 +4,7 @@ import java.util.Map; import javax.ws.rs.core.StreamingOutput; -import org.mifosng.data.ExtraDatasets; +import org.mifosng.data.AdditionalFieldSets; import org.mifosng.data.reports.GenericResultset; public interface ReadExtraDataAndReportingService { @@ -16,7 +16,7 @@ public interface ReadExtraDataAndReportingService { GenericResultset retrieveGenericResultset(String name, String type, Map extractedQueryParams); - ExtraDatasets retrieveExtraDatasetNames(String datasetType); + AdditionalFieldSets retrieveExtraDatasetNames(String datasetType); GenericResultset retrieveExtraData(String datasetType, String datasetName, String datasetPKValue); diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/ReadExtraDataAndReportingServiceImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/ReadExtraDataAndReportingServiceImpl.java index 546df3f5d..c0868b440 100644 --- a/mifosng-provider/src/main/java/org/mifosng/platform/ReadExtraDataAndReportingServiceImpl.java +++ b/mifosng-provider/src/main/java/org/mifosng/platform/ReadExtraDataAndReportingServiceImpl.java @@ -20,8 +20,8 @@ import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.StreamingOutput; -import org.mifosng.data.ExtraDatasetRow; -import org.mifosng.data.ExtraDatasets; +import org.mifosng.data.AdditionalFieldSet; +import org.mifosng.data.AdditionalFieldSets; import org.mifosng.data.reports.GenericResultset; import org.mifosng.data.reports.ResultsetColumnHeader; import org.mifosng.data.reports.ResultsetDataRow; @@ -334,9 +334,9 @@ public class ReadExtraDataAndReportingServiceImpl implements } @Override - public ExtraDatasets retrieveExtraDatasetNames(String type) { + public AdditionalFieldSets retrieveExtraDatasetNames(String type) { - List extraDatasetRows = new ArrayList(); + List additionalFieldsSets = new ArrayList(); Connection db_connection; try { db_connection = dataSource.getConnection(); @@ -354,8 +354,8 @@ public class ReadExtraDataAndReportingServiceImpl implements ResultSet rs = db_statement.executeQuery(sql); while (rs.next()) { - extraDatasetRows - .add(new ExtraDatasetRow(rs.getInt("id"), rs + additionalFieldsSets + .add(new AdditionalFieldSet(rs.getInt("id"), rs .getString("datasetName"), rs .getString("datasetType"))); } @@ -370,7 +370,7 @@ public class ReadExtraDataAndReportingServiceImpl implements .status(Status.BAD_REQUEST).entity(e.getMessage()).build()); } - return new ExtraDatasets(extraDatasetRows); + return new AdditionalFieldSets(additionalFieldsSets); } @Override diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/AdditionalFieldsApiResource.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/AdditionalFieldsApiResource.java new file mode 100644 index 000000000..04dd263d0 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosng/platform/api/AdditionalFieldsApiResource.java @@ -0,0 +1,131 @@ +package org.mifosng.platform.api; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.MultivaluedMap; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import javax.ws.rs.core.UriInfo; + +import org.codehaus.jettison.json.JSONArray; +import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.JSONObject; +import org.mifosng.data.EntityIdentifier; +import org.mifosng.data.ErrorResponse; +import org.mifosng.data.ErrorResponseList; +import org.mifosng.data.AdditionalFieldSets; +import org.mifosng.data.reports.GenericResultset; +import org.mifosng.platform.InvalidSqlException; +import org.mifosng.platform.ReadExtraDataAndReportingService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; +@Path("/v1/additionalfields") +@Component +@Scope("singleton") +public class AdditionalFieldsApiResource { + + private final static Logger logger = LoggerFactory.getLogger(AdditionalFieldsApiResource.class); + + @Autowired + private ReadExtraDataAndReportingService readExtraDataAndReportingService; + + @GET + @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces({ MediaType.APPLICATION_JSON}) + public Response datasets(@Context UriInfo uriInfo) { + + MultivaluedMap queryParams = uriInfo.getQueryParameters(); + String type = queryParams.getFirst("type"); + + AdditionalFieldSets result = this.readExtraDataAndReportingService.retrieveExtraDatasetNames(type); + return Response.ok().entity(result).build(); + } + + @GET + @Path("{datasetType}/{datasetName}/{datasetPKValue}") + @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces({ MediaType.APPLICATION_JSON}) + public Response extraData(@PathParam("datasetType") final String datasetType,@PathParam("datasetName") final String datasetName, @PathParam("datasetPKValue") final String datasetPKValue, @Context UriInfo uriInfo) { + + try { + GenericResultset result = this.readExtraDataAndReportingService.retrieveExtraData(datasetType, datasetName, datasetPKValue); + + return Response.ok().entity(result).build(); + } catch (InvalidSqlException e) { + List allErrors = new ArrayList(); + + ErrorResponse err = new ErrorResponse("extradata.invalid.sql", "sql", e.getSql()); + allErrors.add(err); + + throw new WebApplicationException(Response + .status(Status.BAD_REQUEST) + .entity(new ErrorResponseList(allErrors)).build()); + } + } + + @POST + @Path("{datasetType}/{datasetName}/{datasetPKValue}") + @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Produces({ MediaType.APPLICATION_JSON}) + public Response saveExtraData(@PathParam("datasetType") final String datasetType,@PathParam("datasetName") final String datasetName, @PathParam("datasetPKValue") final String datasetPKValue, String reqbody) { + + try { + + Map queryParams = new HashMap(); + String pValue = ""; + String pName; + try { + JSONObject jsonObj = new JSONObject(reqbody); + JSONArray jsonArr = jsonObj.names(); + if (jsonArr != null) { + for (int i = 0; i < jsonArr.length(); i++) { + pName = (String) jsonArr.get(i); + pValue = jsonObj.getString(pName); + logger.info( pName + " - " + pValue); + queryParams.put(pName, pValue); + } + } else { + throw new WebApplicationException(Response + .status(Status.BAD_REQUEST) + .entity("JSON body empty").build()); + } + } catch (JSONException e) { + throw new WebApplicationException(Response + .status(Status.BAD_REQUEST) + .entity("JSON body is wrong").build()); + } + + + this.readExtraDataAndReportingService.tempSaveExtraData(datasetType, datasetName, datasetPKValue, queryParams); + + EntityIdentifier entityIdentifier = new EntityIdentifier(Long.valueOf(datasetPKValue)); + + return Response.ok().entity(entityIdentifier).build(); + } catch (InvalidSqlException e) { + List allErrors = new ArrayList(); + + ErrorResponse err = new ErrorResponse("extradata.invalid.sql", "sql", e.getSql()); + allErrors.add(err); + + logger.info("way bad: " + err.toString()); + throw new WebApplicationException(Response + .status(Status.BAD_REQUEST) + .entity(new ErrorResponseList(allErrors)).build()); + } + } +} \ No newline at end of file