import frappe import json from functools import lru_cache from sql_metadata import Parser import frappe import frappe.permissions from frappe import _ from frappe.core.doctype.access_log.access_log import make_access_log from frappe.model import child_table_fields, default_fields, get_permitted_fields, optional_fields from frappe.model.base_document import get_controller from frappe.model.db_query import DatabaseQuery from frappe.model.utils import is_virtual_doctype from frappe.utils import add_user_info, cint, format_duration from frappe.utils.data import sbool @frappe.whitelist() @frappe.read_only() def export_query(): """export from report builder""" from frappe.desk.utils import get_csv_bytes, pop_csv_params, provide_binary_file form_params = get_form_params() form_params["limit_page_length"] = None form_params["as_list"] = True doctype = form_params.pop("doctype") file_format_type = form_params.pop("file_format_type") title = form_params.pop("title", doctype) csv_params = pop_csv_params(form_params) add_totals_row = 1 if form_params.pop("add_totals_row", None) == "1" else None frappe.permissions.can_export(doctype, raise_exception=True) if selection := form_params.pop("selected_items", None): form_params["filters"] = {"name": ("in", json.loads(selection))} make_access_log( doctype=doctype, file_type=file_format_type, report_name=form_params.report_name, filters=form_params.filters, ) db_query = DatabaseQuery(doctype) ret = frappe.get_list(doctype) if add_totals_row: ret = append_totals_row(ret) # //data = [[_("Sr"), *get_labels(fields, doctype)]] data.extend([i + 1, *list(row)] for i, row in enumerate(ret.value)) data = handle_duration_fieldtype_values(doctype, data, db_query.fields) if file_format_type == "CSV": from frappe.utils.xlsxutils import handle_html file_extension = "csv" content = get_csv_bytes( [[handle_html(frappe.as_unicode(v)) if isinstance(v, str) else v for v in r] for r in data], csv_params, ) elif file_format_type == "Excel": from frappe.utils.xlsxutils import make_xlsx file_extension = "xlsx" content = make_xlsx(data, doctype).getvalue() provide_binary_file(title, file_extension, content) def get_form_params(): """parse GET request parameters.""" data = frappe._dict(frappe.local.form_dict) # clean_params(data) # validate_args(data) return data def get_labels(fields, doctype): """get column labels based on column names""" labels = [] for key in fields: try: parenttype, fieldname = parse_field(key) except ValueError: continue parenttype = parenttype or doctype if parenttype == doctype and fieldname == "name": label = _("ID", context="Label of name column in report") else: df = frappe.get_meta(parenttype).get_field(fieldname) label = _(df.label if df else fieldname.title()) if parenttype != doctype: # If the column is from a child table, append the child doctype. # For example, "Item Code (Sales Invoice Item)". label += f" ({ _(parenttype) })" labels.append(label) return labels def handle_duration_fieldtype_values(doctype, data, fields): for field in fields: try: parenttype, fieldname = parse_field(field) except ValueError: continue parenttype = parenttype or doctype df = frappe.get_meta(parenttype).get_field(fieldname) if df and df.fieldtype == "Duration": index = fields.index(field) + 1 for i in range(1, len(data)): val_in_seconds = data[i][index] if val_in_seconds: duration_val = format_duration(val_in_seconds, df.hide_days) data[i][index] = duration_val return data