Diferencia entre revisiones de «Odoo»

De Jose Castillo Aliaga
Ir a la navegación Ir a la búsqueda
Línea 184: Línea 184:
* Binary : Per guardar, per exemple, imatges. Utilitza codificació base64
* Binary : Per guardar, per exemple, imatges. Utilitza codificació base64
* Selection : Mostra un select amb les opcions indicades.
* Selection : Mostra un select amb les opcions indicades.
<syntaxhighlight lang="python">  
<syntaxhighlight lang="python" style="font-family:monospace">  
  aselection = fields.Selection([('a', 'A')])
  aselection = fields.Selection([('a', 'A')])
  aselection = fields.Selection(selection=[('a', 'A')])
  aselection = fields.Selection(selection=[('a', 'A')])

Revisión del 10:06 21 oct 2015

A partir de la versió 8, OpenERP passa a anomenar-se Odoo.

Les novetats que ens interessen més són la possibilitat de crear una web per als clients i les noves funcions de l'API.

Instal·lar Odoo

El servidor Odoo

El servidor Odoo s'arranca simplement amb el comandament:

$ odoo.py

Tal vegada es necessita ficar la ruta on està instal·lat.

Pot ser que estiga configurat el servici en l'arranc del sistema operatiu. No obstant, si volem depurar, cal parar el servici i arrancar de manera manual.

En el cas d'un Odoo instal·lat en Debian amb els paquets, si fer un ps -aux, vorem que el comandament que té Odoo és:

/usr/bin/python /usr/bin/odoo.py --config /etc/odoo/openerp-server.conf --logfile /var/log/odoo/odoo-server.log

Per reiniciar-lo de manera manual:

$ sudo systemctl restart odoo

El servici Odoo proporciona accés als clients via RPC, Odoo proporciona per defecte un client web.

Arquitectura

L’OpenObject facilita diversos components que permeten construir l’aplicació:

Arquitectura MVC
Cliente Servidor OpenERP/Odoo
  • La capa ORM (Object Relational Mapping) entre els objectes Python i la base de dades PostgreSQL. El dissenyador-programador no efectua el disseny de la base de dades; únicament dissenya classes, per les quals la capa ORM d’OpenObject n’efectuarà el mapat sobre el SGBD PostgreSQL.
  • Una arquitectura MVC (model-vista-controlador) en la qual el model resideix en les dades de les classes dissenyades amb Python, la vista resideix en els formularis, llistes, calendaris, gràfics… definits en fitxers XML i el controlador resideix en els mètodes definits en les classes que proporcionen la lògica de negoci.
  • Odoo és un ERP amb una arquitectura de Tenencia Múltiple. És A dir, té una base de dades i un servidor comú per a tots els clients. El contrari sería tindre un servidor o base de dades per client o virtualitzar.
  • Un sistema de fluxos de treball o workflows.
  • Dissenyadors d’informes.
  • Facilitats de traducció de l’aplicació a diversos idiomes.

El servidor Odoo proporciona un accés a la base de dades emb ORM. El servidor necessita tindre instal·lats mòduls, ja que comença buit.

Per altra banda, el client es comunica amb el servidor en XML-RPC, els clients web per JSON-RPC. El client sols té que mostrar el que dona el servidor o demanar correctament les dades. Per tant, un client pot ser molt simple i fer-se en qualsevol llenguatge de programació. Odoo proporciona un client web encara que es pot fer un client en qualsevol plateforma.

Les dades estan guardades en una base de dades relacional. Gràcies a l'ORM, no cal fer consultes SQL dirèctament. ORM proporciona una serie de mètodes per a treballar de manera més ràpida i segura. En compte de parlar de taules es parla de models. Aquest són mapejats per l'ORM en taules. No obstant, un model té més que dades en una taula. Un model es comporta con un objecte al tindre camps funcionals, restriccions i camps relacionals que deixen la normalització de la base de dades en mans d'Odoo.

L'accés del client a les dades es fa fent ús d'un servici. Aquest pot ser WSGI. WSGI és una solució estàndar per a fer servidors i clients HTTP en Python. En el cas d'Odoo, aquest té el OpenERP Web Project, que és el servidor web.

Un altre concepte dins d'Odoo són els Business Objects quasi tot en Odoo és un Business Object, és persistent gràcies a ORM i es troba estructurat en el directori /modules.

Odoo proporciona els anomenats Wizards, que es comporten com un assistent per introduir dades d'una manera més fàcil per a l'usuari.

El client web és fàcil de desenvolupar gràcies al Widgets o Window GaDGETS. Aquests proporcionen un comportament i visualització correctes per a cada tipus de dades. Per exemple: si el camp és per definir una data, mostrarà un calendari. Alguns tenen diferents visualitzacions en funció del tipus de vista i se'n poden definir Widgets personalitzats.

Tal com es pot observar, són molts els components d’OpenObject a conèixer per poder adequar l’Odoo a les necessitats de l’organització, en cas que les funcionalitats que aporta l’Odoo, tot i ser moltes, no siguin suficients.

La base de dades d'Odoo

En l’Odoo no hi ha un disseny explícit de la base de dades, sinó que la base de dades d’una empresa d’Odoo és el resultat del mapatge del disseny de classes de l’ERP cap el SGBD PostgreSQL que és el que proporciona la persistència necessària per als objectes.

En conseqüència, l’Odoo no facilita cap disseny entitat-relació sobre la base de dades d’una empresa ni tampoc cap diagrama del model relacional.

Si sorgeix la necessitat de detectar la taula o les taules on resideix determinada informació, és perquè es coneix l’existència d’aquesta informació gestionada des de l’ERP i, per tant, es coneix algun formulari de l’ERP a través del qual s’introdueix la informació.

L’Odoo possibilita, mitjançant els clients web i GTK, recuperar el nom de la classe Python que defineix la informació que s’introdueix a través d’un formulari i el nom de la dada membre de la classe corresponent a cada camp del formulari. Aquesta informació permet arribar a la taula i columna afectades, tenint en compte dues qüestions:

  • El nom de les classes Python d’Odoo sempre són en minúscula (s’utilitza el guió baix per fer llegible els mots compostos) i segueix la nomenclatura nom_del_modul.nom1.nom2.nom3… en la qual s’utilitza el punt per indicar un cert nivell de jerarquia. Cada classe Python d’Odoo és mapada en una taula de PostgreSQL amb moltes possibilitats que el seu nom coincideixi amb el nom de la classe, tot substituint els punts per guions baixos.
  • Els noms dels atributs d’una classe Python sempre són en minúscula (s’utilitza el guió baix per fer llegible els mots compostos). Cada dada membre d’una classe Python d’Odoo que sigui persistent (una classe pot tenir dades membres calculades no persistents) és mapat com un atribut en la corresponent taula de PostgreSQL amb el mateix nom.
Per exemple: La classe Python sale.order d’Odoo està pensada per descriure la capçalera de les comandes de venda i la corresponent taula a PostgreSQL és sale_order.

D’aquesta manera, coneixent el nom de la classe i el nom de la dada membre, és molt possible conèixer el nom de la taula i de la columna corresponents. Es pot configurar els clients web i GTK per tal que informin del nom de la classe i de la dada membre en situar el ratolí damunt les etiquetes dels camps dels formularis.

Figura 1.1 Activar el debug mode


Si observem la figura 1.2, podem observar com:

Dalt apareix un desplegable que diu depurar#574, és la vista per defecte per a analitzar els elements dels formularis.

El camp Referencia cliente es diu client_order_ref de l'objecte sale.order. Per tant, la columna client_order_ref de la taula sale_order.

Figura 1.2 Dades de depuració

Respecte al desplegable de dalt, la resta d'opcions són:

  • View Fields que permet obtenir una llista dels camps de la vista actual, amb els paràmetres corresponents.
  • Fields View Get que mostra l’XML generat per la vista actual. Cal tenir en compte que si la vista s’ha generat a partir de diverses vistes XML heretant les unes de les altres, aquí se’n mostra el resultat final.
  • Manage Views que mostra un llistat de les vistes relacionades amb la vista actual. Des d’aquest punt es poden crear noves vistes, eliminar-les o editar-les, encara que és recomanable utilitzar aquesta funcionalitat només per consultar. Es recomana realitzar les modificacions creant nous mòduls, per no perdre les modificacions davant actualitzacions de l’ERP.
  • Edit TreeView, Edit SearchView, Edit Action i Edit Workflow que serveixen per accedir a l’edició de les vistes relacionades amb la vista actual.
  • Si estem editant un registre (mode formulari) o consultant-lo (mode pàgina), apareix una nova opció View Log (perm_read) que mostra informació relativa al registre actual.

Els mòduls

Tant el servidor com els clients són mòduls. Tots estàn guardats en una base de dades. Tot els que es puga fer per modificar Odoo es fa en mòduls.

Composició d'un mòdul

Els mòduls d'Odoo amplien o modifiquen parts de Model-Vista-Controlador. D'aquesta manera, un mòdul pot tindre:

  • Objectes de negoci: Són la part del model, estan definits en classes de Python segons una sintaxy pròpia de l'ORM d'Odoo.
  • Fitxers de dades: Són fitxers XML que poden definir dades, vistes o configuracions.
  • Controladors web: Gestionen les peticions dels navegadors web.
  • Dades estàtiques: Imatges, CSS, o javascript utilitzats per l'interficie web.

Estructura de fitxers d'un mòdul

Tots el mòduls estan en un directori definit en l'opció --addons-path o el fitxer de configuració. Poden ser més d'un directori.

Un mòdul de python es declara en un fitxer de manifest que dona informació sobre el mòdul, el que fa el mòduls dels que depen i cóm s'ha d'instal·lar o actualitzar. [1]

Un mòdul es un paquet de Python que necessita un __init__.py per a instanciar tots els fitxers python.

Creació de mòduls

Per ajudar al programador, Odoo conté un comandament per crear mòduls buits. Aquest crea l'estructura de fitxers necessaria per començar a treballar:

$ odoo.py scaffold <module name> <where to put it>
https://www.odoo.com/documentation/8.0/reference/cmdline.html#scaffolding

ORM

Odoo mapeja els seus objectes en una base de dades amb ORM, evitant la majoria de consultes SQL. D'aquesta manera el desenvolupament dels mòduls és molt ràpid i evitem errades de programació.

Els models són creats com classes de python que extenen la classe model que conté els camps i mètodes útils per a fer anar l'ORM.

Els models, al heretat de model, necessiten donar valor a algunes variables, com ara _name

És en aquest punt on més diferència trobem amb OpenERP 7, per tant, cal tindre cura de no fer cas totalment de tutorials o ajuda per al 7

Odoo considera que un model és la referència a una o més taules en la base de dades. Un model no és una fila en la taula, és tota la taula.

Fields

Les "columnes" del model són els fields. Estos poden ser de dades normals com Integer, Float, Boolean, date, char... o especials como many2one, one2many, related...

Hi ha uns fields reservats:

  • id (Id) the unique identifier for a record in its model
  • create_date (Datetime) creation date of the record
  • create_uid (Many2one) user who created the record
  • write_date (Datetime) last modification date of the record
  • write_uid (Many2one) user who last modified the record

Els fields es declaren amb un constructor:

from openerp import models, fields

class LessMinimalModel(models.Model):
    _name = 'test.model2'

    name = fields.Char()

Tenen uns atributs comuns:

  • string (unicode, default: field's name) The label of the field in UI (visible by users).
  • required (bool, default: False) If True, the field can not be empty, it must either have a default value or always be given a value when creating a record.
  • help (unicode, default: ) Long-form, provides a help tooltip to users in the UI.
  • index (bool, default: False) Requests that Odoo create a database index on the column

I algunes, sobretot les especials, tenen atributs particulars.

Si volem valors per defecte, es poden indicar com un atribut del field.

 name = fields.Char(default='A name')
 # or
 name = fields.Char(default=a_fun)
 #...
 def a_fun(self):
   return self.do_something()

Fields normals

Aquests són els fields per a dades normals que proporciona Odoo:

  • Integer
  • Char
  • Text
  • Date : Mostra un calendari en la vista.
  • Datetime
  • Float
  • Boolean
  • Html : Guarda un text, però es representa de manera especial en el client.
  • Binary : Per guardar, per exemple, imatges. Utilitza codificació base64
  • Selection : Mostra un select amb les opcions indicades.
 
 aselection = fields.Selection([('a', 'A')])
 aselection = fields.Selection(selection=[('a', 'A')])
 aselection = fields.Selection(selection='a_function_name')

Fields Relacionals

  • Reference : Una referència arbitrària a un model i un camp.
 
 aref = fields.Reference([('model_name', 'String')])
 aref = fields.Reference(selection=[('model_name', 'String')])
 aref = fields.Reference(selection='a_function_name')
  • Many2one : Relació amb un altre model
  • One2many : Inversa del Many2one. Necessita de la existència d'un Many2one en l'altre:
 arel_ids = fields.One2many('res.users', 'rel_id')
 arel_ids = fields.One2many(comodel_name='res.users', inverse_name='rel_id')
  • Many2many : Relació molts a molts.
 arel_ids = fields.Many2many('res.users')
 arel_ids = fields.Many2many(comodel_name='res.users',
                            relation='table_name',
                            column1='col_name',
                            column2='other_col_name')
  • Related : Un camp d'un altre model, necessita una relació Many2one. Encara que estiga Store=True, Odoo 8.0 l'actualitza correctament. D'aquesta manera es poden aprofitar les funcionalitats de guardar, com ara les búsquedes o referències en funcions.
participant_nick = fields.Char(string='Nick name',
                               store=True,
                               related='partner_id.name'

Fields Computed

En el OpenERP existia un camp fields.function. Ara s'ha simplificat amb els atributs compute.

class AModel(models.Model):
    _name = 'a_name'

    computed_total = fields.Float(compute='compute_total')

    def compute_total(self):
        ...
        self.computed_total = x

Fitxers de dades

En Odoo, es poden definir dades que es guardaran en models de l'ORM sobre la base de dades. Aquestes dades poden ser de demostració o inclús part de la vista.

Alguns mòduls sols estan per clavar dades en Odoo

Tots els fitxers de dades són en XML i tenen una estructura com esta:

<openerp>
    <data>
        <record model="{model name}" id="{record identifier}">
            <field name="{a field name}">{a value}</field>
        </record>
    </data>
<openerp>


Dins de les etiquetes openerp i data poden trobar una etiqueta record per cada fila en la taula que volem introduir. Cal especificar el model i el id. El id és un identificador extern, que no te perquè coincidir amb la clau primària que l'ORM utilitzarà després. Cada field tindrà un nom i un valor.

Exemple:

<openerp>
    <data>
        <record model="openacademy.course" id="course0">
            <field name="name">Course 0</field>
            <field name="description">Course 0's description

Can have multiple lines
            </field>
        </record>
        <record model="openacademy.course" id="course1">
            <field name="name">Course 1</field>
            <!-- no description for this one -->
        </record>
        <record model="openacademy.course" id="course2">
            <field name="name">Course 2</field>
            <field name="description">Course 2's description</field>
        </record>
    </data>
</openerp>


Accions i menús

Les accions i els menús es declaren en fitxers de dades en XML. Les accions poden ser cridades de tres maneres:

  • Fent clic en un menú.
  • Fent clic en botons de les vistes (han d'estar connectats amb accions).
  • Com accions contextuals en el objectes.

Les accions són un record més. No obstant, els menús, tenen una manera més ràpida de ser declarats amb una etiqueta menuitem:

<record model="ir.actions.act_window" id="action_list_ideas">
    <field name="name">Ideas</field>
    <field name="res_model">idea.idea</field>
    <field name="view_mode">tree,form</field>
</record>
<menuitem id="menu_ideas" parent="menu_root" name="Ideas" sequence="10"
          action="action_list_ideas"/>
Les accions han de ser declarades abans que els menús que les accionen

Exemple:

<?xml version="1.0" encoding="UTF-8"?>
<openerp>
    <data>
        <!-- window action -->
        <!--
            The following tag is an action definition for a "window action",
            that is an action opening a view or a set of views
        -->
        <record model="ir.actions.act_window" id="course_list_action">
            <field name="name">Courses</field>
            <field name="res_model">openacademy.course</field>
            <field name="view_type">form</field>
            <field name="view_mode">tree,form</field>
            <field name="help" type="html">
                <p class="oe_view_nocontent_create">Create the first course
                </p>
            </field>
        </record>

        <!-- top level menu: no parent -->
        <menuitem id="main_openacademy_menu" name="Open Academy"/>
        <!-- A first level in the left side menu is needed
             before using action= attribute -->
        <menuitem id="openacademy_menu" name="Open Academy"
                  parent="main_openacademy_menu"/>
        <!-- the following menuitem should appear *after*
             its parent openacademy_menu and *after* its
             action course_list_action -->
        <menuitem id="courses_menu" name="Courses" parent="openacademy_menu"
                  action="course_list_action"/>
        <!-- Full id location:
             action="openacademy.course_list_action"
             It is not required when it is the same module -->
    </data>
</openerp>

Vistes Bàsiques

Les vistes són la manera en la que es representen els models. En cas de que no declarem les vistes, es poden referenciar per el seu tipus i Odoo generarà una vista de llista o formulari estandar per poder vorer els registres de cada model. No obstant, quasi sempre volem personalitzar les vistes i en aquest cas, es poden referenciar per un identificador.

Les vistes tenen una prioritat i, si no s'especifica el identificador de la que volem mostrar, es mostrarà la que més prioritat tinga.

<record model="ir.ui.view" id="view_id">
    <field name="name">view.name</field>
    <field name="model">object_name</field>
    <field name="priority" eval="16"/>
    <field name="arch" type="xml">
        <!-- view content: <form>, <tree>, <graph>, ... -->
    </field>
</record>

Exemple:

  <record model="ir.ui.view" id="course_form_view">
            <field name="name">course.form</field>
            <field name="model">openacademy.course</field>
            <field name="arch" type="xml">
                <form string="Course Form">
                    <sheet>
                        <group>
                            <field name="name"/>
                            <field name="description"/>
                        </group>
                    </sheet>
                </form>
            </field>
        </record>

Vorer més

Enllaços

https://www.odoo.com/documentation/8.0/

https://www.odoo.com/documentation/8.0/howtos/backend.html

Curs 2015-2016