Loading Report...
')
+ .appendTo(this.wrapper);
+
+ },
load_filter_values: function() {
var me = this;
$.each(this.filter_inputs, function(i, f) {
@@ -191,6 +208,12 @@ wn.views.GridReport = Class.extend({
}
}
});
+
+ if(this.filter_inputs.from_date && this.filter_inputs.to_date && (this.to_date < this.from_date)) {
+ msgprint("From Date must be before To Date");
+ return;
+ }
+
},
make_name_map: function(data, key) {
var map = {};
@@ -200,6 +223,16 @@ wn.views.GridReport = Class.extend({
})
return map;
},
+
+ reset_item_values: function(item) {
+ var me = this;
+ $.each(this.columns, function(i, col) {
+ if (col.formatter==me.currency_formatter) {
+ item[col.id] = 0;
+ }
+ });
+ },
+
import_slickgrid: function() {
wn.require('js/lib/slickgrid/slick.grid.css');
wn.require('js/lib/slickgrid/slick-default-theme.css');
@@ -207,7 +240,8 @@ wn.views.GridReport = Class.extend({
wn.require('js/lib/slickgrid/slick.core.js');
wn.require('js/lib/slickgrid/slick.grid.js');
wn.require('js/lib/slickgrid/slick.dataview.js');
- wn.dom.set_style('.slick-cell { font-size: 12px; }');
+ wn.dom.set_style('.slick-cell { font-size: 12px; }');
+ if(this.tree_grid.show) wn.require("js/app/tree_grid.css");
},
refresh: function() {
this.waiting.toggle(false);
@@ -219,7 +253,10 @@ wn.views.GridReport = Class.extend({
this.setup_dataview_columns();
this.apply_link_formatters();
this.prepare_data();
+ this.prepare_data_view();
// plot might need prepared data
+ this.wrapper.find(".processing").toggle(true);
+ this.wrapper.find(".processing").delay(2000).fadeOut(300);
this.render();
this.render_plot();
},
@@ -231,11 +268,13 @@ wn.views.GridReport = Class.extend({
make: function() {
// plot wrapper
- $('
\
+
\
+ Updated!
\
Print \
| \
Export \
@@ -286,6 +325,10 @@ wn.views.GridReport = Class.extend({
+ '=' + encodeURIComponent(val);
}).join('&'))
},
+ options: {
+ editable: false,
+ enableColumnReorder: false
+ },
render: function() {
// new slick grid
this.grid = new Slick.Grid("#"+this.id, this.dataView, this.dataview_columns, this.options);
@@ -302,14 +345,15 @@ wn.views.GridReport = Class.extend({
me.grid.render();
});
- this.add_grid_events && this.add_grid_events();
+ this.tree_grid.show && this.add_tree_grid_events();
},
- prepare_data_view: function(items) {
+ prepare_data_view: function() {
// initialize the model
this.dataView = new Slick.Data.DataView({ inlineFilters: true });
this.dataView.beginUpdate();
- this.dataView.setItems(items);
+ this.dataView.setItems(this.data);
if(this.dataview_filter) this.dataView.setFilter(this.dataview_filter);
+ if(this.tree_grid.show) this.dataView.setFilter(this.tree_dataview_filter);
this.dataView.endUpdate();
},
export: function() {
@@ -342,19 +386,287 @@ wn.views.GridReport = Class.extend({
return false;
},
+ add_tree_grid_events: function() {
+ var me = this;
+ this.grid.onClick.subscribe(function (e, args) {
+ if ($(e.target).hasClass("toggle")) {
+ var item = me.dataView.getItem(args.row);
+ if (item) {
+ if (!item._collapsed) {
+ item._collapsed = true;
+ } else {
+ item._collapsed = false;
+ }
+
+ me.dataView.updateItem(item.id, item);
+ }
+ e.stopImmediatePropagation();
+ }
+ });
+ },
+ tree_formatter: function (row, cell, value, columnDef, dataContext) {
+ var me = wn.cur_grid_report;
+ value = value.replace(/&/g,"&").replace(//g,">");
+ var data = me.data;
+ var spacer = "
";
+ var idx = me.dataView.getIdxById(dataContext.id);
+ var link = me.tree_grid.formatter(dataContext);
+
+ if(columnDef.doctype) {
+ link += me.get_link_open_icon(columnDef.doctype, value);
+ }
+
+ if (data[idx + 1] && data[idx + 1].indent > data[idx].indent) {
+ if (dataContext._collapsed) {
+ return spacer + "
" + link;
+ } else {
+ return spacer + "
" + link;
+ }
+ } else {
+ return spacer + "
" + link;
+ }
+ },
+ tree_dataview_filter: function(item) {
+ var me = wn.cur_grid_report;
+ if(!me.apply_filters(item)) return false;
+
+ var parent = item[me.tree_grid.parent_field];
+ while (parent) {
+ if (me.item_by_name[parent]._collapsed) {
+ return false;
+ }
+ parent = me.parent_map[parent];
+ }
+ return true;
+ },
+ set_indent: function() {
+ var me = this;
+ $.each(this.data, function(i, d) {
+ var indent = 0;
+ var parent = me.parent_map[d.name];
+ if(parent) {
+ while(parent) {
+ indent++;
+ parent = me.parent_map[parent];
+ }
+ }
+ d.indent = indent;
+ });
+ },
+ apply_filters: function(item) {
+ // generic filter: apply filter functiions
+ // from all filter_inputs
+ var filters = this.filter_inputs;
+ if(item._show) return true;
+
+ for (i in filters) {
+ if(!this.apply_filter(item, i)) return false;
+ }
+
+ return true;
+ },
+ apply_filter: function(item, fieldname) {
+ var filter = this.filter_inputs[fieldname].get(0);
+ if(filter.opts.filter) {
+ if(!filter.opts.filter(this[filter.opts.fieldname], item, filter.opts, this)) {
+ return false;
+ }
+ }
+ return true;
+ },
+ apply_zero_filter: function(val, item, opts, me) {
+ // show only non-zero values
+ if(!me.show_zero) {
+ for(var i=0, j=me.columns.length; i
0.001 || flt(item[col.field]) < -0.001) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ return true;
+ },
+ show_zero_check: function() {
+ var me = this;
+ this.wrapper.bind('make', function() {
+ me.wrapper.find('.show-zero').toggle(true).find('input').click(function(){
+ me.refresh();
+ });
+ });
+ },
+ is_default: function(fieldname) {
+ return this[fieldname]==this[fieldname + "_default"];
+ },
+ date_formatter: function(row, cell, value, columnDef, dataContext) {
+ return dateutil.str_to_user(value);
+ },
+ currency_formatter: function(row, cell, value, columnDef, dataContext) {
+ return repl('%(value)s
', {
+ _style: dataContext._style || "",
+ value: fmt_money(value)
+ });
+ },
+ text_formatter: function(row, cell, value, columnDef, dataContext) {
+ return repl('%(value)s', {
+ _style: dataContext._style || "",
+ esc_value: cstr(value).replace(/"/g, '\"'),
+ value: cstr(value)
+ });
+ },
+ check_formatter: function(row, cell, value, columnDef, dataContext) {
+ return repl("", {
+ "id": dataContext.id,
+ "checked": dataContext.checked ? "checked" : ""
+ })
+ },
+ apply_link_formatters: function() {
+ var me = this;
+ $.each(this.dataview_columns, function(i, col) {
+ if(col.link_formatter) {
+ col.formatter = function(row, cell, value, columnDef, dataContext) {
+ // added link and open button to links
+ // link_formatter must have
+ // filter_input, open_btn (true / false), doctype (will be eval'd)
+ if(!value) return "";
+
+ var me = wn.cur_grid_report;
+
+ if(dataContext._show) {
+ return repl('%(value)s', {
+ _style: dataContext._style || "",
+ value: value
+ });
+ }
+
+ // make link to add a filter
+ var link_formatter = me.dataview_columns[cell].link_formatter;
+ var html = repl('\
+ %(value)s', {
+ value: value,
+ col_name: link_formatter.filter_input,
+ page_name: wn.container.page.page_name
+ })
+
+ // make icon to open form
+ if(link_formatter.open_btn) {
+ html += me.get_link_open_icon(eval(link_formatter.doctype), value);
+ }
+ return html;
+ }
+ }
+ })
+ },
+ get_link_open_icon: function(doctype, name) {
+ return repl(' \
+ ', {
+ name: name,
+ doctype: doctype
+ });
+ },
+ make_date_range_columns: function() {
+ this.columns = [];
+
+ var me = this;
+ var range = this.filter_inputs.range.val();
+ this.from_date = dateutil.user_to_str(this.filter_inputs.from_date.val());
+ this.to_date = dateutil.user_to_str(this.filter_inputs.to_date.val());
+ var date_diff = dateutil.get_diff(this.to_date, this.from_date);
+
+ me.column_map = {};
+
+ var add_column = function(date) {
+ me.columns.push({
+ id: date,
+ name: dateutil.str_to_user(date),
+ field: date,
+ formatter: me.currency_formatter,
+ width: 100
+ });
+ }
+
+ var build_columns = function(condition) {
+ // add column for each date range
+ for(var i=0; i < date_diff; i++) {
+ var date = dateutil.add_days(me.from_date, i);
+ if(!condition) condition = function() { return true; }
+
+ if(condition(date)) add_column(date);
+ me.last_date = date;
+
+ if(me.columns.length) {
+ me.column_map[date] = me.columns[me.columns.length-1];
+ }
+ }
+ }
+
+ // make columns for all date ranges
+ if(range=='Daily') {
+ build_columns();
+ } else if(range=='Weekly') {
+ build_columns(function(date) {
+ if(!me.last_date) return true;
+ return !(dateutil.get_diff(date, me.from_date) % 7)
+ });
+ } else if(range=='Monthly') {
+ build_columns(function(date) {
+ if(!me.last_date) return true;
+ return dateutil.str_to_obj(me.last_date).getMonth() != dateutil.str_to_obj(date).getMonth()
+ });
+ } else if(range=='Quarterly') {
+ build_columns(function(date) {
+ if(!me.last_date) return true;
+ return dateutil.str_to_obj(date).getDate()==1 && in_list([0,3,6,9], dateutil.str_to_obj(date).getMonth())
+ });
+ } else if(range=='Yearly') {
+ build_columns(function(date) {
+ if(!me.last_date) return true;
+ return $.map(wn.report_dump.data['Fiscal Year'], function(v) {
+ return date==v.year_start_date ? true : null;
+ }).length;
+ });
+ }
+
+ // set label as last date of period
+ $.each(this.columns, function(i, col) {
+ col.name = me.columns[i+1]
+ ? dateutil.str_to_user(dateutil.add_days(me.columns[i+1].id, -1))
+ : dateutil.str_to_user(me.to_date);
+ });
+ }
+});
+
+wn.views.GridReportWithPlot = wn.views.GridReport.extend({
render_plot: function() {
var plot_data = this.get_plot_data ? this.get_plot_data() : null;
if(!plot_data) {
- this.wrapper.find('.plot').toggle(false);
+ this.plot_area.toggle(false);
return;
}
wn.require('js/lib/flot/jquery.flot.js');
- this.plot = $.plot(this.wrapper.find('.plot').toggle(true), plot_data,
+ this.plot = $.plot(this.plot_area.toggle(true), plot_data,
this.get_plot_options());
this.setup_plot_hover();
},
+ setup_plot_check: function() {
+ var me = this;
+ me.wrapper.bind('make', function() {
+ me.wrapper.on("click", ".plot-check", function() {
+ var checked = $(this).attr("checked");
+ me.item_by_name[$(this).attr("data-id")].checked = checked ? true : false;
+ me.render_plot();
+ });
+ });
+ },
setup_plot_hover: function() {
var me = this;
this.tooltip_id = wn.dom.set_unique_id();
@@ -413,125 +725,4 @@ wn.views.GridReport = Class.extend({
}
return res;
},
- options: {
- editable: false,
- enableColumnReorder: false
- },
- apply_filters: function(item) {
- // generic filter: apply filter functiions
- // from all filter_inputs
- var filters = this.filter_inputs;
- if(item._show) return true;
-
- for (i in filters) {
- if(!this.apply_filter(item, i)) return false;
- }
-
- // hand over to additional filters (if applicable)
- if(this.custom_dataview_filter) {
- return this.custom_dataview_filter(item);
- }
-
- return true;
- },
- apply_filter: function(item, fieldname) {
- var filter = this.filter_inputs[fieldname].get(0);
- if(filter.opts.filter) {
- if(!filter.opts.filter(this[filter.opts.fieldname], item, filter.opts, this)) {
- return false;
- }
- }
- return true;
- },
- apply_zero_filter: function(val, item, opts, me) {
- // show only non-zero values
- if(!me.show_zero) {
- for(var i=0, j=me.columns.length; i 0.001 || flt(item[col.field]) < -0.001) {
- return true;
- }
- }
- }
- return false;
- }
- return true;
- },
- show_zero_check: function() {
- var me = this;
- this.wrapper.bind('make', function() {
- me.wrapper.find('.show-zero').toggle(true).find('input').click(function(){
- me.refresh();
- });
- });
- },
- is_default: function(fieldname) {
- return this[fieldname]==this[fieldname + "_default"];
- },
- date_formatter: function(row, cell, value, columnDef, dataContext) {
- return dateutil.str_to_user(value);
- },
- currency_formatter: function(row, cell, value, columnDef, dataContext) {
- return repl('%(value)s
', {
- _style: dataContext._style || "",
- value: fmt_money(value)
- });
- },
- text_formatter: function(row, cell, value, columnDef, dataContext) {
- return repl('%(value)s', {
- _style: dataContext._style || "",
- esc_value: cstr(value).replace(/"/g, '\"'),
- value: cstr(value)
- });
- },
- check_formatter: function(row, cell, value, columnDef, dataContext) {
- return repl("", {
- "id": dataContext.id,
- "checked": dataContext.checked ? "checked" : ""
- })
- },
- apply_link_formatters: function() {
- var me = this;
- $.each(this.dataview_columns, function(i, col) {
- if(col.link_formatter) {
- col.formatter = function(row, cell, value, columnDef, dataContext) {
- // added link and open button to links
- // link_formatter must have
- // filter_input, open_btn (true / false), doctype (will be eval'd)
- if(!value) return "";
-
- if(dataContext._show) {
- return repl('%(value)s', {
- _style: dataContext._style || "",
- value: value
- });
- }
-
- // make link to add a filter
- var link_formatter = wn.cur_grid_report.dataview_columns[cell].link_formatter;
- var html = repl('\
- %(value)s', {
- value: value,
- col_name: link_formatter.filter_input,
- page_name: wn.container.page.page_name
- })
-
- // make icon to open form
- if(link_formatter.open_btn) {
- html += repl(' \
- ', {
- value: value,
- doctype: eval(link_formatter.doctype)
- });
- }
- return html;
- }
- }
- })
- }
})
\ No newline at end of file
diff --git a/py/webnotes/utils/nestedset.py b/py/webnotes/utils/nestedset.py
index 7c864886bd..ee16348b58 100644
--- a/py/webnotes/utils/nestedset.py
+++ b/py/webnotes/utils/nestedset.py
@@ -29,8 +29,13 @@
# 3. call update_nsm(doc_obj) in the on_upate method
# ------------------------------------------
-
from __future__ import unicode_literals
+
+# uncomment below lines for testing
+# import sys, unittest
+# sys.path.append("lib/py")
+# sys.path.append(".")
+
import webnotes, unittest
class TestNSM(unittest.TestCase):
@@ -259,3 +264,7 @@ class DocTypeNestedSet:
def on_trash(self):
update_remove_node(self.doc.doctype, self.doc.name)
+
+if __name__=="__main__":
+ webnotes.connect()
+ unittest.main()
\ No newline at end of file