WEBKIT Reports in OpenERP

WEBKIT reports

Introduction

I remember touching on this solution during the OpenERP technical training at the OpenERP's HQ 'The Farm' in Belgium - so was quite looking forward to try this on my server installation. 

The OpenERP WebKit Module adds a new Report Engine based on WebKit library (wkhtmltopdf) to support reports designed in HTML + CSS.

The module structure and some code is inspired by the report_openoffice module.

The module allows:
  • HTML report definition
  • Multi header support
  • Multi logo
  • Multi company support
  • HTML and CSS-3 support (In the limit of the actual WebKIT version)
  • JavaScript support
  • Raw HTML debugger
  • Book printing capabilities
  • Margins definition
  • Paper size definition

This installation didn't go as smoothly as I expected. Not due to the OpenERP modules, but due to the fact my ERP server is running on a separate hardware (with amd64) and most of the documentation assumes your running the client and server on the same PC H/W with 32bit architecture. The issues I experience are now resolved as explained later. 

Version 7.0

Installation Guide: 

1. Install the openerp modules


Install the webkit module /Settings/Modules/Modules
enter webkit in the 'name' field

These are the WebKit Modules to install:


2. Add a Logo

After installing the webkit modules, Go to menu /Settings/Companies/Webkit Logos

If you installed the webkit_sample module too, the you'll see a demo logo already installed. 



Press Create to make a new Logo


You can upload you own company logo by pressing 'Create'. Add a name for this logo, the file type (e.g jpg) and associate it with a company. Then press the file icon to upload the image. Then press save :



3. View the Header and Footers

Go to menu /Settings/Companies/Webkit Headers & Footers

Here the details of the header and footers. Don't change anything for now, but here are the details for reference:

CSS Style Sheet

CSS Style


body {
font-family:helvetica;
font-size:12;
}


.dest_address {
margin-left:60%;
font-size:12;
}
.header {
margin-left:0;
text-align:left;
width:300px;
font-size:12;
}

.title {
font-size:16;
font-weight: bold;

}


.basic_table{
text-align:center;
border:1px solid lightGrey;
border-collapse: collapse;
}
.basic_table td {
border:1px solid lightGrey;
font-size:12;


}

.list_table {
border-color:black;
text-align:center;
border-collapse: collapse;

}
.list_table td {
border-color:gray;
border-top:1px solid gray;
text-align:left;
font-size:12;
padding-right:3px
padding-left:3px
padding-top:3px
padding-bottom:3px
}

.list_table th {
border-bottom:2px solid black;
text-align:left;
font-size:12;
font-weight:bold;
padding-right:3px
padding-left:3px
}

.list_tabe thead {
    display:table-header-group;
}


.total {
width:100%;
}
.lib {
width:10.3%;
}
.tot {
text-align:right;
width:15%;
}
.lefttot {
width:74%;
}
.tax {
width:50%;

Header

Header

<html>
    <head>
        <meta content="text/html; charset=UTF-8" http-equiv="content-type"/>
        <script>
            function subst() {
            var vars={};
            var x=document.location.search.substring(1).split('&');
            for(var i in x) {var z=x[i].split('=',2);vars[z[0]] = unescape(z[1]);}
            var x=['frompage','topage','page','webpage','section','subsection','subsubsection'];
            for(var i in x) {
            var y = document.getElementsByClassName(x[i]);
            for(var j=0; j<y.length; ++j) y[j].textContent = vars[x[i]];
                }
            }
        </script>
        <style type="text/css">
            ${css}
        </style>
    </head>
    <body style="border:0; margin: 0;" onload="subst()">
        <table class="header" style="border-bottom: 0px solid black; width: 100%">
            <tr>
                <td>${helper.embed_logo_by_name('camptocamp_logo')|n}</td>
                <td style="text-align:right"> </td>
            </tr>
            <tr>
                <td><br/></td>
                <td style="text-align:right"> </td>
            </tr>
            <tr>
                <td>${company.partner_id.name |entity}</td>
                <td/>
            </tr>
            <tr>
                <td >${company.partner_id.address and company.partner_id.address[0].street or ''|entity}</td>
                <td/>
            </tr>
            <tr>
                <td>Phone: ${company.partner_id.address and company.partner_id.address[0].phone or ''|entity} </td>
                <td/>
            </tr>
            <tr>
                <td>Mail: ${company.partner_id.address and company.partner_id.address[0].email or ''|entity}<br/></td>
            </tr>
        </table> ${_debug or ''|n} </body>
</html>



Footer


Footer

<html>
    <head>
        <meta content="text/html; charset=UTF-8" http-equiv="content-type"/>
        <script>
            function subst() {
            var vars={};
            var x=document.location.search.substring(1).split('&');
            for(var i in x) {var z=x[i].split('=',2);vars[z[0]] = unescape(z[1]);}
            var x=['frompage','topage','page','webpage','section','subsection','subsubsection'];
            for(var i in x) {
            var y = document.getElementsByClassName(x[i]);
            for(var j=0; j<y.length; ++j) y[j].textContent = vars[x[i]];
                }
            }
        </script>
    </head>
    <body style="border:0; margin: 0;" onload="subst()">
        <table style="border-top: 1px solid black; width: 100%">
            <tr >
                <td style="text-align:right;font-size:12;" width="95%">Page <span class="page"/></td><td style="text-align:left;font-size:12;">  of <span class="topage"/></td>
            </tr>
        </table>
    </body>
</html>

4. Configuration of Company Settings


Leave the headers and footers as they are  and go to menu /Settings/Companies/Companies and open the company master. What's very clever with this solution is that if you are running a multi-company installation,  then each company can have a different report configuration i.e. a different logo, header, footer etc, which would normally be required. 

You'll see a new tab called 'Webkit' has been added to the company form.

Click on the Webkit Tab


On this view you'll see the main configuration settings. The important part is the WebKit Executable Path i.e. the path where the executable program for converting  HTLM to .pdf format is located. The program is called wkhtlmtopdf and needs to be installed on the server. If you are running Ubuntu on 32bit hardware then you should be able to install this with apt-get install wkhtmltojpg. and the program should be installed in /usr/bin/. (BTW: if you don't install this software the webkit  will still work in debug mode, but will only produce html files)

If  you're running 64bit hardware then don't install it this way as this configuration didn't go as smoothly as I expected, as after installation I received a lot of error messages when trying to print a .pdf documet - (this is explained in more detail later). Not due to the OpenERP modules, but due to the fact my ERP server is running on a separate hardware (with amd64) and most of the documentation incorrectly assumed I was running the client and server on the same PC H/W with 32bit architecture. The issues I experience are now resolved after installing the correct version of WKHTMLTOJPG program.  

Here is a forum discussion where I found the hint to the resolution -> Forum Discussion-1

The discussion describes the same issue I encoutered with the installation. It was resovled by installing the latest Linux Static Binary for Amd64 machine. So if you are also using a 64bit server, don't use the software version that's installed from the general Ubuntu repositories, as these don't always have the latest versions i.e. don't use apt-get install wkhtmltojpg as the wrong version will be installed. Just down load the program from the webkit website (link below, but check for latest versions)

WKHTMLTOJPG Application that needed to be installed:

So after downloading / unzipping I moved the program into /user/bin manually. 

I also tested the following solution (intended for a Drupal installation) which did not work from within OpenERP -> http://drupal.org/node/870058  I could, however, run the script from the command line on the server. This could therefore have been a solution but the modules's Python code would need to be changed. (calling    wkhtmltopdf.sh rather than  wkhtmltopdf

Add the logo and header / Footers that was created in the previous steps 2 & 3


Report Configuration

If you've installed the Webkit sample module, then go to menu  /Setting/Customisation/Low Level Object/Actions/Report and you'll see a new report format created called WebKit Invoice.  The output format field does not seem to have any influence so just leave it blank. The report Type is webkit. The report file is the template file of the document. More details on how to make this are explained later.



Now you are ready for printing. There is a demo report that you can run which is available from the /Finance/Customers/Customer Invoices  view. In the right hand menu you'll see a new menu open WebKit Invoice. Select an invoice and press the button to print. If all went well the .pdf document will print.

Configuration of new Reports

The main challenge with this solution is getting your head around MAKO files. You'll also need to understand  Python. and creation of  rml parsers to extract repeating child records, such as the BOM of a BOM componentBut then all the other solutions I test,  also required you get your head around programming.