133. Odoo desarrollo Módulo Odoo¶
133.1 Introducción¶
------ REVISAR----- fichero odoo.conf y odoo-bin -u modulo
Arquitectura de tres capas: presentación, lógica de negocio y datos:
133.2 Preparar e instalar entorno de desarrollo¶
Preparar la instalacion de desarrollo Instalar odoo
Siempre se debe utilizar un entorno ddistinto al de producción.
133.2.1 Instalamos odoo desde fuente¶
Creamos el directorio ./src
que usaremos para todo el proceso.
Creamos un entorno virtual Python
Creamos y activamos un entorno virtual
python -m venv ./envodoo
source ./envodoo/bin/activate
Ver documento de odoo para Linux
Tendremos instalados git y
Python 3.7 o posterior
Clonamos Odoo:
git clone https://github.com/odoo/odoo.git -b 15.0 --depth=1
Normalmente para cambiar de rama se utiliza:
git git switch 15.0
PostgresSQL En el entorno de desarrollo instalamos el resto de los componentes de odoo como postgresql
sudo apt install postgresql postgresql-client
Instalamos postgres:
sudo apt install postgresql postgresql-client
$ sudo -u postgres createuser -s $USER
$ createdb $USER
Para el desarrollo son necesarios algunos paquetes Linux:
sudo apt install python3-dev libxml2-dev libxslt1-dev libldap2-dev libsasl2-dev \
libtiff5-dev libjpeg8-dev libopenjp2-7-dev zlib1g-dev libfreetype6-dev \
liblcms2-dev libwebp-dev libharfbuzz-dev libfribidi-dev libxcb1-dev libpq-dev
requirements.txt
con los paquetes Python dependientes.Con el entorno python activado se instalan en
envodoo\lib
$ pip3 install setuptools wheel
$ pip3 install -r requirements.txt
Sia instalación falla en gevent-21.8.0 y greelet (PENDIENTE DE CORREGIR) Comentamos las líneas:
#gevent==1.5.0 ; python_version == '3.7'
#gevent==20.9.0 ; python_version >= '3.8'
#gevent==21.8.0 ; python_version > '3.9' # (Jammy)
#greenlet==0.4.15 ; python_version == '3.7'
#greenlet==0.4.17 ; python_version > '3.7'
#greenlet==1.1.2 ; python_version > '3.9' # (Jammy)
Que nos permite continuar el desarrollo del módulo ----- Explorar soluciones ----
Truco
From there, you can create and manage new users.
The user account you use to log into Odoo’s web interface differs from the --db_user CLI argument.
Usuario y contraseña de PostgreSQL. Odoo no tiene predeterminados fuera de los predeterminados psycopg2: conecta con un socket UNIX en el puerto 5432 con el usuario actual y sin contraseña. Rutas de complementos personalizadas más allá de lo predeterminado para cargar los módulos. Una forma típica de ejecutar el servidor sería desde el directorio de instalación
python3 odoo-bin --addons-path=addons -d mydb -p 8070
Si aparece un error que mydb no está inicializada se fuerza usando -i base
( literal como aparece aquí )
Algunos argumentos de la línea de comandos:
-d<database>
Base de datos que se va a usar
--addons-path<directories>
Lista de directorios separados por coma (`,` ) donde se encuentran los módulos
--limit-time-cpu<limit>
Prevent the worker from using more than <limit> CPU seconds for each request.
--limit-time-real<limit>
Prevent the worker from taking longer than <limit> seconds to process a request.
para conectar http://localhost:8070
como administrador principal usar:
admin Para el correo y la clave.
133.3 Configuration file¶
Most of the command-line options can also be specified via a configuration file. Most of the time, they use similar names with the prefix - removed and other - are replaced by _ e.g. --db-template becomes db_template.
Some conversions don’t match the pattern:
--db-filter becomes dbfilter --no-http corresponds to the http_enable boolean logging presets (all options starting with --log- except for --log-handler and --log-db) just add content to log_handler, use that directly in the configuration file --smtp is stored as smtp_server --database is stored as db_name --i18n-import and --i18n-export aren’t available at all from configuration files The default configuration file is $HOME/.odoorc which can be overridden using --config. Specifying --save will save the current configuration state back to that file. The configuration items relative to the command-line are to be specified in the section [options].
Here is a sample file:
[options]
db_user=odoo
dbfilter=odoo
133.4 Activar modo desarrollador¶
El modo desarrollador permite usar herramientas avanzadas. Es necesario para el resto del tutorial tener activado el modo desarrollador.
133.5 HERRAMIENTAS¶
Con git tenemos el comando para cambiar a la rama 15.0:
git switch 15.0
133.6 Crear un módulo odoo¶
Un nuevo módulo servirá para extender la funcionalidad o modificar la existente.
La lógica de negocio y las extensiones se desarrollan en el lado serividor con facilidades para el lado cliente.
Una aplicación en Odoo es un conjunto de módulos que realizan una funcionalidad completa.
PASOS para crear un módudlo Odoo:
1. Crea una carpeta con el nombre del módulo en el directorio addons en la instalación de Odoo ( ./src/custom-addons
)
2. Crea un archivo llamado __manifest__.py
en la carpeta del módulo que acabas de crear. Este archivo es esencial ya que es el que indica a Odoo que existe un módulo en esa carpeta.
3. Crea un archivo llamado models.py
en la carpeta del módulo. Este archivo es donde se definirán los modelos (tablas) que utilizará el módulo.
4. Crea un archivo llamado views.xml
en la carpeta del módulo. Este archivo es donde se definirán las vistas (interfaz de usuario) que utilizará el módulo.
5. Crea un archivo llamado security.xml
en la carpeta del módulo. Este archivo es donde se definirán los permisos (acceso) que utilizará el módulo.
6. Crea un archivo llamado __init__.py
en la carpeta del módulo. Este archivo es esencial ya que es el que indica a Python que la carpeta es un paquete.
7. Crea un archivo llamado __init__.py
en la carpeta models. Este archivo es esencial ya que es el que indica a Python que la carpeta es un paquete.
Finalmente, actualiza la lista de módulos en Odoo y busca tu módulo para instalarlo.
Un poco más adelante se muestra la estructura de directorios y ficheros. Esta estructura se puede crear usando el comando odoo-bin scaffold
que veremos en el ejemplo de la academia.
133.7 Componentes del módulo¶
- Objetos de negocio, modelos
- Ficheros de datos: XML o CSV para declarar metadata:
- views y reports
- Datos de configuración y reglas de seguridad
- datos de demostración
- mas...
- Web controllers : gestionan peticiones desde los navegadores web
133.8 Creación y estructura del módulo¶
Cada 'módulo Odoo' es un directorio. Se especifican con la opción --addons-path
cuando ejecutamos el servidor con odoo-bin
.
Un módulo odoo debe declararse en el manifiesto.
Un módulo odoo es un paquete python que incluye __init__.py
.
Odoo-bin dispone del siguiente comando para crear la estructura de directorio:
odoo-bin scaffold <module name> <where to put it>
/opt/odoo15/custom-addons
La estructura de directorios de un módulo 'my_module' sería:
odoo-bin scaffold "Open Academy" ./
tree
── open_academy
├── controllers
│ ├── controllers.py
│ └── __init__.py
├── demo
│ └── demo.xml
├── __init__.py
├── __manifest__.py
├── models
│ ├── __init__.py
│ └── models.py
├── security
│ └── ir.model.access.csv
└── views
├── templates.xml
└── views.xml
133.9 Fichero de manifiesto (manifest.py)¶
El manifiesto es un diccionarios con metadata para Odoo:
{
'name': "A Module",
'version': '1.0',
'depends': ['base'],
'author': "Author Name",
'category': 'Category',
'description': """
Description text
""",
# data files always loaded at installation
'data': [
'views/mymodule_view.xml',
],
# data files containing optionally loaded demonstration data
'demo': [
'demo/demo_data.xml',
],
}
Se puede consultar la referencia y las entradas que admite el diccionario.
category
Aparece en la categoría en el apartado de app
de Odoo. Se pueden usar las categorías definidas o crear nuevas. Se utiliz la barra /
para crear categorías de forma jerarquica
etc.
133.10 Modelo. Object-Relational Mapping (ORM)¶
ORM permite tratar con objetos Python en lugar de sql.
Un objeto de negocio se declara en Python extendiento la clase Model
que se encarga de la persistencia.
Los modelos se configuran declarando atributos en la nueva clase. El principal atributo es _name
que define el nombre del modelo en Odoo. Por ejemplo:
from odoo import models
class MinimalModel(models.Model):
_name = 'test.model'
En las variables de clase del modelo incluimos campos (field) que sólo pueden ser los definidos en el ORM de Odoo.
133.10.1 Campos del modelo (fields)¶
Los campos definen que guarda el modelo y donde (similar a los campos en una tabla sql).
from odoo import models, fields
class LessMinimalModel(models.Model):
_name = 'test.model2'
nombre = fields.Char()
nombre
es un campo de tipo Char
y se corresponde a una columna de la tabla en la BD. Otro campos definidos:
133.10.1.1 Atributos de los campos¶
Se pueden pasar atributos en los campos, por ejemplo para indicar que el campo es obligatorio:
name = fields.Char(required=True)
Algunos son comunes a todos los campos, como :
* string
* required
* help
* index
Una lista completa en esta documentacion
Otros solamente se utilizan con un campo.
133.10.1.2 Campos simples¶
Hay dos categorías de campos 'simples' valores atomicos que se guardan directamente en las tablas y 'relacionales' que enlazan registros.
Simples como:
* Char
* Float
* Integer
133.10.1.3 Campos avanzados¶
Como
* Binary
* Html
* Image
* Monetary
* Selection
* Text
133.10.1.3.1 Campos de Date(time)¶
- Date
- Datetime
133.10.1.3.2 Relacionales¶
- Many2One
- One2Many
- Many2many
Command Y campos pseudorelacionales:
* Reference
* Many2oneReference
Campos de cálculo:
*
133.10.1.4 Campos automáticos.¶
Odoo crea unos pocos campos que se gestionan solamente por el sistema y no pueen escribirse.
* id : identificador único. Si se intenta insertar con mismo id levanta una excepción
* create_date(Date)
* create_uid(Many2one) usuario que crea el registro
* write_date(Datetime)
* write_uid(Many2one) usuario que escribe el registro.
133.10.1.5 Campos reservados¶
- name
- active
- state
- parent_id
- parent_path
- company_id
La referencia ORM API contiene información detallada de campos y atributos.
133.10.2 ficheros de datos (DATA FILES)¶
133.11 Declaraciones de vistas genéricos.¶
133.12 BASIC VIEWS¶
Las vistas definen como se ven los registros del modelo. Cada tipo de vista representa un modo de visualización (listas, graficos, etc) .....
<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>
133.12.1 Tree views¶
También llamado list views, muestran elementos tabulados
El elemento raíz es <tree>
<tree string="Idea list">
<field name="name"/>
<field name="inventor_id"/>
</tree>
133.12.2 Form views¶
Sirven para crear y modificar registros.
El elemento raíz is <form>
. Se componen de elementos de estructura como groups
y notebooks
y elementos interactivos como botones y campos
<form string="Idea form">
<group colspan="4">
<group colspan="2" col="2">
<separator string="General stuff" colspan="2"/>
<field name="name"/>
<field name="inventor_id"/>
</group>
<group colspan="2" col="2">
<separator string="Dates" colspan="2"/>
<field name="active"/>
<field name="invent_date" readonly="1"/>
</group>
<notebook colspan="4">
<page string="Description">
<field name="description" nolabel="1"/>
</page>
</notebook>
<field name="state"/>
</group>
</form>
Las vistan form
pueden crearse también usando html :
<form string="Idea Form">
<header>
<button string="Confirm" type="object" name="action_confirm"
states="draft" class="oe_highlight" />
<button string="Mark as done" type="object" name="action_done"
states="confirmed" class="oe_highlight"/>
<button string="Reset to draft" type="object" name="action_draft"
states="confirmed,done" />
<field name="state" widget="statusbar"/>
</header>
<sheet>
<div class="oe_title">
<label for="name" class="oe_edit_only" string="Idea Name" />
<h1><field name="name" /></h1>
</div>
<separator string="General" colspan="2" />
<group colspan="2" col="2">
<field name="description" placeholder="Idea description..." />
</group>
</sheet>
</form>
133.12.3 Search views¶
Las vistas se declaran como un registro del modelo ir.ui.view
.....
133.13 Relaciones entre modelos¶
Un registro de un modelo puede relacionarse con un registro de otro. Por ejemplo, el registro orden de ventas se relaciona con el del cliente.
133.13.1 Relational fields¶
Los campos relación enlazan registros, bien del mismo modelo (herarquicos) o entre modelos
Tipos:
Many2one(other_model, ondelete='set null')
enlace simple a otro modelo
One2many(other_model, related_field)
....
Many2many(other_model)
....
133.14 Herencia¶
133.14.1 Herencia de modelos¶
133.14.2 Herencia de Vistas¶
133.14.2.1 Dominios¶
133.15 Computed fields y valores por defecto¶
En este caso los campos no se obtienen directamente de la BD si no que son calculados.
Los campos calculados son campos con el atributo compute
y valor igual al métodos de la clase que hece el cálculo y asigna valor al campo, ejemplo:
import random
from odoo import models, fields, api
class ComputedModel(models.Model):
_name = 'test.computed'
name = fields.Char(compute='_compute_name')
def _compute_name(self):
for record in self:
record.name = str(random.randint(1, 1e6))
133.15.1 Dependencias¶
Los campos calculados suelen depender de otros campos del mismo registro. El modeo ORM espera que se especifiquen estas dependencias en le método que realiza el cálculo. Esto se consigue usando el decorador depends
. Y es usamo por el ORM para recalcular el campo cuando alguna dependencia cambia.
En el siguiente ejemplo,name
depende de value
:
from odoo import models, fields, api
class ComputedModel(models.Model):
_name = 'test.computed'
name = fields.Char(compute='_compute_name')
value = fields.Integer()
@api.depends('value')
def _compute_name(self):
for record in self:
record.name = "Record with value %s" % record.value
133.15.2 Valores por defecto¶
Se puede dar un valor por defecto a cualquier campo en la definición de campo con default=xxx
name = fields.Char(default="Unknown")
user_id = fields.Many2one('res.users', default=lambda self: self.env.user)
The object self.env gives access to request parameters and other useful things:
self.env.cr or self._cr is the database cursor object; it is used for querying the database
self.env.uid or self._uid is the current user’s database id
self.env.user is the current user’s record
self.env.context or self._context is the context dictionary
self.env.ref(xml_id) returns the record corresponding to an XML id
self.env[model_name] returns an instance of the given model
133.16 Onchange¶
El mecanismo «onchange» permite al intefaz cliente actualizar una forma cuando el usuario rellena un campo, sin guardar nada en la BD Por ejemplo, suponer un modelo con tres campos:
<!-- content of form view -->
<field name="amount"/>
<field name="unit_price"/>
<field name="price" readonly="1"/>
self
representa el registro en el formulario y
* Usando el decorador onchange()
en el métodos donde se especifica en que campo se recacula. Cualquier campo en self
se refleja en el formularios
# onchange handler
@api.onchange('amount', 'unit_price')
def _onchange_price(self):
# set auto-changing field
self.price = self.amount * self.unit_price
# Can optionally return a warning and domains
return {
'warning': {
'title': "Something bad happened",
'message': "It was very bad indeed",
}
}
133.17 Model constraints¶
133.18 Seguridad¶
Los requisitos mínimos de seguridad para usar un módulo aqui .
Los grupos se crean como registros del modelo res.group
y dando acceso a los menús via definición de menús.
Sin menús también es posible acceder a los modelos indirectamente y los permisos reales de los objetos (CRUD) deben ser definidos para los grupos. Normalmente con ficheros CSV.
133.18.1 Access rights¶
Se definen como registros del modelo ir.model.access
Cada derecho de acceso se asocia a un modelo, grupo ( o ninguno) y un conjunto de permisos CRU. Normalmente en ficheros CSV nombrados después de su modelo ir.model.access.csv
id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
access_idea_idea,idea.idea,model_idea_idea,base.group_user,1,1,1,0
access_idea_vote,idea.vote,model_idea_vote,base.group_user,1,1,1,0
133.18.2 Record rules¶
Record rules restringen el acceso a un subconjunto de registos de un modelo. Una regla es un registro del modelo ir.rule
y está asociado a un modelo, un numero de grupos (campo many2many
), permisos a los que se aplica la restricción y un dominio.
El siguiente ejemplo evita el borrado de "leads" que no estén en el estado "cancel".
Observar que el valor del grupo sigue la misma forma que el método write()
del modelo ORM.
<record id="delete_cancelled_only" model="ir.rule">
<field name="name">Only cancelled leads may be deleted</field>
<field name="model_id" ref="crm.model_crm_lead"/>
<field name="groups" eval="[(4, ref('sales_team.group_sale_manager'))]"/>
<field name="perm_read" eval="0"/>
<field name="perm_write" eval="0"/>
<field name="perm_create" eval="0"/>
<field name="perm_unlink" eval="1" />
<field name="domain_force">[('state','=','cancel')]</field>
</record>
133.19 Vistas avanzadas¶
Para la vista continuar aqui
133.20 Wizards (Asistentes)¶
Los asistentes simplifican y automatizan ciertas tares en Odoo.
133.21 Internacionalización¶
133.22 Reporting (Informes)¶
133.22.1 Informes impresos¶
133.22.2 Dashboard (Tablero de instrumentos)¶
133.23 CLI Command Line Interface¶
https://www.odoo.com/documentation/15.0/es/developer/cli.html#command-line-interface-cli
133.24 Enlaces¶
- oficial Odoo
- Libro con ficheros .md. Incluye el desarrollo de un módulo real_state y hospital
133.24.1 Ejemplos de módulos para v15.0¶
- en github
- Odoo 15 module exercise
- De un particular ejemplo estate module, descripciones en ruso.
- ---- Muchos módulos en .zip ajhamaal
- Otro
- Módulo Hospital
- colegio
Interesante Openacademy y demo
Modulo con video sobre hospital