diff --git a/frappe/public/js/frappe/list/bulk_operations.js b/frappe/public/js/frappe/list/bulk_operations.js index dd85c3da0d..f6731edde9 100644 --- a/frappe/public/js/frappe/list/bulk_operations.js +++ b/frappe/public/js/frappe/list/bulk_operations.js @@ -166,6 +166,100 @@ export default class BulkOperations { dialog.show(); } + consolidated_print(docs) { + const print_settings = frappe.model.get_doc(":Print Settings", "Print Settings"); + const allow_print_for_draft = cint(print_settings.allow_print_for_draft); + const is_submittable = frappe.model.is_submittable(this.doctype); + const allow_print_for_cancelled = cint(print_settings.allow_print_for_cancelled); + const letterheads = this.get_letterhead_options(); + const MAX_CONSOLIDATED_LIMIT = 100; + + const valid_docs = docs + .filter((doc) => { + return ( + !is_submittable || + doc.docstatus === 1 || + (allow_print_for_cancelled && doc.docstatus == 2) || + (allow_print_for_draft && doc.docstatus == 0) || + frappe.user.has_role("Administrator") + ); + }) + .map((doc) => doc.name); + + const invalid_docs = docs.filter((doc) => !valid_docs.includes(doc.name)); + + if (invalid_docs.length > 0) { + frappe.msgprint(__("You selected Draft or Cancelled documents")); + return; + } + + if (valid_docs.length === 0) { + frappe.msgprint(__("Select atleast 1 record for printing")); + return; + } + + if (valid_docs.length > MAX_CONSOLIDATED_LIMIT) { + frappe.msgprint( + __("You can only consolidate up to {0} documents at a time", [MAX_CONSOLIDATED_LIMIT]) + ); + return; + } + + const dialog = new frappe.ui.Dialog({ + title: __("Consolidated Print"), + fields: [ + { + fieldtype: "HTML", + options: `
${__("All selected documents will be rendered in a single continuous layout without page breaks between them.")}
`, + }, + { + fieldtype: "Select", + label: __("Letter Head"), + fieldname: "letter_sel", + options: letterheads, + default: letterheads[0], + }, + { + fieldtype: "Select", + label: __("Print Format"), + fieldname: "print_sel", + options: frappe.meta.get_print_formats(this.doctype), + default: frappe.get_meta(this.doctype).default_print_format, + }, + ], + }); + + dialog.set_primary_action(__("Print"), (args) => { + if (!args) return; + const default_print_format = frappe.get_meta(this.doctype).default_print_format; + const with_letterhead = args.letter_sel == __("No Letterhead") ? 0 : 1; + const print_format = args.print_sel ? args.print_sel : default_print_format; + const names_json = JSON.stringify(valid_docs); + const letterhead = args.letter_sel; + + const w = window.open( + "/consolidated_printview?" + + "doctype=" + + encodeURIComponent(this.doctype) + + "&names=" + + encodeURIComponent(names_json) + + "&format=" + + encodeURIComponent(print_format) + + "&no_letterhead=" + + (with_letterhead ? "0" : "1") + + "&letterhead=" + + encodeURIComponent(letterhead) + + "&trigger_print=1" + ); + + if (!w) { + frappe.msgprint(__("Please enable pop-ups")); + } + dialog.hide(); + }); + dialog.show(); + } + get_letterhead_options() { const letterhead_options = [__("No Letterhead")]; frappe.call({ diff --git a/frappe/public/js/frappe/list/list_view.js b/frappe/public/js/frappe/list/list_view.js index 4fcd01514b..6b72b0e17f 100644 --- a/frappe/public/js/frappe/list/list_view.js +++ b/frappe/public/js/frappe/list/list_view.js @@ -2264,6 +2264,14 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList { }; }; + const bulk_consolidated_printing = () => { + return { + label: __("Consolidated Print", null, "Button in list view actions menu"), + action: () => bulk_operations.consolidated_print(this.get_checked_items()), + standard: true, + }; + }; + const bulk_delete = () => { return { label: __("Delete", null, "Button in list view actions menu"), @@ -2552,6 +2560,7 @@ frappe.views.ListView = class ListView extends frappe.views.BaseList { // bulk printing if (frappe.model.can_print(doctype)) { actions_menu_items.push(bulk_printing()); + actions_menu_items.push(bulk_consolidated_printing()); } // bulk submit