Un module openerp est généralement composé de fichiers et repertoires suivants.
module_name/
├── module_name.py
├── module_name_view.xml
├── __init__.py
├── __openerp__.py
├── reports
├── wizards
└── workflows
init : Indique que le dossier est un package
module_name.py : Il contient les objects de votre module
module_name_view.xml : Gere les donnees via une definition d'interface (view, les menu, les interactions ...)
openerp : Decrit le module (nom , version, auteur, dependances,...)
reports : Dossier contenant les objest et fichiers lies au reporting
wizards : Dossier contenant les objets definissant les interactions client-server (voir)
workflow : Dossier contenant la definition d'un workflow (voir)
A- Un hello world
Pour notre hello world j'ai pensé à un module nous permettant d'enregistrer une famille et ses membres .
A vos terminaux !!!
Creer un dossier family dans votre espace de travail avec les fichier suivants :
1- openerp.py dont le contenu est le suivant :
{
"name":"family", # le nom du module, il apparait dans la liste des modules
"version":"1.0", # la version
"author":"Josue", # l'auteur
"website":"none", # site web
"category":"Generic Modules/Others", # category du module
"depends":["base"], # liste des modules de dependances
"description":"Simple module permettant d'enregistrer une famille est ses memebres",
"update_xml":["family_view.xml"], #liste des vue, dans notre cas family_view.xml
"demo_xml":[],
"init_xml":[],
"active":False,
"installable":True,
}
NB : Tous les modules dependent de base .
2- init.py contenant ceci :
import family
Simple importation d'un module python
3- family.py
from osv import osv, fields
class family_family(osv.osv):
_name = 'family.family'
_columns = {
'name': fields.char('Family Name',size=128),
'member_ids': fields.one2many('family.member','family_id','Members'),
}
family_family()
class family_member(osv.osv):
_name = 'family.member'
_columns = { # dictionnaire des champs de l'object
'firstname': fields.char('FirstName',size=128),
'lastname': fields.char('LastName',size=128),
'family_id': fields.many2one('family.family','Family',ondelete='cascade'),
'gender': fields.selection( # definition d'un champ de selection
[('male','Male'),
('female','Female'),
],'Gender',readonly=False,select=True),
}
# default : dictionnaire des valeurs par defaut
_defaults = {
'lastname' : lambda self, cr, uid, context : self.pool.get('family.family').browse(cr, uid, context['family_id']).name if context and 'family_id' in context else None,
'gender' : lambda *a: 'male', # "male" sera la valeur par defaut du champ "gender"
}
family_member() #instanciation de la classe , __N'oubliez jamais de le faire__
Ce fichier decrit les objects du modules et leur caracteristiques
Documentation sur l'objet osv
Documentation sur l'objet fields
explications :
_defaults['lastname'], j'ai utilisé une fonction lambda afin de permettre que le champ lastname soit automatiquement rempli en se servant du context family_id definit dans le fichier family_view.xml au sein de l'objet family. Mais cela ne se fera que dans la condition ou un membre sera crée à partir du menu(vue,interface) d'une famille.
4- family_view.xml
<?xml version="1.0" ?>
<openerp>
<data>
<menuitem id="family" name="Family" />
<!--Family-->
<record model="ir.ui.view" id="family_form"> <!-- definition d'une vuew dont l'id est "family_form"-->
<field name="name">family.form</field> <!-- nom de la vue -->
<field name="model">family.family</field> <!-- classe sur laquelle on se base pour creer la vue (une des classes de "family.py", dans notre cas "family.family")-->
<field name="type">form</field> <!--type de vue : form/tree/graph -->
<field name="arch" type="xml">
<form string="Family" > <!-- declaration d'un formulaire -->
<field name="name"/> <!-- declaration d'un champ -->
<notebook colspan="4">
<page string="Members">
<field name="member_ids" domain="[('family_id','=',active_id)]" context="{'family_id':active_id}"/> <!-- definition d'un context -->
</page>
</notebook>
</form>
</field>
</record>
<record model="ir.ui.view" id="family_tree">
<field name="name">family.tree</field>
<field name="model">family.family</field>
<field name="type">tree</field> <!--type de vue : tree, correspond a l'affichage en liste d'elements -->
<field name="arch" type="xml">
<tree string="Family" > <!-- on declare "tree" cette fois ci et non un "form"-->
<field name="name"/>
<field name="member_ids"/> <!-- declaration des champs -->
</tree>
</field>
</record>
<!-- Notez que tous les champs declarés ici sont dans family.py, sinon une erreur sera levée -->
<!--Definition d'une action -->
<record model="ir.actions.act_window" id="action_family"> <!-- le model est bien différent : "ir.actions" et non "ir.ui.view" -->
<field name="name">Family</field> <!-- nom de l'action -->
<field name="res_model">family.family</field> <!-- model sur lequel se base l'action -->
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<!-- Declaration d'un menu -->
<menuitem id="family_menu" name="Family" parent="family" action="action_family"/>
<!--
id : identifiant du menu
name : nom du menu
parent : le menu dont depend celui-ci, il sera donc un sous-menu
action : action relier au menu
-->
<!-- "action_family" correspond à l'id de l'acton déclarée pécedement -->
<!--Members-->
<record model="ir.ui.view" id="member_form">
<field name="name">member.form</field>
<field name="model">family.member</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Member" >
<field name="firstname"/>
<field name="lastname"/>
<field name="gender" />
<field name="family_id"/>
</form>
</field>
</record>
<record model="ir.ui.view" id="member_tree">
<field name="name">member.tree</field>
<field name="model">family.member</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Member" >
<field name="firstname"/>
<field name="lastname"/>
<field name="gender" />
<field name="family_id"/>
</tree>
</field>
</record>
<record model="ir.actions.act_window" id="action_member">
<field name="name">Member</field>
<field name="res_model">family.member</field>
<field name="view_type">form</field>
<field name="view_mode">tree,form</field>
</record>
<menuitem id="member_menu" name="Members" parent="family" action="action_member"/>
</data>
</openerp>