Advertencia
Esta guía asume conocimientos básicos de Python
Esta guía asume que tienes Odoo instalado
Creación de un módulo básico
En Odoo, las tareas se realizan mediante la creación de módulos.
Los módulos personalizan el comportamiento de una instalación de Odoo, añadiendo nuevos comportamientos o modificando los existentes (incluyendo nuevas características o modificando las de otros módulos).
Odoo's scaffolding puede configurar un módulo básico. Para rápidamente comenzar con simplemente invocar:
$ ./odoo-bin scaffold Academy my-modules
Esto creará automáticamente un directorio de módulo ( my-modules
) con un módulo de la academy
dentro. El directorio puede ser un directorio de módulos existente si quieres, pero el nombre del módulo debe ser único dentro del directorio.
Un módulo para demostración
Contamos con un módulo “completo” listo para su instalación.
Aunque no hace absolutamente nada lo podemos instalar:
Inicia el servidor de Odoo
$ ./odoo-bin --addons-path addons,my-modules
Abre un navegador con la dirección http://localhost:8069
Crear una nueva base de datos incluyendo datos de demostración
Luego ir
En la esquina superior derecha, quite el filtro Installed y busca academy
Haga clic en Install para el módulo Academy
En el explorador
Los Controllers interpretan las peticiones del navegador y envía datos de regreso.
Agregar un controlador simple y asegura que es importado en el __init__.py
(de tal modo que Odoo pueda encontrarlo):
# -*- coding: utf-8 -*-
from odoo import http
class Academy(http.Controller):
@http.route('/academy/academy/', auth='public')
def index(self, **kw):
return "Hello, world"
# @http.route('/academy/academy/objects/', auth='public')
# def list(self, **kw):
Mata el servidor (^C
) y luego reinicialo:
$ ./odoo-bin --addons-path addons,my-modules
Abre una página en tu navegador en http://localhost:8069/academy/academy/, debería aparecer tu “página”:

Plantillas
Generar HTML en Python no es muy agradable.
La solución habitual es usar algo llamado “Plantillas” (templates en inglés), son pseudo-documentos con marcadores de posición y con la lógica de la vista. Odoo permite usar cualquier sistema de plantillas de Python, pero ofrece su propio sistema de plantillas llamado QWeb que está integrado con otras funciones.
Create a template and ensure the template file is registered in the
__manifest__.py
manifest, and alter the controller to use our template:
class Academy(http.Controller):
@http.route('/academy/academy/', auth='public')
def index(self, **kw):
return http.request.render('academy.index', {
'teachers': ["Diana Padilla", "Jody Caroll", "Lester Vaughn"],
})
# @http.route('/academy/academy/objects/', auth='public')
# def list(self, **kw):
<odoo>
<template id="index">
<title>Academy</title>
<t t-foreach="teachers" t-as="teacher">
<p><t t-esc="teacher"/></p>
</t>
</template>
<!-- <template id="object"> -->
<!-- <h1><t t-esc="object.display_name"/></h1> -->
<!-- <dl> -->
La plantilla itera (t-foreach
) en todos los profesores (pasados a través del Contexto del template (template context en inglés)), e imprime cada docente en su propio párrafo.
Para terminar reinicia Odoo y actualiza los datos del módulo (para instalar la plantilla) esto lo haces yendo a Upgrade.
y haciendo clic enTruco
Alternatively, Odoo can be restarted and update modules at
the same time
:
$ odoo-bin --addons-path addons,my-modules -d academy -u academy
Ve a http://localhost:8069/academy/academy/ y ahora debe aparecer:

Almacenamiento de datos en Odoo
Los modelos de Odoo mapean elementos tablas en la base de datos.
En la sección anterior sólo nos muestra una lista de cadenas estáticamente escritas en código Python. Esto no permite modificaciones o almacenamiento persistente así que ahora grabaremos nuestros datos a la base de datos.
Definir el modelo de datos
Definir un modelo que represente a un profesor y asegurate que se importa en el __init__.py
así es cargado correctamente por odoo:
from odoo import models, fields, api
class Teachers(models.Model):
_name = 'academy.teachers'
name = fields.Char()
Luego crea los controles de acceso básicos para el modelo y declara los archivos en el manifiesto:
# always loaded
'data': [
'security/ir.model.access.csv',
'templates.xml',
],
# only loaded in demonstration mode
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_academy_teachers,access_academy_teachers,model_academy_teachers,,1,0,0,0
Simplemente da acceso de lectura (perm_read
) a todos los usuarios (eso significa deja group_id:id
vacío)
Nota
Los archivos de datos (XML o CSV) debe ser agregados al manifiesto del módulo, pero no es así con los archivos de Python (modelos o controladores), sino que tienen que ser importados en el archivo __init__.py
(directa o relativamente aunque es recomendable cómo buena práctica hacer la importación relativa)
Advertencia
El usuario administrador ignora el control de acceso y tiene acceso a todos los modelos aunque no tenga permisos definidos de forma explícita
Datos de demostración
El segundo paso es añadir algunos datos de demostración del sistema para que sea posible probar fácilmente. Esto se hace agregando un Archivo de datos demo
, que debe estar declarado en el manifiesto:
<odoo>
<record id="padilla" model="academy.teachers">
<field name="name">Diana Padilla</field>
</record>
<record id="carroll" model="academy.teachers">
<field name="name">Jody Carroll</field>
</record>
<record id="vaughn" model="academy.teachers">
<field name="name">Lester Vaughn</field>
</record>
</odoo>
Truco
Los archivos de datos pueden ser utilizados para datos de demostración y datos no-demostración. los datos demo sólo se cargan en "demonstration mode" y pueden utilizarse para demostración y pruebas de flujo, los datos no-demo son siempre cargados y utilizados como configuración inicial del sistema.
En este caso estamos utilizando datos de demostración ya que un usuario real del sistema le gustaría con solo instalar tener una lista de profesores o importar su propia lista, esta lista sólo es útil para probar.
Acceder a los datos
El último paso es modificar el modelo y la plantilla a utilizar nuestros datos de demostración:
Buscar los registros de la base de datos en lugar de tener una lista estática
- Because
search()
returns a set of records matching the filter ("all records" here), alter the template to print each teacher'sname
class Academy(http.Controller):
@http.route('/academy/academy/', auth='public')
def index(self, **kw):
Teachers = http.request.env['academy.teachers']
return http.request.render('academy.index', {
'teachers': Teachers.search([])
})
# @http.route('/academy/academy/objects/', auth='public')
<template id="index">
<title>Academy</title>
<t t-foreach="teachers" t-as="teacher">
<p><t t-esc="teacher.id"/> <t t-esc="teacher.name"/></p>
</t>
</template>
<!-- <template id="object"> -->
Reinicia el servidor y actualiza el módulo (con el fin de actualizar el manifiesto así cómo las plantillas y cargar también el archivo de demostración) ve a http://localhost:8069/academy/academy/. La página debe parecer levemente diferente: nombres simplemente deben ser prefijados por un número (el identificador de base de datos para el profesor).
Soporte de sitio web
Odoo tiene un módulo dedicado a la construcción de sitios Web.
Hasta ahora hemos utilizado controladores directamente, pero Odoo 8 agrega una integración más profunda y algunos otros servicios (por ejemplo estilos por defecto, manejo de temas) a través del módulo website
.
En primer lugar, añadir
website
como una dependencia del móduloAcademy
luego agregar la bandera
website=True
al controlador, esta establece nuevas variables en el objeto *request* y le permite utilizar una el esquema de disposición de los elementos del sitio (layout en inglés) en nuestra plantillaUtilizar el layout en nuestra plantilla.
'version': '0.1',
# any module necessary for this one to work correctly
'depends': ['website'],
# always loaded
'data': [
from odoo import http
class Academy(http.Controller):
@http.route('/academy/academy/', auth='public', website=True)
def index(self, **kw):
Teachers = http.request.env['academy.teachers']
return http.request.render('academy.index', {
<odoo>
<template id="index">
<t t-call="website.layout">
<t t-set="title">Academy</t>
<div class="oe_structure">
<div class="container">
<t t-foreach="teachers" t-as="teacher">
<p><t t-esc="teacher.id"/> <t t-esc="teacher.name"/></p>
</t>
</div>
</div>
</t>
</template>
<!-- <template id="object"> -->
Después de reiniciar el servidor al actualizar el módulo (para actualizar el manifiesto y la plantilla) entramos a http://localhost:8069/academy/academy/ debería mostrar una página más agradable con un esquema de imagen y otros elementos en la página incorporados (menú de primer nivel, pie de página,…)

El layout del módulo website
también proporciona soporte para herramientas de edición: haga clic en: Sign In (en la parte superior derecha), coloca las credenciales (admin
/ admin
por defecto) haga clic en: Log In.
Estás ahora en Odoo: la interfaz administrativa. Por ahora haga clic en el botón Website (esquina superior izquierda).
Estamos ahora en el website pero como administrador, con acceso a funciones de edición avanzadas dichas opciones son provistas por el módulo website:
Un editor de código para la plantilla (
) donde puedes ver y editar todas las plantillas utilizadas actualmenteEl botón Edit en la parte superior izquierda cambia al "modo edición" donde hay bloques (fragmentos) y edición de texto
Un número de otras características tales como vista previa móvil y SEO
URLs y enrutamiento
Controller methods are associated with routes via the
route()
decorator which takes a routing string and a
number of attributes to customise its behavior or security.
Hemos visto una cadena enrutamiento “literal”, que corresponde exactamente a una sección de URL, pero las cadenas de enrutamiento también pueden usar patrones convertidores que coincide con los bits de direcciones URL y los pone disponibles como variables locales. Por ejemplo podemos crear un nuevo método de control controller que toma una parte del URL y lo imprime:
'teachers': Teachers.search([])
})
@http.route('/academy/<name>/', auth='public', website=True)
def teacher(self, name):
return '<h1>{}</h1>'.format(name)
# @http.route('/academy/academy/objects/', auth='public')
# def list(self, **kw):
# return http.request.render('academy.listing', {
reiniciar Odoo, accede a http://localhost:8069/academy/Alice/ y http://localhost:8069/academy/Bob/ y ver la diferencia.
As the name indicates, converter patterns don't just do extraction, they also do validation and conversion, so we can change the new controller to only accept integers:
'teachers': Teachers.search([])
})
@http.route('/academy/<int:id>/', auth='public', website=True)
def teacher(self, id):
return '<h1>{} ({})</h1>'.format(id, type(id).__name__)
# @http.route('/academy/academy/objects/', auth='public')
Reinicia Odoo, entra a http://localhost:8069/academy/2, nota cómo el valor anterior era una cadena, pero el nuevo fue convertido a un entero. Tratar de acceder a http://localhost:8069/academy/Carol/ y tenga en cuenta que la página no se encontró: “Carol” no es un número entero, la ruta fue ignorada y ninguna ruta pudo encontrarse.
Odoo ofrece un convertidor adicional llamado model
que provee un registro directamente dado su id. Vamos a usar esto para crear una página genérica para las biografías de los maestros:
'teachers': Teachers.search([])
})
@http.route('/academy/<model("academy.teachers"):teacher>/', auth='public', website=True)
def teacher(self, teacher):
return http.request.render('academy.biography', {
'person': teacher
})
# @http.route('/academy/academy/objects/', auth='public')
</div>
</t>
</template>
<template id="biography">
<t t-call="website.layout">
<t t-set="title">Academy</t>
<div class="oe_structure"/>
<div class="oe_structure">
<div class="container">
<p><t t-esc="person.id"/> <t t-esc="person.name"/></p>
</div>
</div>
<div class="oe_structure"/>
</t>
</template>
<!-- <template id="object"> -->
<!-- <h1><t t-esc="object.display_name"/></h1> -->
<!-- <dl> -->
luego cambia la lista de modelo a nuestro nuevo controlador:
<div class="oe_structure">
<div class="container">
<t t-foreach="teachers" t-as="teacher">
<p><a t-attf-href="/academy/{{ slug(teacher) }}">
<t t-esc="teacher.name"/></a>
</p>
</t>
</div>
</div>
<div class="oe_structure"/>
<div class="oe_structure">
<div class="container">
<h3><t t-esc="person.name"/></h3>
</div>
</div>
<div class="oe_structure"/>
Reiniciar Odoo y actualizar el módulo, a continuación, puede visitar la página de cada profesor. Como ejercicio, intente agregar bloques a la página de un maestro para escribir una biografía, y luego ir a la página de otro maestro y así sucesivamente. Descubrirá que su modelo de biografía es compartida entre todos los maestros, porque los bloques se agregan a la plantilla y la plantilla de la biografía es compartida entre todos los maestros, cuando se edita una página están todas siendo editadas al mismo tiempo.
Edición de campos
Los datos que son específicos de un registro se guardará en ese registro, así que nosotros agregar un nuevo campo biography
a nuestros maestros:
_name = 'academy.teachers'
name = fields.Char()
biography = fields.Html()
<div class="oe_structure">
<div class="container">
<h3><t t-esc="person.name"/></h3>
<div><t t-esc="person.biography"/></div>
</div>
</div>
<div class="oe_structure"/>
Reinicia Odoo y actualiza las vistas, re-carga la página del profesor el campo es invisible porque no contiene nada.
Para los campos de registro, las plantillas pueden utilizar una directiva del t-field
especial que permite editar el contenido del campo desde el website mediante interfaces específicamente diseñadas para campos. Cambio la plantilla de la person para usar t-field
:
<div class="oe_structure"/>
<div class="oe_structure">
<div class="container">
<h3 t-field="person.name"/>
<div t-field="person.biography"/>
</div>
</div>
<div class="oe_structure"/>
Reinicia Odoo y actualiza el módulo, ahora hay un marcador de posición con el nombre del profesor y una nueva zona de bloques en modo Edit.El contenido que se suelte allí es almacenado en el campo de biografía
del profesor correspondiente y por lo tanto es específica a ese maestro.
El nombre del profesor también es editable y cuando se modifica el cambio es visible en el índice.
t-field
también puede tomar opciones de formato que dependen del formato del campo. Por ejemplo si desplegamos la fecha de modificación de registro de un maestro:
<div class="oe_structure">
<div class="container">
<h3 t-field="person.name"/>
<p>Last modified: <i t-field="person.write_date"/></p>
<div t-field="person.biography"/>
</div>
</div>
es mostrado de una manera muy “computista” y difícil de leer, pero podríamos hacer una versión legible:
<div class="oe_structure">
<div class="container">
<h3 t-field="person.name"/>
<p>Last modified: <i t-field="person.write_date" t-options='{"format": "long"}'/></p>
<div t-field="person.biography"/>
</div>
</div>
o un despliegue relativo:
<div class="oe_structure">
<div class="container">
<h3 t-field="person.name"/>
<p>Last modified: <i t-field="person.write_date" t-options='{"widget": "relative"}'/></p>
<div t-field="person.biography"/>
</div>
</div>
administración e Integración con el ERP
Una introducción breve e incompleta a la administración de Odoo
La administración de Odoo fue vista brevemente durante la sección website support. Podemos volver a hacerlo usando en el menú (o Sign In si no estás autenticado).
La estructura conceptual del backend Odoo es simple:
en primer lugar son menús, un árbol (menús pueden tener submenús) de registros. Los menús sin hijos apuntan a…
acciones. Las acciones tienen varios tipos: enlaces, informes, datos y código que debe ejecutar Odoo o Mostrar. Las acciones de visualización de datos son llamadas Acciones de ventana, y le dicen a Odoo como mostrar un determinado modelo según un conjunto de vistas…
una vista tiene un tipo, una categoría a la que ésta corresponde (una lista, un gráfico, un calendario) y una arquitectura la cual personaliza la manera en que el modelo se muestra en la vista.
Editar en la interfaz de administración
De forma predeterminada, un modelo de Odoo es esencialmente invisible a un usuario. Para que sea visible debe estar disponible a través de una acción, la cuál en sí mismo debe ser accesible, generalmente esto se hace a través de un menú.
Vamos a crear un menú para nuestro modelo:
'data': [
'security/ir.model.access.csv',
'templates.xml',
'views.xml',
],
# only loaded in demonstration mode
'demo': [
<odoo>
<record id="action_academy_teachers" model="ir.actions.act_window">
<field name="name">Academy teachers</field>
<field name="res_model">academy.teachers</field>
</record>
<menuitem sequence="0" id="menu_academy" name="Academy"/>
<menuitem id="menu_academy_content" parent="menu_academy"
name="Academy Content"/>
<menuitem id="menu_academy_content_teachers"
parent="menu_academy_content"
action="action_academy_teachers"/>
entonces acceder a http://localhost:8069/web/ en la parte superior izquierda debería haber un menú Academy, que está seleccionada por defecto, ya que es el primer menú y abre un listado de los docentes. Desde el listado es posible Create (crear) nuevos registros de maestros y para cambiar a la vista formulario.
Si no hay ninguna definición de cómo presentar los registros (un view) Odoo creará automáticamente uno básico on-the-fly. En nuestro caso funciona para la vista “list” por ahora (sólo muestra el nombre del profesor), pero en la vista “formulario” HTML el campo biography
es al lado del campo name
y no hay suficiente espacio. Vamos a definir una vista de formulario personalizado para hacer ver y editar registros maestros con una mejor experiencia:
<field name="name">Academy teachers</field>
<field name="res_model">academy.teachers</field>
</record>
<record id="academy_teacher_form" model="ir.ui.view">
<field name="name">Academy teachers: form</field>
<field name="model">academy.teachers</field>
<field name="arch" type="xml">
<form>
<sheet>
<label for="name"/> <field name="name"/>
<label for="biography"/>
<field name="biography"/>
</sheet>
</form>
</field>
</record>
<menuitem sequence="0" id="menu_academy" name="Academy"/>
<menuitem id="menu_academy_content" parent="menu_academy"
Relaciones entre modelos
Hemos visto un par de campos «básicos» almacenados directamente en el registro. Hay un número de campos básicos. Las segunda categorías de campos son relacionase y suelen vincular registros entre ellos (dentro de un modelo o de diferentes modelos).
Para la demostración, vamos a crear un courses modelo. Cada curso debe tener un campo teacher
, con un registro de solo maestro, pero cada profesor puede impartir varios cursos:
name = fields.Char()
biography = fields.Html()
class Courses(models.Model):
_name = 'academy.courses'
name = fields.Char()
teacher_id = fields.Many2one('academy.teachers', string="Teacher")
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_academy_teachers,access_academy_teachers,model_academy_teachers,,1,0,0,0
access_academy_courses,access_academy_courses,model_academy_courses,,1,0,0,0
Agreguemos también vistas para que podamos ver y editar profesor de un curso:
</form>
</field>
</record>
<record id="action_academy_courses" model="ir.actions.act_window">
<field name="name">Academy courses</field>
<field name="res_model">academy.courses</field>
</record>
<record id="academy_course_search" model="ir.ui.view">
<field name="name">Academy courses: search</field>
<field name="model">academy.courses</field>
<field name="arch" type="xml">
<search>
<field name="name"/>
<field name="teacher_id"/>
</search>
</field>
</record>
<record id="academy_course_list" model="ir.ui.view">
<field name="name">Academy courses: list</field>
<field name="model">academy.courses</field>
<field name="arch" type="xml">
<tree string="Courses">
<field name="name"/>
<field name="teacher_id"/>
</tree>
</field>
</record>
<record id="academy_course_form" model="ir.ui.view">
<field name="name">Academy courses: form</field>
<field name="model">academy.courses</field>
<field name="arch" type="xml">
<form>
<sheet>
<label for="name"/>
<field name="name"/>
<label for="teacher_id"/>
<field name="teacher_id"/>
</sheet>
</form>
</field>
</record>
<menuitem sequence="0" id="menu_academy" name="Academy"/>
<menuitem id="menu_academy_content" parent="menu_academy"
name="Academy Content"/>
<menuitem id="menu_academy_content_courses"
parent="menu_academy_content"
action="action_academy_courses"/>
<menuitem id="menu_academy_content_teachers"
parent="menu_academy_content"
It should also be possible to create new courses directly from a teacher's
page, or to see all the courses they teach, so add
the inverse relationship
to the teachers
model:
name = fields.Char()
biography = fields.Html()
course_ids = fields.One2many('academy.courses', 'teacher_id', string="Courses")
class Courses(models.Model):
_name = 'academy.courses'
<field name="arch" type="xml">
<form>
<sheet>
<label for="name"/> <field name="name"/>
<label for="biography"/>
<field name="biography"/>
<field name="course_ids">
<tree string="Courses" editable="bottom">
<field name="name"/>
</tree>
</field>
</sheet>
</form>
Discusiones y notificaciones
Odoo ofrece modelos técnicos, que no satisfacen directamente las necesidades del negocio pero que agrega capacidades a objetos de negocio sin tener que construirlas a mano.
One of these is the Chatter system, part of Odoo's email and messaging
system, which can add notifications and discussion threads to any model.
The model simply has to _inherit
mail.thread
, and add the message_ids
field to its form view to display
the discussion thread. Discussion threads are per-record.
Para nuestra Academia, tiene sentido permitir intercambio de mensajes en los cursos para manejar, por ejemplo, la programación cambios o discusiones entre profesores y asistentes:
class Courses(models.Model):
_name = 'academy.courses'
_inherit = 'mail.thread'
name = fields.Char()
teacher_id = fields.Many2one('academy.teachers', string="Teacher")
<field name="name"/>
<label for="teacher_id"/>
<field name="teacher_id"/>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="message_ids" widget="mail_thread"/>
</div>
</form>
</field>
En la parte inferior de cada formulario de curso, ahora hay un hilo de discusión y la posibilidad para los usuarios del sistema dejar mensajes y seguir o dejar de seguir cursos vinculados a ciertos debates.
Venta de cursos
Odoo ofrece también modelos de negocio que permiten utilizar más directamente en las necesidades del negocio. Por ejemplo con el módulo website_sale
es posible configurar un sitio de comercio electrónico basado en los productos en Odoo. Con éste podemos hacer la subscripción a los cursos vendibles usando un tipo de producto específico
En lugar de usar una herencia clásica anterior, esto significa cambiar nuestro modelo course por el modelo product y extender los productos en-sitio (para agregar cualquier cosa que necesitemos de él).
En primer lugar tenemos que agregar una dependencia en website_sale
, con lo que obtenemos productos (a través de sale
) y la interfaz de comercio electrónico:
'version': '0.1',
# any module necessary for this one to work correctly
'depends': ['website_sale'],
# always loaded
'data': [
reinicia Odoo, actualice su módulo, ahora hay un menú Shop, listando un número de productos existentes (se crearon como datos de demostración) de la tienda.
El segundo paso es sustituir el modelo courses por product.template
y añadir una nueva categoría de producto para ser usada como cursos:
'security/ir.model.access.csv',
'templates.xml',
'views.xml',
'data.xml',
],
# only loaded in demonstration mode
'demo': [
<odoo>
<record model="product.public.category" id="category_courses">
<field name="name">Courses</field>
<field name="parent_id" ref="website_sale.categ_others"/>
</record>
</odoo>
<record id="vaughn" model="academy.teachers">
<field name="name">Lester Vaughn</field>
</record>
<record id="course0" model="product.template">
<field name="name">Course 0</field>
<field name="teacher_id" ref="padilla"/>
<field name="public_categ_ids" eval="[(4, ref('academy.category_courses'), False)]"/>
<field name="website_published">True</field>
<field name="list_price" type="float">0</field>
<field name="type">service</field>
</record>
<record id="course1" model="product.template">
<field name="name">Course 1</field>
<field name="teacher_id" ref="padilla"/>
<field name="public_categ_ids" eval="[(4, ref('academy.category_courses'), False)]"/>
<field name="website_published">True</field>
<field name="list_price" type="float">0</field>
<field name="type">service</field>
</record>
<record id="course2" model="product.template">
<field name="name">Course 2</field>
<field name="teacher_id" ref="vaughn"/>
<field name="public_categ_ids" eval="[(4, ref('academy.category_courses'), False)]"/>
<field name="website_published">True</field>
<field name="list_price" type="float">0</field>
<field name="type">service</field>
</record>
</odoo>
name = fields.Char()
biography = fields.Html()
course_ids = fields.One2many('product.template', 'teacher_id', string="Courses")
class Courses(models.Model):
_inherit = 'product.template'
teacher_id = fields.Many2one('academy.teachers', string="Teacher")
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_academy_teachers,access_academy_teachers,model_academy_teachers,,1,0,0,0
</form>
</field>
</record>
<menuitem sequence="0" id="menu_academy" name="Academy"/>
<menuitem id="menu_academy_content" parent="menu_academy"
name="Academy Content"/>
<menuitem id="menu_academy_content_teachers"
parent="menu_academy_content"
Con esto instalado, algunos cursos ya están disponibles en el Shop, puede que tengas que buscarlo.
Modificar vistas existentes
Hasta ahora, hemos visto brevemente:
la creación de nuevos modelos
la creación de nuevos puntos de vista
la creación de nuevos registros
la alteración de los modelos existentes
Estamos a trabajando con la alteración de los registros existentes y la alteraciónvistas existente. Lo vamos a hacer tanto en la Shop como en las vistas regulares.
Alterar las vista se realiza mediante la creación de vistas extension, que se aplican por encima la vista original y ls modifican. Estas modificaciones de la vista se pueden añadir o quitar sin modificar el original, haciéndolo más sencillo probar cosas y deshacer cambios.
Ya que nuestros cursos son gratis, no hay ninguna razón para mostrar su precio en la página de la tienda, así que vamos a modificar la vista y ocultar el precio si es 0. La primera tarea es averiguar que vista muestra el precio, esto puede hacerse a través de
el cual nos permite leer las plantillas involucradas en el despliegue de la página. Pasando por algunos de ellos, la vista llamada “Product Item” pareciera ser la probable culpable.La modificación de la arquitectura de una vista se realiza en 3 pasos:
Crear una nueva vista
Ampliar la vista para modificar estableciendo la de nueva vista colocando en el campo
inherit_id
la identificación externa (xml_id) de la vista modificadaEn la arquitectura (campo arch), utilice la etiqueta de
xpath
para seleccionar y modificar elementos de la vista modificada
<div class="oe_structure"/>
</t>
</template>
<template id="product_item_hide_no_price" inherit_id="website_sale.products_item">
<xpath expr="//div[hasclass('product_price')]/b" position="attributes">
<attribute name="t-if">product.price > 0</attribute>
</xpath>
</template>
<!-- <template id="object"> -->
<!-- <h1><t t-esc="object.display_name"/></h1> -->
<!-- <dl> -->
Lo segundo que vamos a cambiar es hacer la barra lateral de categorías de producto visible por defecto:
le permite alternar entre un árbol de categorías (usado para filtrar la visualización principal) con solo alternarlo entre activado y desactivado.Esto se hace vía los campos customize_show
y active
de plantillas usada para extender: una plantilla de extensión (como la que acabamos de crear) puede ser customize_show = True. Esta opción mostrará la vista en menú Customize con una casilla de verificación, permitiendo a los administradores activar o desactivar (y personalizar fácilmente sus páginas web).
Simplemente debemos modificar el registro Product Categories y establecer su valor predeterminado a activo = “True”:
</xpath>
</template>
<record id="website_sale.products_categories" model="ir.ui.view">
<field name="active" eval="True"/>
</record>
<!-- <template id="object"> -->
<!-- <h1><t t-esc="object.display_name"/></h1> -->
<!-- <dl> -->
Con esto, la cara lateral sidebar Product Categories automáticamente será activado cuando el módulo Academia sea instalado.