I’m facing an issue in ERPNext when generating PDFs from the Sales Invoice print screen. There are two options for PDF generation:
- Print → Save as PDF (Works perfectly, maintains layout and everything)
- Direct PDF Button (Breaks layout: font size, margins, and page size change)
I tried modifying the Print Settings CSS, which affects both methods. While some changes reflect, it also disrupts the “Print → Save as PDF” output.
I’ve searched and found similar issues, but the solutions are not working in my case as maybe it’s outdated or I’ve different version of Erpnext/Frappe/wkhtmltopdf etc.
What I’ve Found:
- Wkhtmltopdf rendering without CSS - custom and core - all standard solutions have no affect - ubuntu 18.04
- Generated PDF looks weird, wkhtmltopdf, no bootstrap CSS
- WKHTMLTOPDF not loading local css
- WkHTMLtoPDF not loading local CSS and images
What I’ve Tried, Resolved:
- Adjusting CSS in Print Settings
- Ensuring
wkhtmltopdf
is correctly installed (using the Qt-patched version 0.12.6) - Added “host_name”: “example.com”, in sitename/site_config.json and ran command
bench migrate
- In my case, pictures (QR, Header, Footer) are displayed, so no issue with paths
Questions:
- How can I apply styles specifically to the PDF button output without affecting Print → Save as PDF?
- Any ERPNext configuration changes needed to standardize both outputs?
I’ve attached both screenshots:
You’ll notice the difference of Font Size, Font Family, Overlapping of texts, Page Size etc.
I’ve also attached the Print Format to understand the css applied.
Print Format
.print-format table, .print-format tr, .print-format td { font-family: serif; line-height: 0.3 !important; vertical-align: middle; direction: rtl !important; } @media print { body { font-family: 'Cairo'; width: 220mm; height: 297mm; margin: 5mm 5mm 10mm 5mm; footer { page-break-after: always; } /* change the margins as you want them to be. */ } } @media screen { .print-format { width: 200mm; padding: 5mm; min-height: 297mm; footer { page-break-after: always; } } } table { width: 100%; white-space: nowrap; } th { font-size: 10px; color: black; } body:last-child .print-format td img { width: 60% !important; } .ql-editor read-mode { line-height: 1 !important; } .ql-editor p, .ql-editor h1, .ql-editor h2, .ql-editor h3, .ql-editor h4, .ql-editor h5, .ql-editor h6, .ql-editor span { counter-reset: list-0 list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9; line-height: 1.2; overflow: hidden !important; text-overflow: ellipsis !important; white-space: nowrap !important; display: inline-flex !important; } .print-format p { margin: 3px 0px 3px; display: inline-block !important; } .si { color: darkblue !important; margin-top: -5px !important; } .w1 {} .w2 { border-top: 3px solid #d1d8dd !important; padding-top: 4px !important; text-align: center; direction: rtl; margin-top: 15px; } @media print { div.print-footer { display:block !important; position: fixed !important; bottom: 0; width: 97%; background-color: white; text-align: center; padding: 2mm 2; box-sizing: border-box; page-break-after: always; z-index: 9999; } div.print-footer .page-number { position: absolute; bottom: 5mm; width: 100%; text-align: center; } @page :first { table:nth-of-type(4) tr:nth-child(n+10) { page-break-after: always; } } @page { table tr:nth-child(28n+1) { page-break-after: always; } } } * { box-sizing: content-box !important; } body { counter-reset: page; } /* Define a style for the page number */ .page-number:before { counter-increment: page; content: counter(page) " of "counter(pages); }<table style="white-space: nowrap;margin-top:-4% !important;">
<tr>
<td style="width:50%;">
<!-- Table2 -->
<table style="white-space: nowrap;line-height: 1.3 !important;">
<tr style="line-height: 1.3 !important;">
<td style="width:30%;font-size: 10px;text-align: center;">
<span style="color: #5b5b5b;font-size: 25px;font-weight: 800;text-align: center;line-height: 1;">
<br> {{ "TAX INVOICE" }}
<br> {{ "فاتورة ضريبية " }}
</span>
</td>
</tr>
</table>
</td>
<td style="width:10%;">
<!-- Table1 -->
<table>
<tr>
<td>
<div style="width: 200px !important;text-align: center; display: block !important;margin: 0 149px 0 -13px!important;vertical-align: middle !important;margin-top: 0px !important;">
{{ letter_head }}</div>
</td>
</tr>
</table>
</table>
<table style="white-space: nowrap;table-layout: fixed;">
<tr>
<td style="width:50%;">
<!-- Table1 -->
<table style="white-space: nowrap;table-layout: fixed;">
<tr>
<td>
<div style="width: 200px !important;text-align: center; display: block !important;margin: 0 auto !important;vertical-align: middle !important;margin-top: -25px !important;">
<img class="qr-code" src={{doc.ksa_einv_qr}}>
</div>
</td>
</tr>
</table>
</td>
<td style="width:50%; border: solid 2px gray; ">
<!-- Table2 -->
<table style="white-space: nowrap;table-layout: fixed;line-height: 1.3 !important;">
<tr style="line-height: 1.3 !important;">
<td style="width:30%;font-size: 10px;text-align: left;line-height: 1.3 !important;">
<b>{{ "رقم الفاتورة" }} :</b>
<br>
<b>{{ "تاريخ الفاتورة" }} :</b>
<br>
<b>{{ "رقم العقد " }} :</b>
<br>
<b>{{ "رقم أمر الشراء/الخدمة " }} :</b>
<br>
<b>{{ " تاريخ التوريد/الإنجاز " }} :</b>
<br>
<b>{{ "الرقم المرجعي " }} :</b>
<br>
<b>{{ "رمز البائع " }} :</b>
<br>
</td>
<td style="width:40%;font-size: 10px;text-align: center;line-height: 1.3 !important;">
<b style="color: darkblue;">{{ doc.name }}</b>
<br>
<b style="color: darkblue;"> {{ doc.get_formatted("posting_date") }}</b>
<br>
<b style="color: darkblue;">{{ doc.custom_contract_number or "" }}</b>
<br>
<b style="color: darkblue;">{{ doc.po_no or "" }}</b>
<br>
<b style="color: darkblue;">{{ doc.delivery_date_and_time or "" }}</b>
<br>
<b style="color: darkblue;">{{ doc.custom_rfx_number or "" }}</b>
<br>
<b style="color: darkblue;">{{ doc.custom_vendor_no or "" }}</b>
<br>
</td>
<td style="width:35%;font-size: 10px;text-align: right;line-height: 1.3 !important;">
<b>:{{ "Invoice No" }}</b>
<br>
<b>:{{ "Invoice Date" }}</b>
<br>
<b>:{{ "Contract Number" }}</b>
<br>
<b>:{{ "Order/Service No" }}</b>
<br>
<b>:{{ "Complet/Delivery Date" }}</b>
<br>
<b>:{{ " P.T.Ref" }}</b>
<br>
<b>:{{"Vender No " }}</b>
<br>
</td>
</tr>
</table>
</td>
</tr>
</table>
<table style="white-space:nowrap; table-layout:fixed; margin-top:5px; width:100%; text-align:center;">
<tr>
<td style="width:50%; border:2px solid gray;">
<!-- Table1 -->
<table style="white-space: nowrap; table-layout: fixed; margin-top: -6px; width:100%;">
<tr style="border-bottom: 2px solid black;">
<td style="width:35%; font-size:16px; font-weight:900; text-align:right;"></td>
<td style="width:80%; font-size:12px; font-weight:900; text-align:center;">
<b> {{ " Supplier " }}</b>
<br>
<br>
<br>
<br>
<b> {{ " المورد" }} </b>
</td>
<td style="width:35%; font-size:16px; font-weight:900; text-align:left;"></td>
</tr>
<tr style="border-bottom:1px solid black;">
<td colspan="3" style="font-size:10px; text-align:center;">
<b style="color: darkblue;">{{ "شركة الرواد الفنية للتجارة والمقاولات العامه المحدوده" }}</b>
<br>
<br>
<br>
<br>
<b style="color: darkblue;">{{ "Pioneers Technical For Trading & General Contracting Co. Ltd" }}</b>
</td>
</tr>
<tr style="border-bottom: 1px solid black;">
<td style="width:30%; font-size:10px; text-align:right;">
<b>{{ "الرقم الضريبي" }}:</b>
</td>
<td style="width:40%; font-size:10px; text-align:center; color:darkblue;">
<b>{{ doc.company_tax_id }}</b>
</td>
<td style="width:30%; font-size:10px; text-align:left;">
<b>:{{ "VAT ID" }}</b>
</td>
</tr>
<tr style="border-bottom: 1px solid black;">
<td style="width:25% !important; font-size:10px; text-align:center;">
<div style="font-weight:900; padding: 5px; border-bottom: 1px solid black;">
ترخيص الموارد البشرية
</div>
<div style="padding: 5px;">
85953
</div>
</td>
<td style="width:25% !important; font-size:10px; text-align:center;">
<div style="font-weight:900; padding: 5px; border-bottom: 1px solid black;">
السجل التجاري (CR)
</div>
<div style="padding: 5px;">
4030138666
</div>
</td>
<td style="width:25% !important; font-size:10px; text-align:center;">
<div style="font-weight:900; padding: 5px; border-bottom: 1px solid black;">
التامينات الاجتماعية
</div>
<div style="padding: 5px;">
511414695
</div>
</td>
</tr>
<tr>
<td style="width:30%; font-size:10px; text-align:right; height:75px;">
<b>{{ "العنوان" }}:</b>
</td>
<td style="width:40%; font-size:10px; text-align:center; height:75px; line-height:1 !important; color:darkblue;">
<b style="white-space: normal !important;color: darkblue !important;"> {{ frappe.db.get_value("Address", doc.company_address, "address_line1") or "" }}
<br>
<br> {{ frappe.db.get_value("Address", doc.company_address, "address_in_arabic") or "" }}
</b>
</td>
<td style="width:30%; font-size:10px; text-align:left; height:75px;">
<b>:{{ "Address" }}</b>
</td>
</tr>
</table>
</td>
<td style="width:50%; border:2px solid gray;">
<!-- Table2 -->
<table style="white-space:nowrap; table-layout:fixed; margin-top:-6px; width:100%;">
<tr style="border-bottom: 2px solid black;">
<td style="width:35%; font-size:16px; font-weight:900; text-align:right;"></td>
<td style="width:80%; font-size:12px; font-weight:900; text-align:center;">
<b> {{ " Customer " }}</b>
<br>
<br>
<br>
<br>
<b> {{ " العميل" }} </b>
</td>
<td style="width:35%; font-size:16px; font-weight:900; text-align:left;"></td>
</tr>
<tr style="border-bottom:1px solid black;">
<td colspan="3" style="font-size:10px; text-align:center;">
<b style="color: darkblue;">{{ doc.customer_name_in_arabic or "" }} </b>
<br>
<br>
<br>
<br>
<b style="color: darkblue;">{{ doc.customer_name }} </b>
</td>
</tr>
<tr style="border-bottom:1px solid black;">
<td style="width:30%; font-size:10px; text-align:right;">
<b>{{ "الرقم الضريبي" }}:</b>
</td>
<td style="width:40%; font-size:10px; text-align:center; color:darkblue;">
<b>{{ doc.tax_id or "" }}</b>
</td>
<td style="width:30%; font-size:10px; text-align:left;">
<b>:{{ "VAT ID" }}</b>
</td>
</tr>
<tr style="border-bottom:1px solid black;">
<td style="width:30%; font-size:10px; text-align:right;">
<b>{{ "رقم السجل التجاري"}}:</b>
</td>
<td style="width:40%; font-size:10px; text-align:center; color:darkblue;">
<b>{{ frappe.get_doc("Customer", doc.customer).custom_company_cr or ""}} </b>
</td>
<td style="width:30%; font-size:10px; text-align:left;">
<b>:{{ "CR NO" }}</b>
</td>
</tr>
<tr>
<td style="width:30%; font-size:10px; text-align:right; height:75px;">
<b>{{ "العنوان" }}:</b>
</td>
<td style="width:40%; font-size:10px; text-align:center; height:75px; line-height:1 !important; color:darkblue;">
<b style="white-space: normal !important;color: darkblue !important;"> {{ frappe.db.get_value("Address", doc.customer_address, "address_line1") or "" }}
<br>
<br> {{ frappe.db.get_value("Address", doc.customer_address, "address_in_arabic") or "" }}
</b>
</td>
<td style="width:30%; font-size:10px; text-align:left; height:75px;">
<b>:{{ "Address" }}</b>
</td>
</tr>
</table>
</td>
</tr>
</table>
<!--Dynamic Colspan for total row columns-->
{% set col = namespace(one = 2, two = 1) %} {% set length = doc.taxes | length %} {% set length = length / 2 | round %} {% set col.one = col.one + length %} {% set col.two = col.two + length %} {%- if(doc.taxes | length % 2 > 0 ) -%} {% set col.two =
col.two + 1 %} {% endif %}
<!-- Items -->
{% set total = namespace(amount = 0) %}
<table style="margin-top: 15px;direction: ltr !important;white-space:nowrap; table-layout:fixed;">
<thead>
<tr style="border-bottom: solid 2px black;border-top: solid 2px black;line-height: 2 !important;">
<th colspan="1" style="width:3%;text-align:center;color:black;font-size:12px;font-weight: 600;">S
<br>م </th>
<th colspan="3" style="width:57%;text-align:center;color:black;font-size:12px;font-weight: 600;">Description
<br>وصف المنتج </th>
<th colspan="1" style="width:5%;text-align:center;color:black;font-size:12px;font-weight: 600;">QTY
<br>الكمية </th>
<th style="width:10%;text-align:left;color:black;font-size:12px;font-weight: 600;">Unit Price
<br>سعر الوحدة </th>
<th style="width:15%;text-align:left;color:black;font-size:12px;font-weight: 600;">Taxable Amount
<br />الاجمالي قبل الضريبة </th> {% for row in doc.taxes %}
<th style="width:15%;text-align:center;color:black;font-size:12px;font-weight: 600;">Tax Percentage
<br>نسبة الضريبة </th>
<th style="width:10%;text-align:center;color:black;font-size:12px;font-weight: 600;">Tax Amount
<br>مبلغ الضريبة </th> {% endfor %}
<th style="width:15%;text-align:center;color:black;font-size:12px;font-weight: 600;">Total With VAT
<br>المجموع بالضريبة </th>
</tr>
</thead>
<tbody>
{%- for item in doc.items -%} {% set total.amount = item.amount %}
<tr style="margin-bottom: -10px !important;line-height:0.1 !important; height: 20px !important;">
<td colspan="1" style="width: 2%;text-align: center;">{{ item.idx }}</td>
<td colspan="3" style="width: 40%;text-align: left;line-height:0.3!important;font-size: 11px;font-weight: 700;">{{ item.item_code }}</td>
<td colspan="1" style="text-align: center;font-size: 12px;font-weight: 700;">{{ item.qty }}</td>
<td style="text-align: left;font-size: 12px;font-weight: 700;">{{ item.get_formatted("rate") }}</td>
<td style="text-align: left;font-size: 12px;font-weight: 700;">{{ item.get_formatted("amount") }}</td>
{% for row in doc.taxes %} {% set data_object = json.loads(row.item_wise_tax_detail) %} {% set key = item.item_code or item.item_name %} {% set taxable_amount = item.amount %} {% set tax_percentage = data_object[key][0] or 0 %} {% set tax_amount = taxable_amount
* (tax_percentage / 100) %} {% set total.amount = total.amount + tax_amount %}
<td style="text-align: center;font-size: 12px;font-weight: 700;">
<div class="qr-flex"> {%- if data_object[key][0] -%} <span>{{ frappe.format(data_object[key][0], {'fieldtype': 'Percent'}) }}</span> {%- endif -%} </div>
</td>
<td style="text-align: center;font-size: 12px;font-weight: 700;">
<span> {% if data_object[key][0] %} {{ frappe.format_value(tax_amount, currency=doc.currency) }} {% endif %} </span>
</td> {% endfor %}
<td style="text-align: center;font-size: 12px;font-weight: 700;"> {{ frappe.format_value(frappe.utils.flt(total.amount, doc.precision('total_taxes_and_charges')), currency=doc.currency) }} </td>
</tr>
<tr style="border-bottom: solid 1px gray;height: 20px !important;font-size: 11px;font-weight: 700;margin-top:-1% !important">
<td> </td>
<td colspan="10" style="width: 60%; text-align: left; font-size: 10px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
{{ item.description.replace('\n', ' ').replace('\r', '').replace('\t', '+').replace(' ', '+').strip() }}
</tr>
{%- endfor -%}
</tbody>
</table>
<table style="white-space: nowrap;table-layout: fixed;margin-top: 5px;">
<tr>
<td style="width:50%; border: solid 2px gray; ">
<!-- Table1 -->
<table style="white-space: nowrap;table-layout: fixed;margin-top: -6px;">
<tr style="border-bottom: solid 2px black;">
<td style="width:30%;font-size: 16px;font-weight: 900;text-align: right;">
<b>{{ " اجمالي المبالغ" }}:</b>
</td>
<td style="width:40%;font-size: 10px;"></td>
<td style="width:30%;font-size: 16px;font-weight: 900;text-align: left;">
<b>:{{ " Total Amount" }}</b>
</td>
</tr style="line-height: .4 !important;">
<tr style="border-bottom: solid 1px gray;">
<td style="width:30%;font-size: 10px;text-align: center;">
<b> {{ doc.get_formatted("total", doc) }} </b>
</td>
<td style="width:40%;font-size: 10px;text-align: right;">
<b>{{ "الاجمالي غير شامل ضريبة القيمة المضافة"}}</b>
</td>
<td style="width:30%;font-size: 10px;text-align: left;">
<b>
<b>{{ " Total Without Tax " }}</b>
</b>
</td>
</tr>
<tr style="border-bottom: solid 1px gray;">
<td style="width:30%;font-size: 10px;text-align: center;">
<b> {{ doc.get_formatted("discount_amount") }} </b>
</td>
<td style="width:40%;font-size: 10px;text-align: right;">
<b>{{ "اجمالي الخصومات "}}</b>
</td>
<td style="width:30%;font-size: 10px;text-align: left;">
<b>
<b>{{ ("Total Discount") }}</b>
</b>
</td>
</tr>
<tr style="border-bottom: solid 1px gray;">
<td style="width:30%;font-size: 10px;text-align: center;">
<b> {{ doc.get_formatted("net_total", doc) }} </b>
</td>
<td style="width:40%;font-size: 10px;text-align: right;">
<b>{{ "الاجمالي الخاضع لضريبة القيمة المضافة "}}</b>
</td>
<td style="width:30%;font-size: 10px;text-align: left;">
<b>
<b>{{ (" Total Taxable Amount ") }}</b>
</b>
</td>
</tr>
<tr style="border-bottom: solid 1px gray;">
<td style="width:30%;font-size: 10px;text-align: center;">
<b> {{ doc.get_formatted("total_taxes_and_charges", doc) }}</b>
</td>
<td style="width:40%;font-size: 10px;text-align: right;">
<b>{{ "مجموع ضريبة القيمة المضافة "}}</b>
</td>
<td style="width:30%;font-size: 10px;text-align: left;">
<b>
<b>{{ (" Total VAT ") }}</b>
</b>
</td>
</tr>
<tr style="border-bottom: solid 1px gray;">
<td style="width:30%;font-size: 10px;text-align: center;">
<b> {{ doc.get_formatted("grand_total") }} </b>
</td>
<td style="width:40%;font-size: 10px;text-align: right;">
<b>{{ "اجمالي المبلغ المستحق "}}</b>
</td>
<td style="width:30%;font-size: 10px;text-align: left;">
<b>
<b>{{ (" Total Amount Due ") }}</b>
</b>
</td>
</tr>
<tr>
<td colspan="3" style="width:40%; font-size:10px; text-align:center; line-height:1 !important;">
<b style="white-space: normal !important;"> {{frappe.utils.money_in_words(doc.grand_total).replace('SAR', '').rstrip('only.') ~ ' Saudi Rayals Only'}}
</tr>
</table>
</td>
<td style="width:50%;border: solid 2px gray;">
<!-- Table1 -->
<table style="width:100%; text-align:center; white-space:nowrap; table-layout:fixed; margin-top:-6px;">
<tr style="border-bottom:2px solid gray;">
<td style="width:20%; font-size:16px; font-weight:900; text-align:right;">
<b>{{ "تفاصيل البنك"}}:</b>
</td>
<td style="width:40%; font-size:16px;"></td>
<td style="width:35%; font-size:16px; font-weight:900; text-align:left;">
<b>:{{ "Bank Info"}}</b>
</td>
</tr>
<tr style="border-bottom:1px solid gray;">
<td colspan="3" style="font-size:12px; font-weight:900; height:35px;">
<b style="margin-left: 50px;">{{ "اسم الحساب المصرفي" }}</b>
<b>{{ "Bank Name"}}</b>
<br>
<br>
<br>
<br>
<b style="font-size: 8px;font-weight: 900;">{{ "PIONEERS TECHNICAL FOR TRADING AND GENERAL CONTRACTING CO. LTD"}}</b>
<br>
<br>
<br>
<br>
<br>
<b>{{ "شركة الرواد الفنية للتجارة والمقاولات العامة المحدودة"}}</b>
</td>
</tr>
<tr style="border-bottom:1px solid gray;">
<td colspan="3" style="font-size:10px; text-align:center;">
<b style="margin-left: 180px;">{{ "ايبان بنك الرياض" }}:</b>
<b>:{{ "RB IBAN NO"}}</b>
<br>
<br>
<br>
<b style="color: darkblue;font-size: 12px;">{{ "SA59 2000 0001 6916 2321 9940"}}</b>
</td>
</tr>
<tr style="border-bottom:1px solid gray;">
<td colspan="3" style="font-size:10px; text-align:center;">
<b style="margin-left: 180px;">{{ "ايبان البنك الاهلي" }}:</b>
<b>:{{ "SNB IBAN NO"}}</b>
<br>
<br>
<br>
<b style="color: darkblue;font-size: 12px;">{{ "SA71 1000 0012 9566 0400 0107"}}</b>
</td>
</tr>
</td>
</tr>
</table>
</td>
</tr>
</table>
<div class="print-footer"> {{ footer }}
</div>
Would appreciate any guidance from the community! Thanks.