|
| 1 | +Reporting Engine in v8 |
| 2 | +====================== |
| 3 | + |
| 4 | +Table of content 1/2 |
| 5 | +--------------------- |
| 6 | +**Functional overview** |
| 7 | + |
| 8 | +* How to.. |
| 9 | + * Customize an existing report |
| 10 | + * Change its paper format |
| 11 | + * Add barcodes |
| 12 | + |
| 13 | +* Minimal template |
| 14 | +* Design informations |
| 15 | +* Reports are web pages |
| 16 | + |
| 17 | +Table of content 2/2 |
| 18 | +--------------------- |
| 19 | +**Technical overview** |
| 20 | + |
| 21 | +* Paper Format and Report declaration |
| 22 | +* Structure of the module |
| 23 | +* Generic / particular report |
| 24 | +* Used technologies |
| 25 | +* Future enhancements |
| 26 | + |
| 27 | +Functional |
| 28 | +=========== |
| 29 | + |
| 30 | +A few things before starting |
| 31 | +---------------------------- |
| 32 | +* Reports are written in HTML/QWeb, just like any page of the Odoo Website, thus **the website editor is available**. |
| 33 | +* You are customizing **the template** of the report, thus it affects **all reports**, not only the selected one. |
| 34 | +* The PDF rendering is done by a tool outside the Odoo framework, **Wkhtmltopdf**. |
| 35 | +* All Odoo Addons are converted to QWeb |
| 36 | + |
| 37 | +Customize an existing report |
| 38 | +============================= |
| 39 | + |
| 40 | +Customize an existing report |
| 41 | +---------------------------- |
| 42 | +* First way: Online HTML Editor |
| 43 | + * User in website publisher group |
| 44 | + * Change type of report from PDF to HTML |
| 45 | + |
| 46 | +.. image:: img/func4.png |
| 47 | + :width: 60% |
| 48 | + :align: center |
| 49 | + |
| 50 | +.. image:: img/func5.png |
| 51 | + :align: center |
| 52 | + |
| 53 | +Customize an existing report |
| 54 | +---------------------------- |
| 55 | +* Second way: ir.ui.view form |
| 56 | + * **Technical settings** then **Reports** menu in settings |
| 57 | + |
| 58 | +.. image:: img/func1.png |
| 59 | + :align: center |
| 60 | + |
| 61 | +.. image:: img/func2.png |
| 62 | + |
| 63 | +.. image:: img/func3.png |
| 64 | + :align: center |
| 65 | + |
| 66 | +Change its paper format |
| 67 | +======================= |
| 68 | + |
| 69 | +Change its paper format |
| 70 | +---------------------------- |
| 71 | +* **Technical settings** then **Paper format** under Reports menu in settings |
| 72 | + |
| 73 | +.. image:: img/func6.png |
| 74 | + |
| 75 | +* Default paper format on the company |
| 76 | +* You can define a paper format on a report record |
| 77 | + |
| 78 | +Add barcodes |
| 79 | +============ |
| 80 | + |
| 81 | +Add barcodes |
| 82 | +------------ |
| 83 | +* Barcodes are images returned by a controller |
| 84 | +* Quite easy thanks to the Qweb syntax |
| 85 | + |
| 86 | +.. code-block:: html |
| 87 | + |
| 88 | + <img t-att-src="'/report/barcode/QR/%s' % 'My text in qr code'"/> |
| 89 | + |
| 90 | +* More parameters can be passed as a query string |
| 91 | + |
| 92 | +.. code-block:: html |
| 93 | + |
| 94 | + <img t-att-src="'/report/barcode/? |
| 95 | + type=%s&value=%s&width=%s&height=%s'%('QR', 'text', 200, 200)"/> |
| 96 | + |
| 97 | +.. image:: img/func7.png |
| 98 | + :align: center |
| 99 | + |
| 100 | +Minimal template |
| 101 | +================ |
| 102 | + |
| 103 | +Minimal template |
| 104 | +---------------- |
| 105 | + |
| 106 | +.. code-block:: xml |
| 107 | +
|
| 108 | + <t t-call="report.html_container"> |
| 109 | + <t t-foreach="docs" t-as="o"> |
| 110 | + <t t-call="report.external_layout"> |
| 111 | + <div class="page"> |
| 112 | + <h2>Report title</h2> |
| 113 | + </div> |
| 114 | + </t> |
| 115 | + </t> |
| 116 | + </t> |
| 117 | +
|
| 118 | +* Calling **external_layout** will add the default header and footer |
| 119 | +* PDF body will be the content inside <div class="page"> |
| 120 | + |
| 121 | +Design informations |
| 122 | +------------------- |
| 123 | +* If you use twitter bootstrap to design your report, use col-xs column |
| 124 | +* Local CSS can be put directly in the template |
| 125 | +* Global CSS can be put in the report.style template |
| 126 | +* Two layouts (defining header/footer) are installed by default but you of course can create your own |
| 127 | +* If you don't want header/footer, don't put a div node with a header/footer class |
| 128 | + |
| 129 | +Reports are web pages |
| 130 | +===================== |
| 131 | + |
| 132 | +Reports are web pages |
| 133 | +--------------------- |
| 134 | +* Thus, accessible by an URL |
| 135 | + |
| 136 | +Sale Order in the html mode |
| 137 | + |
| 138 | +.. code-block:: html |
| 139 | + |
| 140 | + [...]/report/html/sale.report_saleorder/38 |
| 141 | + |
| 142 | +You want it in pdf ? |
| 143 | + |
| 144 | +.. code-block:: html |
| 145 | + |
| 146 | + [...]/report/pdf/sale.report_saleorder/38 |
| 147 | + |
| 148 | +Technical |
| 149 | +========== |
| 150 | + |
| 151 | +Paper Format and Report declaration |
| 152 | +=================================== |
| 153 | + |
| 154 | +Declare a report |
| 155 | +---------------- |
| 156 | +**Every report must have an ir.actions.report.xml record** |
| 157 | + |
| 158 | +.. code-block:: xml |
| 159 | +
|
| 160 | + <report |
| 161 | + id="account_invoices" |
| 162 | + model="account.invoice" |
| 163 | + string="Invoices" |
| 164 | + report_type="qweb-pdf" |
| 165 | + name="account.report_invoice" |
| 166 | + file="account.report_invoice" |
| 167 | + attachment_use="True" |
| 168 | + attachment="(object.state in ('open','paid')) and |
| 169 | + ('INV'+(object.number or '').replace('/','')+'.pdf')" |
| 170 | + /> |
| 171 | +
|
| 172 | +Declare a paper format |
| 173 | +---------------------- |
| 174 | + |
| 175 | +.. code-block:: xml |
| 176 | +
|
| 177 | + <record id="paperformat_frenchcheck" model="report.paperformat"> |
| 178 | + <field name="name">French Bank Check</field> |
| 179 | + <field name="default" eval="True"/> |
| 180 | + <field name="format">custom</field> |
| 181 | + <field name="page_height">80</field> |
| 182 | + <field name="page_width">175</field> |
| 183 | + <field name="orientation">Portrait</field> |
| 184 | + <field name="margin_top">3</field> |
| 185 | + <field name="margin_bottom">3</field> |
| 186 | + <field name="margin_left">3</field> |
| 187 | + <field name="margin_right">3</field> |
| 188 | + <field name="header_line" eval="False"/> |
| 189 | + <field name="header_spacing">3</field> |
| 190 | + <field name="dpi">80</field> |
| 191 | + </record> |
| 192 | +
|
| 193 | +Declare a paper format |
| 194 | +---------------------- |
| 195 | + |
| 196 | +You have now everything to create reports ! |
| 197 | + |
| 198 | +* A template (ir.ui.view record) |
| 199 | +* A report record (ir.actions.report.xml record) |
| 200 | +* And maybe a specific paper format (report.paperformat record) |
| 201 | + |
| 202 | +**Most reports do not need more** |
| 203 | + |
| 204 | +Structure of the module |
| 205 | +======================= |
| 206 | + |
| 207 | +Structure of the module |
| 208 | +----------------------- |
| 209 | +* The controllers behind the report's URL are just interface to classic odoo API methods on a model named Report. |
| 210 | + |
| 211 | +.. code-block:: python |
| 212 | +
|
| 213 | + @route([ |
| 214 | + '/report/<path:converter>/<reportname>', |
| 215 | + '/report/<path:converter>/<reportname>/<docids>', |
| 216 | + ], [...]) |
| 217 | + def report_routes([...]): |
| 218 | + report_obj = request.registry['report'] |
| 219 | + cr, uid, context = request.cr, request.uid, request.context |
| 220 | + [...] |
| 221 | + if converter == 'html': |
| 222 | + html = report_obj.get_html( |
| 223 | + cr, uid, docids, reportname, |
| 224 | + data=options_data, context=context |
| 225 | + ) |
| 226 | + return request.make_response(html) |
| 227 | +
|
| 228 | +Structure of the module |
| 229 | +----------------------- |
| 230 | +This report model has three main methods: |
| 231 | + |
| 232 | +* get_html |
| 233 | +* get_pdf |
| 234 | +* get_action |
| 235 | + |
| 236 | +get_html will look for a model named **report.<<report_name>>**. If it exists, then get_html |
| 237 | +returns **report.<<report_name>>**.render_html(). If not, get_html will use a generic render_html. |
| 238 | + |
| 239 | +It is the difference between a generic and a particular report. |
| 240 | + |
| 241 | +Generic / particular report |
| 242 | +=========================== |
| 243 | + |
| 244 | +Generic / particular report |
| 245 | +--------------------------- |
| 246 | +* **Generic** |
| 247 | + * Default rendering context (*docs*, *translate_doc*, ...) |
| 248 | +* **Particular** |
| 249 | + * New rendering context containing anything you want to process your data |
| 250 | + * Odoo AbstractModel, custom module needed |
| 251 | + |
| 252 | +For a particular report, you have to write an Odoo Model containing a render_html method. Classically, this |
| 253 | +method returns a call to the original **QWeb render** with a **custom rendering context**. |
| 254 | + |
| 255 | +Writing a particular report |
| 256 | +--------------------------- |
| 257 | + |
| 258 | +.. code-block:: python |
| 259 | +
|
| 260 | + from openerp.osv import osv |
| 261 | +
|
| 262 | +
|
| 263 | + class ParticularReport(osv.AbstractModel): |
| 264 | + _name = 'report.<<module.reportname>>' |
| 265 | + def render_html(self, cr, uid, ids, data=None, context=None): |
| 266 | + report_obj = self.pool['report'] |
| 267 | + report = report_obj._get_report_from_name( |
| 268 | + cr, uid, '<<module.reportname>>' |
| 269 | + ) |
| 270 | + docargs = { |
| 271 | + 'doc_ids': ids, |
| 272 | + 'doc_model': report.model, |
| 273 | + 'docs': self.pool[report.model].browse( |
| 274 | + cr, uid, ids, context=context |
| 275 | + ), |
| 276 | + } |
| 277 | + return report_obj.render( |
| 278 | + cr, uid, ids, '<<module.reportname>>', |
| 279 | + docargs, context=context |
| 280 | + ) |
| 281 | +
|
| 282 | +Used technologies |
| 283 | +================= |
| 284 | + |
| 285 | +Used technologies |
| 286 | +----------------- |
| 287 | +* The templating engine is **QWeb** (server-side rendering) |
| 288 | + |
| 289 | +* The barcodes images are rendered by **Reportlab** |
| 290 | + * http://www.reportlab.com |
| 291 | + * Please use at least 3.0 |
| 292 | + * Don't forget the fonts http://www.reportlab.com/ftp/pfbfer.zip |
| 293 | + |
| 294 | +Used technologies |
| 295 | +----------------- |
| 296 | +* The PDF rendering is done by **Wkhtmltopdf** |
| 297 | + * http://wkhtmltopdf.org/ |
| 298 | + * https://github.com/wkhtmltopdf |
| 299 | + * Please use at least 0.12.0 |
| 300 | +* Report module can be adapted to competitors like **PhantomJS**, **SlimerJS**, **Weasyprint**, etc. |
| 301 | +* Advantages of **Wkhtmltopdf** |
| 302 | + * Recent versions support table split accross pages |
| 303 | + * Nice API for paper format |
| 304 | + |
| 305 | +Future enhancements |
| 306 | +=================== |
| 307 | + |
| 308 | +Future enhancements |
| 309 | +------------------- |
| 310 | +* Create report-dedicated Website Builder snippets |
| 311 | +* Table edition in the Website Builder RTE |
| 312 | +* Set a larger viewport on the PDF rendering engine (currently 800*600, wkhtmltopdf settings [1]). |
| 313 | +* When using translate_doc on a template, display it the view in the html editor |
| 314 | + |
| 315 | +[1] https://github.com/wkhtmltopdf/wkhtmltopdf/issues/1508 |
| 316 | + |
| 317 | +Thanks for your listening |
| 318 | +========================== |
| 319 | + |
0 commit comments