Merge pull request #9777 from prssanna/report-export-columns
fix(Report): Export custom columns in Excel
This commit is contained in:
commit
c1533cfb95
4 changed files with 61 additions and 37 deletions
|
|
@ -6,7 +6,7 @@ import frappe
|
|||
import json, datetime
|
||||
from frappe import _, scrub
|
||||
import frappe.desk.query_report
|
||||
from frappe.utils import cint
|
||||
from frappe.utils import cint, cstr
|
||||
from frappe.model.document import Document
|
||||
from frappe.modules.export_file import export_to_files
|
||||
from frappe.modules import make_boilerplate
|
||||
|
|
@ -92,6 +92,18 @@ class Report(Document):
|
|||
make_boilerplate("controller.py", self, {"name": self.name})
|
||||
make_boilerplate("controller.js", self, {"name": self.name})
|
||||
|
||||
def execute_query_report(self, filters):
|
||||
if not self.query:
|
||||
frappe.throw(_("Must specify a Query to run"), title=_('Report Document Error'))
|
||||
|
||||
if not self.query.lower().startswith("select"):
|
||||
frappe.throw(_("Query must be a SELECT"), title=_('Report Document Error'))
|
||||
|
||||
result = [list(t) for t in frappe.db.sql(self.query, filters)]
|
||||
columns = [cstr(c[0]) for c in frappe.db.get_description()]
|
||||
|
||||
return [columns, result]
|
||||
|
||||
def execute_script_report(self, filters):
|
||||
# save the timestamp to automatically set to prepared
|
||||
threshold = 30
|
||||
|
|
|
|||
|
|
@ -67,3 +67,19 @@ def find_all(list_of_dict, match_function):
|
|||
if match_function(entry):
|
||||
found.append(entry)
|
||||
return found
|
||||
|
||||
def ljust_list(_list, length, fill_word=None):
|
||||
"""
|
||||
Similar to ljust but for list.
|
||||
|
||||
Usage:
|
||||
$ ljust_list([1, 2, 3], 5)
|
||||
> [1, 2, 3, None, None]
|
||||
"""
|
||||
# make a copy to avoid mutation of passed list
|
||||
_list = list(_list)
|
||||
fill_length = length - len(_list)
|
||||
if fill_length > 0:
|
||||
_list.extend([fill_word] * fill_length)
|
||||
|
||||
return _list
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import os, json
|
|||
|
||||
from frappe import _
|
||||
from frappe.modules import scrub, get_module_path
|
||||
from frappe.utils import flt, cint, get_html_format, cstr, get_url_to_form
|
||||
from frappe.utils import flt, cint, get_html_format, get_url_to_form
|
||||
from frappe.model.utils import render_include
|
||||
from frappe.translate import send_translations
|
||||
import frappe.desk.reportview
|
||||
|
|
@ -16,6 +16,7 @@ from frappe.permissions import get_role_permissions
|
|||
from six import string_types, iteritems
|
||||
from datetime import timedelta
|
||||
from frappe.utils import gzip_decompress
|
||||
from frappe.core.utils import ljust_list
|
||||
|
||||
def get_report_doc(report_name):
|
||||
doc = frappe.get_doc("Report", report_name)
|
||||
|
|
@ -42,44 +43,32 @@ def get_report_doc(report_name):
|
|||
return doc
|
||||
|
||||
|
||||
def generate_report_result(report, filters=None, user=None):
|
||||
status = None
|
||||
if not user:
|
||||
user = frappe.session.user
|
||||
if not filters:
|
||||
filters = []
|
||||
def generate_report_result(report, filters=None, user=None, custom_columns=None):
|
||||
user = user or frappe.session.user
|
||||
filters = filters or []
|
||||
|
||||
if filters and isinstance(filters, string_types):
|
||||
filters = json.loads(filters)
|
||||
columns, result, message, chart, report_summary, skip_total_row = [], [], None, None, None, 0
|
||||
|
||||
res = []
|
||||
|
||||
if report.report_type == "Query Report":
|
||||
if not report.query:
|
||||
status = "error"
|
||||
frappe.msgprint(_("Must specify a Query to run"), raise_exception=True)
|
||||
|
||||
if not report.query.lower().startswith("select"):
|
||||
status = "error"
|
||||
frappe.msgprint(_("Query must be a SELECT"), raise_exception=True)
|
||||
|
||||
result = [list(t) for t in frappe.db.sql(report.query, filters)]
|
||||
columns = [cstr(c[0]) for c in frappe.db.get_description()]
|
||||
res = report.execute_query_report(filters)
|
||||
|
||||
elif report.report_type == 'Script Report':
|
||||
res = report.execute_script_report(filters)
|
||||
|
||||
columns, result = res[0], res[1]
|
||||
if len(res) > 2:
|
||||
message = res[2]
|
||||
if len(res) > 3:
|
||||
chart = res[3]
|
||||
if len(res) > 4:
|
||||
report_summary = res[4]
|
||||
if len(res) > 5:
|
||||
skip_total_row = cint(res[5])
|
||||
columns, result, message, chart, report_summary, skip_total_row = \
|
||||
ljust_list(res, 6)
|
||||
|
||||
if report.custom_columns:
|
||||
columns = json.loads(report.custom_columns)
|
||||
result = add_data_to_custom_columns(columns, result)
|
||||
if custom_columns:
|
||||
result = add_data_to_custom_columns(custom_columns, result)
|
||||
|
||||
for custom_column in custom_columns:
|
||||
columns.insert(custom_column['insert_after_index'] + 1, custom_column)
|
||||
|
||||
if result:
|
||||
result = get_filtered_data(report.ref_doctype, columns, result, user)
|
||||
|
|
@ -93,8 +82,8 @@ def generate_report_result(report, filters=None, user=None):
|
|||
"message": message,
|
||||
"chart": chart,
|
||||
"report_summary": report_summary,
|
||||
"skip_total_row": skip_total_row,
|
||||
"status": status,
|
||||
"skip_total_row": skip_total_row or 0,
|
||||
"status": None,
|
||||
"execution_time": frappe.cache().hget('report_execution_time', report.name) or 0
|
||||
}
|
||||
|
||||
|
|
@ -161,7 +150,7 @@ def get_script(report_name):
|
|||
|
||||
@frappe.whitelist()
|
||||
@frappe.read_only()
|
||||
def run(report_name, filters=None, user=None, ignore_prepared_report=False):
|
||||
def run(report_name, filters=None, user=None, ignore_prepared_report=False, custom_columns=None):
|
||||
|
||||
report = get_report_doc(report_name)
|
||||
if not user:
|
||||
|
|
@ -183,7 +172,7 @@ def run(report_name, filters=None, user=None, ignore_prepared_report=False):
|
|||
dn = ""
|
||||
result = get_prepared_report_result(report, filters, dn, user)
|
||||
else:
|
||||
result = generate_report_result(report, filters, user)
|
||||
result = generate_report_result(report, filters, user, custom_columns)
|
||||
|
||||
result["add_total_row"] = report.add_total_row and not result.get('skip_total_row', False)
|
||||
|
||||
|
|
@ -294,6 +283,8 @@ def export_query():
|
|||
if isinstance(data.get("file_format_type"), string_types):
|
||||
file_format_type = data["file_format_type"]
|
||||
|
||||
custom_columns = frappe.parse_json(data["custom_columns"])
|
||||
|
||||
include_indentation = data["include_indentation"]
|
||||
if isinstance(data.get("visible_idx"), string_types):
|
||||
visible_idx = json.loads(data.get("visible_idx"))
|
||||
|
|
@ -301,7 +292,7 @@ def export_query():
|
|||
visible_idx = None
|
||||
|
||||
if file_format_type == "Excel":
|
||||
data = run(report_name, filters)
|
||||
data = run(report_name, filters, custom_columns=custom_columns)
|
||||
data = frappe._dict(data)
|
||||
if not data.columns:
|
||||
frappe.respond_as_web_page(_("No data to export"),
|
||||
|
|
|
|||
|
|
@ -616,6 +616,7 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
|
|||
prepare_report_data(data) {
|
||||
this.raw_data = data;
|
||||
this.columns = this.prepare_columns(data.columns);
|
||||
this.custom_columns = [];
|
||||
this.data = this.prepare_data(data.result);
|
||||
this.linked_doctypes = this.get_linked_doctypes();
|
||||
this.tree_report = this.data.some(d => 'indent' in d);
|
||||
|
|
@ -1110,6 +1111,7 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
|
|||
const args = {
|
||||
cmd: 'frappe.desk.query_report.export_query',
|
||||
report_name: this.report_name,
|
||||
custom_columns: this.custom_columns.length? this.custom_columns: [],
|
||||
file_format_type: file_format,
|
||||
filters: filters,
|
||||
visible_idx,
|
||||
|
|
@ -1275,16 +1277,20 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
|
|||
primary_action: (values) => {
|
||||
const custom_columns = [];
|
||||
let df = frappe.meta.get_docfield(values.doctype, values.field);
|
||||
const insert_after_index = this.columns
|
||||
.findIndex(column => column.label === values.insert_after);
|
||||
custom_columns.push({
|
||||
fieldname: df.fieldname,
|
||||
fieldtype: df.fieldtype,
|
||||
label: df.label,
|
||||
insert_after_index: insert_after_index,
|
||||
link_field: this.doctype_field_map[values.doctype],
|
||||
doctype: values.doctype,
|
||||
options: df.fieldtype === "Link" ? df.options : undefined,
|
||||
width: 100
|
||||
});
|
||||
|
||||
this.custom_columns = this.custom_columns.concat(custom_columns);
|
||||
frappe.call({
|
||||
method: 'frappe.desk.query_report.get_data_for_custom_field',
|
||||
args: {
|
||||
|
|
@ -1294,7 +1300,8 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
|
|||
callback: (r) => {
|
||||
const custom_data = r.message;
|
||||
const link_field = this.doctype_field_map[values.doctype];
|
||||
this.add_custom_column(custom_columns, custom_data, link_field, values.field, values.insert_after);
|
||||
|
||||
this.add_custom_column(custom_columns, custom_data, link_field, values.field, insert_after_index);
|
||||
d.hide();
|
||||
}
|
||||
});
|
||||
|
|
@ -1369,11 +1376,9 @@ frappe.views.QueryReport = class QueryReport extends frappe.views.BaseList {
|
|||
}
|
||||
}
|
||||
|
||||
add_custom_column(custom_column, custom_data, link_field, column_field, insert_after) {
|
||||
add_custom_column(custom_column, custom_data, link_field, column_field, insert_after_index) {
|
||||
const column = this.prepare_columns(custom_column);
|
||||
|
||||
const insert_after_index = this.columns
|
||||
.findIndex(column => column.label === insert_after);
|
||||
this.columns.splice(insert_after_index + 1, 0, column[0]);
|
||||
|
||||
this.data.forEach(row => {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue