diff --git a/report_print/hooks.py b/report_print/hooks.py index 9966ed4..f023574 100644 --- a/report_print/hooks.py +++ b/report_print/hooks.py @@ -159,9 +159,9 @@ # Overriding Methods # ------------------------------ # -# override_whitelisted_methods = { -# "frappe.desk.doctype.event.event.get_events": "report_print.event.get_events" -# } +override_whitelisted_methods = { + "frappe.desk.query_report.get_script": "report_print.overrides.report.get_script", +} # # each overriding function accepts a `data` argument; # generated from the base implementation of the doctype dashboard, diff --git a/report_print/overrides/report.py b/report_print/overrides/report.py new file mode 100644 index 0000000..c0db0fd --- /dev/null +++ b/report_print/overrides/report.py @@ -0,0 +1,45 @@ + +import frappe +import os +from frappe.desk.query_report import get_report_doc +from frappe.modules import get_module_path, scrub +from frappe.model.utils import render_include + + +@frappe.whitelist() +def get_script(report_name): + report = get_report_doc(report_name) + module = report.module or frappe.db.get_value("DocType", report.ref_doctype, "module") + + is_custom_module = frappe.get_cached_value("Module Def", module, "custom") + + # custom modules are virtual modules those exists in DB but not in disk. + module_path = "" if is_custom_module else get_module_path(module) + report_folder = module_path and os.path.join(module_path, "report", scrub(report.name)) + script_path = report_folder and os.path.join(report_folder, scrub(report.name) + ".js") + + script = None + if os.path.exists(script_path): + with open(script_path) as f: + script = f.read() + script += f"\n\n//# sourceURL={scrub(report.name)}.js" + + html_format = get_html_format() + + if not script and report.javascript: + script = report.javascript + script += f"\n\n//# sourceURL={scrub(report.name)}__custom" + + if not script: + script = "frappe.query_reports['%s']={}" % report_name + + return { + "script": render_include(script), + "html_format": html_format, + "execution_time": 0, + "filters": report.filters, + "custom_report_name": report.name if report.get("is_custom_report") else None, + } + +def get_html_format(): + return frappe.db.get_value("Report Print Format", "", "html") \ No newline at end of file diff --git a/report_print/report_print/doctype/__init__.py b/report_print/report_print/doctype/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/report_print/report_print/doctype/report_print_format/__init__.py b/report_print/report_print/doctype/report_print_format/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/report_print/report_print/doctype/report_print_format/report_print_format.js b/report_print/report_print/doctype/report_print_format/report_print_format.js new file mode 100644 index 0000000..d2ac360 --- /dev/null +++ b/report_print/report_print/doctype/report_print_format/report_print_format.js @@ -0,0 +1,8 @@ +// Copyright (c) 2024, Code Venturers and contributors +// For license information, please see license.txt + +frappe.ui.form.on('Report Print Format', { + // refresh: function(frm) { + + // } +}); diff --git a/report_print/report_print/doctype/report_print_format/report_print_format.json b/report_print/report_print/doctype/report_print_format/report_print_format.json new file mode 100644 index 0000000..8a0770e --- /dev/null +++ b/report_print/report_print/doctype/report_print_format/report_print_format.json @@ -0,0 +1,286 @@ +{ + "actions": [], + "allow_rename": 1, + "autoname": "Prompt", + "creation": "2024-08-29 01:52:40.846934", + "default_view": "List", + "doctype": "DocType", + "engine": "InnoDB", + "field_order": [ + "report", + "module", + "default_print_language", + "column_break_3", + "standard", + "custom_format", + "disabled", + "section_break_6", + "print_format_type", + "raw_printing", + "html", + "raw_commands", + "section_break_9", + "margin_top", + "margin_bottom", + "margin_left", + "margin_right", + "align_labels_right", + "show_section_headings", + "line_breaks", + "absolute_value", + "column_break_11", + "font_size", + "font", + "page_number", + "css_section", + "css", + "custom_html_help", + "section_break_13", + "print_format_help", + "format_data", + "print_format_builder", + "print_format_builder_beta" + ], + "fields": [ + { + "fieldname": "report", + "fieldtype": "Link", + "in_filter": 1, + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Report", + "options": "Report", + "reqd": 1 + }, + { + "fieldname": "module", + "fieldtype": "Link", + "label": "Module", + "options": "Module Def" + }, + { + "fieldname": "default_print_language", + "fieldtype": "Link", + "label": "Default Print Language", + "options": "Language" + }, + { + "fieldname": "column_break_3", + "fieldtype": "Column Break" + }, + { + "default": "No", + "fieldname": "standard", + "fieldtype": "Select", + "in_filter": 1, + "label": "Standard", + "no_copy": 1, + "oldfieldname": "standard", + "oldfieldtype": "Select", + "options": "No\nYes", + "reqd": 1, + "search_index": 1 + }, + { + "default": "0", + "fieldname": "custom_format", + "fieldtype": "Check", + "label": "Custom Format" + }, + { + "default": "0", + "fieldname": "disabled", + "fieldtype": "Check", + "label": "Disabled" + }, + { + "depends_on": "custom_format", + "fieldname": "section_break_6", + "fieldtype": "Section Break" + }, + { + "default": "Jinja", + "depends_on": "custom_format", + "fieldname": "print_format_type", + "fieldtype": "Select", + "label": "Print Format Type", + "options": "Jinja\nJS" + }, + { + "default": "0", + "fieldname": "raw_printing", + "fieldtype": "Check", + "label": "Raw Printing" + }, + { + "depends_on": "eval:!doc.raw_printing", + "fieldname": "html", + "fieldtype": "Code", + "label": "HTML", + "oldfieldname": "html", + "oldfieldtype": "Text Editor", + "options": "Jinja" + }, + { + "depends_on": "raw_printing", + "description": "Any string-based printer languages can be used. Writing raw commands requires knowledge of the printer's native language provided by the printer manufacturer. Please refer to the developer manual provided by the printer manufacturer on how to write their native commands. These commands are rendered on the server side using the Jinja Templating Language.", + "fieldname": "raw_commands", + "fieldtype": "Code", + "label": "Raw Commands", + "options": "Jinja" + }, + { + "depends_on": "eval:!doc.custom_format", + "fieldname": "section_break_9", + "fieldtype": "Section Break", + "label": "Style Settings" + }, + { + "default": "15", + "fieldname": "margin_top", + "fieldtype": "Float", + "label": "Margin Top" + }, + { + "default": "15", + "fieldname": "margin_bottom", + "fieldtype": "Float", + "label": "Margin Bottom" + }, + { + "default": "15", + "fieldname": "margin_left", + "fieldtype": "Float", + "label": "Margin Left" + }, + { + "default": "15", + "fieldname": "margin_right", + "fieldtype": "Float", + "label": "Margin Right" + }, + { + "default": "0", + "fieldname": "align_labels_right", + "fieldtype": "Check", + "label": "Align Labels to the Right" + }, + { + "default": "0", + "fieldname": "show_section_headings", + "fieldtype": "Check", + "label": "Show Section Headings" + }, + { + "default": "0", + "fieldname": "line_breaks", + "fieldtype": "Check", + "label": "Show Line Breaks after Sections" + }, + { + "default": "0", + "depends_on": "doc_type", + "description": "If checked, negative numeric values of Currency, Quantity or Count would be shown as positive", + "fieldname": "absolute_value", + "fieldtype": "Check", + "label": "Show Absolute Values" + }, + { + "fieldname": "column_break_11", + "fieldtype": "Column Break" + }, + { + "default": "14", + "fieldname": "font_size", + "fieldtype": "Int", + "label": "Font Size" + }, + { + "depends_on": "eval:!doc.custom_format", + "fieldname": "font", + "fieldtype": "Data", + "label": "Google Font" + }, + { + "default": "Hide", + "fieldname": "page_number", + "fieldtype": "Select", + "label": "Page Number", + "options": "Hide\nTop Left\nTop Center\nTop Right\nBottom Left\nBottom Center\nBottom Right" + }, + { + "depends_on": "eval:!doc.raw_printing", + "fieldname": "css_section", + "fieldtype": "Section Break" + }, + { + "fieldname": "css", + "fieldtype": "Code", + "label": "Custom CSS", + "options": "CSS" + }, + { + "fieldname": "custom_html_help", + "fieldtype": "HTML", + "label": "Custom HTML Help", + "options": "
Notes:
\n\ndata-fieldtype
and data-fieldname
value
section-break
column-break
1. Left align integers
\n\n[data-fieldtype=\"Int\"] .value { text-align: left; }
\n\n1. Add border to sections except the last section
\n\n.section-break { padding: 30px 0px; border-bottom: 1px solid #eee; }\n.section-break:last-child { padding-bottom: 0px; border-bottom: 0px; }
\n"
+ },
+ {
+ "depends_on": "custom_format",
+ "fieldname": "section_break_13",
+ "fieldtype": "Section Break"
+ },
+ {
+ "depends_on": "custom_format",
+ "fieldname": "print_format_help",
+ "fieldtype": "HTML",
+ "label": "Print Format Help",
+ "options": "Print Formats are rendered on the server side using the Jinja Templating Language. All forms have access to the doc
object which contains information about the document that is being formatted. You can also access common utilities via the frappe
module.
For styling, the Boostrap CSS framework is provided and you can enjoy the full range of classes.
\n<h3>{{ doc.select_print_heading or \"Invoice\" }}</h3>\n<div class=\"row\">\n\t<div class=\"col-md-3 text-right\">Customer Name</div>\n\t<div class=\"col-md-9\">{{ doc.customer_name }}</div>\n</div>\n<div class=\"row\">\n\t<div class=\"col-md-3 text-right\">Date</div>\n\t<div class=\"col-md-9\">{{ doc.get_formatted(\"invoice_date\") }}</div>\n</div>\n<table class=\"table table-bordered\">\n\t<tbody>\n\t\t<tr>\n\t\t\t<th>Sr</th>\n\t\t\t<th>Item Name</th>\n\t\t\t<th>Description</th>\n\t\t\t<th class=\"text-right\">Qty</th>\n\t\t\t<th class=\"text-right\">Rate</th>\n\t\t\t<th class=\"text-right\">Amount</th>\n\t\t</tr>\n\t\t{%- for row in doc.items -%}\n\t\t<tr>\n\t\t\t<td style=\"width: 3%;\">{{ row.idx }}</td>\n\t\t\t<td style=\"width: 20%;\">\n\t\t\t\t{{ row.item_name }}\n\t\t\t\t{% if row.item_code != row.item_name -%}\n\t\t\t\t<br>Item Code: {{ row.item_code}}\n\t\t\t\t{%- endif %}\n\t\t\t</td>\n\t\t\t<td style=\"width: 37%;\">\n\t\t\t\t<div style=\"border: 0px;\">{{ row.description }}</div></td>\n\t\t\t<td style=\"width: 10%; text-align: right;\">{{ row.qty }} {{ row.uom or row.stock_uom }}</td>\n\t\t\t<td style=\"width: 15%; text-align: right;\">{{\n\t\t\t\trow.get_formatted(\"rate\", doc) }}</td>\n\t\t\t<td style=\"width: 15%; text-align: right;\">{{\n\t\t\t\trow.get_formatted(\"amount\", doc) }}</td>\n\t\t</tr>\n\t\t{%- endfor -%}\n\t</tbody>\n</table>
\ndoc.get_formatted(\"[fieldname]\", [parent_doc]) | \n\t\t\tGet document value formatted as Date, Currency, etc. Pass parent doc for currency type fields. | \n\t\t
frappe.db.get_value(\"[doctype]\", \"[name]\", \"fieldname\") | \n\t\t\tGet value from another document. | \n\t\t