I have been working on/with ERPNext for some time now, but had never tried to change much in terms of the output formatting – mostly because I was too afraid to mess anything up. I only made minor changes with the format builder/GUI tool, which, I must say – is not intuitive, and which I personally found a bit frustrating.
Anyway – it turns out that setting up custom formatting using Jinja2 is not as terrifying as I thought.
Here’s my 2nd attempt/updated 1st attempt (no longer hard-coded tax-rate), with some commenting within the code to explain what I am doing, and also where/why. The biggest difference between my version and the default, is that I show the excl-VAT, VAT and incl-VAT values separately.
x <style>
/* My personal syle abbreviations to use minimal characters while coding the HTML portions*/
/*.bd0 { border: 1px dotted red; padding: 0px;}*/
.lf { text-align: left;}
.cn { text-align: center;}
.rt { text-align: right;}
.vt { vertical-align: top;}
.vc { vertical-align: middle;}
.vb { vertical-align: bottom;}
.xs { font-size: x-small;}
.sm { font-size: small;}
.md { font-size: medium;}
.lg { font-size: large;}
.xl { font-size: x-large;}
.xxl { font-size: xx-large;}
.b { font-weight: bold;}
.bb { font-weight: bolder;}
.i { font-style: italic;}
.u { text-decoration: underline;}
.bd0 { border: 1px dashed;}
.bd1 { border: 1px dotted;}
.bd2 { border: 2px solid;}
.blk { color: black;}
.lgr { color: lightgrey;}
.lblu{ color: lightblue;}
.blu { color: blue;}
.grn { color: green;}
.red { color: red;}
.ylw { color: yellow;}
.org { color: orange;}
.ord { color: orangered;}
.prp { color: purple;}
.lim { color: lime;}
.spacer { color: white; font-weight: bold;}
.print-format table, .print-format tr,
.print-format td, .print-format div, .print-format p {
//font-family: Monospace;
vertical-align: middle;
font-family: "Roboto", Helvetica, Arial, sans-serif;
font-smoothing: antialiased;
osx-font-smoothing: grayscale;
padding: 0px;
z-index: 10;
}
@media screen {
.print-format {
padding: 10mm;
}
}
</style>
{# NOTE: default is to use looked up company name from ERPNext, but that doesn't suit us, so I hardcoded it #}
{# {{ doc.company }}<br> #}
<h3 class="cn b">{{ _("Company Name") }}</h3>
<div class="cn">{{ _("VAT No: ") }}{{ _("777777777") }}</div>
<br>
{# NOTE: conditional date type based on SINV status #}
<div class="cn"> {% if doc.docstatus == 0 %} {{ doc.status + " " + (doc.select_print_heading or _("Tax Invoice: ")) }} {% else %} {{ doc.select_print_heading or _("Tax Invoice: ") }} {% endif %} {{ doc.name }} </div>
<br>
<table class="table-condensed no-border">
<tr>
<td class="rt b">
{{ _("Date") }}:
</td>
<td class="lf">
{% if doc.docstatus == 0 %} {{ doc.get_formatted("posting_date") }} {% else %} {{ doc.get_formatted("invoice_date") }} {% endif %}
</td>
<td class="rt b">
{{ _("Time") }}:
</td>
<td class="lf">
{{ frappe.utils.get_datetime().strftime('%H:%M:%S') }}
</td>
</tr>
<tr>
<td class="rt b">
{{ _("Customer: ") }}<br>
{{ _("VAT No: ") }}<br>
{{ _("Contact: ") }}
</td>
<td class="lf">
{{ doc.customer_name }}<br>
{{ doc.tax_id }}<br>
{{ doc.contact_display }}<br>{{ doc.contact_mobile }}
</td>
<td class="rt b">
{{ _("Address") }}
</td>
<td class="lf">
{{ doc.address_display }}
</td>
</tr>
</table>
<table class="table table-condensed table-bordered">
{# <table class="table table-condensed cart no-border"> #}
<thead>
<tr>
<th>Row</th>
<th>Code/Item</th>
<th class="cn">ea.<br>exc</th>
<th class="cn">ea.<br>VAT</th>
<th class="cn">ea.<br>inc</th>
<th class="cn">qty*ea.</th>
<th class="cn">amt<br>inc</th>
</tr>
</thead>
<tbody>
{# Get the tax/VAT rate for THIS.document #}
{% set this_docs_vat_rate = frappe.db.get_value("Sales Taxes and Charges", {"parent": doc.name}, "rate") %}
{# This matches doc.name [parent= THIS.SalesInvoice] to ONE db row, and then extracts ONE/relevant column [RATE] #}
{%- for row in doc.items -%}
<tr>
<td style="width: 3%;">{{ row.idx }}</td>
<td><small>
{{ row.item_code }}</small><br>
{% if row.item_code != row.item_name -%} {{ row.item_name}} {%- endif %}
</td>
<td class="rt sm" style="width: 10%;">{{ "%.2f"|format(row.rate) }}</td>
<td class="rt sm" style="width: 10%;">{{ "%.2f"|format(row.rate * (this_docs_vat_rate/100) )}}</td>
{# <br><small>@{{ (this_docs_vat_rate) }}%</small> #}
<td class="rt sm" style="width: 10%;">{{ "%.2f"|format(row.rate * (1+(this_docs_vat_rate/100)) ) }}</td>
<td class="rt" style="width: 15%;">{{ row.qty }}<small> @ </small>{{ "%.2f"|format(row.rate * (1+(this_docs_vat_rate/100)) ) }}</td>
<td class="rt vb" style="width: 10%;">{{ "%.2f"|format(row.amount * (1+ (this_docs_vat_rate/100)) ) }}</td>
</tr>
{%- endfor -%}
</tbody>
</table>
<table>
<tr>
<td style="width:65%"></td>
<td>
{# Totals subsection #}
<table class="table table-condensed no-border">
<tbody>
<tr>
{% if doc.flags.show_inclusive_tax_in_print %}
<td class="rt b" style="width: 50%">{{ _("Total Excl. Tax") }}</td>
{# <td class="rt">{{ doc.get_formatted("net_total", doc) }}</td> #}
<td class="rt">{{ "R {:,.2f}".format(doc.net_total) }}</td>
{% else %}
<td class="rt b" style="width: 50%">{{ _("SubTotal (Excl)") }}</td>
<td class="rt">{{ "R {:,.2f}".format(doc.total) }}</td>
{% endif %}
</tr>
{%- for row in doc.taxes -%}
{%- if not row.included_in_print_rate or doc.flags.show_inclusive_tax_in_print -%}
<tr>
<td class="rt b" style="width: 50%">{{ row.description }}</td>
<td class="rt">{{ "R {:,.2f}".format(row.tax_amount) }}</td>
<tr>
{%- endif -%}
{%- endfor -%}
{%- if doc.discount_amount -%}
<tr>
<td class="rt b" style="width: 50%">{{ _("Discount") }}</td>
{# <td class="rt">{{ doc.get_formatted("discount_amount") }}</td> #}
<td class="rt">{{ "R {:,.2f}".format(doc.discount_amount) }}</td>
</tr>
{%- endif -%}
<tr>
<td class="rt b" style="width: 50%">{{ _("Grand Total (Incl)") }}</td>
<td class="rt lg">{{ "R {:,.2f}".format(doc.grand_total) }}</td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
<hr>
<p>{{ doc.terms or "" }}</p>
<p class="cn b">{{ _("Thank you for your business.") }}</p>
<table>
<tr>
<td class="lf">{{ _("www.example.com<br>info@example.com<br>+27 11 555 5555<br>+27 xx xxx xxxx<br>GPS: -XX.xxxxxx, YY.yyyyyy") }}</td>
<td class="rt">{{ _("Address Line 1, Line 2<br>Building Name<br>cnr Street 1/Street 2<br>Suburb<br>PostCode") }}</td>
</tr>
</table>
which produces something like this…
Hi there,
Looks very similar to my template. At the moment I am struggling with the following:
The customer has a name. The contact of the customer has a company_name. In the invoice I want to print:
company_name (from contact)
customer name (from customer)
My struggle is getting the company_name. Any suggestion how to get?
Best regars
Sam
Hi all,
Has anyone tried this on V13?
Not yet – I had to fix a series of (unrelated) server crashes, so I haven’t had a chance to try it. Those are (as of today 27 Aug) now working again, so I will have a crack at the v13 and create a new post or update this one ASAP
Do you mind if I quote a few of your posts as
long ɑs I provide credit and sources back to youг ѡeblog?
My bloց is in the very same niche as yours and my users would definitely benefit from some of the information you provide here.
Please let me know if this okɑy with you. Cheers!