Cómo hacer un informe a medida en Odoo 12

Nota: Si trabajas con Odoo 15 puedes mirarte este otro ejemplo: https://www.flashodoo.com/blog/flashodoo-1/post/como-hacer-un-informe-a-medida-en-odoo-15-178#

Para este ejemplo vamos a hacer un informe que nos muestre las ventas diarias. Partiremos de una pantalla en la que podamos seleccionar la la fecha de inicio y de final y un boton que al hacer click nos mostrará el resumen de ventas diario en un informe.

Prerequisitos

Antes de continuar tienes que tener instalado  wkhtmltopdf 0.12.5 (con los parches de qt). Si no lo tienes instalado, puedes seguir  estas instrucciones para descargar e instalarlo.

Puedes descargar e instalar el ejemplo.

1. Inicializar una nueva tabla

Primero, tienes que crear una nueva tabla junto con los datos de demostración, de esta forma podremos generar nuestros informes usando datos pre-creados o pre-definidos.

Además tienes que instalar el módulo de Ventas (sale_management. Una vez instalado, navega a Ventas → Informes. Ahí puedes ver sólo un menú de  ventas.  Añadiremos una nueva opción de menú llamada Sale Summary Report. Cuando hagas click en el menú, se abrirá un wizard modal para despues de indicar la fecha de inicio y final puedas generar el informe de ventas.

Así que continuemos e instalemos el módulol custom_report_odoo12 .

Install Sample Custom Report Module

2. Crear un Wizard

Crearemos un wizard model y una wizard view.

Wizard TransientModel

Crearemos un wizard model que deberia ser TransientModel. También, crearemos dos campos uno para la fecha de inicio y otro para la fecha final.

A continuación, ves definido el método get_report ,  se llamará cuando hagas click en el boton que llama al report en el wizard.

# -*- coding: utf-8 -*-

from odoo import models, fields, api


class SaleSummaryReportWizard(models.TransientModel):
    _name = 'sale.summary.report.wizard'

    date_start = fields.Date(string='Start Date', required=True, default=fields.Date.today)
    date_end = fields.Date(string='End Date', required=True, default=fields.Date.today)

    @api.multi
    def get_report(self):
        data = {
            'model': self._name,
            'ids': self.ids,
            'form': {
                'date_start': self.date_start, 'date_end': self.date_end,
            },
        }

        # ref `module_name.report_id` as reference.
        return self.env.ref('custom_report_odoo12.sale_summary_report').report_action(self, data=data)
Python

Crear la Vista Wizard

Crear una vista wizard mostrando los botones date_startdate_end
También, hay que crear la acción del wizard y el menú que lo llama.

<record id="sale_summary_report_wizard" model="ir.ui.view" >
    <field name="name">Sale Summary Report</field>
    <field name="model">sale.summary.report.wizard</field>
    <field name="type">form</field>
    <field name="arch" type="xml">
        <form string="Sale Summary Report">
            <group>
                <group>
                    <field name="date_start"/>
                </group>
                <group>
                    <field name="date_end"/>
                </group>
            </group>
            <footer>
                <button name="get_report" string="Get Report" type="object" class="oe_highlight"/>
                <button string="Cancel" special="cancel"/>
            </footer>
        </form>
    </field>
</record>

<act_window id="action_sale_summary_report_wizard"
    name="Sale Summary Report"
    res_model="sale.summary.report.wizard"
    view_mode="form"
    target="new"/>

<menuitem action="action_sale_summary_report_wizard"
    id="menu_sale_summary_report_wizard"
    parent="sale.menu_sale_report"/>
XML

3. Juntando los datos del Report

Crear un objeto model abstracto. De esta forma tiene que añadir el método  _get_report_values a este objeto.

Basicamente el método, _get_report_values colecciona datos desde la tabla y se los entrega al informe.

# -*- coding: utf-8 -*-

from datetime import datetime, timedelta

from odoo import models, fields, api
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT as DATE_FORMAT
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT as DATETIME_FORMAT


class ReportSaleSummaryReportView(models.AbstractModel):
    """
        Abstract Model specially for report template.
        _name = Use prefix `report.` along with `module_name.report_name`
    """
    _name = 'report.custom_report_odoo12.sale_summary_report_view'

    @api.model
    def _get_report_values(self, docids, data=None):
        date_start = data['form']['date_start']
        date_end = data['form']['date_end']

        SO = self.env['sale.order']
        start_date = datetime.strptime(date_start, DATE_FORMAT)
        end_date = datetime.strptime(date_end, DATE_FORMAT)
        delta = timedelta(days=1)

        docs = []
        while start_date <= end_date:
            date = start_date
            start_date += delta

            print(date, start_date)
            orders = SO.search([
                ('confirmation_date', '>=', date.strftime(DATETIME_FORMAT)),
                ('confirmation_date', '<', start_date.strftime(DATETIME_FORMAT)),
                ('state', 'in', ['sale', 'done'])
            ])

            total_orders = len(orders)
            amount_total = sum(order.amount_total for order in orders)

            docs.append({
                'date': date.strftime("%Y-%m-%d"),
                'total_orders': total_orders,
                'amount_total': amount_total,
                'company': self.env.user.company_id
            })

        return {
            'doc_ids': data['ids'],
            'doc_model': data['model'],
            'date_start': date_start,
            'date_end': date_end,
            'docs': docs,
        }
Python

4. Crear el formato del papel

Crea un nuevo formato del documento según tus necesidades.

<record id="paperformat_sale_summary_report" model="report.paperformat">
    <field name="name">Sale Summary</field>
    <field name="default" eval="False"/>
    <field name="format">A4</field>
    <field name="page_width">0</field>
    <field name="page_width">0</field>
    <field name="orientation">Portrait</field>
    <field name="margin_top">30</field>
    <field name="margin_bottom">28</field>
    <field name="margin_right">7</field>
    <field name="margin_left">7</field>
    <field name="header_line" eval="False"/>
    <field name="header_spacing">15</field>
    <field name="dpi">90</field>
</record>
XML

5. Hacemos la plantilla QWeb del informe

Finalmente, crear un método report template. _get_report_values que devolverá los datos para mostrar en el informe y generará el informe PDF.

<report id="sale_summary_report"
    model="sale.summary.report.wizard"
    string="Sale Summary Report"
    report_type="qweb-pdf"
    name="custom_report_odoo12.sale_summary_report_view"
    paperformat="custom_report_odoo12.paperformat_sale_summary_report"
    menu="False"/>

<template id="sale_summary_report_view">
    <t t-call="web.html_container">
        <div class="header" style="border-bottom: 1px solid black;">
            <h3 class="text-center">Sales Summary Report 
                <span style="font-size: 14px;"><strong>From</strong>: <t t-esc="date_start"/> <strong>To</strong>: <t t-esc="date_end"/></span>
            </h3>
        </div>
        <div class="article mt0 o_report_layout_standard">
            <table class="table table-condensed table-bordered">
                <thead>
                    <th style="width: 65%">Date</th>
                    <th class="text-center" style="width: 15%">Total Orders</th>
                    <th class="text-center" style="width: 20%">Total Amount</th>
                </thead>
                <tbody>
                    <t t-foreach="docs" t-as="doc">
                        <tr>
                            <td><span t-esc="doc['date']"/></td>
                            <td class="text-center"><span t-esc="doc['total_orders']"/></td>
                            <td class="text-center">
                                <span t-esc="doc['amount_total']" t-options='{"widget": "monetary", "display_currency": doc["company"].currency_id}'/>
                            </td>
                        </tr>
                    </t>
                </tbody>
            </table>
        </div>
        <div class="footer o_standard_footer" style="border-top: 1px solid black;">
            <div class="row text-center">
                <div class="col col-12 text-center">
                    <ul class="list-inline">
                        <li class="list-inline-item">Page:</li>
                        <li class="list-inline-item">
                            <span class="page"/>
                        </li>
                        <li class="list-inline-item">/</li>
                        <li class="list-inline-item">
                            <span class="topage"/>
                        </li>
                    </ul>
                </div>
            </div>
        </div>
    </t>
</template>
XML

Una vez realizado lo anterior, reinicio Odoo e instala el módulo. A continuación, vete a Ventas → Informes. Verás un nuevo menú Sale Summary Report.

Wizard Menu - Create custom report in Odoo

Al hacer click en el menú se nos abre el wizard modal como en la ventana que sigue. Selecciona el rango de fechas y haz click en el boton para conseguir el Informe.

Wizard view - Select Date Range

Verás el siguiente informe.

Daily Sales Summary Report - Custom report in Odoo

Tienes más información en la web oficial de Odoo QWeb Reports.