updated query report and modified Report to include query reports
This commit is contained in:
parent
9cf14c6559
commit
bc11149738
9 changed files with 438 additions and 268 deletions
|
|
@ -5,7 +5,7 @@
|
|||
{
|
||||
u'creation': '2012-06-13 19:07:26',
|
||||
u'docstatus': 0,
|
||||
u'modified': '2012-10-01 14:00:02',
|
||||
u'modified': '2012-10-01 17:58:19',
|
||||
u'modified_by': u'Administrator',
|
||||
u'owner': u'Administrator'
|
||||
},
|
||||
|
|
@ -48,6 +48,15 @@
|
|||
u'name': u'Report'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
u'doctype': u'DocField',
|
||||
'fieldname': u'is_standard',
|
||||
'fieldtype': u'Select',
|
||||
'label': u'Is Standard',
|
||||
'options': u'No\nYes'
|
||||
},
|
||||
|
||||
# DocField
|
||||
{
|
||||
u'doctype': u'DocField',
|
||||
|
|
|
|||
|
|
@ -1,3 +1,25 @@
|
|||
// Copyright (c) 2012 Web Notes Technologies Pvt Ltd (http://erpnext.com)
|
||||
//
|
||||
// MIT License (MIT)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
wn.pages['query-report'].onload = function(wrapper) {
|
||||
wn.ui.make_app_page({
|
||||
parent: wrapper,
|
||||
|
|
@ -5,7 +27,384 @@ wn.pages['query-report'].onload = function(wrapper) {
|
|||
single_column: true
|
||||
});
|
||||
|
||||
wn.test = new wn.views.QueryReport({
|
||||
wn.query_report = new wn.views.QueryReport({
|
||||
parent: wrapper,
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
wn.pages['query-report'].show = function(wrapper) {
|
||||
wn.query_report && wn.query_report.load()
|
||||
}
|
||||
|
||||
wn.provide("wn.views");
|
||||
|
||||
wn.views.QueryReport = Class.extend({
|
||||
init: function(opts) {
|
||||
$.extend(this, opts);
|
||||
// globalify for slickgrid
|
||||
this.appframe = this.parent.appframe;
|
||||
this.parent.query_report = this;
|
||||
this.make();
|
||||
},
|
||||
slickgrid_options: {
|
||||
enableColumnReorder: false,
|
||||
showHeaderRow: true,
|
||||
headerRowHeight: 30,
|
||||
explicitInitialization: true,
|
||||
multiColumnSort: true
|
||||
},
|
||||
make: function() {
|
||||
this.wrapper = $("<div>").appendTo($(this.parent).find(".layout-main"));
|
||||
$('<div class="query-edit well" style="display: none;">\
|
||||
<div class="query-form" style="width: 60%; float: left;"></div>\
|
||||
<div class="help" style="width: 30%; float: left; margin-left: 15px;">\
|
||||
<b>Column Rules: "label:datatype:width"</b><br>\
|
||||
<ol>\
|
||||
<li>"datatype" and "width" are optional.\
|
||||
<li>"datatype" can be "Link", "Date", "Float", "Currency".\
|
||||
<li>For Links, use define linked Doctype as "Link/Customer".<br>\
|
||||
Example: "Customer:Link/Customer:120"\
|
||||
</ol>\
|
||||
</div>\
|
||||
<div class="clear"></div>\
|
||||
</div>\
|
||||
<div class="result-area" style="height:400px; \
|
||||
border: 1px solid #aaa;"></div>\
|
||||
<p class="help"><br>\
|
||||
For comparative filters, start with ">" or "<", e.g. >5 or >01-02-2012\
|
||||
<br>For ranges (values and dates) use ":", e.g. "5:10" (to filter values between 5 & 10)\
|
||||
</p>').appendTo(this.wrapper);
|
||||
|
||||
this.make_query_form();
|
||||
this.make_toolbar();
|
||||
this.import_slickgrid();
|
||||
},
|
||||
make_toolbar: function() {
|
||||
var me = this;
|
||||
this.appframe.add_button("Run", function() {
|
||||
me.refresh();
|
||||
}).addClass("btn-success");
|
||||
|
||||
if(in_list(user_roles, "System Manager")) {
|
||||
// Edit
|
||||
this.appframe.add_button("Edit", function() {
|
||||
me.wrapper.find(".query-edit").slideToggle();
|
||||
});
|
||||
}
|
||||
},
|
||||
make_query_form: function() {
|
||||
this.query_form = new wn.ui.FieldGroup({
|
||||
parent: $(this.wrapper).find(".query-form").get(0),
|
||||
fields: [
|
||||
{label:"Report Name", reqd: 1, fieldname:"name"},
|
||||
{label:"Based on", fieldtype:"Link", options:"DocType",
|
||||
fieldname: "ref_doctype",
|
||||
reqd:1, description:"Permissions will be based on this DocType"},
|
||||
{label:"Query", fieldtype: "Text", reqd: 1},
|
||||
{label:"Save", fieldtype:"Button"}
|
||||
]
|
||||
});
|
||||
|
||||
// text style
|
||||
$(this.query_form.fields_dict.query.input).css({
|
||||
width: "100%",
|
||||
height: "300px",
|
||||
"font-weight": "Normal",
|
||||
"font-family": "Monaco, Courier, Fixed"
|
||||
});
|
||||
|
||||
// Save
|
||||
var me = this;
|
||||
$(this.query_form.fields_dict.save.input).click(function() {
|
||||
var doc = me.query_form.get_values();
|
||||
if(!doc) return;
|
||||
|
||||
// new report
|
||||
if(!me.doc) {
|
||||
doc.doctype = "Report";
|
||||
if(user=="Administrator") doc.is_standard="Yes";
|
||||
else doc.is_standard="No"
|
||||
doc.__islocal = 1;
|
||||
} else{
|
||||
doc = $.extend(copy_dict(me.doc), doc);
|
||||
}
|
||||
|
||||
|
||||
wn.call({
|
||||
method:"webnotes.client.save",
|
||||
args: { doclist: [doc] },
|
||||
callback: function(r) {
|
||||
wn.provide("locals.Report");
|
||||
me.doc = r.message[0]
|
||||
locals["Report"][me.doc.name] = r.message[0];
|
||||
wn.set_route("query-report", me.doc.name);
|
||||
}
|
||||
})
|
||||
});
|
||||
},
|
||||
load: function() {
|
||||
// load from route
|
||||
var route = wn.get_route();
|
||||
var me = this;
|
||||
this.doc = null;
|
||||
if(route[1]) {
|
||||
wn.model.with_doc("Report", route[1], function(doc) {
|
||||
me.doc = locals["Report"] && locals["Report"][route[1]];
|
||||
if(!me.doc) {
|
||||
msgprint("Bad Report Name");
|
||||
return;
|
||||
}
|
||||
me.appframe.title("Query Report: " + me.doc.name);
|
||||
me.query_form.set_values(me.doc);
|
||||
|
||||
// only administrator can edit standard reports
|
||||
$(me.wrapper).find("query-form :input").attr('disabled',
|
||||
(me.doc.is_standard=="Yes" && user!="Administrator")
|
||||
? "disabled" : null);
|
||||
me.refresh();
|
||||
})
|
||||
}
|
||||
},
|
||||
import_slickgrid: function() {
|
||||
wn.require('lib/js/lib/slickgrid/slick.grid.css');
|
||||
wn.require('lib/js/lib/slickgrid/slick-default-theme.css');
|
||||
wn.require('lib/js/lib/slickgrid/jquery.event.drag.min.js');
|
||||
wn.require('lib/js/lib/slickgrid/slick.core.js');
|
||||
wn.require('lib/js/lib/slickgrid/slick.grid.js');
|
||||
wn.require('lib/js/lib/slickgrid/slick.dataview.js');
|
||||
wn.dom.set_style('.slick-cell { font-size: 12px; }\
|
||||
.slick-headerrow-column {\
|
||||
background: #87ceeb;\
|
||||
text-overflow: clip;\
|
||||
-moz-box-sizing: border-box;\
|
||||
box-sizing: border-box;\
|
||||
}\
|
||||
.slick-headerrow-column input {\
|
||||
margin: 0;\
|
||||
padding: 0;\
|
||||
width: 100%;\
|
||||
height: 100%;\
|
||||
-moz-box-sizing: border-box;\
|
||||
box-sizing: border-box;}');
|
||||
},
|
||||
refresh: function() {
|
||||
// Run
|
||||
var me =this;
|
||||
wn.call({
|
||||
method: "webnotes.widgets.query_report.run",
|
||||
args: {
|
||||
doctype: me.query_form.get_value("ref_doctype"),
|
||||
query: me.query_form.get_value("query")
|
||||
},
|
||||
callback: function(r) {
|
||||
me.make_results(r.message.result, r.message.columns);
|
||||
}
|
||||
})
|
||||
},
|
||||
make_results: function(result, columns) {
|
||||
this.make_columns(columns);
|
||||
this.make_data(result, columns);
|
||||
this.render(result, columns);
|
||||
},
|
||||
render: function(result, columns) {
|
||||
this.columnFilters = {};
|
||||
this.make_dataview();
|
||||
this.id = wn.dom.set_unique_id($(this.wrapper.find(".result-area")).get(0));
|
||||
|
||||
this.grid = new Slick.Grid("#"+this.id, this.dataView, this.columns,
|
||||
this.slickgrid_options);
|
||||
this.setup_header_row();
|
||||
this.grid.init();
|
||||
this.setup_sort();
|
||||
},
|
||||
make_columns: function(columns) {
|
||||
this.columns = [{id: "_id", field: "_id", name: "Sr No", width: 60}]
|
||||
.concat($.map(columns, function(c) {
|
||||
var col = {name:c, id: c, field: c, sortable: true, width: 80}
|
||||
|
||||
if(c.indexOf(":")!=-1) {
|
||||
var opts = c.split(":");
|
||||
|
||||
// link
|
||||
if(opts[1].substr(0,4)=="Link") {
|
||||
col.doctype = opts[1].split('/')[1];
|
||||
col.formatter = function(row, cell, value, columnDef, dataContext) {
|
||||
return repl('<a href="#Form/%(doctype)s/%(name)s">%(name)s</a>', {
|
||||
doctype: columnDef.doctype,
|
||||
name: value
|
||||
});
|
||||
}
|
||||
} else if(opts[1]=="Date") {
|
||||
col.formatter = function(row, cell, value, columnDef, dataContext) {
|
||||
return dateutil.str_to_user(value);
|
||||
};
|
||||
} else if(opts[1]=="Currency") {
|
||||
col.formatter = function(row, cell, value, columnDef, dataContext) {
|
||||
return repl('<div style="text-align: right;">%(value)s</div>', {
|
||||
value: fmt_money(value)
|
||||
});
|
||||
};
|
||||
} else if(opts[1]=="Float") {
|
||||
col.formatter = function(row, cell, value, columnDef, dataContext) {
|
||||
return repl('<div style="text-align: right;">%(value)s</div>', {
|
||||
value: value.toFixed(6)
|
||||
});
|
||||
};
|
||||
} else if(opts[1]=="Int") {
|
||||
col.formatter = function(row, cell, value, columnDef, dataContext) {
|
||||
return repl('<div style="text-align: right;">%(value)s</div>', {
|
||||
value: parseInt(value)
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
col.name = col.id = col.field = opts[0];
|
||||
col.fieldtype = opts[1];
|
||||
|
||||
// width
|
||||
if(opts[2]) {
|
||||
col.width=parseInt(opts[2]);
|
||||
}
|
||||
}
|
||||
col.name = toTitle(col.name.replace(/ /g, " "))
|
||||
return col
|
||||
}));
|
||||
},
|
||||
make_data: function(result, columns) {
|
||||
var me = this;
|
||||
this.data = $.map(result, function(row, row_idx) {
|
||||
var newrow = {};
|
||||
for(var i=1, j=me.columns.length; i<j; i++) {
|
||||
newrow[me.columns[i].field] = row[i-1];
|
||||
};
|
||||
newrow._id = row_idx + 1;
|
||||
newrow.id = newrow.name ? newrow.name : ("_" + newrow._id);
|
||||
return newrow;
|
||||
});
|
||||
},
|
||||
make_dataview: function() {
|
||||
// initialize the model
|
||||
this.dataView = new Slick.Data.DataView({ inlineFilters: true });
|
||||
this.dataView.beginUpdate();
|
||||
this.dataView.setItems(this.data);
|
||||
this.dataView.setFilter(this.inline_filter);
|
||||
this.dataView.endUpdate();
|
||||
|
||||
var me = this;
|
||||
this.dataView.onRowCountChanged.subscribe(function (e, args) {
|
||||
me.grid.updateRowCount();
|
||||
me.grid.render();
|
||||
});
|
||||
|
||||
this.dataView.onRowsChanged.subscribe(function (e, args) {
|
||||
me.grid.invalidateRows(args.rows);
|
||||
me.grid.render();
|
||||
});
|
||||
},
|
||||
inline_filter: function (item) {
|
||||
var me = wn.container.page.query_report;
|
||||
for (var columnId in me.columnFilters) {
|
||||
if (columnId !== undefined && me.columnFilters[columnId] !== "") {
|
||||
var c = me.grid.getColumns()[me.grid.getColumnIndex(columnId)];
|
||||
if (!me.compare_values(item[c.field], me.columnFilters[columnId],
|
||||
me.columns[me.grid.getColumnIndex(columnId)])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
compare_values: function(value, filter, columnDef) {
|
||||
var invert = false;
|
||||
|
||||
// check if invert
|
||||
if(filter[0]=="!") {
|
||||
invert = true;
|
||||
filter = filter.substr(1);
|
||||
}
|
||||
|
||||
var out = false;
|
||||
var cond = "=="
|
||||
|
||||
// parse condition
|
||||
if(filter[0]==">") {
|
||||
filter = filter.substr(1);
|
||||
cond = ">"
|
||||
} else if(filter[0]=="<") {
|
||||
filter = filter.substr(1);
|
||||
cond = "<"
|
||||
}
|
||||
|
||||
|
||||
if(in_list(['Float', 'Currency', 'Int', 'Date'], columnDef.fieldtype)) {
|
||||
// non strings
|
||||
if(filter.indexOf(":")==-1) {
|
||||
if(columnDef.fieldtype=="Date") {
|
||||
filter = dateutil.user_to_str(filter);
|
||||
}
|
||||
out = eval("value" + cond + "filter");
|
||||
} else {
|
||||
// range
|
||||
filter = filter.split(":");
|
||||
if(columnDef.fieldtype=="Date") {
|
||||
filter[0] = dateutil.user_to_str(filter[0]);
|
||||
filter[1] = dateutil.user_to_str(filter[1]);
|
||||
}
|
||||
out = value >= filter[0] && value <= filter[1];
|
||||
}
|
||||
} else {
|
||||
// string
|
||||
value = value + "";
|
||||
value = value.toLowerCase();
|
||||
filter = filter.toLowerCase();
|
||||
out = value.indexOf(filter) != -1;
|
||||
}
|
||||
|
||||
if(invert)
|
||||
return !out;
|
||||
else
|
||||
return out;
|
||||
},
|
||||
setup_header_row: function() {
|
||||
var me = this;
|
||||
|
||||
$(this.grid.getHeaderRow()).delegate(":input", "change keyup", function (e) {
|
||||
var columnId = $(this).data("columnId");
|
||||
if (columnId != null) {
|
||||
me.columnFilters[columnId] = $.trim($(this).val());
|
||||
me.dataView.refresh();
|
||||
}
|
||||
});
|
||||
|
||||
this.grid.onHeaderRowCellRendered.subscribe(function(e, args) {
|
||||
$(args.node).empty();
|
||||
$("<input type='text'>")
|
||||
.data("columnId", args.column.id)
|
||||
.val(me.columnFilters[args.column.id])
|
||||
.appendTo(args.node);
|
||||
});
|
||||
},
|
||||
setup_sort: function() {
|
||||
var me = this;
|
||||
this.grid.onSort.subscribe(function (e, args) {
|
||||
var cols = args.sortCols;
|
||||
|
||||
me.data.sort(function (dataRow1, dataRow2) {
|
||||
for (var i = 0, l = cols.length; i < l; i++) {
|
||||
var field = cols[i].sortCol.field;
|
||||
var sign = cols[i].sortAsc ? 1 : -1;
|
||||
var value1 = dataRow1[field], value2 = dataRow2[field];
|
||||
var result = (value1 == value2 ? 0 : (value1 > value2 ? 1 : -1)) * sign;
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
me.dataView.beginUpdate();
|
||||
me.dataView.setItems(me.data);
|
||||
me.dataView.endUpdate();
|
||||
me.dataView.refresh();
|
||||
});
|
||||
}
|
||||
})
|
||||
|
|
@ -141,7 +141,6 @@
|
|||
"lib/public/js/wn/views/formview.js",
|
||||
"lib/public/js/wn/views/reportview.js",
|
||||
"lib/public/js/wn/views/grid_report.js",
|
||||
"lib/public/js/wn/views/query_report.js",
|
||||
"lib/public/js/legacy/widgets/dialog.js",
|
||||
"lib/public/js/legacy/widgets/layout.js",
|
||||
"lib/public/js/legacy/widgets/tabbedpage.js",
|
||||
|
|
|
|||
|
|
@ -305,4 +305,8 @@ div.std-footer-item {
|
|||
|
||||
.markdown h3, .markdown h4 {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.clear {
|
||||
clear: both;
|
||||
}
|
||||
|
|
@ -86,6 +86,10 @@ wn.ui.FieldGroup = Class.extend({
|
|||
}
|
||||
return ret;
|
||||
},
|
||||
get_value: function(key) {
|
||||
var f = this.fields_dict[key];
|
||||
return f && (f.get_value ? f.get_value() : null);
|
||||
},
|
||||
set_value: function(key, val){
|
||||
var f = this.fields_dict[key];
|
||||
if(f) {
|
||||
|
|
|
|||
|
|
@ -1,258 +0,0 @@
|
|||
// Copyright (c) 2012 Web Notes Technologies Pvt Ltd (http://erpnext.com)
|
||||
//
|
||||
// MIT License (MIT)
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// and/or sell copies of the Software, and to permit persons to whom the
|
||||
// Software is furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
|
||||
// OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
wn.provide("wn.views");
|
||||
|
||||
wn.views.QueryReport = Class.extend({
|
||||
init: function(opts) {
|
||||
$.extend(this, opts);
|
||||
// globalify for slickgrid
|
||||
this.appframe = this.parent.appframe;
|
||||
this.parent.query_report = this;
|
||||
this.make();
|
||||
},
|
||||
slickgrid_options: {
|
||||
enableColumnReorder: false,
|
||||
showHeaderRow: true,
|
||||
headerRowHeight: 30,
|
||||
explicitInitialization: true,
|
||||
multiColumnSort: true
|
||||
},
|
||||
make: function() {
|
||||
this.wrapper = $("<div>").appendTo($(this.parent).find(".layout-main"));
|
||||
$('<div class="query-edit" style="display: none;">\
|
||||
<div class="query-form" style="width: 60%; float: left;"></div>\
|
||||
<div class="help" style="width: 30%; float: left; margin-left: 15px;">\
|
||||
<b>Query Rules:</b><br>\
|
||||
<ol>\
|
||||
<li>Define column names as JSON objects to specifiy types and links:\
|
||||
<li>Labels are automatically defined from column headings.\
|
||||
To define for doctype, set `{"label": "Customer", "type": "Link", "options":"Customer"}`\
|
||||
<li>For DataTypes, use suffix: eg. `{"label":"Qty", "type":"Float"}`\
|
||||
<li>For Links, use suffix "link": eg. `customer:float`\
|
||||
</ol>\
|
||||
</div>\
|
||||
<hr style="clear: both;" />\
|
||||
</div>\
|
||||
<div class="result-area" style="height:400px; \
|
||||
border: 1px solid #aaa;"></div>').appendTo(this.wrapper);
|
||||
|
||||
this.make_query_form();
|
||||
this.make_toolbar();
|
||||
this.import_slickgrid();
|
||||
},
|
||||
make_toolbar: function() {
|
||||
var me = this;
|
||||
this.appframe.add_button("Run", function() {
|
||||
// Run
|
||||
wn.call({
|
||||
method: "webnotes.widgets.query_report.run",
|
||||
args: {
|
||||
query: $(me.wrapper).find("textarea").val()
|
||||
},
|
||||
callback: function(r) {
|
||||
me.refresh(r.message.result, r.message.columns);
|
||||
}
|
||||
})
|
||||
}).addClass("btn-success");
|
||||
|
||||
if(in_list(user_roles, "System Manager")) {
|
||||
// Edit
|
||||
this.appframe.add_button("Edit", function() {
|
||||
me.wrapper.find(".query-edit").slideToggle();
|
||||
});
|
||||
|
||||
// Save
|
||||
this.appframe.add_button("Save", function() {
|
||||
var doc = me.query_form.get_values();
|
||||
if(!doc) return;
|
||||
doc.doctype = "Report"
|
||||
wn.call({
|
||||
method:"webnotes.client.save",
|
||||
args: {
|
||||
doclist: [doc],
|
||||
},
|
||||
callback: function(r) {
|
||||
//wn.set_route("query-form", doc.name);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
},
|
||||
make_query_form: function() {
|
||||
this.query_form = new wn.ui.FieldGroup({
|
||||
parent: $(this.wrapper).find(".query-form").get(0),
|
||||
fields: [
|
||||
{label:"Report Name", reqd: 1, fieldname:"name"},
|
||||
{label:"Based on", fieldtype:"Link", options:"DocType",
|
||||
fieldname: "ref_doctype",
|
||||
reqd:1, description:"Permissions will be based on this DocType"},
|
||||
{label:"Query", fieldtype: "Text", reqd: 1}
|
||||
]
|
||||
});
|
||||
|
||||
$(this.query_form.fields_dict.query.input).css({
|
||||
width: "100%",
|
||||
height: "300px",
|
||||
"font-weight": "Normal",
|
||||
"font-family": "Monaco, Courier, Fixed"
|
||||
});
|
||||
},
|
||||
import_slickgrid: function() {
|
||||
wn.require('lib/js/lib/slickgrid/slick.grid.css');
|
||||
wn.require('lib/js/lib/slickgrid/slick-default-theme.css');
|
||||
wn.require('lib/js/lib/slickgrid/jquery.event.drag.min.js');
|
||||
wn.require('lib/js/lib/slickgrid/slick.core.js');
|
||||
wn.require('lib/js/lib/slickgrid/slick.grid.js');
|
||||
wn.require('lib/js/lib/slickgrid/slick.dataview.js');
|
||||
wn.dom.set_style('.slick-cell { font-size: 12px; }\
|
||||
.slick-headerrow-column {\
|
||||
background: #87ceeb;\
|
||||
text-overflow: clip;\
|
||||
-moz-box-sizing: border-box;\
|
||||
box-sizing: border-box;\
|
||||
}\
|
||||
.slick-headerrow-column input {\
|
||||
margin: 0;\
|
||||
padding: 0;\
|
||||
width: 100%;\
|
||||
height: 100%;\
|
||||
-moz-box-sizing: border-box;\
|
||||
box-sizing: border-box;}');
|
||||
},
|
||||
refresh: function(result, columns) {
|
||||
this.make_data(result, columns);
|
||||
this.make_columns(columns);
|
||||
this.render(result, columns);
|
||||
},
|
||||
render: function(result, columns) {
|
||||
this.columnFilters = {};
|
||||
this.make_dataview();
|
||||
this.id = wn.dom.set_unique_id($(this.wrapper.find(".result-area")).get(0));
|
||||
|
||||
this.grid = new Slick.Grid("#"+this.id, this.dataView, this.columns,
|
||||
this.slickgrid_options);
|
||||
this.setup_header_row();
|
||||
this.grid.init();
|
||||
this.setup_sort();
|
||||
},
|
||||
make_columns: function(columns) {
|
||||
this.columns = [{id: "_id", field: "_id", name: "Sr No", width: 60}]
|
||||
.concat($.map(columns, function(c) {
|
||||
return {id: c, field: c, sortable: true,
|
||||
name: toTitle(c.replace(/_/g, " ")) }
|
||||
}));
|
||||
},
|
||||
make_data: function(result, columns) {
|
||||
this.data = $.map(result, function(row, row_idx) {
|
||||
var newrow = {};
|
||||
$.each(columns, function(i, col) {
|
||||
newrow[col] = row[i];
|
||||
});
|
||||
newrow._id = row_idx + 1;
|
||||
newrow.id = newrow.name ? newrow.name : ("_" + newrow._id);
|
||||
return newrow;
|
||||
});
|
||||
},
|
||||
make_dataview: function() {
|
||||
// initialize the model
|
||||
this.dataView = new Slick.Data.DataView({ inlineFilters: true });
|
||||
this.dataView.beginUpdate();
|
||||
this.dataView.setItems(this.data);
|
||||
this.dataView.setFilter(this.inline_filter);
|
||||
this.dataView.endUpdate();
|
||||
|
||||
var me = this;
|
||||
this.dataView.onRowCountChanged.subscribe(function (e, args) {
|
||||
me.grid.updateRowCount();
|
||||
me.grid.render();
|
||||
});
|
||||
|
||||
this.dataView.onRowsChanged.subscribe(function (e, args) {
|
||||
me.grid.invalidateRows(args.rows);
|
||||
me.grid.render();
|
||||
});
|
||||
},
|
||||
inline_filter: function (item) {
|
||||
var me = wn.container.page.query_report;
|
||||
for (var columnId in me.columnFilters) {
|
||||
if (columnId !== undefined && me.columnFilters[columnId] !== "") {
|
||||
var c = me.grid.getColumns()[me.grid.getColumnIndex(columnId)];
|
||||
if (!me.compare_values(item[c.field], me.columnFilters[columnId])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
compare_values: function(value, filter) {
|
||||
value = value + "";
|
||||
value = value.toLowerCase();
|
||||
filter = filter.toLowerCase();
|
||||
|
||||
if(filter.length < value.length) {
|
||||
return filter==value.substr(0, filter.length)
|
||||
}
|
||||
},
|
||||
setup_header_row: function() {
|
||||
var me = this;
|
||||
|
||||
$(this.grid.getHeaderRow()).delegate(":input", "change keyup", function (e) {
|
||||
var columnId = $(this).data("columnId");
|
||||
if (columnId != null) {
|
||||
me.columnFilters[columnId] = $.trim($(this).val());
|
||||
me.dataView.refresh();
|
||||
}
|
||||
});
|
||||
|
||||
this.grid.onHeaderRowCellRendered.subscribe(function(e, args) {
|
||||
$(args.node).empty();
|
||||
$("<input type='text'>")
|
||||
.data("columnId", args.column.id)
|
||||
.val(me.columnFilters[args.column.id])
|
||||
.appendTo(args.node);
|
||||
});
|
||||
},
|
||||
setup_sort: function() {
|
||||
var me = this;
|
||||
this.grid.onSort.subscribe(function (e, args) {
|
||||
var cols = args.sortCols;
|
||||
|
||||
me.data.sort(function (dataRow1, dataRow2) {
|
||||
for (var i = 0, l = cols.length; i < l; i++) {
|
||||
var field = cols[i].sortCol.field;
|
||||
var sign = cols[i].sortAsc ? 1 : -1;
|
||||
var value1 = dataRow1[field], value2 = dataRow2[field];
|
||||
var result = (value1 == value2 ? 0 : (value1 > value2 ? 1 : -1)) * sign;
|
||||
if (result != 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
me.dataView.beginUpdate();
|
||||
me.dataView.setItems(me.data);
|
||||
me.dataView.endUpdate();
|
||||
me.dataView.refresh();
|
||||
});
|
||||
}
|
||||
})
|
||||
|
|
@ -33,8 +33,8 @@ def save():
|
|||
|
||||
if not webnotes.has_permission(doclist[0]["doctype"], "write"):
|
||||
webnotes.msgprint("No Write Permission", raise_exception=True)
|
||||
|
||||
|
||||
doclistobj = DocList(doclist)
|
||||
doclistobj.save()
|
||||
|
||||
webntoes.msgprint("%s: '%s' saved" % form.doctype, form.name)
|
||||
|
||||
return [d.fields for d in doclist]
|
||||
|
|
@ -259,7 +259,7 @@ def runquery(q='', ret=0, from_export=0):
|
|||
q = q.replace('__user', session['user'])
|
||||
q = q.replace('__today', webnotes.utils.nowdate())
|
||||
|
||||
res = sql(q, as_list=1, formatted=formatted, debug=1)
|
||||
res = sql(q, as_list=1, formatted=formatted)
|
||||
|
||||
colnames, coltypes, coloptions, colwidths = build_description_standard(meta, tl)
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,20 @@ import webnotes
|
|||
|
||||
@webnotes.whitelist()
|
||||
def run():
|
||||
query = webnotes.form_dict.query
|
||||
globals().update(webnotes.form_dict)
|
||||
|
||||
if not doctype:
|
||||
webnotes.msgprint("Must specify DocType for permissions.",
|
||||
raise_exception=1)
|
||||
|
||||
if not ("tab" + doctype.lower()) in query.lower().split("from")[1].split("where")[0]:
|
||||
webnotes.msgprint("Specified DocType must appear in query.",
|
||||
raise_exception=1)
|
||||
|
||||
if not webnotes.has_permission(doctype, "read"):
|
||||
webnotes.msgprint("Must have read permission to access this report.",
|
||||
raise_exception=1)
|
||||
|
||||
if not query.lower().startswith("select"):
|
||||
webnotes.msgprint("Query must be a SELECT", raise_exception=True)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue