diff --git a/frappe/public/build.json b/frappe/public/build.json index 620b360f47..64fe3eb2c5 100755 --- a/frappe/public/build.json +++ b/frappe/public/build.json @@ -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", diff --git a/frappe/public/js/frappe/views/reports/grid_report.js b/frappe/public/js/frappe/views/reports/grid_report.js deleted file mode 100644 index a8dda60606..0000000000 --- a/frappe/public/js/frappe/views/reports/grid_report.js +++ /dev/null @@ -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 = $('
').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 = $('
').appendTo(this.wrapper); - - this.page.add_menu_item(__("Export"), () => this.export(), true); - - // grid wrapper - this.grid_wrapper = $("
") - .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 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('
%(value)s
', { - _style: dataContext._style || "", - value: ((value==null || value==="") ? "" : format_number(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="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('%(value)s', { - _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('\ - %(value)s', { - 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(' \ - ', { - 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 = ""; - 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 + "  " + link; - } else { - return spacer + "  " + link; - } - } else { - return spacer + "  " + 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('

{0}

\ -

{1}

\ -

{2}

\ -

', [ - __('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').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("", { - 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('

'+__('Sort By')+'

\ -
\ -
\ -

'+__('Then By (optional)')+'

\ -
\ -

\ -
'); - - // 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('
'+__("Drag to sort columns")+'
\ -
\ -
'); - - }, - 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 = $('
\ -
\ -
\ -
\ - \ -
') - .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(); - } -}); diff --git a/frappe/public/js/frappe/views/reports/reportview_footer.html b/frappe/public/js/frappe/views/reports/reportview_footer.html deleted file mode 100644 index d6362eb558..0000000000 --- a/frappe/public/js/frappe/views/reports/reportview_footer.html +++ /dev/null @@ -1,18 +0,0 @@ -
-
- {% if has_child_column %} -
- -
- {% endif %} -
- {% if can_write %} -

- {{ __("Tip: Double click cell to edit") }}

- {% endif %} -
\ No newline at end of file