Creating Custom print formats. A walkthrough - Part - 1

Creating Custom print formats. A walkthrough This is an explanation and source for the video on our youtube channel with same title.

 · 4 min read

Professional Invoice Design: 27 Samples & Templates to Inspire You


Creating Custom print formats. A walkthrough

This is an explanation and source for the video on our youtube channel with same title. ( Link here https://youtu.be/Mn_YHcQz-6M )


1- A simple HTML

<p>Hello </p>


2-

color it

<p style="color:blue;"> Hello </p>


3-Add CSS

CSS

.mycss{

color: blue;

background-color: yellow;

font-style: italic;

}

HTML

<p class="mycss"> Hello </p>


4- Jinja ( template engines )

<p class="mycss"> Now time is : {{ frappe.utils.now()}} </p>


5-Variable on Jinja

{% set greeting = "Hello How are you" %}

<p> {{ greeting }} </p>


6-Condition on Jinja

{% set age = 10 %}

  {% if age >= 18 %}

   <h1>You are an adult.</h1>

  {% else %}

   <h1>You are a minor.</h1>

  {% endif %}


7- For condition on Jinja

{% set items = ["item1", "item2", "item3", "item4"] %}

   {% for item in items %}

    <li>{{ item }}</li>

   {% endfor %}


8- Get something from Frappe

<p>{{frappe.get_doc("Company", doc.company)}}</p>


9- Get invoice number

<p>{{doc.customer_name}}</p>


10-Table


  <table border="1">

   <tr>

    <th>Column 1</th>

    <th>Column 2</th>

    <th>Column 3</th>

   </tr>

   <tr>

    <td>Row 1, Column 1</td>

    <td>Row 1, Column 2</td>

    <td>Row 1, Column 3</td>

   </tr>

   <tr>

    <td>Row 2, Column 1</td>

    <td>Row 2, Column 2</td>

    <td>Row 2, Column 3</td>

   </tr>

   <tr>

    <td>Row 3, Column 1</td>

    <td>Row 3, Column 2</td>

    <td>Row 3, Column 3</td>

   </tr>

   <tr>

    <td>Row 4, Column 1</td>

    <td>Row 4, Column 2</td>

    <td>Row 4, Column 3</td>

   </tr>

  </table>


11- COLSPAN and ROWSPAN


  <table border="1">

   <tr>

    <th colspan="2">Column 1 and Column 2</th>

    <th>Column 3</th>

   </tr>

   <tr>

    <td>Row 1, Column 1</td>

    <td>Row 1, Column 2</td>

    <td>Row 1, Column 3</td>

   </tr>

   <tr>

    <td>Row 2, Column 1</td>

    <td>Row 2, Column 2</td>

    <td>Row 2, Column 3</td>

   </tr>

   <tr>

    <td>Row 3, Column 1</td>

    <td>Row 3, Column 2</td>

    <td>Row 3, Column 3</td>

   </tr>

   <tr>

    <td>Row 4, Column 1</td>

    <td>Row 4, Column 2</td>

    <td>Row 4, Column 3</td>

   </tr>

  </table>


12-


  <table border="1">

   <tr>

    <th colspan="2">Column 1 and Column 2</th>

    <th rowspan="2">Column 3</th>

   </tr>

   <tr>

    <td>Row 1, Column 1</td>

    <td>Row 1, Column 2</td>

   </tr>

   <tr>

    <td>Row 2, Column 1</td>

    <td>Row 2, Column 2</td>

    <td>Row 2, Column 3</td>

   </tr>

   <tr>

    <td>Row 3, Column 1</td>

    <td>Row 3, Column 2</td>

    <td>Row 3, Column 3</td>

   </tr>

   <tr>

    <td>Row 4, Column 1</td>

    <td>Row 4, Column 2</td>

    <td>Row 4, Column 3</td>

   </tr>

  </table>


13- show class usage

<table class=mycss border="1">


14- Put invoice number and customer name

Show how to find it on customize invoice

{{frappe.db.get_value('Customer', doc.customer, 'customer_name')}} - Column 1 and Column 2

{{frappe.db.get_value('Customer', doc.customer, 'tax_id')}} - column 3

invoice number {{doc.name}} row1 column1


15- Macro

{% macro myheader() %}

{% endmacro %}


16 - Show the macro multiple times.


{{ myheader() }}

<p></p>

{{ myheader() }}

<p></p>

{{ myheader() }}


17-Code for the header


{% macro myheader() %}

<table class=mycss border="1">


   <tr>

    <th colspan="2">{{frappe.db.get_value('Customer', doc.customer, 'customer_name')}}</th>

    <th rowspan="2"> {{frappe.db.get_value('Customer', doc.customer, 'tax_id')}} </th>

   </tr>

   <tr>

    <td>Row 1, Column 1</td>

    <td>Row 1, Column 2</td>

   </tr>

   <tr>

    <td>Row 2, Column 1</td>

   <td>Row 2, Column 2</td>

    <td>Row 2, Column 3</td>

   </tr>

   <tr>

    <td>Row 3, Column 1</td>

    <td>Row 3, Column 2</td>

    <td>Row 3, Column 3</td>

   </tr>

   <tr>

    <td>Row 4, Column 1</td>

    <td>Row 4, Column 2</td>

    <td>Row 4, Column 3</td>

   </tr>

  </table>

  {% endmacro %}



18

Make a footer


  <table>

      <style>

    table {

      border-collapse: collapse;

      border: 1px solid red;

    }

    th, td {

      border: 1px solid red;

      padding: 8px;

    }

  </style>


    <tr>

      <td colspan="3">Row 1, Column 1 & 2 & 3</td>

      <td>Row 1, Column 4</td>

    </tr>

    <tr>

      <td colspan="4">Row 2, Column 1 & 2 & 3 & 4</td>

    </tr>

  </table>


19-

and Grand total ( row1 column 4 ) and total in numbers ( Row 2, Column 1 & 2 & 3 & 4 )

{{doc.get_formatted("base_total")}} and {{ frappe.utils.money_in_words(doc.base_total)}}


20- Put footer also as macro


{% macro myfooter() %}

{% endmacro %}

{{ myfooter() }}


21- Lets save the footer

{% macro myfooter() %}

  <table>

      <style>

    table {

      border-collapse: collapse;

      border: 1px solid red;

    }

    th, td {

      border: 1px solid red;

      padding: 8px;

    }

  </style>


    <tr>

      <td colspan="3">Total Amount</td>

      <td>{{doc.get_formatted("base_total")}} </td>

    </tr>

    <tr>

      <td colspan="4"> {{ frappe.utils.money_in_words(doc.base_total)}}</td>

    </tr>

  </table>

{% endmacro %}


{{ myfooter() }}



22 - Let us build Item table-header

    <table class=myitemtablestyle>

    <colgroup>

      <col>

      <col>

      <col>

      <col>

    </colgroup>

    <tr>

      <td>Item</td>

      <td>ItemName</td>

      <td>Qty</td>

      <td>Total</td>

    </tr>

  </table>



CSS

itemtablestyle

  {

      border-collapse: collapse;

      width: 100%;

    }

    th, td {

      border: 1px solid blue;

      padding: 8px;

      text-align: left;

      font-size: 10px;

    }

    /* Set width for first and third columns */

    colgroup col:first-child,

    colgroup col:nth-child(3) {

      width: 10%;

    }

    /* Set width for second column */

    colgroup col:nth-child(2) {

      width: 60%;

    }

----------

23 - Build item table - detail

  <table class=itemtablestyle-details>

    <colgroup>

      <col>

      <col>

      <col>

      <col>

    </colgroup>

    {% set items = ["item1", "item2", "item3", "item4"] %}

    {% for item in items %}

    <tr>

      <td>Item</td>

      <td>ItemName</td>

      <td>Qty</td>

      <td>Total</td>

    </tr>

    {% endfor %}

    

  </table>


24- put the values.

  <table class=itemtablestyle-details>

    <colgroup>

      <col>

      <col>

      <col>

      <col>

    </colgroup>

    {%- for item in doc.items -%}

    <tr>

      <td>{{loop.index}}</td>

      <td>{{item.item_name}}</td>

      <td>{{item.qty }}</td>

      <td>{{ item.get_formatted("amount") }}</td>

    </tr>

    {% endfor %}

    

  </table>

25- Page break

 <h1 class="break">Element 1 </h1>

 <p>I am on page-1. It will be printed on the first page.</p>

  <h1 style="page-break-before: always;"></h1>

 <h1 class="break"> Element 2</h1>

 <p>I am on page-2. It will be printed on a separate page due to the page-break-before property.</p>



26- Page break on Item list .

<table class="itemtablestyle-details">

  <colgroup>

    <col>

    <col>

    <col>

    <col>

  </colgroup>

  

  {%- for item in doc.items -%}

  <tr>

    <td>{{loop.index}}</td>

    <td>{{item.item_name}}</td>

    <td>{{item.qty }}</td>

    <td>{{ item.get_formatted("amount") }}</td>

  

  </tr>

  {% if loop.index % 9 == 0 %}

    <tr><td>Break the page here </td></tr>

    <tr style="page-break-before: always;"></tr>

  {% endif %}

  {% endfor %}

</table>


CSS

itemtablestyle-details

  {

      border-collapse: collapse;

      width: 100%;

    }

    th, td {

      border: 1px solid blue;

      padding: 8px;

      text-align: left;

      font-size: 10px;

    }

    /* Set width for first and third columns */

    colgroup col:first-child,

    colgroup col:nth-child(3) {

      width: 10%;

    }

    /* Set width for second column */

    colgroup col:nth-child(2) {

      width: 60%;

    }


------------

27- Page numbers .

{% set pages = namespace(current=1) %}

<table class="itemtablestyle-details">

  <colgroup>

    <col>

    <col>

    <col>

    <col>

  </colgroup>

  

  {%- for item in doc.items -%}

  <tr>

    <td>{{loop.index}}</td>

    <td>{{item.item_name}}</td>

    <td>{{item.qty }}</td>

    <td>{{ item.get_formatted("amount") }}</td>

  

  </tr>

  {% if loop.index % 9 == 0 %}

    <tr><td>Break the page here </td> <td>current page is : {{pages.current}}</td></tr>

    <tr style="page-break-before: always;"></tr>

    {% set pages.current = pages.current +1 %}

  {% endif %}

  {% endfor %}

</table>


28- Total pages


{% set pages = namespace(current=1) %}

{% set pagetotal = namespace(total=1) %}

<table class="itemtablestyle-details">

  <colgroup>

    <col>

    <col>

    <col>

    <col>

  </colgroup>

  {% set pagetotal.total = ((doc.items | length) / 9) | round(0, 'ceil') | int %}

  {%- for item in doc.items -%}

  <tr>

    <td>{{loop.index}}</td>

    <td>{{item.item_name}}</td>

    <td>{{item.qty }}</td>

    <td>{{ item.get_formatted("amount") }}</td>

  </tr>

  {% if loop.index % 9 == 0 %}

    <tr><td>Break the page here </td> <td>current page is : {{pages.current}} / total pages {{pagetotal.total}} : Total items {{(doc.items | length)}}</td></tr>

    <tr style="page-break-before: always;"></tr>

    {% set pages.current = pages.current +1 %}

  {% endif %}

  {% endfor %}

  <tr><td>Break the page here </td> <td>current page is : {{pages.current}} / total pages {{pagetotal.total}} : Total items {{(doc.items | length)}}</td></tr>

</table>

  


29-


Now add head on top and footer in the bottom. And this is the final code


{% macro myheader() %}


<table class=headerCSS border="1">


   <tr>


    <th colspan="2">{{frappe.db.get_value('Customer', doc.customer, 'customer_name')}}</th>


    <th rowspan="2"> {{frappe.db.get_value('Customer', doc.customer, 'tax_id')}} </th>


   </tr>


   <tr>


    <td>Row 1, Column 1</td>


    <td>Row 1, Column 2</td>


   </tr>


   <tr>


    <td>Row 2, Column 1</td>


    <td>Row 2, Column 2</td>


    <td>Row 2, Column 3</td>


   </tr>


   <tr>


    <td>Row 3, Column 1</td>


    <td>Row 3, Column 2</td>


    <td>Row 3, Column 3</td>


   </tr>


   <tr>


    <td>Row 4, Column 1</td>


    <td>Row 4, Column 2</td>


    <td>Row 4, Column 3</td>


   </tr>


  </table>


  {% endmacro %}


{% macro myfooter() %}


{% endmacro %}


{{ myfooter() }}








{% macro myfooter() %}


  <table class="footerCSS">


    <tr>


      <td colspan="4">Total Amount</td>


      <td>{{doc.get_formatted("base_total")}} </td>


    </tr>


    <tr>


      <td colspan="4"> {{ frappe.utils.money_in_words(doc.base_total)}}</td>


    </tr>


  </table>




{% endmacro %}




  




<table class=headerCS border="1">


<tr>{{ myheader() }}<tr>




</table>


{% set pages = namespace(current=1) %}


{% set pagetotal = namespace(total=1) %}


<table class="itemtablestyle-details">


  


    


  {% set pagetotal.total = ((doc.items | length) / 20) | round(0, 'ceil') | int %}


  


  {%- for item in doc.items -%}


  <colgroup>


    <col>


    <col>


    <col>


    <col>


  </colgroup>


  <tr>


    <td>{{loop.index}}</td>


    <td>{{item.item_name}}</td>


    <td>{{item.qty }}</td>


    <td>{{ item.get_formatted("amount") }}</td>


  


  </tr>


  {% if loop.index % 20 == 0 %}


    <tr style="page-break-before: always;"> </tr>


    {% set pages.current = pages.current +1 %}


    


  <tr><td colspan="4">  {{myheader()}} </td></tr>


  <tr><td colspan="4">Break the page here : current page is : {{pages.current}} / total pages {{pagetotal.total}} : Total items {{(doc.items | length)}}</td></tr>


 


  {% endif %}


  {% endfor %}


 <tr>

 <td><img class="qr-code" src="{{doc.ksa_einv_qr}}"></td>

  </tr>



</table>

{{ myfooter() }}



CSS

.headerCSS{


color: blue;


background-color: yellow;


font-style: italic;

border-collapse: collapse;


      width: 100%;


}

.footercss{


color: white;


background-color: grey;


font-style: italic;


}

itemtablestyle


  {


      border-collapse: collapse;


      width: 100%;


    }


    th, td {


      border: 1px solid blue;


      padding: 8px;


      text-align: left;


      font-size: 10px;


    }


    /* Set width for first and third columns */


    colgroup col:first-child,


    colgroup col:nth-child(3) {


      width: 20%;


    }


    /* Set width for second column */


    colgroup col:nth-child(2) {


      width: 60%;


    }




30-

Add a picture. ( QR CODE in this case )



 <tr>

 <td><img class="qr-code" src="{{doc.ksa_einv_qr}}"></td>

  </tr>



Second part in this serial is here https://cloud.erpgulf.com/blog/blogs/print-formats-2.

Let's know you feedback on this, send email to training@ERPGulf.com






























Team ERPGulf

The team behind ERPGulf blogs here, expresses their thoughts, shares the experience, often show the frustrations. Contact us on support@ERPGulf.com

1 comment
Mitesh Choksi April 10, 2024

Awesome work

Add Comment