chore: Remove deprecated files (#7379)
- reportview.js - grid_report.js
This commit is contained in:
parent
6ef45bd5c8
commit
238a496bae
4 changed files with 0 additions and 1829 deletions
|
|
@ -357,9 +357,7 @@
|
|||
"public/js/lib/clusterize.min.js",
|
||||
"public/js/frappe/views/reports/report_factory.js",
|
||||
"public/js/frappe/views/reports/report_view.js",
|
||||
"public/js/frappe/views/reports/reportview_footer.html",
|
||||
"public/js/frappe/views/reports/query_report.js",
|
||||
"public/js/frappe/views/reports/grid_report.js",
|
||||
"public/js/frappe/views/reports/print_grid.html",
|
||||
"public/js/frappe/views/reports/print_tree.html",
|
||||
"public/js/frappe/ui/group_by/group_by.html",
|
||||
|
|
|
|||
|
|
@ -1,859 +0,0 @@
|
|||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
// MIT License. See license.txt
|
||||
|
||||
import DataTable from 'frappe-datatable';
|
||||
frappe.provide("frappe.report_dump");
|
||||
|
||||
$.extend(frappe.report_dump, {
|
||||
data: {},
|
||||
last_modified: {},
|
||||
with_data: function(doctypes, callback) {
|
||||
var pre_loaded = Object.keys(frappe.report_dump.last_modified);
|
||||
return frappe.call({
|
||||
method: "frappe.desk.report_dump.get_data",
|
||||
type: "GET",
|
||||
args: {
|
||||
doctypes: doctypes,
|
||||
last_modified: frappe.report_dump.last_modified
|
||||
},
|
||||
freeze: true,
|
||||
callback: function(r) {
|
||||
// creating map of data from a list
|
||||
$.each(r.message, function(doctype, doctype_data) {
|
||||
frappe.report_dump.set_data(doctype, doctype_data);
|
||||
});
|
||||
|
||||
// reverse map names
|
||||
$.each(r.message, function(doctype, doctype_data) {
|
||||
// only if not pre-loaded
|
||||
if(!in_list(pre_loaded, doctype)) {
|
||||
if(doctype_data.links) {
|
||||
$.each(frappe.report_dump.data[doctype], function(row_idx, row) {
|
||||
$.each(doctype_data.links, function(link_key, link) {
|
||||
if(frappe.report_dump.data[link[0]][row[link_key]]) {
|
||||
row[link_key] = frappe.report_dump.data[link[0]][row[link_key]][link[1]];
|
||||
} else {
|
||||
row[link_key] = null;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
callback();
|
||||
}
|
||||
});
|
||||
},
|
||||
set_data: function(doctype, doctype_data) {
|
||||
var data = [];
|
||||
var replace_dict = {};
|
||||
var make_row = function(d) {
|
||||
var row = {};
|
||||
$.each(doctype_data.columns, function(idx, col) {
|
||||
row[col] = d[idx];
|
||||
});
|
||||
row.id = row.name;
|
||||
row.doctype = doctype;
|
||||
return row;
|
||||
};
|
||||
if(frappe.report_dump.last_modified[doctype]) {
|
||||
// partial loading, make a name dict
|
||||
$.each(doctype_data.data, function(i, d) {
|
||||
var row = make_row(d);
|
||||
replace_dict[row.name] = row;
|
||||
});
|
||||
|
||||
// replace old data
|
||||
$.each(frappe.report_dump.data[doctype], function(i, d) {
|
||||
if(replace_dict[d.name]) {
|
||||
data.push(replace_dict[d.name]);
|
||||
delete replace_dict[d.name];
|
||||
} else if(doctype_data.modified_names.indexOf(d.name)!==-1) {
|
||||
// if modified but not in replace_dict, then assume it as cancelled
|
||||
// don't push in data
|
||||
} else {
|
||||
data.push(d);
|
||||
}
|
||||
});
|
||||
|
||||
// add new records
|
||||
$.each(replace_dict, function(name, d) {
|
||||
data.push(d);
|
||||
});
|
||||
} else {
|
||||
|
||||
// first loading
|
||||
$.each(doctype_data.data, function(i, d) {
|
||||
data.push(make_row(d));
|
||||
});
|
||||
}
|
||||
frappe.report_dump.last_modified[doctype] = doctype_data.last_modified;
|
||||
frappe.report_dump.data[doctype] = data;
|
||||
}
|
||||
});
|
||||
|
||||
frappe.provide("frappe.views");
|
||||
frappe.views.GridReport = Class.extend({
|
||||
init: function(opts) {
|
||||
this.filter_inputs = {};
|
||||
this.preset_checks = [];
|
||||
this.tree_grid = {show: false};
|
||||
$.extend(this, opts);
|
||||
|
||||
this.wrapper = $('<div class="grid-report"></div>').appendTo(this.page.main);
|
||||
this.page.main.find(".page").css({"padding-top": "0px"});
|
||||
|
||||
if(this.filters) {
|
||||
this.make_filters();
|
||||
}
|
||||
this.make_waiting();
|
||||
|
||||
this.get_data_and_refresh();
|
||||
},
|
||||
bind_show: function() {
|
||||
// bind show event to reset cur_report_grid
|
||||
// and refresh filters from url
|
||||
// this must be called after init
|
||||
// because "frappe.container.page" will only be set
|
||||
// once "load" event is over.
|
||||
|
||||
var me = this;
|
||||
$(this.page).bind('show', function() {
|
||||
// reapply filters on show
|
||||
frappe.cur_grid_report = me;
|
||||
me.get_data_and_refresh();
|
||||
});
|
||||
|
||||
},
|
||||
get_data_and_refresh: function() {
|
||||
var me = this;
|
||||
this.get_data(function() {
|
||||
me.apply_filters_from_route();
|
||||
me.refresh();
|
||||
});
|
||||
},
|
||||
get_data: function(callback) {
|
||||
var me = this;
|
||||
|
||||
frappe.report_dump.with_data(this.doctypes, function() {
|
||||
if(!me.setup_filters_done) {
|
||||
me.setup_filters();
|
||||
me.setup_filters_done = true;
|
||||
}
|
||||
callback();
|
||||
});
|
||||
},
|
||||
setup_filters: function() {
|
||||
var me = this;
|
||||
|
||||
$.each(me.filter_inputs, function(i, v) {
|
||||
var opts = v.get(0).opts;
|
||||
if(opts.fieldtype == "Select" && in_list(me.doctypes, opts.link)) {
|
||||
$(v).add_options(frappe.report_dump.data[opts.link].map(d => d.name));
|
||||
} else if(opts.fieldtype == "Link" && in_list(me.doctypes, opts.link)) {
|
||||
opts.list = frappe.report_dump.data[opts.link].map(d => d.name);
|
||||
me.set_autocomplete(v, opts.list);
|
||||
}
|
||||
});
|
||||
|
||||
// refresh
|
||||
this.page.set_primary_action(__("Refresh"), function() {
|
||||
me.get_data(function() {
|
||||
me.refresh();
|
||||
});
|
||||
});
|
||||
|
||||
// reset filters button
|
||||
if (this.filter_inputs) {
|
||||
this.page.add_menu_item(__("Reset Filters"), function() {
|
||||
me.init_filter_values();
|
||||
me.refresh();
|
||||
}, true);
|
||||
}
|
||||
|
||||
this.page.add_menu_item(__("Print"), function() {
|
||||
frappe.ui.get_print_settings(false, function(print_settings) {
|
||||
frappe.render_grid({grid: me.grid, title: me.page.title, print_settings: print_settings, report: me});
|
||||
});
|
||||
|
||||
}, true);
|
||||
|
||||
// range
|
||||
this.filter_inputs.range && this.filter_inputs.range.on("change", function() {
|
||||
me.refresh();
|
||||
});
|
||||
},
|
||||
set_filter: function(key, value) {
|
||||
var filters = this.filter_inputs[key];
|
||||
if(filters) {
|
||||
var opts = filters.get(0).opts;
|
||||
if(opts.fieldtype === "Check") {
|
||||
filters.prop("checked", cint(value) ? true : false);
|
||||
} if(opts.fieldtype=="Date") {
|
||||
filters.val(frappe.datetime.str_to_user(value));
|
||||
} else {
|
||||
filters.val(value);
|
||||
}
|
||||
} else {
|
||||
frappe.msgprint(__("Invalid Filter: {0}", [key]));
|
||||
}
|
||||
},
|
||||
set_autocomplete: function($filter, list) {
|
||||
var me = this;
|
||||
new Awesomplete($filter.get(0), {
|
||||
list: list
|
||||
});
|
||||
$filter.on("awesomplete-select", function(e) {
|
||||
var value = e.originalEvent.text.value;
|
||||
$filter.val(value);
|
||||
me.refresh();
|
||||
});
|
||||
},
|
||||
init_filter_values: function() {
|
||||
$.each(this.filter_inputs, function(key, filter) {
|
||||
var opts = filter.get(0).opts;
|
||||
if(frappe.sys_defaults[key]) {
|
||||
filter.val(frappe.sys_defaults[key]);
|
||||
} else if(opts.fieldtype=='Select') {
|
||||
filter.get(0).selectedIndex = 0;
|
||||
} else if(opts.fieldtype=='Data') {
|
||||
filter.val("");
|
||||
} else if(opts.fieldtype=="Link") {
|
||||
filter.val("");
|
||||
}
|
||||
});
|
||||
|
||||
this.set_default_values();
|
||||
},
|
||||
|
||||
set_default_values: function() {
|
||||
var values = {
|
||||
from_date: frappe.datetime.str_to_user(frappe.sys_defaults.year_start_date),
|
||||
to_date: frappe.datetime.str_to_user(frappe.sys_defaults.year_end_date)
|
||||
};
|
||||
|
||||
var me = this;
|
||||
$.each(values, function(i, v) {
|
||||
if(me.filter_inputs[i] && !me.filter_inputs[i].val())
|
||||
me.filter_inputs[i].val(v);
|
||||
});
|
||||
},
|
||||
|
||||
make_filters: function() {
|
||||
var me = this;
|
||||
$.each(this.filters, function(i, v) {
|
||||
v.fieldname = v.fieldname || v.label.replace(/ /g, '_').toLowerCase();
|
||||
var input = null;
|
||||
if(v.fieldtype=='Select') {
|
||||
input = me.page.add_select(v.label, v.options || [v.default_value]);
|
||||
} else if(v.fieldtype=="Link") {
|
||||
input = me.page.add_data(v.label);
|
||||
new Awesomplete(input.get(0), {
|
||||
list: v.list || []
|
||||
});
|
||||
} else if(v.fieldtype==='Button' && v.label===__("Refresh")) {
|
||||
input = me.page.set_primary_action(v.label, null, v.icon);
|
||||
} else if(v.fieldtype==='Button') {
|
||||
input = me.page.add_menu_item(v.label, null, true);
|
||||
} else if(v.fieldtype==='Date') {
|
||||
input = me.page.add_date(v.label);
|
||||
} else if(v.fieldtype==='Label') {
|
||||
input = me.page.add_label(v.label);
|
||||
} else if(v.fieldtype==='Data') {
|
||||
input = me.page.add_data(v.label);
|
||||
} else if(v.fieldtype==='Check') {
|
||||
input = me.page.add_check(v.label);
|
||||
}
|
||||
|
||||
if(input) {
|
||||
input && (input.get(0).opts = v);
|
||||
if(v.cssClass) {
|
||||
input.addClass(v.cssClass);
|
||||
}
|
||||
input.keypress(function(e) {
|
||||
if(e.which==13) {
|
||||
me.refresh();
|
||||
}
|
||||
});
|
||||
}
|
||||
me.filter_inputs[v.fieldname] = input;
|
||||
});
|
||||
},
|
||||
make_waiting: function() {
|
||||
this.waiting = frappe.messages.waiting(this.wrapper, __("Loading Report")+"...");
|
||||
},
|
||||
load_filter_values: function() {
|
||||
var me = this;
|
||||
$.each(this.filter_inputs, function(i, f) {
|
||||
var opts = f.get(0).opts;
|
||||
if(opts.fieldtype=='Check') {
|
||||
me[opts.fieldname] = f.prop('checked') ? 1 : 0;
|
||||
} else if(opts.fieldtype!='Button') {
|
||||
me[opts.fieldname] = f.val();
|
||||
if(opts.fieldtype=="Date") {
|
||||
me[opts.fieldname] = frappe.datetime.user_to_str(me[opts.fieldname]);
|
||||
} else if (opts.fieldtype == "Select") {
|
||||
me[opts.fieldname+'_default'] = opts.default_value;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if(this.filter_inputs.from_date && this.filter_inputs.to_date && (this.to_date < this.from_date)) {
|
||||
frappe.msgprint(__("From Date must be before To Date"));
|
||||
return;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
make_name_map: function(data, key) {
|
||||
var map = {};
|
||||
key = key || "name";
|
||||
$.each(data, function(i, v) {
|
||||
map[v[key]] = v;
|
||||
});
|
||||
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.0;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
round_item_values: function(item) {
|
||||
var me = this;
|
||||
$.each(this.columns, function(i, col) {
|
||||
if (col.formatter==me.currency_formatter) {
|
||||
item[col.id] = flt(item[col.id], frappe.defaults.get_default("float_precision") || 3);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
round_off_data: function() {
|
||||
var me = this;
|
||||
$.each(this.data, function(i, d) {
|
||||
me.round_item_values(d);
|
||||
});
|
||||
},
|
||||
|
||||
refresh: function() {
|
||||
this.waiting.toggle(false);
|
||||
if(!this.grid_wrapper)
|
||||
this.make();
|
||||
// this.show_zero = $('.show-zero input:checked').length;
|
||||
this.load_filter_values();
|
||||
this.setup_columns();
|
||||
this.setup_dataview_columns();
|
||||
this.apply_link_formatters();
|
||||
this.prepare_data();
|
||||
this.round_off_data();
|
||||
this.prepare_data_view();
|
||||
// chart might need prepared data
|
||||
frappe.show_alert("Updated", 2);
|
||||
this.render();
|
||||
this.setup_chart && this.setup_chart();
|
||||
},
|
||||
setup_dataview_columns: function() {
|
||||
this.columns = this.columns.filter(col => !col.hidden);
|
||||
this.datatable_columns = this.columns.map(column => {
|
||||
return Object.assign(column, {
|
||||
format: (value, row, column, data) => {
|
||||
return column.formatter ?
|
||||
column.formatter(row, {}, value, column, data) :
|
||||
value || '';
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
make: function() {
|
||||
// chart wrapper
|
||||
this.chart_area = $('<div class="chart" style="padding-bottom: 1px"></div>').appendTo(this.wrapper);
|
||||
|
||||
this.page.add_menu_item(__("Export"), () => this.export(), true);
|
||||
|
||||
// grid wrapper
|
||||
this.grid_wrapper = $("<div style='height: 500px;'>")
|
||||
.appendTo(this.wrapper);
|
||||
this.id = frappe.dom.set_unique_id(this.grid_wrapper.get(0));
|
||||
|
||||
this.bind_show();
|
||||
|
||||
frappe.cur_grid_report = this;
|
||||
$(this.wrapper).trigger('make');
|
||||
|
||||
},
|
||||
apply_filters_from_route: function() {
|
||||
var me = this;
|
||||
if(frappe.route_options) {
|
||||
$.each(frappe.route_options, function(key, value) {
|
||||
me.set_filter(key, value);
|
||||
});
|
||||
frappe.route_options = null;
|
||||
} else {
|
||||
this.init_filter_values();
|
||||
}
|
||||
this.set_default_values();
|
||||
|
||||
$(this.wrapper).trigger('apply_filters_from_route');
|
||||
},
|
||||
options: {
|
||||
editable: false,
|
||||
enableColumnReorder: false
|
||||
},
|
||||
render: function() {
|
||||
this.datatable = new DataTable('#' + this.id, {
|
||||
columns: this.datatable_columns,
|
||||
data: this.data,
|
||||
layout: 'fixed',
|
||||
inlineFilters: true,
|
||||
treeView: true,
|
||||
checkboxColumn: true,
|
||||
checkedRowStatus: false,
|
||||
events: {
|
||||
onCheckRow: (row) => {
|
||||
const rowIndex = row.meta.rowIndex;
|
||||
const checked = this.datatable.rowmanager.checkMap[rowIndex];
|
||||
const data = this.datatable.datamanager.getData(rowIndex);
|
||||
data.checked = Boolean(checked);
|
||||
|
||||
this.setup_chart && this.setup_chart();
|
||||
}
|
||||
},
|
||||
hooks: {
|
||||
columnTotal: frappe.utils.report_column_total
|
||||
}
|
||||
});
|
||||
|
||||
this.data.forEach((d, i) => {
|
||||
if (d.checked) {
|
||||
this.datatable.rowmanager.checkRow(i, true);
|
||||
}
|
||||
});
|
||||
},
|
||||
prepare_data_view: function() {
|
||||
},
|
||||
export: function() {
|
||||
frappe.tools.downloadify(frappe.slickgrid_tools.get_view_data(this.columns, this.dataView),
|
||||
["Report Manager", "System Manager"], this.title);
|
||||
return 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 (var 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<j; i++) {
|
||||
var col = me.columns[i];
|
||||
if(col.formatter==me.currency_formatter && !col.hidden) {
|
||||
if(flt(item[col.field]) > 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) {
|
||||
return frappe.datetime.str_to_user(value);
|
||||
},
|
||||
currency_formatter: function(row, cell, value, columnDef, dataContext) {
|
||||
if (isNaN(value)) value = '';
|
||||
return repl('<div style="text-align: right; %(_style)s">%(value)s</div>', {
|
||||
_style: dataContext._style || "",
|
||||
value: ((value==null || value==="") ? "" : format_number(value))
|
||||
});
|
||||
},
|
||||
text_formatter: function(row, cell, value, columnDef, dataContext) {
|
||||
return repl('<span style="%(_style)s" title="%(esc_value)s">%(value)s</span>', {
|
||||
_style: dataContext._style || "",
|
||||
esc_value: cstr(value).replace(/"/g, '\\"'),
|
||||
value: cstr(value)
|
||||
});
|
||||
},
|
||||
check_formatter: function(row, cell, value, columnDef, dataContext) {
|
||||
return repl('<input type="checkbox" data-id="%(id)s" \
|
||||
class="chart-check" %(checked)s>', {
|
||||
"id": dataContext.id,
|
||||
"checked": dataContext.checked ? 'checked="checked"' : ""
|
||||
});
|
||||
},
|
||||
apply_link_formatters: function() {
|
||||
$.each(this.columns, function(i, col) {
|
||||
if(col.link_formatter) {
|
||||
col.formatter = function(row, cell, value, columnDef, dataContext, for_print) {
|
||||
// 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(for_print) {
|
||||
return value;
|
||||
}
|
||||
|
||||
var me = frappe.cur_grid_report;
|
||||
|
||||
if(dataContext._show) {
|
||||
return repl('<span style="%(_style)s">%(value)s</span>', {
|
||||
_style: dataContext._style || "",
|
||||
value: value
|
||||
});
|
||||
}
|
||||
|
||||
// make link to add a filter
|
||||
var html;
|
||||
var link_formatter = me.dataview_columns[cell].link_formatter;
|
||||
if (link_formatter.filter_input) {
|
||||
html = repl('<a href="#" \
|
||||
onclick="frappe.cur_grid_report.set_filter(\'%(col_name)s\', \'%(value)s\'); \
|
||||
frappe.cur_grid_report.refresh(); return false;">\
|
||||
%(value)s</a>', {
|
||||
value: value,
|
||||
col_name: link_formatter.filter_input,
|
||||
page_name: frappe.container.page.page_name
|
||||
});
|
||||
} else {
|
||||
html = value;
|
||||
}
|
||||
|
||||
// make icon to open form
|
||||
if(link_formatter.open_btn) {
|
||||
var doctype = link_formatter.doctype
|
||||
? eval(link_formatter.doctype)
|
||||
: dataContext.doctype;
|
||||
html += me.get_link_open_icon(doctype, value);
|
||||
}
|
||||
return html;
|
||||
};
|
||||
}
|
||||
});
|
||||
},
|
||||
get_link_open_icon: function(doctype, name) {
|
||||
return repl(' <a href="#Form/%(doctype)s/%(name)s">\
|
||||
<i class="fa fa-share" style="cursor: pointer;"></i></a>', {
|
||||
doctype: doctype,
|
||||
name: encodeURIComponent(name)
|
||||
});
|
||||
},
|
||||
make_date_range_columns: function() {
|
||||
this.columns = [];
|
||||
|
||||
var me = this;
|
||||
var range = this.filter_inputs.range.val();
|
||||
this.from_date = frappe.datetime.user_to_str(this.filter_inputs.from_date.val());
|
||||
this.to_date = frappe.datetime.user_to_str(this.filter_inputs.to_date.val());
|
||||
var date_diff = frappe.datetime.get_diff(this.to_date, this.from_date);
|
||||
|
||||
me.column_map = {};
|
||||
me.last_date = null;
|
||||
|
||||
var add_column = function(date) {
|
||||
me.columns.push({
|
||||
id: date,
|
||||
name: frappe.datetime.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 = frappe.datetime.add_days(me.from_date, i);
|
||||
if(!condition) condition = () => 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 !(frappe.datetime.get_diff(date, me.from_date) % 7);
|
||||
});
|
||||
} else if(range=='Monthly') {
|
||||
build_columns(function(date) {
|
||||
if(!me.last_date) return true;
|
||||
return frappe.datetime.str_to_obj(me.last_date).getMonth() != frappe.datetime.str_to_obj(date).getMonth();
|
||||
});
|
||||
} else if(range=='Quarterly') {
|
||||
build_columns(function(date) {
|
||||
if(!me.last_date) return true;
|
||||
return frappe.datetime.str_to_obj(date).getDate()==1 && in_list([0,3,6,9], frappe.datetime.str_to_obj(date).getMonth());
|
||||
});
|
||||
} else if(range=='Yearly') {
|
||||
build_columns(function(date) {
|
||||
if(!me.last_date) return true;
|
||||
return $.map(frappe.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]
|
||||
? frappe.datetime.str_to_user(frappe.datetime.add_days(me.columns[i+1].id, -1))
|
||||
: frappe.datetime.str_to_user(me.to_date);
|
||||
});
|
||||
},
|
||||
trigger_refresh_on_change: function(filters) {
|
||||
var me = this;
|
||||
$.each(filters, function(i, f) {
|
||||
me.filter_inputs[f] && me.filter_inputs[f].on("change", function() {
|
||||
me.refresh();
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
frappe.views.GridReportWithPlot = frappe.views.GridReport.extend({
|
||||
setup_chart: function() {
|
||||
if (in_list(["Daily", "Weekly"], this.filter_inputs.range.val())) {
|
||||
this.chart_area.toggle(false);
|
||||
return;
|
||||
} else {
|
||||
this.chart_area.toggle(true);
|
||||
}
|
||||
var chart_data = this.get_chart_data ? this.get_chart_data() : null;
|
||||
|
||||
const parent = this.wrapper.find('.chart')[0];
|
||||
this.chart = new Chart(parent, {
|
||||
height: 200,
|
||||
data: chart_data,
|
||||
type: 'line'
|
||||
});
|
||||
},
|
||||
|
||||
get_chart_data: function() {
|
||||
var me = this;
|
||||
var plottable_cols = [];
|
||||
$.each(me.columns, function(idx, col) {
|
||||
if(col.formatter==me.currency_formatter && !col.hidden && col.plot!==false) {
|
||||
plottable_cols.push(col.field);
|
||||
}
|
||||
});
|
||||
|
||||
var data = {
|
||||
labels: plottable_cols,
|
||||
datasets: []
|
||||
};
|
||||
|
||||
$.each(this.data, function(i, item) {
|
||||
if (item.checked) {
|
||||
let dataset = {};
|
||||
dataset.name = item.name;
|
||||
dataset.values = [];
|
||||
$.each(plottable_cols, function(idx, col) {
|
||||
dataset.values.push(item[col]);
|
||||
});
|
||||
data["datasets"].push(dataset);
|
||||
}
|
||||
});
|
||||
return data;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
frappe.views.TreeGridReport = frappe.views.GridReportWithPlot.extend({
|
||||
make_transaction_list: function(parent_doctype, doctype) {
|
||||
var me = this;
|
||||
var tmap = {};
|
||||
$.each(frappe.report_dump.data[doctype], function(i, v) {
|
||||
if(!tmap[v.parent]) tmap[v.parent] = [];
|
||||
tmap[v.parent].push(v);
|
||||
});
|
||||
if (!this.tl) this.tl = {};
|
||||
if (!this.tl[parent_doctype]) this.tl[parent_doctype] = [];
|
||||
|
||||
$.each(frappe.report_dump.data[parent_doctype], function(i, parent) {
|
||||
if(tmap[parent.name]) {
|
||||
$.each(tmap[parent.name], function(i, d) {
|
||||
me.tl[parent_doctype].push($.extend(copy_dict(parent), d));
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
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 = frappe.cur_grid_report;
|
||||
var data = me.data;
|
||||
var spacer = "<span style='display:inline-block;height:1px;width:" +
|
||||
(15 * dataContext["indent"]) + "px'></span>";
|
||||
var idx = me.dataView.getIdxById(dataContext.id);
|
||||
var link = me.tree_grid.formatter(dataContext);
|
||||
|
||||
if(dataContext.doctype) {
|
||||
link += me.get_link_open_icon(dataContext.doctype, dataContext.name);
|
||||
}
|
||||
|
||||
if (data[idx + 1] && data[idx + 1].indent > data[idx].indent) {
|
||||
if (dataContext._collapsed) {
|
||||
return spacer + " <span class='toggle expand'></span> " + link;
|
||||
} else {
|
||||
return spacer + " <span class='toggle collapse'></span> " + link;
|
||||
}
|
||||
} else {
|
||||
return spacer + " <span class='toggle'></span> " + link;
|
||||
}
|
||||
},
|
||||
tree_dataview_filter: function(item) {
|
||||
var me = frappe.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;
|
||||
},
|
||||
prepare_tree: function(item_dt, group_dt) {
|
||||
var group_data = frappe.report_dump.data[group_dt];
|
||||
var item_data = frappe.report_dump.data[item_dt];
|
||||
|
||||
// prepare map with child in respective group
|
||||
var me = this;
|
||||
var item_group_map = {};
|
||||
var group_ids = group_data.map(v => v.id);
|
||||
|
||||
$.each(item_data, function(i, item) {
|
||||
var parent = item[me.tree_grid.parent_field];
|
||||
if(!item_group_map[parent]) item_group_map[parent] = [];
|
||||
if(group_ids.indexOf(item.name)==-1) {
|
||||
item_group_map[parent].push(item);
|
||||
} else {
|
||||
frappe.msgprint(__("Ignoring Item {0}, because a group exists with the same name!", [item.name.bold()]));
|
||||
}
|
||||
});
|
||||
|
||||
// arrange items besides their parent item groups
|
||||
var items = [];
|
||||
$.each(group_data, function(i, group){
|
||||
group.is_group = true;
|
||||
items.push(group);
|
||||
items = items.concat(item_group_map[group.name] || []);
|
||||
});
|
||||
return items;
|
||||
},
|
||||
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;
|
||||
});
|
||||
},
|
||||
|
||||
export: function() {
|
||||
var msgbox = frappe.msgprint($.format('<p>{0}</p>\
|
||||
<p><input type="checkbox" name="with_groups" checked="checked"> {1}</p>\
|
||||
<p><input type="checkbox" name="with_ledgers" checked="checked"> {2}</p>\
|
||||
<p><button class="btn btn-primary"> {3}</button>', [
|
||||
__('Select To Download:'),
|
||||
__('With Groups'),
|
||||
__('With Ledgers'),
|
||||
__('Download')
|
||||
]));
|
||||
|
||||
var me = this;
|
||||
|
||||
$(msgbox.body).find("button").click(function() {
|
||||
var with_groups = $(msgbox.body).find("[name='with_groups']").prop("checked");
|
||||
var with_ledgers = $(msgbox.body).find("[name='with_ledgers']").prop("checked");
|
||||
|
||||
var data = frappe.slickgrid_tools.get_view_data(me.columns, me.data,
|
||||
function(row, item) {
|
||||
if(with_groups) {
|
||||
// add row
|
||||
for(var i=0; i<item.indent; i++) row[0] = " " + row[0];
|
||||
}
|
||||
if(with_groups && (item.is_group == 1 || item.is_group)) {
|
||||
return true;
|
||||
}
|
||||
if(with_ledgers && (item.is_group != 1 && !item.is_group)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
frappe.tools.downloadify(data, ["Report Manager", "System Manager"], me.title);
|
||||
return false;
|
||||
});
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
});
|
||||
|
|
@ -1,950 +0,0 @@
|
|||
// Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
||||
// MIT License. See license.txt
|
||||
|
||||
frappe.views.ReportFactory = frappe.views.Factory.extend({
|
||||
make: function(route) {
|
||||
new frappe.views.ReportViewPage(route[1], route[2]);
|
||||
}
|
||||
});
|
||||
|
||||
frappe.views.ReportViewPage = Class.extend({
|
||||
init: function(doctype, docname) {
|
||||
if(!frappe.model.can_get_report(doctype)) {
|
||||
frappe.show_not_permitted(frappe.get_route_str());
|
||||
return;
|
||||
}
|
||||
|
||||
this.doctype = doctype;
|
||||
this.docname = docname;
|
||||
this.page_name = frappe.get_route_str();
|
||||
this.make_page();
|
||||
|
||||
var me = this;
|
||||
frappe.model.with_doctype(this.doctype, function() {
|
||||
me.make_report_view();
|
||||
if(me.docname) {
|
||||
frappe.model.with_doc('Report', me.docname, function(r) {
|
||||
me.parent.reportview.set_columns_and_filters(
|
||||
JSON.parse(frappe.get_doc("Report", me.docname).json || '{}'));
|
||||
me.parent.reportview.set_route_filters();
|
||||
me.parent.reportview.run();
|
||||
});
|
||||
} else {
|
||||
me.parent.reportview.set_route_filters();
|
||||
me.parent.reportview.run();
|
||||
}
|
||||
});
|
||||
},
|
||||
make_page: function() {
|
||||
var me = this;
|
||||
this.parent = frappe.container.add_page(this.page_name);
|
||||
frappe.ui.make_app_page({parent:this.parent, single_column:true});
|
||||
this.page = this.parent.page;
|
||||
|
||||
frappe.container.change_to(this.page_name);
|
||||
|
||||
$(this.parent).on('show', function(){
|
||||
if(me.parent.reportview.set_route_filters()) {
|
||||
me.parent.reportview.run();
|
||||
}
|
||||
});
|
||||
},
|
||||
make_report_view: function() {
|
||||
this.page.set_title(__(this.doctype));
|
||||
var module = locals.DocType[this.doctype].module;
|
||||
frappe.breadcrumbs.add(module, this.doctype);
|
||||
|
||||
this.parent.reportview = new frappe.views.ReportView({
|
||||
doctype: this.doctype,
|
||||
docname: this.docname,
|
||||
parent: this.parent
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
frappe.views.ReportView = frappe.ui.BaseList.extend({
|
||||
init: function(opts) {
|
||||
var me = this;
|
||||
$.extend(this, opts);
|
||||
this.can_delete = frappe.model.can_delete(me.doctype);
|
||||
this.tab_name = '`tab'+this.doctype+'`';
|
||||
this.setup();
|
||||
},
|
||||
|
||||
setup: function() {
|
||||
var me = this;
|
||||
|
||||
this.add_totals_row = 0;
|
||||
this.page = this.parent.page;
|
||||
this.meta = frappe.get_meta(this.doctype);
|
||||
this._body = $('<div>').appendTo(this.page.main);
|
||||
this.page_title = __('Report')+ ': ' + (this.docname ?
|
||||
__(this.doctype) + ' - ' + __(this.docname) : __(this.doctype));
|
||||
this.page.set_title(this.page_title);
|
||||
this.init_user_settings();
|
||||
this.make({
|
||||
page: this.parent.page,
|
||||
method: 'frappe.desk.reportview.get',
|
||||
save_user_settings: true,
|
||||
get_args: this.get_args,
|
||||
parent: this._body,
|
||||
start: 0,
|
||||
show_filters: true,
|
||||
allow_delete: true,
|
||||
});
|
||||
|
||||
this.make_new_and_refresh();
|
||||
this.make_delete();
|
||||
this.make_column_picker();
|
||||
this.make_sorter();
|
||||
this.make_totals_row_button();
|
||||
this.setup_print();
|
||||
this.make_export();
|
||||
this.setup_auto_email();
|
||||
this.set_init_columns();
|
||||
this.make_save();
|
||||
this.make_user_permissions();
|
||||
this.set_tag_and_status_filter();
|
||||
this.setup_listview_settings();
|
||||
|
||||
},
|
||||
|
||||
make_new_and_refresh: function() {
|
||||
var me = this;
|
||||
this.page.set_primary_action(__("Refresh"), function() {
|
||||
me.run();
|
||||
});
|
||||
|
||||
this.page.add_menu_item(__("New {0}", [this.doctype]), function() {
|
||||
me.make_new_doc(me.doctype);
|
||||
}, true);
|
||||
|
||||
},
|
||||
|
||||
setup_auto_email: function() {
|
||||
var me = this;
|
||||
this.page.add_menu_item(__("Setup Auto Email"), function() {
|
||||
if(me.docname) {
|
||||
frappe.set_route('List', 'Auto Email Report', {'report' : me.docname});
|
||||
} else {
|
||||
frappe.msgprint({message:__('Please save the report first'), indicator: 'red'});
|
||||
}
|
||||
}, true);
|
||||
},
|
||||
|
||||
set_init_columns: function() {
|
||||
// pre-select mandatory columns
|
||||
var me = this;
|
||||
var columns = [];
|
||||
if(this.user_settings.fields && !this.docname) {
|
||||
this.user_settings.fields.forEach(function(field) {
|
||||
var coldef = me.get_column_info_from_field(field);
|
||||
if(!in_list(['_seen', '_comments', '_user_tags', '_assign', '_liked_by', 'docstatus'], coldef[0])) {
|
||||
columns.push(coldef);
|
||||
}
|
||||
});
|
||||
}
|
||||
if(!columns.length) {
|
||||
var columns = [['name', this.doctype],];
|
||||
$.each(frappe.meta.docfield_list[this.doctype], function(i, df) {
|
||||
if((df.in_standard_filter || df.in_list_view) && df.fieldname!='naming_series'
|
||||
&& !in_list(frappe.model.no_value_type, df.fieldtype)
|
||||
&& !df.report_hide) {
|
||||
columns.push([df.fieldname, df.parent]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.set_columns(columns);
|
||||
|
||||
this.page.footer.on('click', '.show-all-data', function() {
|
||||
me.show_all_data = $(this).prop('checked');
|
||||
me.run();
|
||||
})
|
||||
},
|
||||
|
||||
set_columns: function(columns) {
|
||||
this.columns = columns;
|
||||
this.column_info = this.get_columns();
|
||||
this.refresh_footer();
|
||||
},
|
||||
|
||||
refresh_footer: function() {
|
||||
var can_write = frappe.model.can_write(this.doctype);
|
||||
var has_child_column = this.has_child_column();
|
||||
|
||||
this.page.footer.empty();
|
||||
|
||||
if(can_write || has_child_column) {
|
||||
$(frappe.render_template('reportview_footer', {
|
||||
has_child_column: has_child_column,
|
||||
can_write: can_write,
|
||||
show_all_data: this.show_all_data
|
||||
})).appendTo(this.page.footer);
|
||||
this.page.footer.removeClass('hide');
|
||||
} else {
|
||||
this.page.footer.addClass('hide');
|
||||
}
|
||||
},
|
||||
|
||||
// preset columns and filters from saved info
|
||||
set_columns_and_filters: function(opts) {
|
||||
var me = this;
|
||||
this.filter_list.clear_filters();
|
||||
if(opts.columns) {
|
||||
this.set_columns(opts.columns);
|
||||
}
|
||||
if(opts.filters) {
|
||||
$.each(opts.filters, function(i, f) {
|
||||
// f = [doctype, fieldname, condition, value]
|
||||
var df = frappe.meta.get_docfield(f[0], f[1]);
|
||||
if (df && df.fieldtype == "Check") {
|
||||
var value = f[3] ? "Yes" : "No";
|
||||
} else {
|
||||
var value = f[3];
|
||||
}
|
||||
me.filter_list.add_filter(f[0], f[1], f[2], value);
|
||||
});
|
||||
}
|
||||
|
||||
if(opts.add_total_row) {
|
||||
this.add_total_row = opts.add_total_row
|
||||
}
|
||||
|
||||
// first sort
|
||||
if(opts.sort_by) this.sort_by_select.val(opts.sort_by);
|
||||
if(opts.sort_order) this.sort_order_select.val(opts.sort_order);
|
||||
|
||||
// second sort
|
||||
if(opts.sort_by_next) this.sort_by_next_select.val(opts.sort_by_next);
|
||||
if(opts.sort_order_next) this.sort_order_next_select.val(opts.sort_order_next);
|
||||
|
||||
this.add_totals_row = cint(opts.add_totals_row);
|
||||
},
|
||||
|
||||
set_route_filters: function() {
|
||||
var me = this;
|
||||
if(frappe.route_options) {
|
||||
this.set_filters_from_route_options({clear_filters: this.docname ? false : true});
|
||||
return true;
|
||||
} else if(this.user_settings
|
||||
&& this.user_settings.filters
|
||||
&& !this.docname
|
||||
&& (this.user_settings.updated_on != this.user_settings_updated_on)) {
|
||||
// list settings (previous settings)
|
||||
this.filter_list.clear_filters();
|
||||
$.each(this.user_settings.filters, function(i, f) {
|
||||
me.filter_list.add_filter(f[0], f[1], f[2], f[3]);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
this.user_settings_updated_on = this.user_settings.updated_on;
|
||||
},
|
||||
|
||||
setup_print: function() {
|
||||
var me = this;
|
||||
this.page.add_menu_item(__("Print"), function() {
|
||||
frappe.ui.get_print_settings(false, function(print_settings) {
|
||||
var title = __(me.docname || me.doctype);
|
||||
frappe.render_grid({grid:me.grid, title:title, print_settings:print_settings});
|
||||
})
|
||||
|
||||
}, true);
|
||||
},
|
||||
|
||||
// build args for query
|
||||
get_args: function() {
|
||||
let me = this;
|
||||
let filters = this.filter_list? this.filter_list.get_filters(): [];
|
||||
|
||||
return {
|
||||
doctype: this.doctype,
|
||||
fields: $.map(this.columns || [], function(v) {
|
||||
return me.get_full_column_name(v);
|
||||
}),
|
||||
order_by: this.get_order_by(),
|
||||
add_total_row: this.add_total_row,
|
||||
filters: filters,
|
||||
save_user_settings_fields: 1,
|
||||
with_childnames: 1,
|
||||
file_format_type: this.file_format_type
|
||||
}
|
||||
},
|
||||
|
||||
get_order_by: function() {
|
||||
var order_by = [];
|
||||
|
||||
// first
|
||||
var sort_by_select = this.get_selected_table_and_column(this.sort_by_select);
|
||||
if (sort_by_select) {
|
||||
order_by.push(sort_by_select + " " + this.sort_order_select.val());
|
||||
}
|
||||
|
||||
// second
|
||||
if(this.sort_by_next_select && this.sort_by_next_select.val()) {
|
||||
order_by.push(this.get_selected_table_and_column(this.sort_by_next_select)
|
||||
+ ' ' + this.sort_order_next_select.val());
|
||||
}
|
||||
|
||||
return order_by.join(", ");
|
||||
},
|
||||
|
||||
get_selected_table_and_column: function(select) {
|
||||
if(!select) {
|
||||
return
|
||||
}
|
||||
|
||||
return select.selected_doctype ?
|
||||
this.get_full_column_name([select.selected_fieldname, select.selected_doctype]) : "";
|
||||
},
|
||||
|
||||
// get table_name.column_name
|
||||
get_full_column_name: function(v) {
|
||||
if(!v) return;
|
||||
return (v[1] ? ('`tab' + v[1] + '`') : this.tab_name) + '.`' + v[0] + '`';
|
||||
},
|
||||
|
||||
get_column_info_from_field: function(t) {
|
||||
if(t.indexOf('.')===-1) {
|
||||
return [strip(t, '`'), this.doctype];
|
||||
} else {
|
||||
var parts = t.split('.');
|
||||
return [strip(parts[1], '`'), strip(parts[0], '`').substr(3)];
|
||||
}
|
||||
},
|
||||
|
||||
// build columns for slickgrid
|
||||
build_columns: function() {
|
||||
var me = this;
|
||||
return $.map(this.columns, function(c) {
|
||||
var docfield = frappe.meta.docfield_map[c[1] || me.doctype][c[0]];
|
||||
if(!docfield) {
|
||||
var docfield = frappe.model.get_std_field(c[0]);
|
||||
if(docfield) {
|
||||
docfield.parent = me.doctype;
|
||||
if(c[0]=="name") {
|
||||
docfield.options = me.doctype;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!docfield) return;
|
||||
|
||||
let coldef = {
|
||||
id: c[0],
|
||||
field: c[0],
|
||||
docfield: docfield,
|
||||
name: __(docfield ? docfield.label : toTitle(c[0])),
|
||||
width: (docfield ? cint(docfield.width) : 120) || 120,
|
||||
formatter: function(row, cell, value, columnDef, dataContext, for_print) {
|
||||
var docfield = columnDef.docfield;
|
||||
docfield.fieldtype = {
|
||||
"_user_tags": "Tag",
|
||||
"_comments": "Comment",
|
||||
"_assign": "Assign",
|
||||
"_liked_by": "LikedBy",
|
||||
}[docfield.fieldname] || docfield.fieldtype;
|
||||
|
||||
if(docfield.fieldtype==="Link" && docfield.fieldname!=="name") {
|
||||
|
||||
// make a copy of docfield for reportview
|
||||
// as it needs to add a link_onclick property
|
||||
if(!columnDef.report_docfield) {
|
||||
columnDef.report_docfield = copy_dict(docfield);
|
||||
}
|
||||
docfield = columnDef.report_docfield;
|
||||
|
||||
docfield.link_onclick =
|
||||
repl('frappe.container.page.reportview.filter_or_open("%(parent)s", "%(fieldname)s", "%(value)s")',
|
||||
{parent: docfield.parent, fieldname:docfield.fieldname, value:value});
|
||||
}
|
||||
return frappe.format(value, docfield, {for_print: for_print, always_show_decimals: true}, dataContext);
|
||||
}
|
||||
}
|
||||
return coldef;
|
||||
});
|
||||
},
|
||||
|
||||
filter_or_open: function(parent, fieldname, value) {
|
||||
// set filter on click, if filter is set, open the document
|
||||
var filter_set = false;
|
||||
this.filter_list.get_filters().forEach(function(f) {
|
||||
if(f[1]===fieldname) {
|
||||
filter_set = true;
|
||||
}
|
||||
});
|
||||
|
||||
if(!filter_set) {
|
||||
this.set_filter(fieldname, value, false, false, parent);
|
||||
} else {
|
||||
var df = frappe.meta.get_docfield(parent, fieldname);
|
||||
if(df.fieldtype==='Link') {
|
||||
frappe.set_route('Form', df.options, value);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// render data
|
||||
render_view: function() {
|
||||
var me = this;
|
||||
var data = this.get_unique_data(this.column_info);
|
||||
|
||||
this.set_totals_row(data, this.column_info);
|
||||
|
||||
// add sr in data
|
||||
$.each(data, function(i, v) {
|
||||
// add index
|
||||
v._idx = i+1;
|
||||
v.id = v._idx;
|
||||
});
|
||||
|
||||
var options = {
|
||||
enableCellNavigation: true,
|
||||
enableColumnReorder: false,
|
||||
};
|
||||
|
||||
if(this.slickgrid_options) {
|
||||
$.extend(options, this.slickgrid_options);
|
||||
}
|
||||
|
||||
this.dataView = new Slick.Data.DataView();
|
||||
this.set_data(data);
|
||||
|
||||
var grid_wrapper = this.wrapper.find('.result-list').addClass("slick-wrapper");
|
||||
|
||||
// set height if not auto
|
||||
if(!options.autoHeight)
|
||||
grid_wrapper.css('height', '500px');
|
||||
|
||||
this.grid = new Slick.Grid(grid_wrapper
|
||||
.get(0), this.dataView,
|
||||
this.column_info, options);
|
||||
|
||||
if (!frappe.dom.is_touchscreen()) {
|
||||
this.grid.setSelectionModel(new Slick.CellSelectionModel());
|
||||
this.grid.registerPlugin(new Slick.CellExternalCopyManager({
|
||||
dataItemColumnValueExtractor: function(item, columnDef, value) {
|
||||
return item[columnDef.field];
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
frappe.slickgrid_tools.add_property_setter_on_resize(this.grid);
|
||||
if(this.start!=0 && !options.autoHeight) {
|
||||
this.grid.scrollRowIntoView(data.length-1);
|
||||
}
|
||||
|
||||
this.grid.onDblClick.subscribe(function(e, args) {
|
||||
var row = me.dataView.getItem(args.row);
|
||||
var cell = me.grid.getColumns()[args.cell];
|
||||
me.edit_cell(row, cell.docfield);
|
||||
});
|
||||
|
||||
this.dataView.onRowsChanged.subscribe(function (e, args) {
|
||||
me.grid.invalidateRows(args.rows);
|
||||
me.grid.render();
|
||||
});
|
||||
|
||||
this.grid.onHeaderClick.subscribe(function(e, args) {
|
||||
if(e.target.className === "slick-resizable-handle")
|
||||
return;
|
||||
|
||||
|
||||
var df = args.column.docfield,
|
||||
sort_by = df.parent + "." + df.fieldname;
|
||||
|
||||
if(sort_by===me.sort_by_select.val()) {
|
||||
me.sort_order_select.val(me.sort_order_select.val()==="asc" ? "desc" : "asc");
|
||||
} else {
|
||||
me.sort_by_select.val(df.parent + "." + df.fieldname);
|
||||
me.sort_order_select.val("asc");
|
||||
}
|
||||
|
||||
me.run();
|
||||
});
|
||||
},
|
||||
|
||||
has_child_column: function() {
|
||||
var me = this;
|
||||
return this.column_info.some(function(c) {
|
||||
return c.docfield && c.docfield.parent !== me.doctype;
|
||||
});
|
||||
},
|
||||
|
||||
get_unique_data: function(columns) {
|
||||
// if child columns are selected, show parent data only once
|
||||
let has_child_column = this.has_child_column();
|
||||
|
||||
var data = [], prev_row = null;
|
||||
this.data.forEach((d) => {
|
||||
if (this.show_all_data || !has_child_column) {
|
||||
data.push(d);
|
||||
} else if (prev_row && d.name == prev_row.name) {
|
||||
var new_row = {};
|
||||
columns.forEach((c) => {
|
||||
if(!c.docfield || c.docfield.parent!==this.doctype) {
|
||||
var val = d[c.field];
|
||||
// add child table row name for update
|
||||
if(c.docfield && c.docfield.parent!==this.doctype) {
|
||||
new_row[c.docfield.parent+":name"] = d[c.docfield.parent+":name"];
|
||||
}
|
||||
} else {
|
||||
var val = '';
|
||||
new_row.__is_repeat = true;
|
||||
}
|
||||
new_row[c.field] = val;
|
||||
});
|
||||
data.push(new_row);
|
||||
} else {
|
||||
data.push(d);
|
||||
}
|
||||
prev_row = d;
|
||||
});
|
||||
return data;
|
||||
},
|
||||
|
||||
edit_cell: function(row, docfield) {
|
||||
if(!docfield || docfield.fieldname !== "idx"
|
||||
&& frappe.model.std_fields_list.indexOf(docfield.fieldname)!==-1) {
|
||||
return;
|
||||
} else if(frappe.boot.user.can_write.indexOf(this.doctype)===-1) {
|
||||
frappe.throw({message:__("No permission to edit"), title:__('Not Permitted')});
|
||||
}
|
||||
var me = this;
|
||||
var d = new frappe.ui.Dialog({
|
||||
title: __("Edit") + " " + __(docfield.label),
|
||||
fields: [docfield],
|
||||
primary_action_label: __("Update"),
|
||||
primary_action: function() {
|
||||
me.update_value(docfield, d, row);
|
||||
}
|
||||
});
|
||||
d.set_input(docfield.fieldname, row[docfield.fieldname]);
|
||||
|
||||
// Show dialog if field is editable and not hidden
|
||||
if (d.fields_list[0].disp_status != "Write") d.hide();
|
||||
else d.show();
|
||||
},
|
||||
|
||||
update_value: function(docfield, dialog, row) {
|
||||
// update value on the serverside
|
||||
var me = this;
|
||||
var args = {
|
||||
doctype: docfield.parent,
|
||||
name: row[docfield.parent===me.doctype ? "name" : docfield.parent+":name"],
|
||||
fieldname: docfield.fieldname,
|
||||
value: dialog.get_value(docfield.fieldname)
|
||||
};
|
||||
|
||||
if (!args.name) {
|
||||
frappe.throw(__("ID field is required to edit values using Report. Please select the ID field using the Column Picker"));
|
||||
}
|
||||
|
||||
frappe.call({
|
||||
method: "frappe.client.set_value",
|
||||
args: args,
|
||||
callback: function(r) {
|
||||
if(!r.exc) {
|
||||
dialog.hide();
|
||||
var doc = r.message;
|
||||
$.each(me.dataView.getItems(), function(i, item) {
|
||||
if (item.name === doc.name) {
|
||||
var new_item = $.extend({}, item);
|
||||
$.each(frappe.model.get_all_docs(doc), function(i, d) {
|
||||
// find the document of the current updated record
|
||||
// from locals (which is synced in the response)
|
||||
var name = item[d.doctype + ":name"];
|
||||
if(!name) name = item.name;
|
||||
|
||||
if(name===d.name) {
|
||||
for(var k in d) {
|
||||
var v = d[k];
|
||||
if(frappe.model.std_fields_list.indexOf(k)===-1
|
||||
&& item[k]!==undefined) {
|
||||
new_item[k] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
me.dataView.updateItem(item.id, new_item);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
set_data: function(data) {
|
||||
this.dataView.beginUpdate();
|
||||
this.dataView.setItems(data);
|
||||
this.dataView.endUpdate();
|
||||
},
|
||||
|
||||
get_columns: function() {
|
||||
var std_columns = [{id:'_idx', field:'_idx', name: 'Sr.', width: 40, maxWidth: 40}];
|
||||
if(this.can_delete) {
|
||||
std_columns = std_columns.concat([{
|
||||
id:'_check', field:'_check', name: "", width: 30, maxWidth: 30,
|
||||
formatter: function(row, cell, value, columnDef, dataContext) {
|
||||
return repl("<input type='checkbox' \
|
||||
data-row='%(row)s' %(checked)s>", {
|
||||
row: row,
|
||||
checked: (dataContext.selected ? "checked=\"checked\"" : "")
|
||||
});
|
||||
}
|
||||
}]);
|
||||
}
|
||||
return std_columns.concat(this.build_columns());
|
||||
},
|
||||
|
||||
// setup column picker
|
||||
make_column_picker: function() {
|
||||
var me = this;
|
||||
this.column_picker = new frappe.ui.ColumnPicker(this);
|
||||
this.page.add_inner_button(__('Pick Columns'), function() {
|
||||
me.column_picker.show(me.columns);
|
||||
});
|
||||
},
|
||||
|
||||
make_totals_row_button: function() {
|
||||
var me = this;
|
||||
|
||||
this.page.add_inner_button(__('Show Totals'), function() {
|
||||
me.add_totals_row = !!!me.add_totals_row;
|
||||
me.render_view();
|
||||
});
|
||||
},
|
||||
|
||||
set_totals_row: function(data, columns) {
|
||||
const field_map = {};
|
||||
const numeric_fieldtypes = ['Int', 'Currency', 'Float'];
|
||||
columns.forEach(function(row) {
|
||||
if (row.docfield) {
|
||||
let r = row.docfield;
|
||||
if (numeric_fieldtypes.includes(r.fieldtype)) {
|
||||
field_map[r.fieldname] = [r.fieldtype];
|
||||
}
|
||||
}
|
||||
})
|
||||
if(this.add_totals_row) {
|
||||
var totals_row = {_totals_row: 1};
|
||||
if(data.length) {
|
||||
data.forEach(function(row, ri) {
|
||||
$.each(row, function(key, value) {
|
||||
if (key in field_map) {
|
||||
totals_row[key] = (totals_row[key] || 0) + (value || 0);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
data.push(totals_row);
|
||||
}
|
||||
},
|
||||
|
||||
set_tag_and_status_filter: function() {
|
||||
var me = this;
|
||||
this.wrapper.find('.result-list').on("click", ".label-info", function() {
|
||||
if($(this).attr("data-label")) {
|
||||
me.set_filter("_user_tags", $(this).attr("data-label"));
|
||||
}
|
||||
});
|
||||
this.wrapper.find('.result-list').on("click", "[data-workflow-state]", function() {
|
||||
if($(this).attr("data-workflow-state")) {
|
||||
me.set_filter(me.state_fieldname,
|
||||
$(this).attr("data-workflow-state"));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// setup sorter
|
||||
make_sorter: function() {
|
||||
var me = this;
|
||||
this.sort_dialog = new frappe.ui.Dialog({title:__('Sorting Preferences')});
|
||||
$(this.sort_dialog.body).html('<p class="help">'+__('Sort By')+'</p>\
|
||||
<div class="sort-column"></div>\
|
||||
<div><select class="sort-order form-control" style="margin-top: 10px; width: 60%;">\
|
||||
<option value="asc">'+__('Ascending')+'</option>\
|
||||
<option value="desc">'+__('Descending')+'</option>\
|
||||
</select></div>\
|
||||
<hr><p class="help">'+__('Then By (optional)')+'</p>\
|
||||
<div class="sort-column-1"></div>\
|
||||
<div><select class="sort-order-1 form-control" style="margin-top: 10px; width: 60%;">\
|
||||
<option value="asc">'+__('Ascending')+'</option>\
|
||||
<option value="desc">'+__('Descending')+'</option>\
|
||||
</select></div><hr>\
|
||||
<div><button class="btn btn-primary">'+__('Update')+'</div>');
|
||||
|
||||
// first
|
||||
this.sort_by_select = new frappe.ui.FieldSelect({
|
||||
parent: $(this.sort_dialog.body).find('.sort-column'),
|
||||
doctype: this.doctype
|
||||
});
|
||||
this.sort_by_select.$select.css('width', '60%');
|
||||
this.sort_order_select = $(this.sort_dialog.body).find('.sort-order');
|
||||
|
||||
// second
|
||||
this.sort_by_next_select = new frappe.ui.FieldSelect({
|
||||
parent: $(this.sort_dialog.body).find('.sort-column-1'),
|
||||
doctype: this.doctype,
|
||||
with_blank: true
|
||||
});
|
||||
this.sort_by_next_select.$select.css('width', '60%');
|
||||
this.sort_order_next_select = $(this.sort_dialog.body).find('.sort-order-1');
|
||||
|
||||
// initial values
|
||||
this.sort_by_select.set_value(this.doctype, 'modified');
|
||||
this.sort_order_select.val('desc');
|
||||
|
||||
this.sort_by_next_select.clear();
|
||||
this.sort_order_next_select.val('desc');
|
||||
|
||||
// button actions
|
||||
this.page.add_inner_button(__('Sort Order'), function() {
|
||||
me.sort_dialog.show();
|
||||
});
|
||||
|
||||
$(this.sort_dialog.body).find('.btn-primary').click(function() {
|
||||
me.sort_dialog.hide();
|
||||
me.run();
|
||||
});
|
||||
},
|
||||
|
||||
// setup export
|
||||
make_export: function() {
|
||||
var me = this;
|
||||
if(!frappe.model.can_export(this.doctype)) {
|
||||
return;
|
||||
}
|
||||
var export_btn = this.page.add_menu_item(__('Export'), function() {
|
||||
var args = me.get_args();
|
||||
var selected_items = me.get_checked_items()
|
||||
frappe.prompt({fieldtype:"Select", label: __("Select File Type"), fieldname:"file_format_type",
|
||||
options:"Excel\nCSV", default:"Excel", reqd: 1},
|
||||
function(data) {
|
||||
args.cmd = 'frappe.desk.reportview.export_query';
|
||||
args.file_format_type = data.file_format_type;
|
||||
|
||||
if(me.add_totals_row) {
|
||||
args.add_totals_row = 1;
|
||||
}
|
||||
|
||||
if(selected_items.length >= 1) {
|
||||
args.selected_items = $.map(selected_items, function(d) { return d.name; });
|
||||
}
|
||||
open_url_post(frappe.request.url, args);
|
||||
|
||||
}, __("Export Report: {0}",[__(me.doctype)]), __("Download"));
|
||||
|
||||
}, true);
|
||||
},
|
||||
|
||||
|
||||
// save
|
||||
make_save: function() {
|
||||
var me = this;
|
||||
if(frappe.user.is_report_manager()) {
|
||||
this.page.add_menu_item(__('Save'), function() { me.save_report('save') }, true);
|
||||
this.page.add_menu_item(__('Save As'), function() { me.save_report('save_as') }, true);
|
||||
}
|
||||
},
|
||||
|
||||
save_report: function(save_type) {
|
||||
var me = this;
|
||||
|
||||
var _save_report = function(name) {
|
||||
// callback
|
||||
return frappe.call({
|
||||
method: 'frappe.desk.reportview.save_report',
|
||||
args: {
|
||||
name: name,
|
||||
doctype: me.doctype,
|
||||
json: JSON.stringify({
|
||||
filters: me.filter_list.get_filters(),
|
||||
columns: me.columns,
|
||||
sort_by: me.sort_by_select.val(),
|
||||
sort_order: me.sort_order_select.val(),
|
||||
sort_by_next: me.sort_by_next_select.val(),
|
||||
sort_order_next: me.sort_order_next_select.val(),
|
||||
add_totals_row: me.add_totals_row
|
||||
})
|
||||
},
|
||||
callback: function(r) {
|
||||
if(r.exc) {
|
||||
frappe.msgprint(__("Report was not saved (there were errors)"));
|
||||
return;
|
||||
}
|
||||
if(r.message != me.docname)
|
||||
frappe.set_route('Report', me.doctype, r.message);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
if(me.docname && save_type == "save") {
|
||||
_save_report(me.docname);
|
||||
} else {
|
||||
frappe.prompt({fieldname: 'name', label: __('New Report name'), reqd: 1, fieldtype: 'Data'}, function(data) {
|
||||
_save_report(data.name);
|
||||
}, __('Save As'));
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
make_delete: function() {
|
||||
var me = this;
|
||||
if(this.can_delete) {
|
||||
$(this.parent).on("click", "input[type='checkbox'][data-row]", function() {
|
||||
me.data[$(this).attr("data-row")].selected
|
||||
= this.checked ? true : false;
|
||||
});
|
||||
|
||||
this.page.add_menu_item(__("Delete"), function() {
|
||||
var delete_list = $.map(me.get_checked_items(), function(d) {
|
||||
return d.name.toString();
|
||||
});
|
||||
if(!delete_list.length)
|
||||
return;
|
||||
if(frappe.confirm(__("This is PERMANENT action and you cannot undo. Continue?"),
|
||||
function() {
|
||||
return frappe.call({
|
||||
method: 'frappe.desk.reportview.delete_items',
|
||||
args: {
|
||||
items: delete_list,
|
||||
doctype: me.doctype
|
||||
},
|
||||
callback: function() {
|
||||
me.refresh();
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
}, true);
|
||||
}
|
||||
},
|
||||
|
||||
make_user_permissions: function() {
|
||||
var me = this;
|
||||
if(this.docname && frappe.model.can_set_user_permissions("Report")) {
|
||||
this.page.add_menu_item(__("User Permissions"), function() {
|
||||
frappe.route_options = {
|
||||
doctype: "Report",
|
||||
name: me.docname
|
||||
};
|
||||
frappe.set_route('List', 'User Permission');
|
||||
}, true);
|
||||
}
|
||||
},
|
||||
|
||||
setup_listview_settings: function() {
|
||||
if(frappe.listview_settings[this.doctype] && frappe.listview_settings[this.doctype].onload) {
|
||||
frappe.listview_settings[this.doctype].onload(this);
|
||||
}
|
||||
},
|
||||
|
||||
get_checked_items: function() {
|
||||
var me = this;
|
||||
var selected_records = []
|
||||
|
||||
$.each(me.data, function(i, d) {
|
||||
if(d.selected && d.name) {
|
||||
selected_records.push(d);
|
||||
}
|
||||
});
|
||||
|
||||
return selected_records
|
||||
}
|
||||
});
|
||||
|
||||
frappe.ui.ColumnPicker = Class.extend({
|
||||
init: function(list) {
|
||||
this.list = list;
|
||||
this.doctype = list.doctype;
|
||||
},
|
||||
clear: function() {
|
||||
this.columns = [];
|
||||
$(this.dialog.body).html('<div class="text-muted">'+__("Drag to sort columns")+'</div>\
|
||||
<div class="column-list"></div>\
|
||||
<div><button class="btn btn-default btn-sm btn-add">'+__("Add Column")+'</button></div>');
|
||||
|
||||
},
|
||||
show: function(columns) {
|
||||
var me = this;
|
||||
if(!this.dialog) {
|
||||
this.dialog = new frappe.ui.Dialog({
|
||||
title: __("Pick Columns"),
|
||||
width: '400',
|
||||
primary_action_label: __("Update"),
|
||||
primary_action: function() {
|
||||
me.update_column_selection();
|
||||
}
|
||||
});
|
||||
this.dialog.$wrapper.addClass("column-picker-dialog");
|
||||
}
|
||||
|
||||
this.clear();
|
||||
|
||||
this.column_list = $(this.dialog.body).find('.column-list');
|
||||
|
||||
// show existing
|
||||
$.each(columns, function(i, c) {
|
||||
me.add_column(c);
|
||||
});
|
||||
|
||||
new Sortable(this.column_list.get(0), {
|
||||
filter: 'input',
|
||||
draggable: '.column-list-item',
|
||||
chosenClass: 'sortable-chosen',
|
||||
dragClass: 'sortable-chosen',
|
||||
onUpdate: function(event) {
|
||||
me.columns = [];
|
||||
$.each($(me.dialog.body).find('.column-list .column-list-item'),
|
||||
function(i, ele) {
|
||||
me.columns.push($(ele).data("fieldselect"))
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// add column
|
||||
$(this.dialog.body).find('.btn-add').click(function() {
|
||||
me.add_column(['name']);
|
||||
});
|
||||
|
||||
this.dialog.show();
|
||||
},
|
||||
add_column: function(c) {
|
||||
if(!c) return;
|
||||
var me = this;
|
||||
|
||||
var w = $('<div class="column-list-item"><div class="row">\
|
||||
<div class="col-xs-1">\
|
||||
<i class="fa fa-sort text-muted"></i></div>\
|
||||
<div class="col-xs-10"></div>\
|
||||
<div class="col-xs-1"><a class="close">×</a></div>\
|
||||
</div></div>')
|
||||
.appendTo(this.column_list);
|
||||
|
||||
var fieldselect = new frappe.ui.FieldSelect({parent:w.find('.col-xs-10'), doctype:this.doctype});
|
||||
fieldselect.val((c[1] || this.doctype) + "." + c[0]);
|
||||
|
||||
w.data("fieldselect", fieldselect);
|
||||
|
||||
w.find('.close').data("fieldselect", fieldselect)
|
||||
.click(function() {
|
||||
delete me.columns[me.columns.indexOf($(this).data('fieldselect'))];
|
||||
$(this).parents('.column-list-item').remove();
|
||||
});
|
||||
|
||||
this.columns.push(fieldselect);
|
||||
},
|
||||
update_column_selection: function() {
|
||||
this.dialog.hide();
|
||||
// selected columns as list of [column_name, table_name]
|
||||
var columns = $.map(this.columns, function(v) {
|
||||
return (v && v.selected_fieldname && v.selected_doctype)
|
||||
? [[v.selected_fieldname, v.selected_doctype]]
|
||||
: null;
|
||||
});
|
||||
|
||||
this.list.set_columns(columns);
|
||||
this.list.run();
|
||||
}
|
||||
});
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
{% if has_child_column %}
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" class="show-all-data"
|
||||
style="margin-top: 2px"
|
||||
{{ show_all_data ? "checked" : "" }}>
|
||||
{{ __("Show all data") }}
|
||||
</label>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if can_write %}
|
||||
<div class="col-md-6 text-right"><p class="text-muted">
|
||||
{{ __("Tip: Double click cell to edit") }}</p></div>
|
||||
{% endif %}
|
||||
</div>
|
||||
Loading…
Add table
Reference in a new issue