17. Desarrollando con Odoo (12). Separando los modelos en ficheros individuales. Introducció a los Reports

 1. Separar los modelos

Dentro de la carpeta models tenemos el fichero __init__.py que ahora hace referencia al megafichero que contiene todos los modulos:

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

from . import models


Ahora hay que eliminar esta entrada y separarla en cada uno de los modelos que contiene quedando

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

#from . import models

from . import developer
from . import project
from . import history
from . import task
from . import bug
from . import improvement
from . import sprint
from . import technology


Ojo: Cada modelo que necesite el logger, hay que añadirles estas 2 líneas antes del class

import logging

_logger= logging.getLogger(__name__)

class ....

Veamos un ejemplo de model (task.py)

from odoo import models, fields, api
import datetime
import logging

_logger= logging.getLogger(__name__)
class task(models.Model):
    _name = 'ximoapp01.task'
    _description = 'ximoapp01.task'

    name = fields.Char(string= "Nombre", readonly=False, required=True, help="Nombre de la Tarea" )
    description = fields.Text()
    start_date = fields.Datetime()
    duration= fields.Integer()
    end_date =fields.Datetime(compute="_get_end_date", store=True )
    is_paused = fields.Boolean(default=False)
    code = fields.Char(compute="_get_code")
    #sprint = fields.Many2one("ximoapp01.sprint", ondelete="set null",help="Macro tarea padre Sprint")
    sprint = fields.Many2one("ximoapp01.sprint", compute="_get_sprint", ondelete="set null", store= True, help="Macro tarea padre Sprint")
    history = fields.Many2one("ximoapp01.history", ondelete="set null",help="Historia relacionada")
    technologies = fields.Many2many(comodel_name="ximoapp01.technology", relation="technology_task", column1="task_id", column2="technology_id", help="Tecnologías empleadas")
    #def _get_definition_date(self):
    #    return datetime.datetime.now()
    #definition_date = fields.Datetime(default=_get_definition_date)
    definition_date = fields.Datetime(default= lambda d: datetime.datetime.now())
    
    def _get_code(self):
        for record in self:
            #record.code=record.name + str(record.id)
            record.code=str(record.id)
            _logger.debug("Por aquí hemos pasado...")

    @api.depends('start_date', 'duration')
    def _get_end_date(self):
        for record in self:
            if isinstance(record.start_date, datetime.datetime) and record.duration > 0 :
                record.end_date = record.start_date + datetime.timedelta(days=record.duration)
            else:
                record.end_date=record.start_date    
    
    @api.depends('history')
    def _get_sprint(self):
        for record in self:
            #sprints = self.env['ximoapp01.sprint'].search([('project.id', '=', record.history.project.id)])
            if isinstance(record.history.project.id, models.NewId):
                id_project= int (record.history.id.origin)
            else:
                id_project= record.history.id
            sprints = self.env['ximoapp01.sprint'].search([('project.id', '=', id_project)])
            found = False
            for sprint in sprints:
                if not found:
                     if isinstance(sprint.end_date, datetime.datetime):
                        if sprint.end_date > datetime.datetime.now():
                            record.sprint = sprint.id
                            found = True
            if not found:
                record.sprint = False

    def _get_default_developer(self):
        developer= self.browse(self._context.get('current_developer'))
        if developer:
            return [developer.id]
        else:
            return []
    #developer = fields.Many2one('res.partner')
    developers = fields.Many2many(comodel_name="res.partner", relation="partner_task", column1="task_id", column2="partner_id", default=_get_default_developer, help="Desarrolladores")


2. Reports

Para documentarme he utilizado Cybrosys youtube, Cybrosys blog y  y Weblearn. Hay que tener en cuenta que ellas aparecen pequeños fallos que hacen que tu aplicación reviente! y hay que ir contrastando lo que dice una y otra.

Veamos los pasos:

1. Si no existe la carpeta report que debe estar al mismo nivel que models o views entonces la creamos.

2. Creamos dentro de la misma un fichero por ejemplo task_report.xml teniendo en cuenta que:

  • El model del record es "ir.action.reports" y su id debe ser único (a ser posible debe conservar esta nomeclatura:"action_report_app_modelClass" (donde action_report es fijo y app se refiere al nombre de la aplicación (ximoapp01) y modelClass es el nombre del modelo (task))
  • field-name es el nombre del report que aparecerá en la interface de usuario
  • field-model es el nombre completo del modelo (app.classModel)
  • field-report_type puede ser qweb-pdf, qweb-html y qweb-txt
  • field-report_name y field-report_file en principio deben coincidir y la nomenclatura debe ser "app.templateId" (donde app se refiere al nombre de la aplicación (ximoapp01) y templateId es el id que se le assigna al template en el siguiente fichero que adjuntaremos (task_template.xml). En cocreto la línea que tiene el id es : <template id="report_template_task_ximo">
  • firld-binding_model_id su nomenclatura es "app.model_app_modelClass"  (donde action_report es fijo y app se refiere al nombre de la aplicación (ximoapp01) y modelClass es el nombre del modelo (task))

y le damos este contenido:

<odoo>
    <record id="action_report_ximoapp01_task" model="ir.actions.report">
        <field name="name">A Task Report</field> 
        <field name="model">ximoapp01.task</field>
        <field name="report_type">qweb-pdf</field>
        <field name="report_name">ximoapp01.report_template_task_ximo</field> <!-- ximoapp01. + FROM task_template : <template id="my_report_template_task"> -->
        <field name="report_file">ximoapp01.report_template_task_ximo</field>
        <field name="binding_model_id" ref="ximoapp01.model_ximoapp01_task"/> <!-- ximoapp01. + 'model_' + ximoapp01 + _ + modelClass  -->
        <field name="binding_type">report</field>
    </record>
</odoo>

3. Creamos el fichero task_template.xml y le damos este contenido:

<odoo>
    <template id="report_template_task_ximo">
        <t t-call="web.html_container">
            <t t-foreach="docs" t-as="o">
                <t t-call="web.external_layout">
                    <div class="page">
                        <div class="oe_structure"/>
                        <h2>Task Report</h2>
                        <p><span t-field="o.name"/></p>
                    </div>
                </t>
            </t>
        </t>
    </template>
</odoo>

4. En el fichero __manifest__.py añadimos dentro de 'data' el acceso a los 2 ficheros anteriores:

    # any module necessary for this one to work correctly
    'depends': ['base'],

    # always loaded
    'data': [
        'security/ir.model.access.csv',
        'views/views.xml',
        'views/project.xml',
        'views/history.xml',
        'views/task.xml',
        'views/sprint.xml',
        'views/technology.xml',
        'views/bug.xml',
        'views/improvement.xml',
        'views/developer.xml',
        'views/templates.xml',
        'report/task_report.xml',
        'report/task_template.xml'
    ],
    # only loaded in demonstration mode
    'demo': [
        'demo/demo.xml',
    ],


Actualizamos la aplicación y suele dar problemas si no definimos bien los parámetros de task_report.xml. Y sale 


Y el report


Este es un report introductorio. En principio, más adelatne se intentará explicar como se define un report con datos...









Comentarios

Entradas populares de este blog

20. Desarrollando con Odoo (15). Permisos y grupos. Crear usuarios de la aplicación. Restringir permisos a usuarios

2. El Modo desarrollador

10. Crear clave de la API