Skip to content
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
0013c27
feat: add Optional PDF Button for Sales and Purchase Doctypes
HenningWendtland Feb 20, 2026
109b32c
chore: update translation files
HenningWendtland Feb 20, 2026
38cf49e
refactor: replace individual scripts by wildcard hook
HenningWendtland Feb 20, 2026
73eaefc
refactor: remove Doctype check in Python to allow user to add button …
HenningWendtland Feb 20, 2026
2c22a49
fix: remove unneeded check
HenningWendtland Feb 20, 2026
c594776
fix: handle case that letter_head field does not exist
HenningWendtland Feb 20, 2026
150f65b
fix: improve type hint
HenningWendtland Feb 20, 2026
41277f1
fix: remove duplicate pdf button hook
HenningWendtland May 26, 2026
362e70f
refactor: display pdf_button for all pdf_on_submit doctypes
HenningWendtland May 26, 2026
3bfb0fd
chore: add tests
HenningWendtland May 26, 2026
5cfdc90
fix: return empty list as bootinfo if show_pdf_button is not checked
HenningWendtland May 26, 2026
2a1b17b
fix: open popup synchronously to avoid browser popup blockers
HenningWendtland May 26, 2026
ca0247a
fix: improve button description
HenningWendtland May 27, 2026
6e02693
fix: add error message for blocked popups
HenningWendtland May 27, 2026
0f96d8a
chore: update translation files
HenningWendtland May 27, 2026
baefd94
chore: rebase onto version-16 and update translation files
HenningWendtland May 27, 2026
fbd7411
refactor: use common backend for attach and pdf button
HenningWendtland May 27, 2026
6cb4d72
fix: use xcall instaed of frappe.call
HenningWendtland May 27, 2026
e60c81b
fix: remove email in .json
HenningWendtland Jun 2, 2026
dce6c67
fix: reinsert deleted comments in hooks.py
HenningWendtland Jun 2, 2026
61e822c
fix: remove dead try/except
HenningWendtland Jun 2, 2026
5bd02f8
fix: remove unneeded existence check
HenningWendtland Jun 2, 2026
f0b1979
Merge remote-tracking branch 'upstream/version-16' into add_pdf_button
barredterra Jun 4, 2026
300254e
test: remove bad test
barredterra Jun 5, 2026
ee7fde5
style: format JS
barredterra Jun 5, 2026
12d5a04
style: format python
barredterra Jun 5, 2026
5095f3b
style: format python (2)
barredterra Jun 5, 2026
cfa5a6f
test: remove _call helpers
HenningWendtland Jun 8, 2026
37d12ec
fix: add client side permission check
HenningWendtland Jun 11, 2026
5d1de42
fix: cleanup guard clause, add file icon
barredterra Jun 12, 2026
68883b6
refactor: clearer separation
barredterra Jun 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 20 additions & 13 deletions pdf_on_submit/attach_pdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,32 @@
from frappe.utils.weasyprint import PrintFormatGenerator


def attach_pdf(doc, event=None):
settings = frappe.get_single("PDF on Submit Settings")
enabled_doctypes = settings.get("enabled_for", {"document_type": doc.doctype})
def iter_matching_enabled_doctypes(doc, settings=None):
"""
Yield enabled_doctype configuration rows whose filters match this document,
in table order (idx).
"""
if settings is None:
settings = frappe.get_single("PDF on Submit Settings")

if not enabled_doctypes:
if not settings.enabled_for:
return

for dt_settings in enabled_doctypes:
process_enabled_doctype(doc, dt_settings, settings.create_pdf_in_background)
for row in settings.get("enabled_for", {"document_type": doc.doctype}):
if row.filters:
filters = json.loads(row.filters)
if filters and not evaluate_filters(doc, filters):
continue
yield row


def process_enabled_doctype(doc, settings, in_background):
if settings.filters:
filters = json.loads(settings.filters)
if filters:
condition_met = evaluate_filters(doc, filters)
if not condition_met:
return
def attach_pdf(doc, event=None):
settings = frappe.get_single("PDF on Submit Settings")
for row in iter_matching_enabled_doctypes(doc, settings):
process_enabled_doctype(doc, row, settings.create_pdf_in_background)


def process_enabled_doctype(doc, settings, in_background):
auto_name = settings.auto_name
print_format = settings.print_format or doc.meta.default_print_format or "Standard"
letter_head = settings.letter_head or None
Expand Down
4 changes: 2 additions & 2 deletions pdf_on_submit/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@

# include js, css files in header of desk.html
# app_include_css = "/assets/pdf_on_submit/css/pdf_on_submit.css"
# app_include_js = "/assets/pdf_on_submit/js/pdf_on_submit.js"
app_include_js = "/assets/pdf_on_submit/js/pdf_button_utils.js"
extend_bootinfo = "pdf_on_submit.utils.extend_boot_info"

# include js, css files in header of web template
# web_include_css = "/assets/pdf_on_submit/css/pdf_on_submit.css"
# web_include_js = "/assets/pdf_on_submit/js/pdf_on_submit.js"

# include js in page
# page_js = {"page" : "public/js/file.js"}

# include js in doctype views
# doctype_js = {"doctype" : "public/js/doctype.js"}
# doctype_list_js = {"doctype" : "public/js/doctype_list.js"}
Expand Down
51 changes: 42 additions & 9 deletions pdf_on_submit/locale/de.po
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PDF on Submit VERSION\n"
"Report-Msgid-Bugs-To: hallo@alyf.de\n"
"POT-Creation-Date: 2026-04-14 21:32+0053\n"
"POT-Creation-Date: 2026-05-27 13:49+0053\n"
"PO-Revision-Date: 2024-07-20 23:34+0053\n"
"Last-Translator: hallo@alyf.de\n"
"Language-Team: hallo@alyf.de\n"
Expand All @@ -16,16 +16,26 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.16.0\n"

#: pdf_on_submit/public/js/pdf_button_utils.js:77
msgid "Additional print formats"
msgstr "Weitere Druckformate"

#. Label of the create_pdf_in_background (Check) field in DocType 'PDF on
#. Submit Settings'
#: pdf_on_submit/pdf_on_submit/doctype/pdf_on_submit_settings/pdf_on_submit_settings.json
msgid "Create PDF In Background"
msgstr "PDF im Hintergrund erstellen"

#: pdf_on_submit/attach_pdf.py:80
#: pdf_on_submit/attach_pdf.py:88
msgid "Creating PDF ..."
msgstr "Erstelle PDF ..."

#. Description of the 'Show PDF Button' (Check) field in DocType 'PDF on Submit
#. Settings'
#: pdf_on_submit/pdf_on_submit/doctype/pdf_on_submit_settings/pdf_on_submit_settings.json
msgid "Displays a PDF button on the Form View for each enabled DocType."
msgstr "Zeigt eine PDF-Schaltfläche in der Formularansicht für jeden aktivierten Dokumenttyp an."

#. Name of a DocType
#: pdf_on_submit/pdf_on_submit/doctype/enabled_doctype/enabled_doctype.json
msgid "Enabled DocType"
Expand All @@ -36,10 +46,18 @@ msgstr "Aktivierter Dokumenttyp"
msgid "Enabled For"
msgstr "Aktiviert für"

#: pdf_on_submit/attach_pdf.py:108
#: pdf_on_submit/attach_pdf.py:116
msgid "Failed to attach XML to PDF for Sales Invoice {0}"
msgstr "Fehler beim Anhängen von XML an PDF für Verkaufsrechnung {0}"

#: pdf_on_submit/public/js/pdf_button_utils.js:91
msgid "Failed to generate PDF. {0}"
msgstr "PDF-Erstellung fehlgeschlagen. {0}"

#: pdf_on_submit/public/js/pdf_button_utils.js:80
msgid "More formats are configured for this document. Click to open:"
msgstr "Für dieses Dokument sind weitere Formate konfiguriert. Zum Öffnen anklicken:"

#. Description of the 'Auto Name' (Data) field in DocType 'Enabled DocType'
#: pdf_on_submit/pdf_on_submit/doctype/enabled_doctype/enabled_doctype.json
msgid ""
Expand All @@ -49,21 +67,36 @@ msgstr ""
"Optionen:\n"
"<ol><li><b>format:BEISPIEL-{MM}-{feldname1}-{feldname2}-{#####}</b> - Ersetzt alle in geschweiften Klammern stehenden Wörter (Feldnamen, Datumsangaben (DD, MM, YY), Nummernkreise) durch ihren Wert. Außerhalb der geschweiften Klammern können beliebige Zeichen verwendet werden.</li></ol>"

#: pdf_on_submit/utils.py:32
msgid "No permission to print this document"
msgstr "Keine Berechtigung zum Drucken dieses Dokuments"

#. Content of the 'filter_description' (HTML) field in DocType 'Enabled
#. DocType'
#: pdf_on_submit/pdf_on_submit/doctype/enabled_doctype/enabled_doctype.json
msgid ""
"Optional: create PDF only if the submitted document matches these "
"filters.<br><br>"
msgstr ""
"Optional: PDF nur erstellen, wenn das eingereichte Dokument diesen Filtern "
"entspricht.<br><br>"
msgid "Optional: create PDF only if the submitted document matches these filters.<br><br>"
msgstr "Optional: PDF nur erstellen, wenn das eingereichte Dokument diesen Filtern entspricht.<br><br>"

#. Name of a DocType
#: pdf_on_submit/pdf_on_submit/doctype/pdf_on_submit_settings/pdf_on_submit_settings.json
msgid "PDF on Submit Settings"
msgstr "PDF-on-Submit-Einstellungen"

#: pdf_on_submit/public/js/pdf_button_utils.js:43
msgid "Please allow popups for this site and try again."
msgstr "Bitte Popups für diese Seite erlauben und erneut versuchen."

#: pdf_on_submit/public/js/pdf_button_utils.js:41
msgid "Popup Blocked"
msgstr "Popup blockiert"

#: pdf_on_submit/pdf_on_submit/doctype/pdf_on_submit_settings/pdf_on_submit_settings.py:16
msgid "Row #{0}: invalid filters for <b>{1}</b>: {2}"
msgstr "Zeile #{0}: Ungültige Filter für <b>{1}</b>: {2}"

#. Label of the show_pdf_button (Check) field in DocType 'PDF on Submit
#. Settings'
#: pdf_on_submit/pdf_on_submit/doctype/pdf_on_submit_settings/pdf_on_submit_settings.json
msgid "Show PDF Button"
msgstr "PDF-Schaltfläche anzeigen"

44 changes: 40 additions & 4 deletions pdf_on_submit/locale/main.pot
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,35 @@ msgid ""
msgstr ""
"Project-Id-Version: PDF on Submit VERSION\n"
"Report-Msgid-Bugs-To: hallo@alyf.de\n"
"POT-Creation-Date: 2026-04-14 21:32+0053\n"
"PO-Revision-Date: 2026-04-14 21:32+0053\n"
"POT-Creation-Date: 2026-05-27 13:49+0053\n"
"PO-Revision-Date: 2026-05-27 13:49+0053\n"
"Last-Translator: hallo@alyf.de\n"
"Language-Team: hallo@alyf.de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Generated-By: Babel 2.16.0\n"

#: pdf_on_submit/public/js/pdf_button_utils.js:77
msgid "Additional print formats"
msgstr ""

#. Label of the create_pdf_in_background (Check) field in DocType 'PDF on
#. Submit Settings'
#: pdf_on_submit/pdf_on_submit/doctype/pdf_on_submit_settings/pdf_on_submit_settings.json
msgid "Create PDF In Background"
msgstr ""

#: pdf_on_submit/attach_pdf.py:80
#: pdf_on_submit/attach_pdf.py:88
msgid "Creating PDF ..."
msgstr ""

#. Description of the 'Show PDF Button' (Check) field in DocType 'PDF on Submit
#. Settings'
#: pdf_on_submit/pdf_on_submit/doctype/pdf_on_submit_settings/pdf_on_submit_settings.json
msgid "Displays a PDF button on the Form View for each enabled DocType."
msgstr ""

#. Name of a DocType
#: pdf_on_submit/pdf_on_submit/doctype/enabled_doctype/enabled_doctype.json
msgid "Enabled DocType"
Expand All @@ -36,17 +46,29 @@ msgstr ""
msgid "Enabled For"
msgstr ""

#: pdf_on_submit/attach_pdf.py:108
#: pdf_on_submit/attach_pdf.py:116
msgid "Failed to attach XML to PDF for Sales Invoice {0}"
msgstr ""

#: pdf_on_submit/public/js/pdf_button_utils.js:91
msgid "Failed to generate PDF. {0}"
msgstr ""

#: pdf_on_submit/public/js/pdf_button_utils.js:80
msgid "More formats are configured for this document. Click to open:"
msgstr ""

#. Description of the 'Auto Name' (Data) field in DocType 'Enabled DocType'
#: pdf_on_submit/pdf_on_submit/doctype/enabled_doctype/enabled_doctype.json
msgid ""
"Naming Options:\n"
"<ol><li><b>format:EXAMPLE-{MM}-{fieldname1}-{fieldname2}-{#####}</b> - Replace all braced words (fieldnames, date words (DD, MM, YY), series) with their value. Outside braces, any characters can be used.</li></ol>"
msgstr ""

#: pdf_on_submit/utils.py:32
msgid "No permission to print this document"
msgstr ""

#. Content of the 'filter_description' (HTML) field in DocType 'Enabled
#. DocType'
#: pdf_on_submit/pdf_on_submit/doctype/enabled_doctype/enabled_doctype.json
Expand All @@ -58,7 +80,21 @@ msgstr ""
msgid "PDF on Submit Settings"
msgstr ""

#: pdf_on_submit/public/js/pdf_button_utils.js:43
msgid "Please allow popups for this site and try again."
msgstr ""

#: pdf_on_submit/public/js/pdf_button_utils.js:41
msgid "Popup Blocked"
msgstr ""

#: pdf_on_submit/pdf_on_submit/doctype/pdf_on_submit_settings/pdf_on_submit_settings.py:16
msgid "Row #{0}: invalid filters for <b>{1}</b>: {2}"
msgstr ""

#. Label of the show_pdf_button (Check) field in DocType 'PDF on Submit
#. Settings'
#: pdf_on_submit/pdf_on_submit/doctype/pdf_on_submit_settings/pdf_on_submit_settings.json
msgid "Show PDF Button"
msgstr ""

Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
"section_break_1",
"enabled_for",
"section_break_8",
"create_pdf_in_background"
"create_pdf_in_background",
"column_break_eoam",
"show_pdf_button"
],
"fields": [
{
Expand All @@ -31,12 +33,23 @@
"fieldtype": "Table",
"label": "Enabled For",
"options": "Enabled DocType"
},
{
"fieldname": "column_break_eoam",
"fieldtype": "Column Break"
},
{
"default": "0",
"description": "Displays a PDF button on the Form View for each enabled DocType.",
"fieldname": "show_pdf_button",
"fieldtype": "Check",
"label": "Show PDF Button"
}
],
"icon": "octicon octicon-file-pdf",
"issingle": 1,
"links": [],
"modified": "2026-01-18 22:11:04.756526",
"modified": "2026-05-27 09:19:52.227943",
"modified_by": "Administrator",
"module": "PDF on Submit",
"name": "PDF on Submit Settings",
Expand All @@ -62,7 +75,9 @@
}
],
"quick_entry": 1,
"row_format": "Dynamic",
"sort_field": "creation",
"sort_order": "ASC",
"states": [],
"track_changes": 1
}
}
89 changes: 89 additions & 0 deletions pdf_on_submit/public/js/pdf_button_utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// Shared PDF button utility.
// Auto-registers for every doctype listed in PDF on Submit Settings > enabled_for
// when the global "Show PDF Button" toggle is on (loaded from boot info).

window.pdf_on_submit = window.pdf_on_submit || {};

$(document).on("app_ready", function () {
const boot = frappe.boot.pdf_on_submit || {};
if (!boot.show_pdf_button) return;

(boot.enabled_doctypes || []).forEach((doctype) => {
frappe.ui.form.on(doctype, {
refresh: pdf_on_submit.add_pdf_button,
});
});
});

pdf_on_submit.build_pdf_url = function (frm, { print_format, letter_head }) {
const params = new URLSearchParams({
doctype: frm.doc.doctype,
name: frm.doc.name,
format: print_format,
no_letterhead: 0,
letterhead: letter_head || "",
...(frm.doc.language && { _lang: frm.doc.language }),
}).toString();
return frappe.urllib.get_full_url("/api/method/frappe.utils.print_format.download_pdf?" + params);
};

pdf_on_submit.add_pdf_button = async function (frm) {
if (frm.is_new()) return;

frm.remove_custom_button(__("PDF"));

frm.add_custom_button(__("PDF"), async () => {
Comment thread
HenningWendtland marked this conversation as resolved.
Outdated
Comment thread
HenningWendtland marked this conversation as resolved.
Outdated
// Open the popup synchronously while still in the user-gesture context,
// before any await, to avoid browser popup blockers.
const popup = window.open("", "_blank");
if (!popup) {
frappe.msgprint({
title: __("Popup Blocked"),
indicator: "orange",
message: __("Please allow popups for this site and try again."),
});
return;
}
try {
const matches = await frappe.xcall("pdf_on_submit.utils.get_print_details", {
doctype: frm.doc.doctype,
docname: frm.doc.name,
});

if (!matches || !matches.length) {
popup.close();
return;
}

const [first, ...rest] = matches;
popup.location.href = pdf_on_submit.build_pdf_url(frm, first);

if (rest.length) {
const items = rest
.map((m) => {
const label = m.letter_head
? `${frappe.utils.escape_html(m.print_format)} – ${frappe.utils.escape_html(m.letter_head)}`
: frappe.utils.escape_html(m.print_format);
const href = frappe.utils.escape_html(pdf_on_submit.build_pdf_url(frm, m));
return `<li><a href="${href}" target="_blank" rel="noopener">${label}</a></li>`;
})
.join("");
frappe.msgprint({
title: __("Additional print formats"),
indicator: "blue",
message: __("More formats are configured for this document. Click to open:") + `<ul>${items}</ul>`,
});
}
} catch (error) {
popup.close();
console.error("PDF generation failed:", error);
frappe.msgprint({
title: __("Error"),
indicator: "red",
message: __("Failed to generate PDF. {0}", [
error.message || __("Please check your permissions and try again."),
]),
});
}
});
};
Loading
Loading