feat: default Sales Invoice print format

Add the "Default Standard Sales Invoice" Print Format fixture and the
Property Setter that makes it the default for Sales Invoice.

The format reproduces Frappe's standard layout and appends a Bank Account
Details section on the last page when the company has an enabled Bank
Account flagged Is Company Account + Is Default Account
(get_company_bank_account jinja method).
This commit is contained in:
2026-09-10 08:04:37 +00:00
parent c82666d563
commit e35179d413
4 changed files with 85 additions and 1 deletions
@@ -0,0 +1,36 @@
[
{
"absolute_value": 0,
"align_labels_right": 0,
"css": null,
"custom_format": 1,
"default_print_language": null,
"disabled": 0,
"doc_type": "Sales Invoice",
"docstatus": 0,
"doctype": "Print Format",
"font": null,
"font_size": 14,
"format_data": null,
"html": "{%- from \"templates/print_formats/standard_macros.html\" import add_header, render_field with context -%}\n{%- set bank_account = get_company_bank_account(doc.company) -%}\n\n{% for page in layout %}\n<div class=\"page-break\">\n\t<div {% if print_settings.repeat_header_footer %} id=\"header-html\" class=\"hidden-pdf\" {% endif %}>\n\t\t{{ add_header(loop.index, layout|len, doc, letter_head, no_letterhead, footer, print_settings, print_heading_template) }}\n\t</div>\n\n\t{% for section in page %}\n\t<div class=\"row section-break\" data-label=\"{{ section.label or '' | e }}\">\n\t\t{%- if doc.print_line_breaks and loop.index != 1 -%}<hr>{%- endif -%}\n\t\t{%- if doc.print_section_headings and section.label and section.has_data -%}\n\t\t<h4 class='col-sm-12'>{{ _(section.label) }}</h4>\n\t\t{%- endif -%}\n\t\t{%- set no_of_cols = section.columns|len -%}\n\t\t{% for column in section.columns %}\n\t\t\t<div class=\"col-xs-{{ (12 / no_of_cols)|int }} column-break\">\n\t\t\t{% for df in column.fields %}\n\t\t\t\t{{ render_field(df, doc, no_of_cols) }}\n\t\t\t{% endfor %}\n\t\t\t</div>\n\t\t{% endfor %}\n\t</div>\n\t{% endfor %}\n\n\t{% if loop.last and bank_account %}\n\t<div class=\"row section-break\" data-label=\"{{ _(\"Bank Account Details\") }}\">\n\t\t{%- if doc.print_line_breaks -%}<hr>{%- endif -%}\n\t\t<div class=\"col-xs-12 column-break\">\n\t\t\t<h4>{{ _(\"Bank Account Details\") }}</h4>\n\t\t\t<style>\n\t\t\t\t.bank-account-details { width: 100%; }\n\t\t\t\t.bank-account-details td { padding: 0 !important; border: 0; }\n\t\t\t</style>\n\t\t\t<table class=\"bank-account-details\">\n\t\t\t\t<tbody>\n\t\t\t\t\t<tr><td class=\"text-muted\" style=\"width: 30%; padding-right: 1em !important\">{{ _(\"Bank\") }}</td><td>{{ bank_account.bank }}</td></tr>\n\t\t\t\t\t<tr><td class=\"text-muted\">{{ _(\"Account Name\") }}</td><td>{{ bank_account.account_name }}</td></tr>\n\t\t\t\t\t{% if bank_account.bank_account_no %}\n\t\t\t\t\t<tr><td class=\"text-muted\">{{ _(\"Bank Account No\") }}</td><td>{{ bank_account.bank_account_no }}</td></tr>\n\t\t\t\t\t{% endif %}\n\t\t\t\t\t{% if bank_account.iban %}\n\t\t\t\t\t<tr><td class=\"text-muted\">{{ _(\"IBAN\") }}</td><td>{{ bank_account.iban }}</td></tr>\n\t\t\t\t\t{% endif %}\n\t\t\t\t\t{% if bank_account.branch_code %}\n\t\t\t\t\t<tr><td class=\"text-muted\">{{ _(\"Branch Code\") }}</td><td>{{ bank_account.branch_code }}</td></tr>\n\t\t\t\t\t{% endif %}\n\t\t\t\t\t{% if bank_account.swift_number %}\n\t\t\t\t\t<tr><td class=\"text-muted\">{{ _(\"SWIFT number\") }}</td><td>{{ bank_account.swift_number }}</td></tr>\n\t\t\t\t\t{% endif %}\n\t\t\t\t</tbody>\n\t\t\t</table>\n\t\t</div>\n\t</div>\n\t{% endif %}\n\n\t<div {% if print_settings.repeat_header_footer %} id=\"footer-html\" class=\"visible-pdf\" {% endif %}>\n\t\t{% if not no_letterhead and footer %}\n\t\t<div class=\"letter-head-footer\">\n\t\t\t{{ footer }}\n\t\t</div>\n\t\t{% endif %}\n\t\t{% if print_settings.repeat_header_footer %}\n\t\t\t<p class=\"text-center small page-number visible-pdf\">\n\t\t\t\t{{ _(\"Page {0} of {1}\").format('<span class=\"page\"></span>', '<span class=\"topage\"></span>') }}\n\t\t\t</p>\n\t\t{% endif %}\n\t</div>\n</div>\n{% endfor %}\n",
"line_breaks": 0,
"margin_bottom": 15.0,
"margin_left": 15.0,
"margin_right": 15.0,
"margin_top": 15.0,
"modified": "2026-09-10 14:59:44.872542",
"module": "Default Thai Company",
"name": "Default Standard Sales Invoice",
"page_number": "Hide",
"pdf_generator": "wkhtmltopdf",
"print_format_builder": 0,
"print_format_builder_beta": 0,
"print_format_for": "DocType",
"print_format_type": "Jinja",
"raw_commands": null,
"raw_printing": 0,
"report": null,
"show_section_headings": 0,
"standard": "No"
}
]
@@ -0,0 +1,18 @@
[
{
"default_value": null,
"doc_type": "Sales Invoice",
"docstatus": 0,
"doctype": "Property Setter",
"doctype_or_field": "DocType",
"field_name": null,
"is_system_generated": 1,
"modified": "2026-09-10 13:55:13.996942",
"module": null,
"name": "Sales Invoice-main-default_print_format",
"property": "default_print_format",
"property_type": "Data",
"row_name": null,
"value": "Default Standard Sales Invoice"
}
]
+9 -1
View File
@@ -75,7 +75,10 @@ required_apps = ["erpnext"]
# add methods and filters to jinja environment # add methods and filters to jinja environment
jinja = { jinja = {
"methods": ["default_thai_company.utils.get_letter_head_company"], "methods": [
"default_thai_company.utils.get_letter_head_company",
"default_thai_company.utils.get_company_bank_account",
],
} }
# Fixtures # Fixtures
@@ -84,6 +87,11 @@ jinja = {
fixtures = [ fixtures = [
{"doctype": "Letter Head", "filters": [["name", "in", ["Default Letter Head"]]]}, {"doctype": "Letter Head", "filters": [["name", "in", ["Default Letter Head"]]]},
{"doctype": "Address Template", "filters": [["name", "in", ["Thailand"]]]}, {"doctype": "Address Template", "filters": [["name", "in", ["Thailand"]]]},
{"doctype": "Print Format", "filters": [["name", "in", ["Default Standard Sales Invoice"]]]},
{
"doctype": "Property Setter",
"filters": [["name", "in", ["Sales Invoice-main-default_print_format"]]],
},
] ]
# Installation # Installation
+22
View File
@@ -29,6 +29,28 @@ def get_letter_head_company(doc=None):
) )
def get_company_bank_account(company=None):
"""Default company Bank Account for print formats.
Returns the enabled Bank Account flagged `Is Company Account` and
`Is Default Account` for `company`, or None when there is none.
"""
if not company:
return None
account = frappe.db.get_value(
"Bank Account",
{"company": company, "is_company_account": 1, "is_default": 1, "disabled": 0},
["account_name", "bank", "bank_account_no", "iban", "branch_code"],
as_dict=True,
)
if not account:
return None
account.swift_number = frappe.db.get_value("Bank", account.bank, "swift_number")
return account
def stash_letter_head_source(doc, method=None): def stash_letter_head_source(doc, method=None):
"""Fixture import re-inserts the Letter Head; remember the fixture's `source`.""" """Fixture import re-inserts the Letter Head; remember the fixture's `source`."""
doc.flags.fixture_source = doc.source doc.flags.fixture_source = doc.source