Vous êtes sur la page 1sur 86

Technical Training - Solutions

Release 6.0.2
OpenERP
2011-10-14
Contents
1 Conguration 4
1.1 Open Source RAD avec OpenObject . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2 Installer OpenERP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Architecture dOpenERP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.3 Installation par les paquets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.4 Installation partir des sources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Procdure typique de rcupration des sources (sur Linux bas sur Debian) . . . . . . . . . . . . 5
1.5 Cration de la base de donnes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
2 Crer un module OpenERP 6
2.1 Composition dun module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.2 Structure dun module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2.3 Objet de service - ORM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Attributs osv.osv prdnis pour les objets mtiers . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.4 Types de champs de lORM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Attributs communs supports par tous les champs (optionnels sauf indication) . . . . . . . . . . . 8
Champs simples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.5 Noms de champs rservs/spciaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.6 Menus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.7 Actions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Dclaration dune action . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
3 Crer des vues : bases 10
3.1 Dclaration gnrique dune vue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.2 Les vues Formulaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
lments des vues formulaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
4 Relations entre objets 13
4.1 Champs relationnels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
5 Hritage 19
5.1 Mcanismes dhritage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
Attributs pr-dnis pour les objets mtiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
5.2 Hritage des vues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2
6 Mthodes de lORM 22
6.1 Champs fonctionnels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
6.2 Attributs osv.osv pr-dnis pour les objets mtier . . . . . . . . . . . . . . . . . . . . . . . . . . 25
7 Vues avances 26
7.1 Liste & Arbre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
7.2 Calendriers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
7.3 Vues de Recherche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
7.4 Diagrammes de Gantt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
7.5 Graphiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
8 Workows 31
9 Scurit 33
9.1 Mcanismes de contrle daccs bass sur les groupes . . . . . . . . . . . . . . . . . . . . . . . . 33
ir.model.access.csv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
10 Assistants 35
10.1 Objets wizard (osv_memory) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
10.2 Vues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
10.3 Excution dun assistant . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
11 Rapports 39
11.1 Rapports imprims . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
Expressions utilises dans OpenERP dans les modles de rapport . . . . . . . . . . . . . . . . . . 39
11.2 Tableaux de bord . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
12 Internationalisation 42
13 WebServices 43
13.1 Exemple Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
14 ooooo 45
14.1 Conguration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Open Source RAD avec OpenObject . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Installer OpenERP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
Installation par les paquets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
Installation partir des sources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
Cration de la base de donnes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
14.2 Crer un module OpenERP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
Composition dun module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
Structure dun module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
Objet de service - ORM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
Types de champs de lORM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
Noms de champs rservs/spciaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
Menus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
Actions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
14.3 Crer des vues : bases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
Dclaration gnrique dune vue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
Les vues Formulaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
14.4 Relations entre objets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
Champs relationnels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
14.5 Hritage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
Mcanismes dhritage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
Hritage des vues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
14.6 Mthodes de lORM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
Champs fonctionnels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
Attributs osv.osv pr-dnis pour les objets mtier . . . . . . . . . . . . . . . . . . . . . . . . . . 66
14.7 Vues avances . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
3
Liste & Arbre . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
Calendriers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Vues de Recherche . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
Diagrammes de Gantt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
Graphiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
14.8 Workows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
14.9 Scurit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
Mcanismes de contrle daccs bass sur les groupes . . . . . . . . . . . . . . . . . . . . . . . . 74
14.10Assistants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
Objets wizard (osv_memory) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
Vues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
Excution dun assistant . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
14.11Internationalisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
14.12Rapports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Rapports imprims . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Tableaux de bord . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
14.13WebServices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
Exemple Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
4
1 Conguration
Ce document contient les solutions tape par tape pour les exercices du livret accompagnant la for-
mation technique OpenERP.
Chaque partie donne la solution des exercices de la section correspondante du livret dexercices.
Des instructions tape par tape sont donnes dans leur plus simple forme, gnralement en donnant
un exemple de code source permettant dimplmenter le comportement requis.
1.1 Open Source RAD avec OpenObject
OpenERP est un Outil de Gestion dEntreprise moderne, publi sous license AGPL, et fournissant les fonctionnal-
its CRM, Ressources Humaines, Ventes, Comptabilit, Production, Inventaires, Gestion de Projet, ... Il est bas
sur OpenObject, un framework modulaire, volutif et intuitif de RAD (Rapid Application Development) crit en
Python.
OpenObject fournit une bote outils complte et modulaire pour rapidement crer des fonctionnalits
: support de lORM (mapping objet-relationnel), interfaces bases sur des templates MVC (Modle-Vue-
Contrleur), un systme de gnration de rapport, internationnalisation automatise et bien plus.
Python est un langage de programmation de haut-niveau, idal pour du RAD, combinant puissance et
syntaxe claire et un noyau de taille rduite par sa conception.
Tip: Liens utiles
Site principal avec les tlchargements dOpenERP : www.openerp.com
Documentation fonctionnelle et technique : doc.openerp.com
Ressources de la communaut : www.launchpad.net/open-object
Serveur dintgration : test,openobject.com
Apprendre Python: doc.python.org
Plateforme dE-Learning OpenERP : edu.openerp.com
1.2 Installer OpenERP
OpenERP est distribu sous la forme de paquets/dinstalleurs pour la plupart des plateformes, mais peut bien
entendu tre install depuis le code source sur nimporte quelle plateforme.
Architecture dOpenERP
OpenERP utilise le paradigme bien connu client-serveur, avec diffrentes pices logicielles agissant en tant que
client et serveur dpendant de la conguration dsire.
OpenERP fournit un client lourd (GTK+) pour toutes les plateformes et une interface web accessible en utilisant
nimporte quel navigateur Web rcent.
Tip: Procdure dinstallation
La procdure dinstallation dOpenERP est susceptible dvoluer (dpendances et autres), assurez-vous alors de
toujours vrier la documentation spcique (package et sur le site Web) pour les dernires procdures. Voir
http://doc.openerp.com/install.
5
1.3 Installation par les paquets
Windows Installeur tout-en-un et installeurs spars pour le serveur, le client, le serveur web sont sur le
site web
Linux Les paquets openerp-server et openerp-client sont disponibles via le gestionnaire de paquets
(e.g. Synaptic sur Ubuntu) OU en utilisant BaZaar bzr branch lp:openerp (ou openerp/trunk
pour la version trunk) une fois identi sur Launchpad, ensuite, cd openerp (cd trunk dans la
version trunk) et ./bzr_set.py
Mac Regardez en ligne pour un paquet dinstallation pour le client GTK, ainsi que des tutoriels pour
installer le serveur (e.g. devteam.taktik.be)
1.4 Installation partir des sources
Il y a deux alternatives :
1. utiliser une archive fournie sur le site web,
2. ou obtenir directement les sources en utilisant Bazaar (gestionnaire de contrle de source distribu).
Vous aurez galement besoin dinstaller les dpendances requises (PostgreSQL et quelques librairies Python - voir
la documentation sur doc.openerp.com).
Note: OpenERP tant bas sur Python, aucune compilation nest ncessaire.
Procdure typique de rcupration des sources (sur Linux bas sur Debian)
$ sudo apt-get install bzr # installation de bazaar
$ bzr branch lp:openerp # rcupration des sources
$ cd openerp && python ./bzr_set.py # chercher le code et lancer linstallation
1.5 Cration de la base de donnes
Aprs linstallation, lancer le serveur et le client. Depuis le client GTK, utilisez le menu Fichier > Base de donnes
> Nouvelle base de donnes pour crer une nouvelle base de donnes (le mot de passe super-admin par dfaut est
admin). Chaque base de donnes a ses propres modules et sa propre conguration.
Note: Des donnes de dmonstration peuvent aussi tre installes.
6
2 Crer un module OpenERP
2.1 Composition dun module
Un module peut contenir les lments suivants :
Objet Mtier : dclars en tant que classes Python hritants de la classe OpenObject osv.osv, la persistance
de ces ressources est compltement gre par OpenObject,
Donnes : chiers XML/CSV contenant des mta-donnes (dclaration de vues et de workow), des don-
nes de conguration (paramtrage des modules) et des donnes de dmonstration (optionnelles mais rec-
ommendes pour tester),
Assistants : formulaire interactif tats utiliss pour aider les utilisateurs, souvent disponibles comme
action contextuelle sur les ressources du systme,
Rapports : RML (format XML). Modles de rapports MAKO ou OpenOfce, dans lesquels sont intgres
les donnes du systme de nimporte quel objet mtier et gnre des rapports aux formats HTML, ODT ou
PDF.
2.2 Structure dun module
Chaque module est contenu dans son propre rpertoire dans le rpertoire server/bin/addons ou dans un
autre rpertoire daddons, congur lors de linstallation du serveur.
Note: Congurer les emplacements des addons
Par dfaut, le seul rpertoire daddons connu par le serveur est server/bin/addons. Il est possibe dajouter
de nouveaux addons en 1) les copiant dans server/bin/addons, ou en crant des liens symboliques vers
chacun deux dans ce rpertoire, ou 2) spcier un autre rpertoire contenant des addons au serveur. Cette
dernire mthode peut tre effectue soit en lanant le serveur avec loption addons-path= option, ou en con-
gurant cette option dans le chier openerp_serverrc, gnr automatiquement sour Linux dans votre rpertoire
personnel lorsque le serveur est lanc avec loption save. Vous pouvez fournir plusieurs rpertoires loption
addons_path en les sparant par des virgules.
Le chier __init__.py est la dclaration en Python du module, car OpenERP est aussi un module Python. Il
contient toutes les instructions dimportation de tous les chiers Python, sans lextension .py. Par exemple, si le
module contient un unique chier Python nomm mymodule.py :
import mymodule
Le chier __openerp__.py est rellement le chier qui dclare le module OpenERP. Il est obligatoire dans chaque
module. Il contient uniquement un dictionnaire Python avec de nombreuses informations importantes, comme le
nom du module, sa description, la liste des autres modules OpenERP dont linstallation est requise pour que le
module courant fonctionne correctement Il contient aussi, entre autres, une rfrence tous les chiers de donnes
7
(xml, csv, yml, ...) du module. Sa structure gnrale est la suivante (voir la documentation ofcielle pour une
description complte du chier) :
{
"name": "MyModule",
"version": "1.0",
"depends": ["base"],
"author": "Author Name",
"category": "Category",
"description": """
Description text
""",
data: [
mymodule_view.xml,
#tous les autres fichiers de donnes, lexception des donnes de dmonstration et de tests
],
demo: [
#fichiers contenant les donnes de dmonstration
],
test: [
#fichiers contenant les donnes de test
],
installable: True,
active: False,
# certificate: certificate,
}
Exercice 1 - Cration dun module
Crez le module vide Open Academy, avec un chier __openerp__.py. Installez-le dans OpenERP.
1. Crez un nouveau dossier openacademy sur votre ordinateur.
2. Ajoutez un lien symbolique vers ce dossier dans le rpertoire server/bin/addons.
3. Crez un chier __openerp__.py dans le dossier OpenAcademy :
{
"name": "Open Academy",
"version": "1.0",
"depends": ["base"],
"author": "Author Name",
"category": "Test",
"description": """
Open Academy module for managing trainings:
- training courses
- training sessions
- attendees registration
""",
data: [openacademy_view.xml],
demo: [],
installable: True,
active: False,
# certificate: certificate,
}
4. Crez un chier openacademy.xml dans le sous-dossier view du dossier OpenAcademy :
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<menuitem id="openacademy_menu" name="OpenAcademy" />
8
</data>
</openerp>
2.3 Objet de service - ORM
Composant cl de OpenObject, lobjet de service (OSV) implmente une couche complte de mapping objet-
relationnel, librant ainsi les dveloppeurs davoir crire du SQL basique. Les objets mtier sont dclars dans
des classes Python hritants de la classe osv.osv, leur permettant de faire partie du modle OpenObject, et comme
par magie persistant grce la couche ORM.
Attributs osv.osv prdnis pour les objets mtiers
2.4 Types de champs de lORM
Les objets peuvent contenir 3 types de champs : simple, relationnel et fonctionnel. Les types simples sont integer,
oat, boolean, string, etc. Les champs relationnels reprsentent les relations entre objets (one2many, many2one,
many2many). Les champs fonctionnels ne sont pas stocks dans la base de donnes mais sont calculs la vole
avec des fonctions Python.
Attributs communs supports par tous les champs (optionnels sauf indication)
string : Libell du champ (requis)
required : True si obligatoire
readonly : True si non ditable
help : Bulle daide
select : 1 pour inclure le champ dans la vue de recherche et optimiser le ltre des listes (avec un index en
base de donnes)
context : Dictionnaire contenant des paramtres contextuels (pour les champs relationnels)
Champs simples
boolean(...) integer(...) date(...) datetime(...) time(...)
start_date: elds.date(Start Date)
active: elds.boolean(Active)
priority: elds.integer(Priority)
char(string,size,translate=False,..) text(string, translate=False,...) [Champs bass sur du texte]
translate: True si la valeur du champ peut tre traduite par les utilisateurs
size: taille maximale pour les champs char (41,45)
oat(string, digits=None, ...) [valeur ottante avec prcision arbitraire et ratio]
digits: tuple (precision, scale) (58) . Si digits nest pas spci, cest un oat, pas un type
decimal.
9
2.5 Noms de champs rservs/spciaux
Quelques noms de champs sont rservs un comportement prdnis dans OpenObject. Certains dentre eux
sont crs automatiquement par le systme, et dans ce cas, nimporte quel champ qui portera ce nom sera ignor.
id identiant unique dans le systme pour lobjet (cr par lORM, ne pas lajouter)
name dnit la valeur utilise par dfaut pour afcher les enregistrements dans les listes,
etc. si manquant, utilisez _rec_name pour spcier un autre champ utiliser dans ce
but
... ...
Exercice 2 - Dnir une classe
Dnir une nouvelle classe Course dans le module openacademy.
1. Dans le nouveau projet OpenAcademy, crez un nouveau chier openacademy.py :
# -
*
- coding: utf-8 -
*
-
##############################################################################
#
# OpenERP, Open Source Enterprise Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from osv import osv, fields
2. Dans ce chier openacademy.py, crez la classe suivante :
class Course (osv.osv):
_name = openacademy.course
_columns = {
name : fields.char(Course Title, 128, required = True),
description : fields.text(Description),
}
Course()
3. Crez un chier __init__.py dans le projet OpenAcademy :
import openacademy
2.6 Menus
Llment menuitem est un raccourci pour dclarer un enregistrement ir.ui.menu et le connecter avec laction
correspondante via un enregistrement ir.model.data.
10
<menuitem id="menu_id" parent="parent_menu_id" name="label" icon="icon-code"
action="action_id" groups="groupname1,groupname2" sequence="10"/>
2.7 Actions
Les actions sont dclares comme des enregistrements normaux et peuvent tre dclenches de 3 faons :
1. en cliquant sur les lments de menu lis une action spcique
2. en cliquant sur des boutons dans des vues, si ces boutons sont connects des actions
3. en tant quactions contextuelles sur un objet
Dclaration dune action
<record model="ir.actions.act_window" id="action_id">
<field name="name">action.name</field>
<field name="view_id" ref="view_id"/>
<field name="domain">[list of 3-tuples (max 250 characters)]</field>
<field name="context">{context dictionary (max 250 characters)}</field>
<field name="res_model">object.model.name</field>
<field name="view_type">form|tree</field>
<field name="view_mode">form,tree,calendar,graph</field>
<field name="target">new</field>
<field name="search_view_id" ref="search_view_id"/>
</record>
Exercice 3 - Dnir de nouvelles entres de menu
Dnissez de nouvelles entres de menu pour accder aux cours et aux sessions sous lentre de menu
OpenAcademy; on devrait tre en mesure de 1) afcher la liste de tous les cours et 2) crer/modier des
cours.
1. Dans le chier view/openacademy.xml, crez les entres de menu suivantes :
<menuitem id="course_menu" name="Courses" parent="openacademy_menu"
action="course_list_action" />
2. Crez les actions correspondantes, permettant les modes tree et form :
<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>
</record>
3 Crer des vues : bases
Exercice 1 - Personnaliser une vue depuis lditeur de vues de linterface web
Crez une vue liste pour lobjet Course , afchant le nom du cours ainsi que sa description.
11
Note: module recorder
Il est possible dexporter (ou dimporter) des vues (ou nimporte quel autre enregistrement) de la base de don-
nes dans un chier XML ou YaML en utilisant le module recorder. Ce point particulier sera trait dans une
prochaine section.
Dans le client web, ouvrez le menu OpenAcademy > Course. Cliquez sur Personnaliser les vues dans le panneau
de droite, crez-en une nouvelle, ditez-la et modiez-la.
Les vues forment une hirarchie. Plusieurs vues du mme type peuvent tre dclares sur le mme objet, et
seront afches selon leurs priorits. En dclarant une vue hrite, il est possible dajouter ou de supprimer des
fonctionnalits dans une vue.
3.1 Dclaration gnrique dune vue
<record model="ir.ui.view" id="view_id">
<field name="name">view.name</field>
<field name="model">object_name</field>
<field name="type">form</field> # tree,form,calendar,search,graph,gantt
<field name="priority" eval="16"/>
<field name="arch" type="xml">
<!-- view content: <form>, <tree>, <graph>, ... -->
</field>
</record>
3.2 Les vues Formulaires
Les vues Formulaires permettent la cration et la modication des ressources, et correspondent aux lments
<form>.
lments des vues formulaires
Attributs communs tous les lments :
string: libell de llment
nolabel: 1 pour cacher le libell du champ
colspan: nombre de colonnes sur lesquelles le champ doit staler
rowspan: nombre de lignes sur lesquelles le champ doit staler
col: nombre de colonnes que cet lment doit allouer ses lments ls
invisible: 1 pour cacher compltement cet lment
eval: evalue ce code Python en tant que contenu de llment (le contenu est une chane de caractres par
dfaut)
attrs: dictionnaire Python dnissant des conditions dynamiques sur ces attributs : readonly, invisible,
required bass sur des tuples de recherche sur les valeurs dautres champs
12
Field Widgets automatiques dpendants du type de champ correspondant. Attributs :
string: libell du champ, aussi pour la recherche (surcharge le nom du champ)
select: 1 pour afcher le champ en recherche normale, 2 pour la recherche
avance seulement
nolabel: 1 pour cacher le libell du champ
required: surcharge lattribut required du champ
readonly: surcharge lattribut readonly du champ
password: 1 pour cacher les caractres saisis dans ce champ
context: code Python dclarant un dictionnaire de contexte
domain: code Python dclarant une liste de tuples pour restreindre les valeurs
on_change: appel dune mthode Python dclencher quand une valeur est
change
completion: 1 pour activer lauto-completion des valeurs lorsque cela est pos-
sible
groups: liste des groupes (spars par des virgules) autoriss voir ce champ
widget: selectionne un widget alternatif (one2many_list, many2many, url,
email, image, oat_time, reference, text_wiki, text_html, progressbar)
properties widget dynamique afchant toutes les proprits disponibles (pas dattributs)
button
widget cliquable associ des actions. Attributs spciques :
type: type de button : workow (dfaut), object ou action
name: signal du workow, nom de la fonction (sans les parenthses) ou
action appeler (selon le type)
conrm: message texte de conrmation lorsque le bouton est cliqu
states: liste des tats (spars par des virgules) pour lesquels le bouton est
visible
icon: icone optionnelle (toutes les icnes GTK STOCK e.g. gtk-ok)
separator ligne horizontale de sparation pour structurer les vues, avec un libell optionnel
newline paramtre virtuel pour complter la ligne courante de la vue
label libell ou lgende libre dans le formulaire
group utilis pour organiser les champs en groupes avec un libell optionnel (ajoute un
cadre)
notebook, page
les lments notebook sont des gestionnaires donglets pour les lments page. Attributs :
name: libell de longlet
position: position de longlet dans son container (inside, top, bottom, left,
right)
Exercice 2 - Personnaliser les vues liste et formulaire via XML
Crez vos propres vues liste et formulaire pour lobjet Course. Les donnes afches doivent tre :
Dans la vue liste, le nom du cours;
Dans la vue formulaire, le nom et la description du cours.
1. Dans le chier openacademy_view.xml, crez les vues suivantes :
<!-- ======= COURSE ====== -->
<record model="ir.ui.view" id="course_tree_view">
<field name="name">course.tree</field>
<field name="model">openacademy.course</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Course Tree">
<field name="name"/>
</tree>
</field>
13
</record>
<record model="ir.ui.view" id="course_form_view">
<field name="name">course.form</field>
<field name="model">openacademy.course</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Course Form">
<field name="name" />
<field name="description"/>
</form>
</field>
</record>
Note: colspan
Par dfaut, la vue est spare en 4 colonnes
2. Nous pouvons amliorer la vue formulaire pour un meilleur afchage.
<record model="ir.ui.view" id="course_form_view">
<field name="name">course.form</field>
<field name="model">openacademy.course</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Course Form">
<field name="name" />
<separator string="Description" colspan="4" />
<field name="description" nolabel="1" colspan="4" />
</form>
</field>
</record>
Exercice 3 - Onglets
Dans la vue formulaire des cours, afchez la description dans un onglet, de cette manire, il sera facile
dajouter dautres onglets par la suite, contenant des informations additionnelles.
Modiez la vue formulaire des cours comme suit :
<record model="ir.ui.view" id="course_form_view">
<field name="name">course.form</field>
<field name="model">openacademy.course</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Course Form">
<field name="name" />
<notebook colspan="4">
<page string="Description">
<field name="description" nolabel="1" colspan="4" />
</page>
</notebook>
</form>
</field>
</record>
4 Relations entre objets
14
Exercice 1 - Crer des classes
Crez les classes Session et Attendee et ajoutez un menu et une action pour afcher les sessions. Une session
a un nom, une date de dbut, une dure (en jours) et un nombre de siges. Un stagiaire a un nom, qui nest
pas requis.
1. Crez les classes Session et Attendee.
Classe Session :
class Session(osv.osv):
_name = openacademy.session
_columns = {
name: fields.char(Session Title, 128, required=True),
start_date: fields.date(Start Date),
duration: fields.float(Duration, digits=(6,2), help="Duration in days"),
seats:fields.integer(Seats number),
}
Session()
Classe Attendee :
class Attendee(osv.osv):
_name = openacademy.attendee
_columns = {
}
Attendee()
Note: digits=(6,2)
6 est le nombre total de chiffres rservs pour le nombre ottant, alors que 2 est le nombre de chiffres aprs la
virgule. Il en rsulte que le nombre de chiffres avant la virgule est au maximum de 4 dans ce cas.
2. Modiez le chier view/openacademy.xml comme suit :
<record model="ir.actions.act_window" id="session_list_action">
<field name="name">Sessions</field>
<field name="res_model">openacademy.session</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem id="session_menu" name="Sessions" parent="openacademy_menu"
action="session_list_action" />
4.1 Champs relationnels
Attributs commun supports par les champs relationnels
domain: restriction optionnelle sous la forme darguments pour la mthode search (voir search())
many2one(obj, ondelete=set null,...) (50) : Relation vers un objet parent (en utilisant une cl trangre)
obj: _name de lobjet de destination (requis)
ondelete: gestion de la suppression, e.g. set null, cascade, restrict voir la documentation
de PostgreSQL
one2many(obj, eld_id, ...) (55) : Relation virtuelle vers de multiples objets (inverse du many2one)
15
obj: _name de lobjet de destination (requis)
eld_id: nom du champ du many2one inverse, i.e. la cl trangre correspondante (requis)
many2many(obj, rel, eld1, eld2, ...) (56) : Relation multiple bi-directionnelle entre des objets
obj: _name de lobjet de destination (requis)
rel: table de relation utiliser (requis)
eld1: nom du champ dans la table de relation enregistrant lid de lobjet courant (requis)
eld2: nom du champ dans la table de relation enregistrant lid de lobjet cible (requis)
Exercice 2 - Relations many2one, one2many
En utilisant les types de champs de lORM (one2many, many2one), modiez les classes Course, Session et
Attendee an de reter leurs relations avec dautres objets, dnies comme suit :
1. Modiez les classes comme suit :
Classe Course :
class Course(osv.osv):
_name = openacademy.course
_description = OpenAcademy Course
_columns = {
name: fields.char(Course Title, 128, required=True),
responsible_id: fields.many2one(res.users, string=Responsible,ondelete=set null),
description: fields.text(Description),
session_ids: fields.one2many(openacademy.session, course_id, Session),
}
Course()
Classe Session :
class Session(osv.osv):
_name = openacademy.session
_description = OpenAcademy Session
_columns = {
name: fields.char(Session Title, 128, required=True),
start_date: fields.date(Start Date),
duration: fields.float(Duration, digits=(16,2), help="Duration in days"),
seats:fields.integer(Seats number
attendee_ids: fields.one2many(openacademy.attendee,
session_id, Attendees, ),
16
instructor_id: fields.many2one(res.partner, Instructor),
course_id:fields.many2one(openacademy.course, Course,
required=True, ondelete=cascade),),
}
Session()
Classe Attendee :
class Attendee(osv.osv):
_name = openacademy.attendee
_rec_name = partner_id
_columns = {
partner_id: fields.many2one(res.partner,Partner,required=True,
ondelete="cascade"),
session_id: fields.many2one(openacademy.session,Session,
required=True,
ondelete="cascade"),
}
Attendee()
Note: one2many, many2one
La dnition dun champ one2many requiert que le champ many2one correspondant soit dnis dans la classe
vise. Ce nom de champ many2one est donn en second argument du champ one2many eld (ici, course_id).
Exercice 3 - Modiez les vues
Modiez les vues liste et formulaire de lobjet Course et crez les vues pour lobjet Session. Les donnes
afches pour lobjet Course :
Dans la vue liste, le nom du cours et le responsable de ce cours;
Dans la vue formulaire, le nom et le responsable en haut, ainsi que la description du cours dans un
onglet et les sessions lies dans un deuxime onglet.
Pour lobjet Session :
Dans la vue liste, le nom de la session et les cours lis;
Dans la vue formulaire, tous les champs de lobjet Session.
Le nombre de donnes afcher tant important, essayez dorganiser les vues formulaires de telle sorte que
linformation quelles contiennent parasse claire.
1. Modiez les vues de lobjet Course :
<!-- ======= COURSE ====== -->
<record model="ir.ui.view" id="course_tree_view">
<field name="name">course.tree</field>
<field name="model">openacademy.course</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Course Tree">
<field name="name"/>
<field name="responsible_id"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="course_form_view">
<field name="name">course.form</field>
<field name="model">openacademy.course</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Course Form">
17
<field name="name" />
/+++
<field name="responsible_id" />
+++/
<notebook colspan="4">
<page string="Description">
<field name="description" nolabel="1" colspan="4" />
</page>
/+++
<page string="Sessions">
<field name="session_ids" nolabel="1" colspan="4"
mode="tree,form">
<tree string="Registered sessions">
<field name="name"/>
<field name="instructor_id"/>
</tree>
<form string="Registered sessions">
<field name="name"/>
<field name="instructor_id"/>
</form>
</field>
</page>
+++/
</notebook>
</form>
</field>
</record>
Note: Cacher des champs
Dans lexemple ci-dessus, si la vue formulaire du champ session_ids navait pas t personnalise pour ne montrer
que le nom et le responsable de la session, le champ course_id (ainsi que les autres champs de lobjet session)
seraient apparus et auraient t requis. Cependant, quelle que soit la valeur saisie dans le champ course_id, elle
aurait t ignore quand la session aurait t enregistre et remplace par la valeur du course_id de linstance
courante de lobjet Course.
2. Crez les vues de lobjet Session :
<!-- ======= SESSION ====== -->
<record model="ir.ui.view" id="session_tree_view">
<field name="name">session.tree</field>
<field name="model">openacademy.session</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Session Tree">
<field name="name"/>
<field name="course_id"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="session_form_view">
<field name="name">session.form</field>
<field name="model">openacademy.session</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Session Form">
<field name="name" />
<field name="instructor_id" />
<field name="course_id"/>
<field name="seats"/>
<field name="start_date"/>
<field name="duration"/>
18
<field name="attendee_ids" colspan="4" nolabel="1" mode="tree,form">
<form string="Attendees">
<field name="name"/>
<field name="partner_id"/>
</form>
<tree string="Attendees" editable="bottom">
<field name="name"/>
<field name="partner_id"/>
</tree>
</field>
</form>
</field>
</record>
Note: colspan
Par dfaut, la vue est spare en 4 colonnes
3. Nous pouvons amliorer la vue formulaire des sessions pour une meilleure lisibilit :
<record model="ir.ui.view" id="session_form_view">
<field name="name">session.form</field>
<field name="model">openacademy.session</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Session Form">
<group colspan="2" col="2">
<separator string="General" colspan="2"/>
<field name="name" />
<field name="instructor_id" />
<field name="course_id"/>
<field name="seats"/>
</group>
<group colspan="2" col="2">
<separator string="Schedule" colspan="2"/>
<field name="start_date"/>
<field name="duration"/>
</group>
<separator string="Attendees" colspan="4"/>
<field name="attendee_ids" colspan="4" nolabel="1" mode="tree,form">
<form string="Attendees">
<field name="partner_id"/>
</form>
<tree string="Attendees" editable="bottom">
<field name="partner_id"/>
</tree>
</field>
</form>
</field>
</record>
Note: Orientation
Ici, les groupes apparassent en deux colonnes; nous aurions p les afcher sur deux lignes en mettant de colspan
des groupes 4 ou en utilisant la balise <newline/>.
19
5 Hritage
5.1 Mcanismes dhritage
Attributs pr-dnis pour les objets mtiers
_inherit _name de lobjet mtier parent (pour lhritage simple)
_inherits pour lhritage multiple / : dictionnaire faisant correspondre le _name de lobjet
mtier parent au nom des champs correspondant aux cls trangres utiliser
5.2 Hritage des vues
Les vues existantes doivent tre modies travers des vues hrites, jamais directement. Une vue hrite
rfrence sa vue parente en utilisant le champ inherit_id, et doit ajouter ou modier des lments existants dans
cette vue en les rfrenant par des expressions XPath, en spciant la position approprie.
position
inside: plac dans la partie corre-
spondante (dfaut)
before: plac avant la partie cor-
respondante
replace: remplace la partie corre-
spondante
after: plac aprs la partie corre-
spondante
Tip: La rfrence XPath peut tre trouve www.w3.org/TR/xpath
<!-- improved idea categories list -->
<record id="idea_category_list2" model="ir.ui.view">
<field name="name">id.category.list2</field>
<field name="model">ir.ui.view</field>
<field name="inherit_id" ref="id_category_list"/>
<field name="arch" type="xml">
<xpath expr="/tree/field[@name=description]" position="after">
<field name="idea_ids" string="Number of ideas"/>
</xpath>
</field>
</record>
20
Exercice 1 - Ajouter un mcanisme dhritage
En utilisant lhritage de classe, crez une classe Partner qui modie la classe Partner existante, ajoutant
un champ boolen is_instructor, et la liste des sessions o ce partenaire sera prsent. En utilisant lhritage
des vues, modiez la vue formulaire existante an dafcher les nouveaux champs.
1. Crez un chier partner.py sous le projet OpenAcademy. Crez la classe suivante :
# -
*
- coding: utf-8 -
*
-
##############################################################################
#
# OpenERP, Open Source Enterprise Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from osv import osv,fields
class Partner(osv.osv):
Inherited res.partner
_inherit = res.partner
_columns = {
instructor : fields.boolean(Instructor),
session_ids: fields.many2many(openacademy.session,
openacademy_attendee,
partner_id,session_id,Sessions)
}
Partner()
Note: many2many
La table de relation que nous utilisons ici est openacademy_attendee, car il a dj cr une relation many-to-
many entre les partenaires et les sessions. Cependant, nous aurions p dnir un autre nom et lORM aurait
automatiquement cr une nouvelle table de relation.
2. Dans le chier __init__.py, ajoutez la ligne suivante :
import partner
3. Crez un chier partner_view.xml sous le projet OpenAcademy. Crez les vues hrites suivantes :
<!-- Add instructor field to existing view -->
<record model="ir.ui.view" id="partner_instructor_form_view">
<field name="name">partner.instructor.name</field>
<field name="model">res.partner</field>
<field name="type">form</field>
<field name="inherit_id" ref="base.view_partner_form" />
<field name="arch" type="xml">
<field name="supplier" position="after">
21
<field name="instructor"/>
</field>
</record>
Note: position=after
Les lments placs lintrieur dune balise eld ayant un attribut position=after seront afchs dans la vue
aprs le champ identi par la valeur de lattribut name du champ parent. Si il y a plus dun lment, ils seront
afchs dans lordre inverse de leur apparition dans le code XML.
<!-- Add instructor field to existing view -->
<record model="ir.ui.view" id="partner_instructor_form_view">
<field name="name">partner.instructor.name</field>
<field name="model">res.partner</field>
<field name="type">form</field>
<field name="inherit_id" ref="base.view_partner_form" />
<field name="arch" type="xml">
<field name="supplier" position="after">
<field name="instructor"/>
</field>
<xpath expr="/form/notebook/page[@string=Notes]" position="after">
<page string="Sessions">
<field name="session_ids" nolabel="1" colspan="4"/>
</page>
</xpath>
</field>
</record>
Exercice 2 - domain
Ajoutez un mcanisme la vue formulaire des Session an de permettre lutilisateur de choisir linstructeur
seulement parmi les partenaires dont le champ Instructeur est Vrai.
Vous pouvez soit : 1. Modier la classe Session comme suit :
class Session(osv.osv):
_name = openacademy.session
_description = OpenAcademy Session
_columns = {
name: fields.char(Session Title, 128, required=True),
start_date: fields.date(Start Date),
duration: fields.float(Duration, digits=(16,2), help="Duration in days"),
seats:fields.integer(Seats number),
attendee_ids: fields.one2many(openacademy.attendee,
session_id, Attendees, ),
instructor_id: fields.many2one(res.partner, Instructor,
domain=[(instructor,=,True)]),
course_id:fields.many2one(openacademy.course, Course,
required=True, ondelete=cascade),
}
Session()
2. Ou modier la vue formulaire des Session comme suit :
...
<group colspan="2" col="2">
<separator string="General" colspan="2"/>
<field name="name" />
<field name="instructor_id" domain="[(instructor,=,True)]"/>
<field name="course_id"/>
22
<field name="seats"/>
</group>
...
Exercice 3 - domain
Nous dcidons maintenant de crer de nouvelles catgories de partenaires : Professeur/Professeur Niveau 1
and Professeur/Professeur Niveau 2. Modiez le domaine dni prcdemment pour autoriser lutilisateur
choisir linstructeur parmi les partenaires dont le champ Instructeur est Vrai ou ceux qui appartiennent
lune des catgories que nous avons dnies.
1. Modiez la classe Session comme suit :
class Session(osv.osv):
_name = openacademy.session
_description = OpenAcademy Session
_columns = {
name: fields.char(Session Title, 128, required=True),
start_date: fields.date(Start Date),
duration: fields.float(Duration, digits=(16,2), help="Duration in days"),
seats:fields.integer(Seats number),
attendee_ids: fields.one2many(openacademy.attendee,
session_id, Attendees, ),
instructor_id: fields.many2one(res.partner, Instructor,
domain=[|,(instructor,=,True),
(category_id.name,
in,
(Teacher Level 1,Teacher Level 2))
]
),
course_id:fields.many2one(openacademy.course, Course,
required=True, ondelete=cascade),
}
Session()
Note: Toutefois, il nest pas possible dappliquer ce domaine la vue des sessions car les domaines dans les
vues sont reprsents comme des tuples de trois lments reprsentants les conditions, et que loprateur logique
entre eux est ncessairement un et.
6 Mthodes de lORM
6.1 Champs fonctionnels
function(fnct, arg=None, fnct_inv=None, fnct_inv_arg=None, type=oat, fnct_search=None, obj=None,
method=False, store=False, multi=False, ...) : Functional eld simulating a real eld, computed rather than
stored
fnct [fonction pour calculer la valeur du champ (requis)]
def fnct(self, cr, uid, ids, eld_name, arg, context) retourne un dictionnaire { idsvaleurs } avec
des valeurs du type type
fnct_inv [fonction utilise pour crire une valeur dans ce champ]
def fnct_inv(obj, cr, uid, id, name, value, fnct_inv_arg, context)
type : type du champ simul (nimporte quel type part function)
23
fnct_search [fonction utilise pour effectuer une recherche sur ce champ]
def fnct_search(obj, cr, uid, obj, name, args) retourne une liste de tuples pour le search(), e.g.
[(id,in,[1,3,5])]
obj : _name model du champ simul si cest un champ relation
store, multi : mcanismes doptimisation (voir usage dans la section Performances)
related(f1, f2, ..., type=oat, ...) [Champ raccourci quivalent parcourir des relations chaines]
f1,f2,... : champs lis pour atteindre la cible (f1 requis) (51)
type : type du champ cible
property(obj, type=oat, view_load=None, group_name=None, ...) [Attribut dynamique avec des droits
daccs spciques]
obj : objet (requis)
type : type du champ quivalent
Exercice 1 - Champs fonctionnels
Ajoutez un champ fonctionnel la class Session, qui contient le pourcentage de places restantes dans une
session. Afchez ce pourcentage dans les vues liste et formulaire des sessions. Une fois ceci fait, essayez de
lafcher sous la forme dune barre de progression.
1. Dans le chier openacademy.py, modiez la classe Session comme suit :
class Session(osv.osv):
_name = openacademy.session
_description = OpenAcademy Session
def _get_remaining_seats_percent(self,seats,attendee_list):
return seats and ((100.0
*
(seats - len(attendee_list)))/ seats) or 0
def _remaining_seats_percent(self,cr,uid,ids,field,arg,context=None):
#count the percentage of remaining seats
sessions = self.browse(cr,uid,ids,context=context)
result = {}
for session in sessions :
result[session.id] = self._get_remaining_seats_percent(session.seats,
session.attendee_ids)
return result
_columns = {
name: fields.char(Session Title, 128, required=True),
start_date: fields.date(Start Date),
duration: fields.float(Duration, digits=(16,2), help="Duration in days"),
seats:fields.integer(Seats number),
attendee_ids: fields.one2many(openacademy.attendee,
session_id, Attendees,),
remaining_seats_percent:fields.function(_remaining_seats_percent,
method=True,type=float,
string=Remaining seats),
instructor_id: fields.many2one(res.partner, Instructor,
domain=[|,(instructor,=,True),
(category_id.name,
in,
(Teacher Level 1,Teacher Level 2))
]
),
course_id:fields.many2one(openacademy.course, Course, required=True),
}
24
2. Dans le chier openacademy_view.xml, modiez la vue des sessions comme suit :
<!-- ======= SESSION ====== -->
<record model="ir.ui.view" id="session_tree_view">
<field name="name">session.tree</field>
<field name="model">openacademy.session</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Session Tree">
<field name="name"/>
<field name="course_id"/>
<field name="remaining_seats_percent" widget="progressbar"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="session_form_view">
...
<form string="Session Form">
<notebook colspan="4">
<page string="Information">
<group colspan="2" col="2">
<separator string="General" colspan="2"/>
<field name="name" />
<field name="instructor_id" />
<field name="course_id"/>
<field name="seats"/>
<field name="remaining_seats_percent"
widget="progressbar"/>
Exercice 2 - Mthodes Onchange
Modiez la vue formulaire ainsi que la classe reprsentant les sessions de telle sorte que le pourcentage de
places restantes se rafrachisse lorsque le nombre de places ou le nombre de stagiaires change, sans avoir
enregistrer les modications.
1. Modiez les champs attendee_ids et seats de la vue des sessions en leur ajoutant un attribut on_change,
comme suit :
<field name="seats" on_change="onchange_remaining_seats(seats,attendee_ids)">
<field name="attendee_ids" colspan="4" nolabel="1"
on_change="onchange_remaining_seats(seats,attendee_ids)">
2. Modiez la classe des Sessions en y ajoutant la mthode suivante :
def onchange_remaining_seats(self,cr,uid,ids,seats,attendee_ids):
return {
value:{
remaining_seats_percent:
self._get_remaining_seats_percent(seats,
attendee_ids)
}
Exercice 3 - warning
Modiez cette mthode onchange pour lever un avertissement lorsque le nombre de places est infrieur 0.
25
def onchange_remaining_seats(self,cr,uid,ids,seats,attendee_ids):
res={
value:{
remaining_seats_percent:
self._get_remaining_seats_percent(seats,
attendee_ids)
}
if seats < 0:
res[warning]={
title: Warning,
message: You cannot have negative seats,
}
return res
6.2 Attributs osv.osv pr-dnis pour les objets mtier
_constraints liste de tuples dnissant les contraintes Python, de la forme (fonc_name, message,
champs).
_sql_constraints liste de tuples dnissant les contraintes SQL, de la forme (nom, sql_def, message).
Exercice 4 - Ajouter des contraintes
Ajoutez une containte qui contrle que la description et lintitul dun cours ne sont pas les mmes.
#Check whether the course title and the course description are not the same
def _check_description(self,cr,uid,ids,context=None):
courses = self.browse(cr,uid,ids,context=context)
check = True
for course in courses:
#print course.description==course.name
if course.name==course.description:
return False
return check
_constraints = [(_check_description, Please use a different description,
[name,description])]
Exercice 5 - Ajouter une contrainte SQL
Ajoutez une contrainte SQL pour contrler quun cours a un nom unique.
#Check that the course title has an unique name
_sql_constraints = [(unique_name, unique(name),Course Title must be unique)]
Exercice 6 - Ajouter une option de duplication
Depuis que nous avons ajout une contrainte an que le nom dun cours soit unique, il nest plus possible
dutiliser la fonction dupliquer (Formulaire > Dupliquer). R-implmenter votre propre mthode copy
qui permet de dupliquer un objet Cours, en changeant le nom original en Copie de [nom original].
Ajoutez la mthode suivante dans la classe Course :
#Allow to make a duplicate Course
def copy(self,cr,uid,id,defaults,context=None):
previous_name = self.browse(cr,uid,id,context=context).name
new_name= Copy of %s % previous_name
list=self.search(cr, uid, [(name,like,new_name)],context=context)
26
if len(list)>0:
new_name=%s (%s) % (new_name,len(list)+1)
defaults[name]=new_name
return super(Course,self).copy(cr,uid,id,defaults,context=context)
Exercice 7 - Objets actifs Valeurs par dfaut
Dnissez la valeur par dfaut du champ start_date la date du jour. Ajoutez un champ active dans la classe
Session et xez la session comme tant active par dfaut.
Dans le chier openacademy.py, dans la classe Session :
_columns = {
...
course_id: fields.many2one(openacademy.course, Course,
required=True, ondelete=cascade),
active: fields.boolean(Active),
...
#Set the default values for the specified fields
_defaults = {
start_date: lambda
*
a : time.strftime(%Y-%m-%d),
active:True,
}
Note: time.strftime(format[, t])
Convertit un tuple ou une struct_time reprsentant un temps retourn par gmtime() ou localtime() en une chane
de caractres dont le format est spci dans largument format. Si t nest pas fourni, la date courante comme
retourne par localtime() est utilise.
Note: lambda *a
Attention ! Si la fonction anonyme lambda *a nest pas utilise, time.strftime(format[, t]) nest valu quune seule
fois au dmarrage du serveur. An dvaluer la date courante chaque fois quune session est cre, utilisez la
fonction lambda !
Note: Objets inactifs
Les objets pour lesquels le champ active est x False ne sont pas visibles dans OpenERP.
7 Vues avances
7.1 Liste & Arbre
Les vues Liste contiennent des lments eld, sont cres avec le type tree et ont un lment <tree> parent.
<tree string="Idea Categories" toolbar="1" colors="blue:state==draft">
<field name="name"/>
<field name="state"/>
</tree>
Exercice 1 - Coloration de liste
Modiez la vue liste des Sessions de telle manire que les sessions qui ont dur moins de 5 jours soient en
bleu et celles qui ont dur plus de 15 jours soient en rouge.
27
Modiez la vue liste des Sessions comme suit :
<tree string="Session Tree" colors="#00ff00:duration&lt;5;red:duration>15">
<field name="name"/>
<field name="course_id"/>
<field name="duration" invisible="1"/>
<field name="remaining_seats_percent" widget="progressbar"/>
</tree>
Note: duration champ Attention ! Si le champ duration nest pas dclar dans la vue, le client naura pas
conscience de son existence. Cela produira une erreur.
7.2 Calendriers
Vues utilises pour afcher des champs date en tant quvnements dans un calendrier (lment parent <calen-
dar>).
Attributs
color: nom du champ pour la segmentation par couleurs
date_start: nom du champ contenant la date de dbut de lvnement
day_length: longueur en heures dune journe du calendrier (dfaut: 8)
date_stop: nom du champ contenant la date de n de lvnement OU
date_delay: nom du champ contenant la dure de lvnement
lments autoriss eld (pour dnir le libell de chaque vnement du calendrier)
<calendar string="Ideas" date_start="invent_date" color="inventor_id">
<field name="name"/>
</calendar>
Exercice 2 - Vue Calendrier
Ajoutez une vue Calendrier lobjet Session autorisant lutilisateur voir les vnements associs
lOpen Academy.
1. Ajouter une vue Calendrier lobjet Session
<record model="ir.ui.view" id="session_calendar_view">
<field name="name">session.calendar</field>
<field name="model">openacademy.session</field>
<field name="type">calendar</field>
<field name="arch" type="xml">
<calendar string="Session Calendar"
date_start="start_date"
date_delay="duration"
day_length="1"
color="instructor_id">
<field name="name"/>
</calendar>
</field>
</record>
2. Mettez jour la liste des actions de la vue Session
<record model="ir.actions.act_window" id="session_list_action">
<field name="name">Session</field>
<field name="res_model">openacademy.session</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form,calendar</field>
</record>
28
7.3 Vues de Recherche
Les vues de Recherche sont utilises pour personnaliser le bandeau de recherche situ en haut des vues Listes,
sont dclares avec le type search et ont un lment parent <search>. Aprs avoir dni la vue de recherche avec
un id unique, ajoutez-la laction ouvrant la vue liste en utilisant le champ search_view_id de laction.
lments autoriss eld, group, separator, label, search, lter, newline, properties
lter : permet de dnir des boutons pour ltrer dans le domaine
ajouter un attribut contextuel aux champs cre des widgets qui modient le
contexte de recherche (utile pour des champs sensibles au contexte, e.g. prix
dpendants de listes de prix)
Exercice 3 - Vues de recherche
Ajoutez une vue de recherche contenant : 1) un champ pour rechercher des cours bas sur leur nom et
2) un bouton pour lter les cours pour lesquels lutilisateur courant est le respondable. Mettre ce dernier
slectionn par dfaut.
1. Ajoutez la vue suivante :
<record model="ir.ui.view" id="course_search_view">
<field name="name">course.search</field>
<field name="model">openacademy.course</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Session Search">
<filter string="My Courses" icon="terp-partner"
name="my_courses"
domain="[(responsible_id,=,uid)]"
help="My own ideas" />
<field name="name"/>
</search>
</field>
</record>
2. Modiez laction :
<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="search_view_id" ref="course_search_view"/>
<field name="context">{search_default_my_courses:1}</field>
</record>
3. Modiez la classe Course :
_columns = {
name: fields.char(Course Title, 128, required=True),
responsible_id: fields.many2one(res.users, string=Responsible,
select=True),
7.4 Diagrammes de Gantt
Graphique en barres typiquement utilis pour afcher le planning dun projet (lment parent <gantt>).
29
Attributs same as <calendar>
lments autoriss
eld, level
level : utilis pour dnir les niveaux dans le diagramme de Gantt avec le
champ utilis comme libell pour le sous-niveau
<gantt string="Ideas" date_start="invent_date" color="inventor_id">
<level object="idea.idea" link="id" domain="[]">
<field name="inventor_id"/>
</level>
</gantt>
Exercice 4 - Diagramme de Gantt
Ajouter un diagramme de Gantt permettant lutilisateur de voir les sessions planies lies au module Open
Academy. Les sessions devront tre groupes par formateur.
Ajoutez la vue suivante (noubliez pas dajouter cette vue gantt dans laction de lobjet Session) :
<record model="ir.ui.view" id="session_gantt">
<field name="name">session.gantt</field>
<field name="model">openacademy.session</field>
<field name="type">gantt</field>
<field name="arch" type="xml">
<gantt string="Session Gantt" date_start="start_date"
date_delay="duration" day_length="1" color="course_id">
<level object="res.partner" link="instructor_id">
<field name="name"/>
</level>
</gantt>
</field>
</record>
7.5 Graphiques
Vues utilises pour afcher des graphiques statistiques (lment parent <graph>).
Attributs
type: type de graphique : bar, pie (par dfaut)
orientation: horizontal, vertical
lments autoriss
eld, avec un comportement spcique :
le premier champ de la vue sera laxe X, le deuxime laxe Y, le troisime
laxe Z
2 champs sont requis, le troisime est optionnel
lattribut group dnit le champ GROUP BY (affect 1)
lattribut operator permet de dnir quel oprateur daggrgation utiliser
sur les autres champs lorsquun champ est group (+,*,**,min,max)
<graph string="Total idea score by Inventor" type="bar">
<field name="inventor_id" />
<field name="score" operator="+"/>
</graph>
30
Exercice 5 - Vue graphique
Ajoutez un graphique qui afche, pour chaque cours, le nombre de participants sous la forme dun graphique
barres. Vous pouvez le crer soit pour lobjet Course, soit pour lobjet Session.
Pour lobjet Session
1. Tout dabord, nous avons besoin dajouter un champ de type function lobjet Session :
attendee_count: fields.function(_get_attendee_count,
type=integer, string=attendee Count,
method=True),
2. Ensuite, la mthode correspondante :
def _get_attendee_count(self, cr, uid, ids, name, args, context=None):
res = {}
for session in self.browse(cr, uid, ids, context=context):
res[session.id] = len(session.attendee_ids)
return res
3. Et nalement, crer la vue dans le chier des vues de openacademy :
<record model="ir.ui.view" id="openacademy_session_graph_view">
<field name="name">openacademy.session.graph</field>
<field name="model">openacademy.session</field>
<field name="type">graph</field>
<field name="arch" type="xml">
<graph string="Participations by Courses" type="bar">
<field name="course_id"/>
<field name="attendee_count" operator="+"/>
</graph>
</field>
</record>
Pour lobjet Course
1. Tout dabord, nous avons besoin dajouter un champ de type function lobjet Session :
attendee_count: fields.function(_get_attendee_count,
type=integer, string=attendee Count,
method=True),
2. Ensuite, la mthode correspondante :
def _get_attendee_count(self, cr, uid, ids, name, args, context=None):
res = {}
for course in self.browse(cr, uid, ids, context=context):
num=0
for session in course.session_ids:
num+=len(session.attendee_ids)
res[course.id] = num
return res
3. Et nalement, crer la vue dans le chier des vues de openacademy :
<record model="ir.ui.view" id="openacademy_course_graph_view">
<field name="name">openacademy.course.graph</field>
<field name="model">openacademy.course</field>
<field name="type">graph</field>
<field name="arch" type="xml">
<graph string="Participations by Courses" type="bar">
<field name="name"/>
<field name="attendee_count" operator="+"/>
</graph>
31
</field>
</record>
8 Workows
Les workows sont des modles associs aux objets mtiers dcrivant la dynamique de la socit. Les workows
sont aussi utiliss pour suivre des processus qui voluent avec le temps.
Exercice 1 - Workow statique
Crez un attribut state qui sera utilis pour dnir un workow pour lobjet Session. Une session peut
avoir trois tats : Draft (dfaut), Conrmed et Done. Ajoutez un champ (en lecture seule) an de visualiser
ltat et des boutons pour changer dtat dans la vue formulaire des Sessions. Les transitions valides sont :
Draft -> Conrmed
Conrmed -> Draft
Conrmed -> Done
Done -> Draft
1. Ajouter un nouvel attribut dans la classe Session du chier openacademy.py :
state:fields.selection([(draft,Draft),(confirmed,Confirmed),
(done,Done)],Status,readonly=True,
required=True),
2. Dnissez 3 nouvelles mthodes dans la classe Session du chier openacademy.py :
def action_draft(self,cr,uid,ids,context=None):
#set to "draft" state
return self.write(cr,uid,ids,{state:draft},context=context)
def action_confirm(self,cr,uid,ids,context=None):
#set to "confirmed" state
return self.write(cr,uid,ids,{state:confirmed},context=context)
def action_done(self,cr,uid,ids,context=None):
#set to "done" state
return self.write(cr,uid,ids,{state:done},context=context)
3. Ajouter la valeur par dfaut pour le nouveau champ :
#Set the default values for the specified fields
_defaults = {
start_date: lambda
*
a : time.strftime(%Y-%m-%d),
active:True,
state:draft
}
4. Dnissez 3 nouveaux boutons dans la vue formulaire des Sessions, chacun appelant la mthode corre-
spondante :
...
<separator string="Attendees" colspan="4"/>
<field name="attendee_ids" colspan="4" nolabel="1" mode="tree,form"
on_change="onchange_remaining_seats(seats,attendee_ids)">
<form string="Attendee">
<field name="partner_id"/>
</form>
<tree string="Attendees" editable="bottom">
<field name="partner_id"/>
32
</tree>
</field>
<field name="state"/>
<group colspan="2" col="4">
<button string="Confirm" type="object"
name="action_confirm"
states="draft" />
<button string="Mark as done" type="object"
name="action_done"
states="confirmed" />
<button string="Reset to draft" type="object"
name="action_draft"
states="confirmed,done" />
</group>
</form>
</field>
</record>
Une commande gnrant une facture et un bon dexpdition est un exemple de workow utilis dans OpenERP.
Les workows peuvent tre associs nimporte quel objet dans OpenERP et sont entirement paramtrables. Les
workows sont utiliss pour structurer et grer les cycles de vies des objets mtiers ou des documents, et dnir
des transitions, des dclencheurs, etc. avec des outils graphiques. Les workows, les activits (noeuds ou actions)
et les transitions (conditions) sont dclars, comme dhabitude, dans des enregistrements XML. Les jetons qui
naviguent dans les workows sont nomms workitems.
Exercice 2 - diteur dynamique de workow
En utilisant lditeur de workow, crez le mme workow que celui dni prcdemment pour lobjet
Session. Transformez la vue formulaire des Sessions de telle sorte que les boutons changent ltat dans le
workow.
Note: Workow on create Un workow associ une session est cr lors de la cration de cette session.
Par consquent, il ny a pas dinstances du workow associes aux instances des sessions cres avant que lon
dnisse le workow.
1. Crez le workowen utilisant le client web (Administration > Paramtrage > Processus > Processus) et crez
un nouveau workow. Passez en vue diagramme et ajoutez les noeuds et les transitions. Une transition doit
tre associe au signal correspondant, et chaque activit (= noeud) doit appeler une fonction modiant ltat
de la session, en accord avec ltat dans le workow.
2. Modiez les boutons prcdemment crs :
<group colspan="2" col="4">
<button string="Confirm" type="workflow"
name="signal_confirm"
33
states="draft" />
<button string="Mark as done" type="workflow"
name="signal_done"
states="confirmed" />
<button string="Reset to draft" type="workflow"
name="signal_draft"
states="confirmed,done" />
</group>
3. Si la fonction dans lactivit Draft est code, vous pouvez mme supprimer la valeur par dfaut de ltat
dans la classe Session.
Note: Instances de workow Pour contrler que les instances du workow sont effectivement cres lorsquune
session est cre, vous pouvez aller dans le menu Administration > Paramtrage > Objets bas niveau > Processus
> Instances. Cependant, pour pouvoir voir ce menu Objets bas niveau, vous devez vous ajouter (Admin) dans le
groupe Useability > No One.
Note: Workow on create Un workow associ une session est cr pendant la cration de cette session.
Par consquent, il ny a pas dinstances du workow associes aux instances des sessions cres avant que lon
dnisse le workow.
Exercice 3 - Server actions
Crez des server actions et modiez le prcdent workow pour re-crer le mme comportement que
prcdemment, mais sans utiliser les mthodes Python de la classe Session.
1.
Exercice 4 - Workows en XML
Installez le module base_module_record. Utilisez-le pour exporter le workow cr dans lditeur de work-
ow dans un chier XML que vous pouvez incorporer dans votre module.
1. Aprs avoir install le module, allez dans le menu Administration > Paramtrage > Cration de module >
Exporter le paramtrage en donnes
2. Fixez le champ from date au moment juste avant que vous avez cr le workow.
3. Slectionnez les objets Workow, Workow activity et workow transition et enregistrez-les.
4. Copiez/Collez le XML dans un chier workow.xml sous un dossier workow de votre module.
Noubliez pas de mettre jour le chier __openerp__.py :
update_xml: [
...
"workflow/workflow.xml",
...
9 Scurit
Les mcanismes de contrle daccs doivent tre combins pour atteindre une politique de scurit cohrente.
9.1 Mcanismes de contrle daccs bass sur les groupes
Les groupes sont crs comme des enregistrements normaux sur le modle res.groups et laccs aux menus via la
dnition de ces derniers. Cependant mme sans menu, les objets peuvent rester accessible indirectement, cest
pourquoi des vritables permissions par objet (create,read,write,unlink) doivent tre dnies pour les groupes.
34
Elles sont gnralement insres via des chiers CSV prsents dans les modules. Il est galement possible de
restreindre les accs certains champs ou objets en utilisant lattribut groups sur les champs.
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
Exercice 1 - Ajouter des contrles daccs depuis linterface de OpenERP
Crez un nouvel utilisateur John Smith. Crez ensuite un groupe OpenAcademy / SessionRead avec les
accs en lecture sur les objets Session et Attendee.
1. Crez un nouvel utilisateur depuis le menu Administration > Utilisateurs > Utilisateurs.
2. Crez un nouveau groupe OpenAcademy / SessionRead en utilisant le menu Administration > Utilisateurs
> Groupes avec des droits daccs en lecture sur les objets Session et Attendee.
3. ditez lutilisateur John Smith et ajoutez-lui le groupe OpenAcademy / SessionRead (vous pouvez
supprimer les autres).
4. Connectez-vous en tant que John Smith et contrlez les droits daccs.
Exercice 2 - Ajouter des contrles daccs depuis des chiers de donnes dans votre module
En utilisant un chier de donnes XML, crez un groupe OpenAcademy / Manager, sans y dnir de droits
daccs pour le moment (crez simplement un groupe vide).
1. Crez un nouveau dossier security dans le rpertoire openacademy. Crez un nouveau chier
groups.xml :
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="0">
<record id="group_manager" model="res.groups">
<field name="name">OpenAcademy / Manager</field>
</record>
</data>
</openerp>
2. Mettez jour le chier __openerp__.py :
...
update_xml: [
...
"security/groups.xml",
Exercice 3 - Ajouter des contrles daccs depuis des chiers de donnes dans votre module
Utilisez un chier CSV pour ajouter les droits de lecture, criture, cration et suppression sur les objets
Course, Session et Attendees au groupe OpenAcademy / Manager. Vous pouvez aussi crer des droits
associs aucun groupe, comme un accs en lecture seule sur les objets Course et Session.
1. Dnissez un nouveau chier CSV ir.model.access.csv contenant les rgles de scurit :
35
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create",
"perm_unlink"
"course_full_manager","course_full_manager","model_openacademy_course",
"group_manager", 1,1,1,1
"course_read_all","course_read_all","model_openacademy_course",,1,0,0,0
"session_full_all","session_full_all","model_openacademy_session",,1,1,1,1
"attendee_full_all","attendee_full_all","model_openacademy_attendee",,1,1,1,1
2. Mettez jour le chier __openerp__.py :
...
update_xml: [
...
"security/ir.model.access.csv",
10 Assistants
10.1 Objets wizard (osv_memory)
Les assistants dcrivent des sessions interactives tats avec lutilisateur par le biais de formulaires dynamiques.
Les assistants utilisent la persistance en mmoire osv_memory pour permettre de construires des assistants depuis
des objets mtiers et des vues normales, sans les enregistrer dans la base de donnes. Les objets en mmoire sont
crs en hritant de la classe osv.osv_memory.
Exercice 1 - Dnir la classe de lassistant
Nous voulons crer un assistant qui permettra lutilisateur de crer des stagiaires pour une session partic-
ulire, ou pour une liste de sessions en une seule fois. Tout dabord, cet assistant fonctionnera uniquement
pour une session la fois. Pour faire cela, nous crons un objet assistant (hritant de osv.osv_memory)
avec une relation many2one sur lobjet Session et une relation one2many avec un nouvel objet Attendee
(en mmoire) avec un champ name et une relation many2one vers lobjet Partner. Dnissez la classe cre-
ate_attendee_wizard et implmentez sa structure.
1. Crez un nouveau rpertoire wizard dans le projet OpenAcademy et crez un nouveau chier cre-
ate_attendee.py.
# -
*
- coding: utf-8 -
*
-
##############################################################################
#
# OpenERP, Open Source Enterprise Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from osv import osv,fields
36
from tools.translate import _
class attendee_memory(osv.osv_memory):
_name = openacademy.attendee.memory
_columns = {
name: fields.char(Name,64),
partner_id: fields.many2one(res.partner,Partner,required=True),
wiz_id:fields.many2one(openacademy.create.attendee.wizard,),
}
attendee_memory()
class create_attendee_wizard(osv.osv_memory):
_name = openacademy.create.attendee.wizard
2. Crez un nouveau chier __init__.py dans le dossier wizard :
import create_attendee
3. Mettez jour le chier __init__.py du dossier openacademy :
import wizard
10.2 Vues
Les assistants utilisent des vues normales et leurs boutons peuvent utiliser un attribut special=cancel an de
fermer la fentre de lassistant lorsquil est cliqu.
10.3 Excution dun assistant
De tels assistants sont lancs par le biais denregistrements action normaux, avec une cible spciale utilise pour
ouvrir lassistant dans une nouvelle fentre.
Exercice 2 - Rendre lassistant disponible depuis un lment du menu
Crez un lment de menu et laction ncessaire pour utiliser lassistant.
1. Dans le dossier wizard, crez un nouveau chier create_attendee_view.xml contenant llment de
menu :
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<menuitem name="Add attendee" parent="openacademy_menu"
id="create_attendee_wizard_menu"
action="create_attendee_wizard_action"/>
</data>
</openerp>
2. Crez laction create_attendee_wizard_action :
<record model="ir.actions.act_window" id="create_attendee_wizard_action">
<field name="name">Add attendee</field>
<field name="res_model">openacademy.create.attendee.wizard</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
37
3. Mettez jour le chier __openerp__.py sous le projet openacademy :
update_xml: [wizard/create_attendee_view.xml],
Exercice 3 - Personnaliser la vue formulaire
Personnalisez la vue formulaire pour afcher tous les champs de la classe.
<record model="ir.ui.view" id="create_attendee_form_view">
<field name="name">openacademy.create.attendee.wizard.form</field>
<field name="model">openacademy.create.attendee.wizard</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Add attendee" col="2">
<field name="session_id"/>
<field name="attendee_ids" mode="tree">
<tree string="Attendees" editable="bottom">
<field name="partner_id"/>
</tree>
</field>
</form>
</field>
</record>
Exercice 4 - Crer les mthodes
Crez la mthode action_add_attendee dans la classe create_attendee_wizard et ajouter un bouton dans la
vue formulaire pour lappeler. Ajoutez galement un bouton Annuler qui ferme la fentre de lassistant.
1. Ajoutez la mthode la classe create_attendee_wizard.
def action_add_attendee(self, cr, uid, ids, context=None):
wizard = self.browse(cr, uid, ids[0], context=context)
attendee_pool = self.pool.get(openacademy.attendee)
for attendee in wizard.attendee_ids:
attendee_pool.create(cr,uid,{name:attendee.name,
partner_id:attendee.partner_id.id,
session_id:wizard.session_id.id} )
return {}
Note: Deux manires de fermer la fentre dun assistant
Pour fermer la fentre la n dune mthode, vous pouvez soit retourner un dictionnaire vide return {} ou ex-
plicitement retourner la mthode close return {type: ir.actions.act_window.close,}
2. Ajoutez les boutons la vue formulaire.
<record model="ir.ui.view" id="create_attendee_form_view">
<field name="name">openacademy.create.attendee.wizard.form</field>
<field name="model">openacademy.create.attendee.wizard</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Add attendee" col="2">
<field name="session_id"/>
<field name="attendee_ids" mode="tree">
<tree string="Attendees" editable="bottom">
<field name="partner_id"/>
</tree>
</field>
/++
38
<button type="special" special="cancel"
string="Cancel" icon="gtk-cancel"/>
<button type="object" name="action_add_attendee"
string="Add attendees" icon="gtk-ok"
confirm="Are you sure you want to add those attendees?"/>
++/
</form>
</field>
</record>
Exercice 6 - Lier lassistant la barre contextuelle
Liez lassistant la barre contextuelle du modle des sessions.
Mettez jour le chier rcemment cr create_attendee_view.xml :
<act_window name="Add Attendees"
src_model="openacademy.session"
res_model="openacademy.create.attendee.wizard"
id="session_create_attendee_wizard"
view_mode="form"
key2="client_action_multi"
target="new"/>
Note: client_action_multi
Outre client_action_multi, il existe aussi les valeurs client_action_relate et client_print_multi pour lattribut key2.
Ils spcient licone afcher pour lassistant correspondant.
Exercice Supplmentaire - Assistant sur de multiples enregistrements
Rendez lassistant capable dajouter des stagiaires dans plusieurs sessions la fois.
1. Ajoutez un attribut sur le champ session_id dans la vue.
<field name="session_id" invisible="len(context.get(active_ids))>1"/>
2. Ajoutez une valeur par dfaut pour le champ session_id, an dy afcher la valeur de la session courante.
def _get_active_session(self, cr, uid, context=None):
print context
if not context:
return False
else:
return context.get(active_id)
_defaults={
session_id:_get_active_session
}
3. Modiez votre mthode pour ajouter des stagiaires plusieurs sessions.
def action_add_attendee(self, cr, uid, ids, context=None):
wizard = self.browse(cr, uid, ids[0], context=context)
if len(context.get(active_ids))>1:
session_ids=context.get(active_ids)
else:
session_ids=[wizard.session_id.id]
attendee_pool = self.pool.get(openacademy.attendee)
print(_(Hello we are in the wizard %(id)s and %(partner)s) % {id:wizard.id,partner:wizard.partner_id} )
39
for session_id in session_ids:
for attendee in wizard.attendee_ids:
attendee_pool.create(cr,uid,{name:attendee.name,
partner_id:attendee.partner_id.id,
session_id:session_id} )
return {}
Note: Modier les champs relationnels travers la mthode write
Nous aurions p dcider de crer les stagiaires depuis de champ relation vers lobjet des sessions. Pour modi-
er/supprimer/ajouter des valeurs dans un champ relationnel, vous devez utiliser une syntaxe spciale. Les dtails
sont disponibles dans les commentaires avant la classe one2many dans le chier server/bin/osv/elds.py.
11 Rapports
11.1 Rapports imprims
Les rapports dans OpenERP peuvent tre rendus de diffrentes manires :
Rapports personnaliss: ces rapports peuvent tre directement crs depuis linterface client, pas de pro-
grammation requise. Ces rapports sont reprsents par des objets mtiers (ir.report.custom)
Rapport personnaliss de haute qualit utilisant openreport: pas de programmation requise mais il faut
crire 2 petits chiers XML :
un template qui indique les donnes sur lesquelles portera le rapport
un chier XSL : feuille de style RML
Rapports cods en dur
Modles OpenOfce Writer
Il existe plusieurs moteurs de rendu de rapports dans OpenERP pour produire des rapports depuis diffrentes
sources et dans plusieurs formats.
Expressions utilises dans OpenERP dans les modles de rapport
Predened expressions :
objects contient la liste des enregistrements imprimer
data vient de lassistant lanant le rapport
user contient lutilisateur courant (comme un browse())
time donne accs au module Python time
repeatIn(list,var,tag) repte llment parent nomm tag pour chaque objet dans la liste, rendant lobjet
disponible en tant que variable dans chaque boucle
setTag(tag1,tag2) remplace la balise RML tag1 par tag2
40
removeParentNode(tag) supprime llment RML parent tag
formatLang(value, digits=2, date=False, date_time=False, grouping=True, monetary=False) peut tre util-
is pour formater une date, un temps ou un montant selon la locale
setLang(lang_code) xe la langue et la locale courante pour les traductions
Exercice 1 - Installer le plugin OpenOfce
Installez le module report designer et ajouter le plugin OpenERP dans OpenOfce.
Installez le module base > report designer. Allez ensuite dans Administration > Paramtrage > Rapports > Con-
cepteur de Rapports et enregistrez le chier zip
Exercice 2 - Crer un nouveau rapport
Crez un rapport pour lobjet Session, afchant pour chaque session, son nom, sa date de dbut, sa dure, le
pourcentage de remplissage, le responsable ainsi que la liste des stagiaires.
[[repeatIn(objects,session)]]
[[ setLang(session.course_id.responsible_id.context_lang) ]]
Name: [[ session.name ]]
Date: [[ formatLang(session.date,date=True) ]]
Duration: [[ formatLang(session.duration,digits=2) ]]
Percentage of completion: [[ session.perc_completion, digits=2 ]]
Responsable: [[ session.responsible_id.name ]]
============================================= ====================================
Partner Signature
============================================= ====================================
[[repeatIn(session.attendee_ids,attendee)]]
-------------------------------------------------------------------------------------
[[ attendee.partner_id ]]
============================================= ====================================
Exercice 3 - RML
Exportez le rapport OpenOfce en un chier RML, ajoutez-le votre module et ajoutez une action lobjet
Session an dimprimer le rapport.
1. Crez un dossier report dans votre module et enregistrez le chier rml dedans.
2. Ajoutez un chier xml pour la claration de ce rapport dans ce dossier.
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<report id="session_report" string="Print Sessions"
model="openacademy.session" name="session.report"
rml="openacademy/report/session.rml" />
</data>
</openerp>
3. Mettez jour le chier __openerp__.py an dy ajouter une rfrence ce chier de dclaration.
41
Exercice 4 - RML
Amliorez votre rapport. Empchez la ligne start date dapparatre dans le rapport si aucune valeur ne lui
est associe, et afcher le pourcentage de siges restants en rouge si celui-ci est infrieur 10.
1. Enlever la ligne date de dbut
<para style="Standard">Duration: [[ session.duration and formatLang(session.duration,digits=2) or (removeParentNode(para)) ]]</para>
2. Rglez la couleur de la police selon le pourcentage de siges restants.
<para style="Standard">Remaining seats percentage:
<font color="black"> [[session.remaining_seats_percent&lt;50 and setTag(font,font,{color:red})]]
[[session.remaining_seats_percent]]</font>
</para>
11.2 Tableaux de bord
Exercice 5 - Dnir un tableau de bord
Dnissez un tableau de bord contenant la vue graphique que vous avez cre, le calendrier des sessions et
la liste des cours (commutable en vue formulaire). Ce tableau de bord doit tre disponible depuis un menu,
et automatiquement afch dans le client web quand le menu principal OpenAcademy est slectionn.
1. Crez un chier board_session_view.xml dans votre module. Il doit contenir la vue du tableau, les actions
rfrences dans cette vue, une action pour ouvrir ce tableau de bord, ainsi quune rednition du menu
principal openacademy_menu pour lui ajouter laction douvrir le tableau de bord.
<?xml version="1.0"?>
<openerp>
<data>
<record model="ir.actions.act_window" id="act_session_graph">
<field name="res_model">openacademy.session</field>
<field name="view_type">form</field>
<field name="view_mode">graph</field>
<field name="view_id" ref="openacademy.openacademy_session_graph_view"/>
</record>
<record model="ir.actions.act_window" id="act_session_calendar">
<field name="res_model">openacademy.session</field>
<field name="view_type">form</field>
<field name="view_mode">calendar</field>
<field name="view_id" ref="openacademy.session_calendar_view"/>
</record>
<record model="ir.actions.act_window" id="act_course_list">
<field name="res_model">openacademy.course</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<record model="ir.ui.view" id="board_session_form">
<field name="name">Session Dashboard Form</field>
<field name="model">board.board</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Session Dashboard">
<hpaned>
<child1>
<action
string="Attendees by course"
42
name="%(act_session_graph)d"
colspan="4"
height="150"
width="510"/>
<action
string="Courses"
name="%(act_course_list)d"
colspan="4"/>
</child1>
<child2>
<action
string="Sessions"
name="%(act_session_calendar)d"
colspan="4"/>
</child2>
</hpaned>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="open_board_session">
<field name="name">Session Dashboard</field>
<field name="res_model">board.board</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="usage">menu</field>
<field name="view_id" ref="board_session_form"/>
</record>
<menuitem id="openacademy_menu" name="OpenAcademy" action="open_board_session"/>
<menuitem id="board.menu_dashboard" name="Dashboard" sequence="0" parent="openacademy_menu"/>
<menuitem
name="Session Dashboard" parent="board.menu_dashboard"
action="open_board_session"
sequence="1"
id="menu_board_session" icon="terp-graph"
groups="base.group_sale_salesman"/>
</data>
</openerp>
2. Mettez jour le chier __openerp__.py an de rfrencer ce nouveau chier de vues.
12 Internationalisation
Chaque module peut fournir ses propres traductions dans le dossier i18n, en ayant des chiers nomms
LANGUE.po o LANGUE est le code de ce langage, ou une combinaison de la langue et le pays dans le
cas o ils diffrent (e.g. pt.po or pt_BR.po). Les traductions seront automatiquement charges par OpenERP
pour toutes les langues actives. Les dveloppeurs utiliseront toujours lAnglais en crant un module, puis ex-
porteront les termes du modules en utilisant la fonctionnalit dexport de POT gettext de OpenERP (Administra-
tion>Traductions>Exporter une traduction sans spcier de langue ) pour crer le chier template POT du module,
et ensuite en driver les chiers PO traduits. La plupart des environnements intgrs de dveloppement ont des
modes ou des plugins pour diter et merger les chiers PO/POT.
Tip: Le format GNU gettext (Portable Object) utilis par OpenERP est intgr LaunchPad, devenant ainsi une
plateforme collaborative de traduction.
|- idea/ # La racine du module
|- i18n/ # Fichiers de traduction
| - idea.pot # Fichier Template (export depuis OpenERP)
43
| - fr.po # Traduction Franaise
| - pt_BR.po # Traduction Portuguaise du Brsil
| (...)
Tip: Par dfaut, lexport POT dOpenERP extrait seulement les libells dans les chiers XML ou dans la dni-
tion des champs dans le code Python, mais nimporte quelle chane Python peut tre traduite de cette manire en
lencadrant par la mthode tools.translate._ method (e.g. _(Label) )
Exercice 1 - Traduire un module
Slectionnez une seconde langue pour votre installation dOpenERP. Traduisez votre module en utilisant les
fonctionnalits fournies par OpenERP.
1. Crez un dossier i18n dans le rpertoire OpenAcademy.
2. Installez la langue cible dans OpenERP (Administration > Traductions > Charger une traduction ofcielle)
3. Synchronisez les termes de lapplication depuis le menu Administration > Traductions > Termes de
lapplication > Synchroniser les traductions
4. Crez le chier template de traduction openacademy.pot en lexportant (Administration > Traductions >
Importer/Exporter > Exporter une traduction) sans spcier de langue et enregistrez-le dans le dossier i18n.
5. Crez le chier de traduction franaise (ou nimporte quelle autre langue) fr_FR.po en lexportant (Ad-
ministration > Traductions > Importer/Exporter > Exporter une traduction) en spciant une langue, et
enregistrez-le dans le dossier i18n.
6. Ouvrez le chier fr_FR.po avec poedit (ou un simple diteur de texte) et traduisez les termes.
Note: Par dfaut, lexport POT dOpenERP extrait seulement les libells dans les chiers XML ou dans la
dnition des champs dans le code Python, mais nimporte quelle chane Python peut tre traduite de cette manire
en lencadrant par la mthode tools.translate._ method (e.g. _(Label) )
7. Mettez jour le chier openacademy.py.
from tools.translate import _
8. Ajoutez loprateur _ l o il est ncessaire, rpter ensuite les tapes 3, 4, 5 et 6.
13 WebServices
Le module de web-service offre une interface commune pour tous les web-services :
SOAP
XML-RPC
NET-RPC
Les objets mtiers peuvent aussi tre accds depuis le mcanisme dobjets distribus. Il peuvent tous tre modis
par les interfaces clients avec les vues contextuelles.
OpenERP est accessible depuis des interfaces XML-RPC, pour lesquelles des librairies existent dans de nombreux
langages.
13.1 Exemple Python
44
import xmlrpclib
# ... define HOST, PORT, DB, USER, PASS
url = http://%s:%d/xmlrpc/common % (HOST,PORT)
sock = xmlrpclib.ServerProxy(url)
uid = sock.login(DB,USER,PASS)
print "Logged in as %s (uid:%d)" % (USER,uid)
# Create a new idea
url = http://%s:%d/xmlrpc/object % (HOST,PORT)
sock = xmlrpclib.ServerProxy(url)
args = {
name : Another idea,
description : This is another idea of mine,
inventor_id: uid,
}
idea_id = sock.execute(DB,uid,PASS,idea.idea,create,args)
Exercice 1 - Ajouter un nouveau service au client
crivez un programme Python capable denvoyer des requtes XML-RPC un PC ayant lanc OpenERP (le
votre ou celui de votre formateur). Ce programme doit permettre dafcher toutes les sessions existantes, le
nombre de siges correspondants et de crer une nouvelle session pour un des cours. Dans ce cas, demandez
au serveur de crer les objet Session.
1. Crez un nouveau dossier xml-rpc sous le dossier openacademy. Sous ce dossier, crez un nouveau
chier test.py :
#!/usr/bin/python
# -
*
- coding: utf-8 -
*
-
##############################################################################
#
# OpenERP, Open Source Enterprise Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import xmlrpclib
HOST=192.168.0.44
PORT=8069
DB=openacademy
USER=admin
PASS=admin
url = http://%s:%d/xmlrpc/ % (HOST,PORT)
common_proxy = xmlrpclib.ServerProxy(url+common)
object_proxy = xmlrpclib.ServerProxy(url+object)
45
def execute(
*
args):
return object_proxy.execute(DB,uid,PASS,
*
args)
# 1. Login
uid = common_proxy.login(DB,USER,PASS)
print "Logged in as %s (uid:%d)" % (USER,uid)
# 2. Read the session
session_ids = execute(openacademy.session,search,[])
sessions = execute(openacademy.session,read,session_ids, [name,seats])
for session in sessions :
print "Session name :%s (%s seats)" % (session[name], session[seats])
# 3.create a new session
session_id = execute(openacademy.session, create,
{name : My session,
course_id : 2, })
2. Au lieu dajouter une session un cours dont on connait lID, nous pouvons chercher ce cours par rapport
son nom.
# 3.create a new session for the "Functional" course
course_id = execute(openacademy.course, search, [(name,ilike,Functional)])[0]
session_id = execute(openacademy.session, create,
{name : My session,
course_id : course_id, })
Note: Mthodes utilisables
Depuis le XML-RPC, il est possible de crer un objet (create), rechercher des objets (search, utiliser et lire des
donnes, mettre jour des donnes et supprimer des objets (unlink)
14 ooooo
Based on a real case, this chapter covers: building an OpenERP module and its interface, Views,
Reports, Workows, Security aspects, Wizards, WebServices, Internationalization, Rapid Ap-
plication Development (RAD) and Performance Optimization.
14.1 Conguration
Ce document contient les solutions tape par tape pour les exercices du livret accompagnant la for-
mation technique OpenERP.
Chaque partie donne la solution des exercices de la section correspondante du livret dexercices.
Des instructions tape par tape sont donnes dans leur plus simple forme, gnralement en donnant
un exemple de code source permettant dimplmenter le comportement requis.
Open Source RAD avec OpenObject
OpenERP est un Outil de Gestion dEntreprise moderne, publi sous license AGPL, et fournissant les fonctionnal-
its CRM, Ressources Humaines, Ventes, Comptabilit, Production, Inventaires, Gestion de Projet, ... Il est bas
sur OpenObject, un framework modulaire, volutif et intuitif de RAD (Rapid Application Development) crit en
Python.
46
OpenObject fournit une bote outils complte et modulaire pour rapidement crer des fonctionnalits
: support de lORM (mapping objet-relationnel), interfaces bases sur des templates MVC (Modle-Vue-
Contrleur), un systme de gnration de rapport, internationnalisation automatise et bien plus.
Python est un langage de programmation de haut-niveau, idal pour du RAD, combinant puissance et
syntaxe claire et un noyau de taille rduite par sa conception.
Tip: Liens utiles
Site principal avec les tlchargements dOpenERP : www.openerp.com
Documentation fonctionnelle et technique : doc.openerp.com
Ressources de la communaut : www.launchpad.net/open-object
Serveur dintgration : test,openobject.com
Apprendre Python: doc.python.org
Plateforme dE-Learning OpenERP : edu.openerp.com
Installer OpenERP
OpenERP est distribu sous la forme de paquets/dinstalleurs pour la plupart des plateformes, mais peut bien
entendu tre install depuis le code source sur nimporte quelle plateforme.
Architecture dOpenERP
OpenERP utilise le paradigme bien connu client-serveur, avec diffrentes pices logicielles agissant en tant que
client et serveur dpendant de la conguration dsire.
OpenERP fournit un client lourd (GTK+) pour toutes les plateformes et une interface web accessible en utilisant
nimporte quel navigateur Web rcent.
Tip: Procdure dinstallation
La procdure dinstallation dOpenERP est susceptible dvoluer (dpendances et autres), assurez-vous alors de
toujours vrier la documentation spcique (package et sur le site Web) pour les dernires procdures. Voir
http://doc.openerp.com/install.
Installation par les paquets
Windows Installeur tout-en-un et installeurs spars pour le serveur, le client, le serveur web sont sur le
site web
Linux Les paquets openerp-server et openerp-client sont disponibles via le gestionnaire de paquets
(e.g. Synaptic sur Ubuntu) OU en utilisant BaZaar bzr branch lp:openerp (ou openerp/trunk
pour la version trunk) une fois identi sur Launchpad, ensuite, cd openerp (cd trunk dans la
version trunk) et ./bzr_set.py
Mac Regardez en ligne pour un paquet dinstallation pour le client GTK, ainsi que des tutoriels pour
installer le serveur (e.g. devteam.taktik.be)
Installation partir des sources
Il y a deux alternatives :
1. utiliser une archive fournie sur le site web,
2. ou obtenir directement les sources en utilisant Bazaar (gestionnaire de contrle de source distribu).
Vous aurez galement besoin dinstaller les dpendances requises (PostgreSQL et quelques librairies Python - voir
la documentation sur doc.openerp.com).
Note: OpenERP tant bas sur Python, aucune compilation nest ncessaire.
47
Procdure typique de rcupration des sources (sur Linux bas sur Debian)
$ sudo apt-get install bzr # installation de bazaar
$ bzr branch lp:openerp # rcupration des sources
$ cd openerp && python ./bzr_set.py # chercher le code et lancer linstallation
Cration de la base de donnes
Aprs linstallation, lancer le serveur et le client. Depuis le client GTK, utilisez le menu Fichier > Base de donnes
> Nouvelle base de donnes pour crer une nouvelle base de donnes (le mot de passe super-admin par dfaut est
admin). Chaque base de donnes a ses propres modules et sa propre conguration.
Note: Des donnes de dmonstration peuvent aussi tre installes.
14.2 Crer un module OpenERP
Composition dun module
Un module peut contenir les lments suivants :
Objet Mtier : dclars en tant que classes Python hritants de la classe OpenObject osv.osv, la persistance
de ces ressources est compltement gre par OpenObject,
Donnes : chiers XML/CSV contenant des mta-donnes (dclaration de vues et de workow), des don-
nes de conguration (paramtrage des modules) et des donnes de dmonstration (optionnelles mais rec-
ommendes pour tester),
Assistants : formulaire interactif tats utiliss pour aider les utilisateurs, souvent disponibles comme
action contextuelle sur les ressources du systme,
Rapports : RML (format XML). Modles de rapports MAKO ou OpenOfce, dans lesquels sont intgres
les donnes du systme de nimporte quel objet mtier et gnre des rapports aux formats HTML, ODT ou
PDF.
Structure dun module
Chaque module est contenu dans son propre rpertoire dans le rpertoire server/bin/addons ou dans un
autre rpertoire daddons, congur lors de linstallation du serveur.
48
Note: Congurer les emplacements des addons
Par dfaut, le seul rpertoire daddons connu par le serveur est server/bin/addons. Il est possibe dajouter
de nouveaux addons en 1) les copiant dans server/bin/addons, ou en crant des liens symboliques vers
chacun deux dans ce rpertoire, ou 2) spcier un autre rpertoire contenant des addons au serveur. Cette
dernire mthode peut tre effectue soit en lanant le serveur avec loption addons-path= option, ou en con-
gurant cette option dans le chier openerp_serverrc, gnr automatiquement sour Linux dans votre rpertoire
personnel lorsque le serveur est lanc avec loption save. Vous pouvez fournir plusieurs rpertoires loption
addons_path en les sparant par des virgules.
Le chier __init__.py est la dclaration en Python du module, car OpenERP est aussi un module Python. Il
contient toutes les instructions dimportation de tous les chiers Python, sans lextension .py. Par exemple, si le
module contient un unique chier Python nomm mymodule.py :
import mymodule
Le chier __openerp__.py est rellement le chier qui dclare le module OpenERP. Il est obligatoire dans chaque
module. Il contient uniquement un dictionnaire Python avec de nombreuses informations importantes, comme le
nom du module, sa description, la liste des autres modules OpenERP dont linstallation est requise pour que le
module courant fonctionne correctement Il contient aussi, entre autres, une rfrence tous les chiers de donnes
(xml, csv, yml, ...) du module. Sa structure gnrale est la suivante (voir la documentation ofcielle pour une
description complte du chier) :
{
"name": "MyModule",
"version": "1.0",
"depends": ["base"],
"author": "Author Name",
"category": "Category",
"description": """
Description text
""",
data: [
mymodule_view.xml,
#tous les autres fichiers de donnes, lexception des donnes de dmonstration et de tests
],
demo: [
#fichiers contenant les donnes de dmonstration
],
test: [
#fichiers contenant les donnes de test
],
installable: True,
active: False,
# certificate: certificate,
}
Exercice 1 - Cration dun module
Crez le module vide Open Academy, avec un chier __openerp__.py. Installez-le dans OpenERP.
1. Crez un nouveau dossier openacademy sur votre ordinateur.
2. Ajoutez un lien symbolique vers ce dossier dans le rpertoire server/bin/addons.
3. Crez un chier __openerp__.py dans le dossier OpenAcademy :
{
"name": "Open Academy",
"version": "1.0",
"depends": ["base"],
"author": "Author Name",
49
"category": "Test",
"description": """
Open Academy module for managing trainings:
- training courses
- training sessions
- attendees registration
""",
data: [openacademy_view.xml],
demo: [],
installable: True,
active: False,
# certificate: certificate,
}
4. Crez un chier openacademy.xml dans le sous-dossier view du dossier OpenAcademy :
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<menuitem id="openacademy_menu" name="OpenAcademy" />
</data>
</openerp>
Objet de service - ORM
Composant cl de OpenObject, lobjet de service (OSV) implmente une couche complte de mapping objet-
relationnel, librant ainsi les dveloppeurs davoir crire du SQL basique. Les objets mtier sont dclars dans
des classes Python hritants de la classe osv.osv, leur permettant de faire partie du modle OpenObject, et comme
par magie persistant grce la couche ORM.
Attributs osv.osv prdnis pour les objets mtiers
Types de champs de lORM
Les objets peuvent contenir 3 types de champs : simple, relationnel et fonctionnel. Les types simples sont integer,
oat, boolean, string, etc. Les champs relationnels reprsentent les relations entre objets (one2many, many2one,
many2many). Les champs fonctionnels ne sont pas stocks dans la base de donnes mais sont calculs la vole
avec des fonctions Python.
Attributs communs supports par tous les champs (optionnels sauf indication)
string : Libell du champ (requis)
required : True si obligatoire
readonly : True si non ditable
help : Bulle daide
select : 1 pour inclure le champ dans la vue de recherche et optimiser le ltre des listes (avec un index en
base de donnes)
context : Dictionnaire contenant des paramtres contextuels (pour les champs relationnels)
Champs simples
boolean(...) integer(...) date(...) datetime(...) time(...)
50
start_date: elds.date(Start Date)
active: elds.boolean(Active)
priority: elds.integer(Priority)
char(string,size,translate=False,..) text(string, translate=False,...) [Champs bass sur du texte]
translate: True si la valeur du champ peut tre traduite par les utilisateurs
size: taille maximale pour les champs char (41,45)
oat(string, digits=None, ...) [valeur ottante avec prcision arbitraire et ratio]
digits: tuple (precision, scale) (58) . Si digits nest pas spci, cest un oat, pas un type decimal.
Noms de champs rservs/spciaux
Quelques noms de champs sont rservs un comportement prdnis dans OpenObject. Certains dentre eux
sont crs automatiquement par le systme, et dans ce cas, nimporte quel champ qui portera ce nom sera ignor.
id identiant unique dans le systme pour lobjet (cr par lORM, ne pas lajouter)
name dnit la valeur utilise par dfaut pour afcher les enregistrements dans les listes,
etc. si manquant, utilisez _rec_name pour spcier un autre champ utiliser dans ce
but
... ...
Exercice 2 - Dnir une classe
Dnir une nouvelle classe Course dans le module openacademy.
1. Dans le nouveau projet OpenAcademy, crez un nouveau chier openacademy.py :
# -
*
- coding: utf-8 -
*
-
##############################################################################
#
# OpenERP, Open Source Enterprise Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from osv import osv, fields
2. Dans ce chier openacademy.py, crez la classe suivante :
class Course (osv.osv):
_name = openacademy.course
_columns = {
name : fields.char(Course Title, 128, required = True),
description : fields.text(Description),
51
}
Course()
3. Crez un chier __init__.py dans le projet OpenAcademy :
import openacademy
Menus
Llment menuitem est un raccourci pour dclarer un enregistrement ir.ui.menu et le connecter avec laction
correspondante via un enregistrement ir.model.data.
<menuitem id="menu_id" parent="parent_menu_id" name="label" icon="icon-code"
action="action_id" groups="groupname1,groupname2" sequence="10"/>
Actions
Les actions sont dclares comme des enregistrements normaux et peuvent tre dclenches de 3 faons :
1. en cliquant sur les lments de menu lis une action spcique
2. en cliquant sur des boutons dans des vues, si ces boutons sont connects des actions
3. en tant quactions contextuelles sur un objet
Dclaration dune action
<record model="ir.actions.act_window" id="action_id">
<field name="name">action.name</field>
<field name="view_id" ref="view_id"/>
<field name="domain">[list of 3-tuples (max 250 characters)]</field>
<field name="context">{context dictionary (max 250 characters)}</field>
<field name="res_model">object.model.name</field>
<field name="view_type">form|tree</field>
<field name="view_mode">form,tree,calendar,graph</field>
<field name="target">new</field>
<field name="search_view_id" ref="search_view_id"/>
</record>
Exercice 3 - Dnir de nouvelles entres de menu
Dnissez de nouvelles entres de menu pour accder aux cours et aux sessions sous lentre de menu
OpenAcademy; on devrait tre en mesure de 1) afcher la liste de tous les cours et 2) crer/modier des
cours.
1. Dans le chier view/openacademy.xml, crez les entres de menu suivantes :
<menuitem id="course_menu" name="Courses" parent="openacademy_menu"
action="course_list_action" />
2. Crez les actions correspondantes, permettant les modes tree et form :
<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>
</record>
52
14.3 Crer des vues : bases
Exercice 1 - Personnaliser une vue depuis lditeur de vues de linterface web
Crez une vue liste pour lobjet Course , afchant le nom du cours ainsi que sa description.
Note: module recorder
Il est possible dexporter (ou dimporter) des vues (ou nimporte quel autre enregistrement) de la base de don-
nes dans un chier XML ou YaML en utilisant le module recorder. Ce point particulier sera trait dans une
prochaine section.
Dans le client web, ouvrez le menu OpenAcademy > Course. Cliquez sur Personnaliser les vues dans le panneau
de droite, crez-en une nouvelle, ditez-la et modiez-la.
Les vues forment une hirarchie. Plusieurs vues du mme type peuvent tre dclares sur le mme objet, et
seront afches selon leurs priorits. En dclarant une vue hrite, il est possible dajouter ou de supprimer des
fonctionnalits dans une vue.
Dclaration gnrique dune vue
<record model="ir.ui.view" id="view_id">
<field name="name">view.name</field>
<field name="model">object_name</field>
<field name="type">form</field> # tree,form,calendar,search,graph,gantt
<field name="priority" eval="16"/>
<field name="arch" type="xml">
<!-- view content: <form>, <tree>, <graph>, ... -->
</field>
</record>
Les vues Formulaires
Les vues Formulaires permettent la cration et la modication des ressources, et correspondent aux lments
<form>.
lments des vues formulaires
Attributs communs tous les lments :
string: libell de llment
nolabel: 1 pour cacher le libell du champ
colspan: nombre de colonnes sur lesquelles le champ doit staler
rowspan: nombre de lignes sur lesquelles le champ doit staler
col: nombre de colonnes que cet lment doit allouer ses lments ls
invisible: 1 pour cacher compltement cet lment
eval: evalue ce code Python en tant que contenu de llment (le contenu est une chane de caractres par
dfaut)
attrs: dictionnaire Python dnissant des conditions dynamiques sur ces attributs : readonly, invisible,
required bass sur des tuples de recherche sur les valeurs dautres champs
53
Field Widgets automatiques dpendants du type de champ correspondant. Attributs :
string: libell du champ, aussi pour la recherche (surcharge le nom du champ)
select: 1 pour afcher le champ en recherche normale, 2 pour la recherche
avance seulement
nolabel: 1 pour cacher le libell du champ
required: surcharge lattribut required du champ
readonly: surcharge lattribut readonly du champ
password: 1 pour cacher les caractres saisis dans ce champ
context: code Python dclarant un dictionnaire de contexte
domain: code Python dclarant une liste de tuples pour restreindre les valeurs
on_change: appel dune mthode Python dclencher quand une valeur est
change
completion: 1 pour activer lauto-completion des valeurs lorsque cela est pos-
sible
groups: liste des groupes (spars par des virgules) autoriss voir ce champ
widget: selectionne un widget alternatif (one2many_list, many2many, url,
email, image, oat_time, reference, text_wiki, text_html, progressbar)
properties widget dynamique afchant toutes les proprits disponibles (pas dattributs)
button
widget cliquable associ des actions. Attributs spciques :
type: type de button : workow (dfaut), object ou action
name: signal du workow, nom de la fonction (sans les parenthses) ou
action appeler (selon le type)
conrm: message texte de conrmation lorsque le bouton est cliqu
states: liste des tats (spars par des virgules) pour lesquels le bouton est
visible
icon: icone optionnelle (toutes les icnes GTK STOCK e.g. gtk-ok)
separator ligne horizontale de sparation pour structurer les vues, avec un libell optionnel
newline paramtre virtuel pour complter la ligne courante de la vue
label libell ou lgende libre dans le formulaire
group utilis pour organiser les champs en groupes avec un libell optionnel (ajoute un
cadre)
notebook, page
les lments notebook sont des gestionnaires donglets pour les lments page. Attributs :
name: libell de longlet
position: position de longlet dans son container (inside, top, bottom, left,
right)
Exercice 2 - Personnaliser les vues liste et formulaire via XML
Crez vos propres vues liste et formulaire pour lobjet Course. Les donnes afches doivent tre :
Dans la vue liste, le nom du cours;
Dans la vue formulaire, le nom et la description du cours.
1. Dans le chier openacademy_view.xml, crez les vues suivantes :
<!-- ======= COURSE ====== -->
<record model="ir.ui.view" id="course_tree_view">
<field name="name">course.tree</field>
<field name="model">openacademy.course</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Course Tree">
<field name="name"/>
</tree>
</field>
54
</record>
<record model="ir.ui.view" id="course_form_view">
<field name="name">course.form</field>
<field name="model">openacademy.course</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Course Form">
<field name="name" />
<field name="description"/>
</form>
</field>
</record>
Note: colspan
Par dfaut, la vue est spare en 4 colonnes
2. Nous pouvons amliorer la vue formulaire pour un meilleur afchage.
<record model="ir.ui.view" id="course_form_view">
<field name="name">course.form</field>
<field name="model">openacademy.course</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Course Form">
<field name="name" />
<separator string="Description" colspan="4" />
<field name="description" nolabel="1" colspan="4" />
</form>
</field>
</record>
Exercice 3 - Onglets
Dans la vue formulaire des cours, afchez la description dans un onglet, de cette manire, il sera facile
dajouter dautres onglets par la suite, contenant des informations additionnelles.
Modiez la vue formulaire des cours comme suit :
<record model="ir.ui.view" id="course_form_view">
<field name="name">course.form</field>
<field name="model">openacademy.course</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Course Form">
<field name="name" />
<notebook colspan="4">
<page string="Description">
<field name="description" nolabel="1" colspan="4" />
</page>
</notebook>
</form>
</field>
</record>
14.4 Relations entre objets
55
Exercice 1 - Crer des classes
Crez les classes Session et Attendee et ajoutez un menu et une action pour afcher les sessions. Une session
a un nom, une date de dbut, une dure (en jours) et un nombre de siges. Un stagiaire a un nom, qui nest
pas requis.
1. Crez les classes Session et Attendee.
Classe Session :
class Session(osv.osv):
_name = openacademy.session
_columns = {
name: fields.char(Session Title, 128, required=True),
start_date: fields.date(Start Date),
duration: fields.float(Duration, digits=(6,2), help="Duration in days"),
seats:fields.integer(Seats number),
}
Session()
Classe Attendee :
class Attendee(osv.osv):
_name = openacademy.attendee
_columns = {
}
Attendee()
Note: digits=(6,2)
6 est le nombre total de chiffres rservs pour le nombre ottant, alors que 2 est le nombre de chiffres aprs la
virgule. Il en rsulte que le nombre de chiffres avant la virgule est au maximum de 4 dans ce cas.
2. Modiez le chier view/openacademy.xml comme suit :
<record model="ir.actions.act_window" id="session_list_action">
<field name="name">Sessions</field>
<field name="res_model">openacademy.session</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem id="session_menu" name="Sessions" parent="openacademy_menu"
action="session_list_action" />
Champs relationnels
Attributs commun supports par les champs relationnels
domain: restriction optionnelle sous la forme darguments pour la mthode search (voir search())
many2one(obj, ondelete=set null,...) (50) : Relation vers un objet parent (en utilisant une cl trangre)
obj: _name de lobjet de destination (requis)
ondelete: gestion de la suppression, e.g. set null, cascade, restrict voir la documentation
de PostgreSQL
one2many(obj, eld_id, ...) (55) : Relation virtuelle vers de multiples objets (inverse du many2one)
56
obj: _name de lobjet de destination (requis)
eld_id: nom du champ du many2one inverse, i.e. la cl trangre correspondante (requis)
many2many(obj, rel, eld1, eld2, ...) (56) : Relation multiple bi-directionnelle entre des objets
obj: _name de lobjet de destination (requis)
rel: table de relation utiliser (requis)
eld1: nom du champ dans la table de relation enregistrant lid de lobjet courant (requis)
eld2: nom du champ dans la table de relation enregistrant lid de lobjet cible (requis)
Exercice 2 - Relations many2one, one2many
En utilisant les types de champs de lORM (one2many, many2one), modiez les classes Course, Session et
Attendee an de reter leurs relations avec dautres objets, dnies comme suit :
1. Modiez les classes comme suit :
Classe Course :
class Course(osv.osv):
_name = openacademy.course
_description = OpenAcademy Course
_columns = {
name: fields.char(Course Title, 128, required=True),
responsible_id: fields.many2one(res.users, string=Responsible,ondelete=set null),
description: fields.text(Description),
session_ids: fields.one2many(openacademy.session, course_id, Session),
}
Course()
Classe Session :
class Session(osv.osv):
_name = openacademy.session
_description = OpenAcademy Session
_columns = {
name: fields.char(Session Title, 128, required=True),
start_date: fields.date(Start Date),
duration: fields.float(Duration, digits=(16,2), help="Duration in days"),
seats:fields.integer(Seats number
attendee_ids: fields.one2many(openacademy.attendee,
session_id, Attendees, ),
57
instructor_id: fields.many2one(res.partner, Instructor),
course_id:fields.many2one(openacademy.course, Course,
required=True, ondelete=cascade),),
}
Session()
Classe Attendee :
class Attendee(osv.osv):
_name = openacademy.attendee
_rec_name = partner_id
_columns = {
partner_id: fields.many2one(res.partner,Partner,required=True,
ondelete="cascade"),
session_id: fields.many2one(openacademy.session,Session,
required=True,
ondelete="cascade"),
}
Attendee()
Note: one2many, many2one
La dnition dun champ one2many requiert que le champ many2one correspondant soit dnis dans la classe
vise. Ce nom de champ many2one est donn en second argument du champ one2many eld (ici, course_id).
Exercice 3 - Modiez les vues
Modiez les vues liste et formulaire de lobjet Course et crez les vues pour lobjet Session. Les donnes
afches pour lobjet Course :
Dans la vue liste, le nom du cours et le responsable de ce cours;
Dans la vue formulaire, le nom et le responsable en haut, ainsi que la description du cours dans un
onglet et les sessions lies dans un deuxime onglet.
Pour lobjet Session :
Dans la vue liste, le nom de la session et les cours lis;
Dans la vue formulaire, tous les champs de lobjet Session.
Le nombre de donnes afcher tant important, essayez dorganiser les vues formulaires de telle sorte que
linformation quelles contiennent parasse claire.
1. Modiez les vues de lobjet Course :
<!-- ======= COURSE ====== -->
<record model="ir.ui.view" id="course_tree_view">
<field name="name">course.tree</field>
<field name="model">openacademy.course</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Course Tree">
<field name="name"/>
<field name="responsible_id"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="course_form_view">
<field name="name">course.form</field>
<field name="model">openacademy.course</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Course Form">
58
<field name="name" />
/+++
<field name="responsible_id" />
+++/
<notebook colspan="4">
<page string="Description">
<field name="description" nolabel="1" colspan="4" />
</page>
/+++
<page string="Sessions">
<field name="session_ids" nolabel="1" colspan="4"
mode="tree,form">
<tree string="Registered sessions">
<field name="name"/>
<field name="instructor_id"/>
</tree>
<form string="Registered sessions">
<field name="name"/>
<field name="instructor_id"/>
</form>
</field>
</page>
+++/
</notebook>
</form>
</field>
</record>
Note: Cacher des champs
Dans lexemple ci-dessus, si la vue formulaire du champ session_ids navait pas t personnalise pour ne montrer
que le nom et le responsable de la session, le champ course_id (ainsi que les autres champs de lobjet session)
seraient apparus et auraient t requis. Cependant, quelle que soit la valeur saisie dans le champ course_id, elle
aurait t ignore quand la session aurait t enregistre et remplace par la valeur du course_id de linstance
courante de lobjet Course.
2. Crez les vues de lobjet Session :
<!-- ======= SESSION ====== -->
<record model="ir.ui.view" id="session_tree_view">
<field name="name">session.tree</field>
<field name="model">openacademy.session</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Session Tree">
<field name="name"/>
<field name="course_id"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="session_form_view">
<field name="name">session.form</field>
<field name="model">openacademy.session</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Session Form">
<field name="name" />
<field name="instructor_id" />
<field name="course_id"/>
<field name="seats"/>
<field name="start_date"/>
<field name="duration"/>
59
<field name="attendee_ids" colspan="4" nolabel="1" mode="tree,form">
<form string="Attendees">
<field name="name"/>
<field name="partner_id"/>
</form>
<tree string="Attendees" editable="bottom">
<field name="name"/>
<field name="partner_id"/>
</tree>
</field>
</form>
</field>
</record>
Note: colspan
Par dfaut, la vue est spare en 4 colonnes
3. Nous pouvons amliorer la vue formulaire des sessions pour une meilleure lisibilit :
<record model="ir.ui.view" id="session_form_view">
<field name="name">session.form</field>
<field name="model">openacademy.session</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Session Form">
<group colspan="2" col="2">
<separator string="General" colspan="2"/>
<field name="name" />
<field name="instructor_id" />
<field name="course_id"/>
<field name="seats"/>
</group>
<group colspan="2" col="2">
<separator string="Schedule" colspan="2"/>
<field name="start_date"/>
<field name="duration"/>
</group>
<separator string="Attendees" colspan="4"/>
<field name="attendee_ids" colspan="4" nolabel="1" mode="tree,form">
<form string="Attendees">
<field name="partner_id"/>
</form>
<tree string="Attendees" editable="bottom">
<field name="partner_id"/>
</tree>
</field>
</form>
</field>
</record>
Note: Orientation
Ici, les groupes apparassent en deux colonnes; nous aurions p les afcher sur deux lignes en mettant de colspan
des groupes 4 ou en utilisant la balise <newline/>.
60
14.5 Hritage
Mcanismes dhritage
Attributs pr-dnis pour les objets mtiers
_inherit _name de lobjet mtier parent (pour lhritage simple)
_inherits pour lhritage multiple / : dictionnaire faisant correspondre le _name de lobjet
mtier parent au nom des champs correspondant aux cls trangres utiliser
Hritage des vues
Les vues existantes doivent tre modies travers des vues hrites, jamais directement. Une vue hrite
rfrence sa vue parente en utilisant le champ inherit_id, et doit ajouter ou modier des lments existants dans
cette vue en les rfrenant par des expressions XPath, en spciant la position approprie.
position
inside: plac dans la partie corre-
spondante (dfaut)
before: plac avant la partie cor-
respondante
replace: remplace la partie corre-
spondante
after: plac aprs la partie corre-
spondante
Tip: La rfrence XPath peut tre trouve www.w3.org/TR/xpath
<!-- improved idea categories list -->
<record id="idea_category_list2" model="ir.ui.view">
<field name="name">id.category.list2</field>
<field name="model">ir.ui.view</field>
<field name="inherit_id" ref="id_category_list"/>
<field name="arch" type="xml">
<xpath expr="/tree/field[@name=description]" position="after">
<field name="idea_ids" string="Number of ideas"/>
</xpath>
</field>
</record>
61
Exercice 1 - Ajouter un mcanisme dhritage
En utilisant lhritage de classe, crez une classe Partner qui modie la classe Partner existante, ajoutant
un champ boolen is_instructor, et la liste des sessions o ce partenaire sera prsent. En utilisant lhritage
des vues, modiez la vue formulaire existante an dafcher les nouveaux champs.
1. Crez un chier partner.py sous le projet OpenAcademy. Crez la classe suivante :
# -
*
- coding: utf-8 -
*
-
##############################################################################
#
# OpenERP, Open Source Enterprise Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from osv import osv,fields
class Partner(osv.osv):
Inherited res.partner
_inherit = res.partner
_columns = {
instructor : fields.boolean(Instructor),
session_ids: fields.many2many(openacademy.session,
openacademy_attendee,
partner_id,session_id,Sessions)
}
Partner()
Note: many2many
La table de relation que nous utilisons ici est openacademy_attendee, car il a dj cr une relation many-to-
many entre les partenaires et les sessions. Cependant, nous aurions p dnir un autre nom et lORM aurait
automatiquement cr une nouvelle table de relation.
2. Dans le chier __init__.py, ajoutez la ligne suivante :
import partner
3. Crez un chier partner_view.xml sous le projet OpenAcademy. Crez les vues hrites suivantes :
<!-- Add instructor field to existing view -->
<record model="ir.ui.view" id="partner_instructor_form_view">
<field name="name">partner.instructor.name</field>
<field name="model">res.partner</field>
<field name="type">form</field>
<field name="inherit_id" ref="base.view_partner_form" />
<field name="arch" type="xml">
<field name="supplier" position="after">
62
<field name="instructor"/>
</field>
</record>
Note: position=after
Les lments placs lintrieur dune balise eld ayant un attribut position=after seront afchs dans la vue
aprs le champ identi par la valeur de lattribut name du champ parent. Si il y a plus dun lment, ils seront
afchs dans lordre inverse de leur apparition dans le code XML.
<!-- Add instructor field to existing view -->
<record model="ir.ui.view" id="partner_instructor_form_view">
<field name="name">partner.instructor.name</field>
<field name="model">res.partner</field>
<field name="type">form</field>
<field name="inherit_id" ref="base.view_partner_form" />
<field name="arch" type="xml">
<field name="supplier" position="after">
<field name="instructor"/>
</field>
<xpath expr="/form/notebook/page[@string=Notes]" position="after">
<page string="Sessions">
<field name="session_ids" nolabel="1" colspan="4"/>
</page>
</xpath>
</field>
</record>
Exercice 2 - domain
Ajoutez un mcanisme la vue formulaire des Session an de permettre lutilisateur de choisir linstructeur
seulement parmi les partenaires dont le champ Instructeur est Vrai.
Vous pouvez soit : 1. Modier la classe Session comme suit :
class Session(osv.osv):
_name = openacademy.session
_description = OpenAcademy Session
_columns = {
name: fields.char(Session Title, 128, required=True),
start_date: fields.date(Start Date),
duration: fields.float(Duration, digits=(16,2), help="Duration in days"),
seats:fields.integer(Seats number),
attendee_ids: fields.one2many(openacademy.attendee,
session_id, Attendees, ),
instructor_id: fields.many2one(res.partner, Instructor,
domain=[(instructor,=,True)]),
course_id:fields.many2one(openacademy.course, Course,
required=True, ondelete=cascade),
}
Session()
2. Ou modier la vue formulaire des Session comme suit :
...
<group colspan="2" col="2">
<separator string="General" colspan="2"/>
<field name="name" />
<field name="instructor_id" domain="[(instructor,=,True)]"/>
<field name="course_id"/>
63
<field name="seats"/>
</group>
...
Exercice 3 - domain
Nous dcidons maintenant de crer de nouvelles catgories de partenaires : Professeur/Professeur Niveau 1
and Professeur/Professeur Niveau 2. Modiez le domaine dni prcdemment pour autoriser lutilisateur
choisir linstructeur parmi les partenaires dont le champ Instructeur est Vrai ou ceux qui appartiennent
lune des catgories que nous avons dnies.
1. Modiez la classe Session comme suit :
class Session(osv.osv):
_name = openacademy.session
_description = OpenAcademy Session
_columns = {
name: fields.char(Session Title, 128, required=True),
start_date: fields.date(Start Date),
duration: fields.float(Duration, digits=(16,2), help="Duration in days"),
seats:fields.integer(Seats number),
attendee_ids: fields.one2many(openacademy.attendee,
session_id, Attendees, ),
instructor_id: fields.many2one(res.partner, Instructor,
domain=[|,(instructor,=,True),
(category_id.name,
in,
(Teacher Level 1,Teacher Level 2))
]
),
course_id:fields.many2one(openacademy.course, Course,
required=True, ondelete=cascade),
}
Session()
Note: Toutefois, il nest pas possible dappliquer ce domaine la vue des sessions car les domaines dans les
vues sont reprsents comme des tuples de trois lments reprsentants les conditions, et que loprateur logique
entre eux est ncessairement un et.
14.6 Mthodes de lORM
Champs fonctionnels
function(fnct, arg=None, fnct_inv=None, fnct_inv_arg=None, type=oat, fnct_search=None, obj=None,
method=False, store=False, multi=False, ...) : Functional eld simulating a real eld, computed rather than
stored
fnct [fonction pour calculer la valeur du champ (requis)]
def fnct(self, cr, uid, ids, eld_name, arg, context) retourne un dictionnaire { idsvaleurs } avec
des valeurs du type type
fnct_inv [fonction utilise pour crire une valeur dans ce champ]
def fnct_inv(obj, cr, uid, id, name, value, fnct_inv_arg, context)
type : type du champ simul (nimporte quel type part function)
fnct_search [fonction utilise pour effectuer une recherche sur ce champ]
64
def fnct_search(obj, cr, uid, obj, name, args) retourne une liste de tuples pour le search(), e.g.
[(id,in,[1,3,5])]
obj : _name model du champ simul si cest un champ relation
store, multi : mcanismes doptimisation (voir usage dans la section Performances)
related(f1, f2, ..., type=oat, ...) [Champ raccourci quivalent parcourir des relations chaines]
f1,f2,... : champs lis pour atteindre la cible (f1 requis) (51)
type : type du champ cible
property(obj, type=oat, view_load=None, group_name=None, ...) [Attribut dynamique avec des droits
daccs spciques]
obj : objet (requis)
type : type du champ quivalent
Exercice 1 - Champs fonctionnels
Ajoutez un champ fonctionnel la class Session, qui contient le pourcentage de places restantes dans une
session. Afchez ce pourcentage dans les vues liste et formulaire des sessions. Une fois ceci fait, essayez de
lafcher sous la forme dune barre de progression.
1. Dans le chier openacademy.py, modiez la classe Session comme suit :
class Session(osv.osv):
_name = openacademy.session
_description = OpenAcademy Session
def _get_remaining_seats_percent(self,seats,attendee_list):
return seats and ((100.0
*
(seats - len(attendee_list)))/ seats) or 0
def _remaining_seats_percent(self,cr,uid,ids,field,arg,context=None):
#count the percentage of remaining seats
sessions = self.browse(cr,uid,ids,context=context)
result = {}
for session in sessions :
result[session.id] = self._get_remaining_seats_percent(session.seats,
session.attendee_ids)
return result
_columns = {
name: fields.char(Session Title, 128, required=True),
start_date: fields.date(Start Date),
duration: fields.float(Duration, digits=(16,2), help="Duration in days"),
seats:fields.integer(Seats number),
attendee_ids: fields.one2many(openacademy.attendee,
session_id, Attendees,),
remaining_seats_percent:fields.function(_remaining_seats_percent,
method=True,type=float,
string=Remaining seats),
instructor_id: fields.many2one(res.partner, Instructor,
domain=[|,(instructor,=,True),
(category_id.name,
in,
(Teacher Level 1,Teacher Level 2))
]
),
course_id:fields.many2one(openacademy.course, Course, required=True),
}
2. Dans le chier openacademy_view.xml, modiez la vue des sessions comme suit :
65
<!-- ======= SESSION ====== -->
<record model="ir.ui.view" id="session_tree_view">
<field name="name">session.tree</field>
<field name="model">openacademy.session</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Session Tree">
<field name="name"/>
<field name="course_id"/>
<field name="remaining_seats_percent" widget="progressbar"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="session_form_view">
...
<form string="Session Form">
<notebook colspan="4">
<page string="Information">
<group colspan="2" col="2">
<separator string="General" colspan="2"/>
<field name="name" />
<field name="instructor_id" />
<field name="course_id"/>
<field name="seats"/>
<field name="remaining_seats_percent"
widget="progressbar"/>
Exercice 2 - Mthodes Onchange
Modiez la vue formulaire ainsi que la classe reprsentant les sessions de telle sorte que le pourcentage de
places restantes se rafrachisse lorsque le nombre de places ou le nombre de stagiaires change, sans avoir
enregistrer les modications.
1. Modiez les champs attendee_ids et seats de la vue des sessions en leur ajoutant un attribut on_change,
comme suit :
<field name="seats" on_change="onchange_remaining_seats(seats,attendee_ids)">
<field name="attendee_ids" colspan="4" nolabel="1"
on_change="onchange_remaining_seats(seats,attendee_ids)">
2. Modiez la classe des Sessions en y ajoutant la mthode suivante :
def onchange_remaining_seats(self,cr,uid,ids,seats,attendee_ids):
return {
value:{
remaining_seats_percent:
self._get_remaining_seats_percent(seats,
attendee_ids)
}
Exercice 3 - warning
Modiez cette mthode onchange pour lever un avertissement lorsque le nombre de places est infrieur 0.
66
def onchange_remaining_seats(self,cr,uid,ids,seats,attendee_ids):
res={
value:{
remaining_seats_percent:
self._get_remaining_seats_percent(seats,
attendee_ids)
}
if seats < 0:
res[warning]={
title: Warning,
message: You cannot have negative seats,
}
return res
Attributs osv.osv pr-dnis pour les objets mtier
_constraints liste de tuples dnissant les contraintes Python, de la forme (fonc_name, message,
champs).
_sql_constraints liste de tuples dnissant les contraintes SQL, de la forme (nom, sql_def, message).
Exercice 4 - Ajouter des contraintes
Ajoutez une containte qui contrle que la description et lintitul dun cours ne sont pas les mmes.
#Check whether the course title and the course description are not the same
def _check_description(self,cr,uid,ids,context=None):
courses = self.browse(cr,uid,ids,context=context)
check = True
for course in courses:
#print course.description==course.name
if course.name==course.description:
return False
return check
_constraints = [(_check_description, Please use a different description,
[name,description])]
Exercice 5 - Ajouter une contrainte SQL
Ajoutez une contrainte SQL pour contrler quun cours a un nom unique.
#Check that the course title has an unique name
_sql_constraints = [(unique_name, unique(name),Course Title must be unique)]
Exercice 6 - Ajouter une option de duplication
Depuis que nous avons ajout une contrainte an que le nom dun cours soit unique, il nest plus possible
dutiliser la fonction dupliquer (Formulaire > Dupliquer). R-implmenter votre propre mthode copy
qui permet de dupliquer un objet Cours, en changeant le nom original en Copie de [nom original].
Ajoutez la mthode suivante dans la classe Course :
#Allow to make a duplicate Course
def copy(self,cr,uid,id,defaults,context=None):
previous_name = self.browse(cr,uid,id,context=context).name
new_name= Copy of %s % previous_name
list=self.search(cr, uid, [(name,like,new_name)],context=context)
67
if len(list)>0:
new_name=%s (%s) % (new_name,len(list)+1)
defaults[name]=new_name
return super(Course,self).copy(cr,uid,id,defaults,context=context)
Exercice 7 - Objets actifs Valeurs par dfaut
Dnissez la valeur par dfaut du champ start_date la date du jour. Ajoutez un champ active dans la classe
Session et xez la session comme tant active par dfaut.
Dans le chier openacademy.py, dans la classe Session :
_columns = {
...
course_id: fields.many2one(openacademy.course, Course,
required=True, ondelete=cascade),
active: fields.boolean(Active),
...
#Set the default values for the specified fields
_defaults = {
start_date: lambda
*
a : time.strftime(%Y-%m-%d),
active:True,
}
Note: time.strftime(format[, t])
Convertit un tuple ou une struct_time reprsentant un temps retourn par gmtime() ou localtime() en une chane
de caractres dont le format est spci dans largument format. Si t nest pas fourni, la date courante comme
retourne par localtime() est utilise.
Note: lambda *a
Attention ! Si la fonction anonyme lambda *a nest pas utilise, time.strftime(format[, t]) nest valu quune seule
fois au dmarrage du serveur. An dvaluer la date courante chaque fois quune session est cre, utilisez la
fonction lambda !
Note: Objets inactifs
Les objets pour lesquels le champ active est x False ne sont pas visibles dans OpenERP.
14.7 Vues avances
Liste & Arbre
Les vues Liste contiennent des lments eld, sont cres avec le type tree et ont un lment <tree> parent.
<tree string="Idea Categories" toolbar="1" colors="blue:state==draft">
<field name="name"/>
<field name="state"/>
</tree>
Exercice 1 - Coloration de liste
Modiez la vue liste des Sessions de telle manire que les sessions qui ont dur moins de 5 jours soient en
bleu et celles qui ont dur plus de 15 jours soient en rouge.
68
Modiez la vue liste des Sessions comme suit :
<tree string="Session Tree" colors="#00ff00:duration&lt;5;red:duration>15">
<field name="name"/>
<field name="course_id"/>
<field name="duration" invisible="1"/>
<field name="remaining_seats_percent" widget="progressbar"/>
</tree>
Note: duration champ Attention ! Si le champ duration nest pas dclar dans la vue, le client naura pas
conscience de son existence. Cela produira une erreur.
Calendriers
Vues utilises pour afcher des champs date en tant quvnements dans un calendrier (lment parent <calen-
dar>).
Attributs
color: nom du champ pour la segmentation par couleurs
date_start: nom du champ contenant la date de dbut de lvnement
day_length: longueur en heures dune journe du calendrier (dfaut: 8)
date_stop: nom du champ contenant la date de n de lvnement OU
date_delay: nom du champ contenant la dure de lvnement
lments autoriss eld (pour dnir le libell de chaque vnement du calendrier)
<calendar string="Ideas" date_start="invent_date" color="inventor_id">
<field name="name"/>
</calendar>
Exercice 2 - Vue Calendrier
Ajoutez une vue Calendrier lobjet Session autorisant lutilisateur voir les vnements associs
lOpen Academy.
1. Ajouter une vue Calendrier lobjet Session
<record model="ir.ui.view" id="session_calendar_view">
<field name="name">session.calendar</field>
<field name="model">openacademy.session</field>
<field name="type">calendar</field>
<field name="arch" type="xml">
<calendar string="Session Calendar"
date_start="start_date"
date_delay="duration"
day_length="1"
color="instructor_id">
<field name="name"/>
</calendar>
</field>
</record>
2. Mettez jour la liste des actions de la vue Session
<record model="ir.actions.act_window" id="session_list_action">
<field name="name">Session</field>
<field name="res_model">openacademy.session</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form,calendar</field>
</record>
69
Vues de Recherche
Les vues de Recherche sont utilises pour personnaliser le bandeau de recherche situ en haut des vues Listes,
sont dclares avec le type search et ont un lment parent <search>. Aprs avoir dni la vue de recherche avec
un id unique, ajoutez-la laction ouvrant la vue liste en utilisant le champ search_view_id de laction.
lments autoriss eld, group, separator, label, search, lter, newline, properties
lter : permet de dnir des boutons pour ltrer dans le domaine
ajouter un attribut contextuel aux champs cre des widgets qui modient le
contexte de recherche (utile pour des champs sensibles au contexte, e.g. prix
dpendants de listes de prix)
Exercice 3 - Vues de recherche
Ajoutez une vue de recherche contenant : 1) un champ pour rechercher des cours bas sur leur nom et
2) un bouton pour lter les cours pour lesquels lutilisateur courant est le respondable. Mettre ce dernier
slectionn par dfaut.
1. Ajoutez la vue suivante :
<record model="ir.ui.view" id="course_search_view">
<field name="name">course.search</field>
<field name="model">openacademy.course</field>
<field name="type">search</field>
<field name="arch" type="xml">
<search string="Session Search">
<filter string="My Courses" icon="terp-partner"
name="my_courses"
domain="[(responsible_id,=,uid)]"
help="My own ideas" />
<field name="name"/>
</search>
</field>
</record>
2. Modiez laction :
<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="search_view_id" ref="course_search_view"/>
<field name="context">{search_default_my_courses:1}</field>
</record>
3. Modiez la classe Course :
_columns = {
name: fields.char(Course Title, 128, required=True),
responsible_id: fields.many2one(res.users, string=Responsible,
select=True),
Diagrammes de Gantt
Graphique en barres typiquement utilis pour afcher le planning dun projet (lment parent <gantt>).
70
Attributs same as <calendar>
lments autoriss
eld, level
level : utilis pour dnir les niveaux dans le diagramme de Gantt avec le
champ utilis comme libell pour le sous-niveau
<gantt string="Ideas" date_start="invent_date" color="inventor_id">
<level object="idea.idea" link="id" domain="[]">
<field name="inventor_id"/>
</level>
</gantt>
Exercice 4 - Diagramme de Gantt
Ajouter un diagramme de Gantt permettant lutilisateur de voir les sessions planies lies au module Open
Academy. Les sessions devront tre groupes par formateur.
Ajoutez la vue suivante (noubliez pas dajouter cette vue gantt dans laction de lobjet Session) :
<record model="ir.ui.view" id="session_gantt">
<field name="name">session.gantt</field>
<field name="model">openacademy.session</field>
<field name="type">gantt</field>
<field name="arch" type="xml">
<gantt string="Session Gantt" date_start="start_date"
date_delay="duration" day_length="1" color="course_id">
<level object="res.partner" link="instructor_id">
<field name="name"/>
</level>
</gantt>
</field>
</record>
Graphiques
Vues utilises pour afcher des graphiques statistiques (lment parent <graph>).
Attributs
type: type de graphique : bar, pie (par dfaut)
orientation: horizontal, vertical
lments autoriss
eld, avec un comportement spcique :
le premier champ de la vue sera laxe X, le deuxime laxe Y, le troisime
laxe Z
2 champs sont requis, le troisime est optionnel
lattribut group dnit le champ GROUP BY (affect 1)
lattribut operator permet de dnir quel oprateur daggrgation utiliser
sur les autres champs lorsquun champ est group (+,*,**,min,max)
<graph string="Total idea score by Inventor" type="bar">
<field name="inventor_id" />
<field name="score" operator="+"/>
</graph>
71
Exercice 5 - Vue graphique
Ajoutez un graphique qui afche, pour chaque cours, le nombre de participants sous la forme dun graphique
barres. Vous pouvez le crer soit pour lobjet Course, soit pour lobjet Session.
Pour lobjet Session
1. Tout dabord, nous avons besoin dajouter un champ de type function lobjet Session :
attendee_count: fields.function(_get_attendee_count,
type=integer, string=attendee Count,
method=True),
2. Ensuite, la mthode correspondante :
def _get_attendee_count(self, cr, uid, ids, name, args, context=None):
res = {}
for session in self.browse(cr, uid, ids, context=context):
res[session.id] = len(session.attendee_ids)
return res
3. Et nalement, crer la vue dans le chier des vues de openacademy :
<record model="ir.ui.view" id="openacademy_session_graph_view">
<field name="name">openacademy.session.graph</field>
<field name="model">openacademy.session</field>
<field name="type">graph</field>
<field name="arch" type="xml">
<graph string="Participations by Courses" type="bar">
<field name="course_id"/>
<field name="attendee_count" operator="+"/>
</graph>
</field>
</record>
Pour lobjet Course
1. Tout dabord, nous avons besoin dajouter un champ de type function lobjet Session :
attendee_count: fields.function(_get_attendee_count,
type=integer, string=attendee Count,
method=True),
2. Ensuite, la mthode correspondante :
def _get_attendee_count(self, cr, uid, ids, name, args, context=None):
res = {}
for course in self.browse(cr, uid, ids, context=context):
num=0
for session in course.session_ids:
num+=len(session.attendee_ids)
res[course.id] = num
return res
3. Et nalement, crer la vue dans le chier des vues de openacademy :
<record model="ir.ui.view" id="openacademy_course_graph_view">
<field name="name">openacademy.course.graph</field>
<field name="model">openacademy.course</field>
<field name="type">graph</field>
<field name="arch" type="xml">
<graph string="Participations by Courses" type="bar">
<field name="name"/>
<field name="attendee_count" operator="+"/>
</graph>
72
</field>
</record>
14.8 Workows
Les workows sont des modles associs aux objets mtiers dcrivant la dynamique de la socit. Les workows
sont aussi utiliss pour suivre des processus qui voluent avec le temps.
Exercice 1 - Workow statique
Crez un attribut state qui sera utilis pour dnir un workow pour lobjet Session. Une session peut
avoir trois tats : Draft (dfaut), Conrmed et Done. Ajoutez un champ (en lecture seule) an de visualiser
ltat et des boutons pour changer dtat dans la vue formulaire des Sessions. Les transitions valides sont :
Draft -> Conrmed
Conrmed -> Draft
Conrmed -> Done
Done -> Draft
1. Ajouter un nouvel attribut dans la classe Session du chier openacademy.py :
state:fields.selection([(draft,Draft),(confirmed,Confirmed),
(done,Done)],Status,readonly=True,
required=True),
2. Dnissez 3 nouvelles mthodes dans la classe Session du chier openacademy.py :
def action_draft(self,cr,uid,ids,context=None):
#set to "draft" state
return self.write(cr,uid,ids,{state:draft},context=context)
def action_confirm(self,cr,uid,ids,context=None):
#set to "confirmed" state
return self.write(cr,uid,ids,{state:confirmed},context=context)
def action_done(self,cr,uid,ids,context=None):
#set to "done" state
return self.write(cr,uid,ids,{state:done},context=context)
3. Ajouter la valeur par dfaut pour le nouveau champ :
#Set the default values for the specified fields
_defaults = {
start_date: lambda
*
a : time.strftime(%Y-%m-%d),
active:True,
state:draft
}
4. Dnissez 3 nouveaux boutons dans la vue formulaire des Sessions, chacun appelant la mthode corre-
spondante :
...
<separator string="Attendees" colspan="4"/>
<field name="attendee_ids" colspan="4" nolabel="1" mode="tree,form"
on_change="onchange_remaining_seats(seats,attendee_ids)">
<form string="Attendee">
<field name="partner_id"/>
</form>
<tree string="Attendees" editable="bottom">
<field name="partner_id"/>
</tree>
73
</field>
<field name="state"/>
<group colspan="2" col="4">
<button string="Confirm" type="object"
name="action_confirm"
states="draft" />
<button string="Mark as done" type="object"
name="action_done"
states="confirmed" />
<button string="Reset to draft" type="object"
name="action_draft"
states="confirmed,done" />
</group>
</form>
</field>
</record>
Une commande gnrant une facture et un bon dexpdition est un exemple de workow utilis dans OpenERP.
Les workows peuvent tre associs nimporte quel objet dans OpenERP et sont entirement paramtrables. Les
workows sont utiliss pour structurer et grer les cycles de vies des objets mtiers ou des documents, et dnir
des transitions, des dclencheurs, etc. avec des outils graphiques. Les workows, les activits (noeuds ou actions)
et les transitions (conditions) sont dclars, comme dhabitude, dans des enregistrements XML. Les jetons qui
naviguent dans les workows sont nomms workitems.
Exercice 2 - diteur dynamique de workow
En utilisant lditeur de workow, crez le mme workow que celui dni prcdemment pour lobjet
Session. Transformez la vue formulaire des Sessions de telle sorte que les boutons changent ltat dans le
workow.
Note: Workow on create Un workow associ une session est cr lors de la cration de cette session.
Par consquent, il ny a pas dinstances du workow associes aux instances des sessions cres avant que lon
dnisse le workow.
1. Crez le workowen utilisant le client web (Administration > Paramtrage > Processus > Processus) et crez
un nouveau workow. Passez en vue diagramme et ajoutez les noeuds et les transitions. Une transition doit
tre associe au signal correspondant, et chaque activit (= noeud) doit appeler une fonction modiant ltat
de la session, en accord avec ltat dans le workow.
2. Modiez les boutons prcdemment crs :
<group colspan="2" col="4">
<button string="Confirm" type="workflow"
name="signal_confirm"
states="draft" />
74
<button string="Mark as done" type="workflow"
name="signal_done"
states="confirmed" />
<button string="Reset to draft" type="workflow"
name="signal_draft"
states="confirmed,done" />
</group>
3. Si la fonction dans lactivit Draft est code, vous pouvez mme supprimer la valeur par dfaut de ltat
dans la classe Session.
Note: Instances de workow Pour contrler que les instances du workow sont effectivement cres lorsquune
session est cre, vous pouvez aller dans le menu Administration > Paramtrage > Objets bas niveau > Processus
> Instances. Cependant, pour pouvoir voir ce menu Objets bas niveau, vous devez vous ajouter (Admin) dans le
groupe Useability > No One.
Note: Workow on create Un workow associ une session est cr pendant la cration de cette session.
Par consquent, il ny a pas dinstances du workow associes aux instances des sessions cres avant que lon
dnisse le workow.
Exercice 3 - Server actions
Crez des server actions et modiez le prcdent workow pour re-crer le mme comportement que
prcdemment, mais sans utiliser les mthodes Python de la classe Session.
1.
Exercice 4 - Workows en XML
Installez le module base_module_record. Utilisez-le pour exporter le workow cr dans lditeur de work-
ow dans un chier XML que vous pouvez incorporer dans votre module.
1. Aprs avoir install le module, allez dans le menu Administration > Paramtrage > Cration de module >
Exporter le paramtrage en donnes
2. Fixez le champ from date au moment juste avant que vous avez cr le workow.
3. Slectionnez les objets Workow, Workow activity et workow transition et enregistrez-les.
4. Copiez/Collez le XML dans un chier workow.xml sous un dossier workow de votre module.
Noubliez pas de mettre jour le chier __openerp__.py :
update_xml: [
...
"workflow/workflow.xml",
...
14.9 Scurit
Les mcanismes de contrle daccs doivent tre combins pour atteindre une politique de scurit cohrente.
Mcanismes de contrle daccs bass sur les groupes
Les groupes sont crs comme des enregistrements normaux sur le modle res.groups et laccs aux menus via la
dnition de ces derniers. Cependant mme sans menu, les objets peuvent rester accessible indirectement, cest
pourquoi des vritables permissions par objet (create,read,write,unlink) doivent tre dnies pour les groupes.
Elles sont gnralement insres via des chiers CSV prsents dans les modules. Il est galement possible de
restreindre les accs certains champs ou objets en utilisant lattribut groups sur les champs.
75
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
Exercice 1 - Ajouter des contrles daccs depuis linterface de OpenERP
Crez un nouvel utilisateur John Smith. Crez ensuite un groupe OpenAcademy / SessionRead avec les
accs en lecture sur les objets Session et Attendee.
1. Crez un nouvel utilisateur depuis le menu Administration > Utilisateurs > Utilisateurs.
2. Crez un nouveau groupe OpenAcademy / SessionRead en utilisant le menu Administration > Utilisateurs
> Groupes avec des droits daccs en lecture sur les objets Session et Attendee.
3. ditez lutilisateur John Smith et ajoutez-lui le groupe OpenAcademy / SessionRead (vous pouvez
supprimer les autres).
4. Connectez-vous en tant que John Smith et contrlez les droits daccs.
Exercice 2 - Ajouter des contrles daccs depuis des chiers de donnes dans votre module
En utilisant un chier de donnes XML, crez un groupe OpenAcademy / Manager, sans y dnir de droits
daccs pour le moment (crez simplement un groupe vide).
1. Crez un nouveau dossier security dans le rpertoire openacademy. Crez un nouveau chier
groups.xml :
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="0">
<record id="group_manager" model="res.groups">
<field name="name">OpenAcademy / Manager</field>
</record>
</data>
</openerp>
2. Mettez jour le chier __openerp__.py :
...
update_xml: [
...
"security/groups.xml",
Exercice 3 - Ajouter des contrles daccs depuis des chiers de donnes dans votre module
Utilisez un chier CSV pour ajouter les droits de lecture, criture, cration et suppression sur les objets
Course, Session et Attendees au groupe OpenAcademy / Manager. Vous pouvez aussi crer des droits
associs aucun groupe, comme un accs en lecture seule sur les objets Course et Session.
1. Dnissez un nouveau chier CSV ir.model.access.csv contenant les rgles de scurit :
"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create",
"perm_unlink"
"course_full_manager","course_full_manager","model_openacademy_course",
"group_manager", 1,1,1,1
"course_read_all","course_read_all","model_openacademy_course",,1,0,0,0
76
"session_full_all","session_full_all","model_openacademy_session",,1,1,1,1
"attendee_full_all","attendee_full_all","model_openacademy_attendee",,1,1,1,1
2. Mettez jour le chier __openerp__.py :
...
update_xml: [
...
"security/ir.model.access.csv",
14.10 Assistants
Objets wizard (osv_memory)
Les assistants dcrivent des sessions interactives tats avec lutilisateur par le biais de formulaires dynamiques.
Les assistants utilisent la persistance en mmoire osv_memory pour permettre de construires des assistants depuis
des objets mtiers et des vues normales, sans les enregistrer dans la base de donnes. Les objets en mmoire sont
crs en hritant de la classe osv.osv_memory.
Exercice 1 - Dnir la classe de lassistant
Nous voulons crer un assistant qui permettra lutilisateur de crer des stagiaires pour une session partic-
ulire, ou pour une liste de sessions en une seule fois. Tout dabord, cet assistant fonctionnera uniquement
pour une session la fois. Pour faire cela, nous crons un objet assistant (hritant de osv.osv_memory)
avec une relation many2one sur lobjet Session et une relation one2many avec un nouvel objet Attendee
(en mmoire) avec un champ name et une relation many2one vers lobjet Partner. Dnissez la classe cre-
ate_attendee_wizard et implmentez sa structure.
1. Crez un nouveau rpertoire wizard dans le projet OpenAcademy et crez un nouveau chier cre-
ate_attendee.py.
# -
*
- coding: utf-8 -
*
-
##############################################################################
#
# OpenERP, Open Source Enterprise Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from osv import osv,fields
from tools.translate import _
class attendee_memory(osv.osv_memory):
_name = openacademy.attendee.memory
_columns = {
77
name: fields.char(Name,64),
partner_id: fields.many2one(res.partner,Partner,required=True),
wiz_id:fields.many2one(openacademy.create.attendee.wizard,),
}
attendee_memory()
class create_attendee_wizard(osv.osv_memory):
_name = openacademy.create.attendee.wizard
2. Crez un nouveau chier __init__.py dans le dossier wizard :
import create_attendee
3. Mettez jour le chier __init__.py du dossier openacademy :
import wizard
Vues
Les assistants utilisent des vues normales et leurs boutons peuvent utiliser un attribut special=cancel an de
fermer la fentre de lassistant lorsquil est cliqu.
Excution dun assistant
De tels assistants sont lancs par le biais denregistrements action normaux, avec une cible spciale utilise pour
ouvrir lassistant dans une nouvelle fentre.
Exercice 2 - Rendre lassistant disponible depuis un lment du menu
Crez un lment de menu et laction ncessaire pour utiliser lassistant.
1. Dans le dossier wizard, crez un nouveau chier create_attendee_view.xml contenant llment de
menu :
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<menuitem name="Add attendee" parent="openacademy_menu"
id="create_attendee_wizard_menu"
action="create_attendee_wizard_action"/>
</data>
</openerp>
2. Crez laction create_attendee_wizard_action :
<record model="ir.actions.act_window" id="create_attendee_wizard_action">
<field name="name">Add attendee</field>
<field name="res_model">openacademy.create.attendee.wizard</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
3. Mettez jour le chier __openerp__.py sous le projet openacademy :
update_xml: [wizard/create_attendee_view.xml],
78
Exercice 3 - Personnaliser la vue formulaire
Personnalisez la vue formulaire pour afcher tous les champs de la classe.
<record model="ir.ui.view" id="create_attendee_form_view">
<field name="name">openacademy.create.attendee.wizard.form</field>
<field name="model">openacademy.create.attendee.wizard</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Add attendee" col="2">
<field name="session_id"/>
<field name="attendee_ids" mode="tree">
<tree string="Attendees" editable="bottom">
<field name="partner_id"/>
</tree>
</field>
</form>
</field>
</record>
Exercice 4 - Crer les mthodes
Crez la mthode action_add_attendee dans la classe create_attendee_wizard et ajouter un bouton dans la
vue formulaire pour lappeler. Ajoutez galement un bouton Annuler qui ferme la fentre de lassistant.
1. Ajoutez la mthode la classe create_attendee_wizard.
def action_add_attendee(self, cr, uid, ids, context=None):
wizard = self.browse(cr, uid, ids[0], context=context)
attendee_pool = self.pool.get(openacademy.attendee)
for attendee in wizard.attendee_ids:
attendee_pool.create(cr,uid,{name:attendee.name,
partner_id:attendee.partner_id.id,
session_id:wizard.session_id.id} )
return {}
Note: Deux manires de fermer la fentre dun assistant
Pour fermer la fentre la n dune mthode, vous pouvez soit retourner un dictionnaire vide return {} ou ex-
plicitement retourner la mthode close return {type: ir.actions.act_window.close,}
2. Ajoutez les boutons la vue formulaire.
<record model="ir.ui.view" id="create_attendee_form_view">
<field name="name">openacademy.create.attendee.wizard.form</field>
<field name="model">openacademy.create.attendee.wizard</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Add attendee" col="2">
<field name="session_id"/>
<field name="attendee_ids" mode="tree">
<tree string="Attendees" editable="bottom">
<field name="partner_id"/>
</tree>
</field>
/++
<button type="special" special="cancel"
string="Cancel" icon="gtk-cancel"/>
<button type="object" name="action_add_attendee"
string="Add attendees" icon="gtk-ok"
79
confirm="Are you sure you want to add those attendees?"/>
++/
</form>
</field>
</record>
Exercice 6 - Lier lassistant la barre contextuelle
Liez lassistant la barre contextuelle du modle des sessions.
Mettez jour le chier rcemment cr create_attendee_view.xml :
<act_window name="Add Attendees"
src_model="openacademy.session"
res_model="openacademy.create.attendee.wizard"
id="session_create_attendee_wizard"
view_mode="form"
key2="client_action_multi"
target="new"/>
Note: client_action_multi
Outre client_action_multi, il existe aussi les valeurs client_action_relate et client_print_multi pour lattribut key2.
Ils spcient licone afcher pour lassistant correspondant.
Exercice Supplmentaire - Assistant sur de multiples enregistrements
Rendez lassistant capable dajouter des stagiaires dans plusieurs sessions la fois.
1. Ajoutez un attribut sur le champ session_id dans la vue.
<field name="session_id" invisible="len(context.get(active_ids))>1"/>
2. Ajoutez une valeur par dfaut pour le champ session_id, an dy afcher la valeur de la session courante.
def _get_active_session(self, cr, uid, context=None):
print context
if not context:
return False
else:
return context.get(active_id)
_defaults={
session_id:_get_active_session
}
3. Modiez votre mthode pour ajouter des stagiaires plusieurs sessions.
def action_add_attendee(self, cr, uid, ids, context=None):
wizard = self.browse(cr, uid, ids[0], context=context)
if len(context.get(active_ids))>1:
session_ids=context.get(active_ids)
else:
session_ids=[wizard.session_id.id]
attendee_pool = self.pool.get(openacademy.attendee)
print(_(Hello we are in the wizard %(id)s and %(partner)s) % {id:wizard.id,partner:wizard.partner_id} )
for session_id in session_ids:
for attendee in wizard.attendee_ids:
attendee_pool.create(cr,uid,{name:attendee.name,
partner_id:attendee.partner_id.id,
80
session_id:session_id} )
return {}
Note: Modier les champs relationnels travers la mthode write
Nous aurions p dcider de crer les stagiaires depuis de champ relation vers lobjet des sessions. Pour modi-
er/supprimer/ajouter des valeurs dans un champ relationnel, vous devez utiliser une syntaxe spciale. Les dtails
sont disponibles dans les commentaires avant la classe one2many dans le chier server/bin/osv/elds.py.
14.11 Internationalisation
Chaque module peut fournir ses propres traductions dans le dossier i18n, en ayant des chiers nomms
LANGUE.po o LANGUE est le code de ce langage, ou une combinaison de la langue et le pays dans le
cas o ils diffrent (e.g. pt.po or pt_BR.po). Les traductions seront automatiquement charges par OpenERP
pour toutes les langues actives. Les dveloppeurs utiliseront toujours lAnglais en crant un module, puis ex-
porteront les termes du modules en utilisant la fonctionnalit dexport de POT gettext de OpenERP (Administra-
tion>Traductions>Exporter une traduction sans spcier de langue ) pour crer le chier template POT du module,
et ensuite en driver les chiers PO traduits. La plupart des environnements intgrs de dveloppement ont des
modes ou des plugins pour diter et merger les chiers PO/POT.
Tip: Le format GNU gettext (Portable Object) utilis par OpenERP est intgr LaunchPad, devenant ainsi une
plateforme collaborative de traduction.
|- idea/ # La racine du module
|- i18n/ # Fichiers de traduction
| - idea.pot # Fichier Template (export depuis OpenERP)
| - fr.po # Traduction Franaise
| - pt_BR.po # Traduction Portuguaise du Brsil
| (...)
Tip: Par dfaut, lexport POT dOpenERP extrait seulement les libells dans les chiers XML ou dans la dni-
tion des champs dans le code Python, mais nimporte quelle chane Python peut tre traduite de cette manire en
lencadrant par la mthode tools.translate._ method (e.g. _(Label) )
Exercice 1 - Traduire un module
Slectionnez une seconde langue pour votre installation dOpenERP. Traduisez votre module en utilisant les
fonctionnalits fournies par OpenERP.
1. Crez un dossier i18n dans le rpertoire OpenAcademy.
2. Installez la langue cible dans OpenERP (Administration > Traductions > Charger une traduction ofcielle)
3. Synchronisez les termes de lapplication depuis le menu Administration > Traductions > Termes de
lapplication > Synchroniser les traductions
4. Crez le chier template de traduction openacademy.pot en lexportant (Administration > Traductions >
Importer/Exporter > Exporter une traduction) sans spcier de langue et enregistrez-le dans le dossier i18n.
5. Crez le chier de traduction franaise (ou nimporte quelle autre langue) fr_FR.po en lexportant (Ad-
ministration > Traductions > Importer/Exporter > Exporter une traduction) en spciant une langue, et
enregistrez-le dans le dossier i18n.
6. Ouvrez le chier fr_FR.po avec poedit (ou un simple diteur de texte) et traduisez les termes.
Note: Par dfaut, lexport POT dOpenERP extrait seulement les libells dans les chiers XML ou dans la
dnition des champs dans le code Python, mais nimporte quelle chane Python peut tre traduite de cette manire
en lencadrant par la mthode tools.translate._ method (e.g. _(Label) )
7. Mettez jour le chier openacademy.py.
81
from tools.translate import _
8. Ajoutez loprateur _ l o il est ncessaire, rpter ensuite les tapes 3, 4, 5 et 6.
14.12 Rapports
Rapports imprims
Les rapports dans OpenERP peuvent tre rendus de diffrentes manires :
Rapports personnaliss: ces rapports peuvent tre directement crs depuis linterface client, pas de pro-
grammation requise. Ces rapports sont reprsents par des objets mtiers (ir.report.custom)
Rapport personnaliss de haute qualit utilisant openreport: pas de programmation requise mais il faut
crire 2 petits chiers XML :
un template qui indique les donnes sur lesquelles portera le rapport
un chier XSL : feuille de style RML
Rapports cods en dur
Modles OpenOfce Writer
Il existe plusieurs moteurs de rendu de rapports dans OpenERP pour produire des rapports depuis diffrentes
sources et dans plusieurs formats.
Expressions utilises dans OpenERP dans les modles de rapport
Predened expressions :
objects contient la liste des enregistrements imprimer
data vient de lassistant lanant le rapport
user contient lutilisateur courant (comme un browse())
time donne accs au module Python time
repeatIn(list,var,tag) repte llment parent nomm tag pour chaque objet dans la liste, rendant lobjet
disponible en tant que variable dans chaque boucle
setTag(tag1,tag2) remplace la balise RML tag1 par tag2
removeParentNode(tag) supprime llment RML parent tag
formatLang(value, digits=2, date=False, date_time=False, grouping=True, monetary=False) peut tre util-
is pour formater une date, un temps ou un montant selon la locale
setLang(lang_code) xe la langue et la locale courante pour les traductions
82
Exercice 1 - Installer le plugin OpenOfce
Installez le module report designer et ajouter le plugin OpenERP dans OpenOfce.
Installez le module base > report designer. Allez ensuite dans Administration > Paramtrage > Rapports > Con-
cepteur de Rapports et enregistrez le chier zip
Exercice 2 - Crer un nouveau rapport
Crez un rapport pour lobjet Session, afchant pour chaque session, son nom, sa date de dbut, sa dure, le
pourcentage de remplissage, le responsable ainsi que la liste des stagiaires.
[[repeatIn(objects,session)]]
[[ setLang(session.course_id.responsible_id.context_lang) ]]
Name: [[ session.name ]]
Date: [[ formatLang(session.date,date=True) ]]
Duration: [[ formatLang(session.duration,digits=2) ]]
Percentage of completion: [[ session.perc_completion, digits=2 ]]
Responsable: [[ session.responsible_id.name ]]
============================================= ====================================
Partner Signature
============================================= ====================================
[[repeatIn(session.attendee_ids,attendee)]]
-------------------------------------------------------------------------------------
[[ attendee.partner_id ]]
============================================= ====================================
Exercice 3 - RML
Exportez le rapport OpenOfce en un chier RML, ajoutez-le votre module et ajoutez une action lobjet
Session an dimprimer le rapport.
1. Crez un dossier report dans votre module et enregistrez le chier rml dedans.
2. Ajoutez un chier xml pour la claration de ce rapport dans ce dossier.
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<report id="session_report" string="Print Sessions"
model="openacademy.session" name="session.report"
rml="openacademy/report/session.rml" />
</data>
</openerp>
3. Mettez jour le chier __openerp__.py an dy ajouter une rfrence ce chier de dclaration.
Exercice 4 - RML
Amliorez votre rapport. Empchez la ligne start date dapparatre dans le rapport si aucune valeur ne lui
est associe, et afcher le pourcentage de siges restants en rouge si celui-ci est infrieur 10.
1. Enlever la ligne date de dbut
<para style="Standard">Duration: [[ session.duration and formatLang(session.duration,digits=2) or (removeParentNode(para)) ]]</para>
83
2. Rglez la couleur de la police selon le pourcentage de siges restants.
<para style="Standard">Remaining seats percentage:
<font color="black"> [[session.remaining_seats_percent&lt;50 and setTag(font,font,{color:red})]]
[[session.remaining_seats_percent]]</font>
</para>
Tableaux de bord
Exercice 5 - Dnir un tableau de bord
Dnissez un tableau de bord contenant la vue graphique que vous avez cre, le calendrier des sessions et
la liste des cours (commutable en vue formulaire). Ce tableau de bord doit tre disponible depuis un menu,
et automatiquement afch dans le client web quand le menu principal OpenAcademy est slectionn.
1. Crez un chier board_session_view.xml dans votre module. Il doit contenir la vue du tableau, les actions
rfrences dans cette vue, une action pour ouvrir ce tableau de bord, ainsi quune rednition du menu
principal openacademy_menu pour lui ajouter laction douvrir le tableau de bord.
<?xml version="1.0"?>
<openerp>
<data>
<record model="ir.actions.act_window" id="act_session_graph">
<field name="res_model">openacademy.session</field>
<field name="view_type">form</field>
<field name="view_mode">graph</field>
<field name="view_id" ref="openacademy.openacademy_session_graph_view"/>
</record>
<record model="ir.actions.act_window" id="act_session_calendar">
<field name="res_model">openacademy.session</field>
<field name="view_type">form</field>
<field name="view_mode">calendar</field>
<field name="view_id" ref="openacademy.session_calendar_view"/>
</record>
<record model="ir.actions.act_window" id="act_course_list">
<field name="res_model">openacademy.course</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<record model="ir.ui.view" id="board_session_form">
<field name="name">Session Dashboard Form</field>
<field name="model">board.board</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Session Dashboard">
<hpaned>
<child1>
<action
string="Attendees by course"
name="%(act_session_graph)d"
colspan="4"
height="150"
width="510"/>
<action
string="Courses"
name="%(act_course_list)d"
colspan="4"/>
</child1>
<child2>
84
<action
string="Sessions"
name="%(act_session_calendar)d"
colspan="4"/>
</child2>
</hpaned>
</form>
</field>
</record>
<record model="ir.actions.act_window" id="open_board_session">
<field name="name">Session Dashboard</field>
<field name="res_model">board.board</field>
<field name="view_type">form</field>
<field name="view_mode">form</field>
<field name="usage">menu</field>
<field name="view_id" ref="board_session_form"/>
</record>
<menuitem id="openacademy_menu" name="OpenAcademy" action="open_board_session"/>
<menuitem id="board.menu_dashboard" name="Dashboard" sequence="0" parent="openacademy_menu"/>
<menuitem
name="Session Dashboard" parent="board.menu_dashboard"
action="open_board_session"
sequence="1"
id="menu_board_session" icon="terp-graph"
groups="base.group_sale_salesman"/>
</data>
</openerp>
2. Mettez jour le chier __openerp__.py an de rfrencer ce nouveau chier de vues.
14.13 WebServices
Le module de web-service offre une interface commune pour tous les web-services :
SOAP
XML-RPC
NET-RPC
Les objets mtiers peuvent aussi tre accds depuis le mcanisme dobjets distribus. Il peuvent tous tre modis
par les interfaces clients avec les vues contextuelles.
OpenERP est accessible depuis des interfaces XML-RPC, pour lesquelles des librairies existent dans de nombreux
langages.
Exemple Python
import xmlrpclib
# ... define HOST, PORT, DB, USER, PASS
url = http://%s:%d/xmlrpc/common % (HOST,PORT)
sock = xmlrpclib.ServerProxy(url)
uid = sock.login(DB,USER,PASS)
print "Logged in as %s (uid:%d)" % (USER,uid)
# Create a new idea
url = http://%s:%d/xmlrpc/object % (HOST,PORT)
sock = xmlrpclib.ServerProxy(url)
args = {
85
name : Another idea,
description : This is another idea of mine,
inventor_id: uid,
}
idea_id = sock.execute(DB,uid,PASS,idea.idea,create,args)
Exercice 1 - Ajouter un nouveau service au client
crivez un programme Python capable denvoyer des requtes XML-RPC un PC ayant lanc OpenERP (le
votre ou celui de votre formateur). Ce programme doit permettre dafcher toutes les sessions existantes, le
nombre de siges correspondants et de crer une nouvelle session pour un des cours. Dans ce cas, demandez
au serveur de crer les objet Session.
1. Crez un nouveau dossier xml-rpc sous le dossier openacademy. Sous ce dossier, crez un nouveau
chier test.py :
#!/usr/bin/python
# -
*
- coding: utf-8 -
*
-
##############################################################################
#
# OpenERP, Open Source Enterprise Management Solution
# Copyright (C) 2004-2010 Tiny SPRL (<http://openerp.com>).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
import xmlrpclib
HOST=192.168.0.44
PORT=8069
DB=openacademy
USER=admin
PASS=admin
url = http://%s:%d/xmlrpc/ % (HOST,PORT)
common_proxy = xmlrpclib.ServerProxy(url+common)
object_proxy = xmlrpclib.ServerProxy(url+object)
def execute(
*
args):
return object_proxy.execute(DB,uid,PASS,
*
args)
# 1. Login
uid = common_proxy.login(DB,USER,PASS)
print "Logged in as %s (uid:%d)" % (USER,uid)
# 2. Read the session
session_ids = execute(openacademy.session,search,[])
sessions = execute(openacademy.session,read,session_ids, [name,seats])
for session in sessions :
86
print "Session name :%s (%s seats)" % (session[name], session[seats])
# 3.create a new session
session_id = execute(openacademy.session, create,
{name : My session,
course_id : 2, })
2. Au lieu dajouter une session un cours dont on connait lID, nous pouvons chercher ce cours par rapport
son nom.
# 3.create a new session for the "Functional" course
course_id = execute(openacademy.course, search, [(name,ilike,Functional)])[0]
session_id = execute(openacademy.session, create,
{name : My session,
course_id : course_id, })
Note: Mthodes utilisables
Depuis le XML-RPC, il est possible de crer un objet (create), rechercher des objets (search, utiliser et lire des
donnes, mettre jour des donnes et supprimer des objets (unlink)